diff --git a/.env.example b/.env.example index 35ea12a88566..fbf5d0e6aa02 100644 --- a/.env.example +++ b/.env.example @@ -10,7 +10,7 @@ OPENAI_API_KEY='' # For production, you should only need one host as # fastapi serves the svelte-kit built frontend and backend from the same host and port. # To test with CORS locally, you can set something like -# CORS_ALLOW_ORIGIN='http://localhost:5173;http://localhost:8080' +# CORS_ALLOW_ORIGIN='http://localhost:5173;http://localhost:8083' CORS_ALLOW_ORIGIN='*' # For production you should set this to match the proxy configuration (127.0.0.1) @@ -19,4 +19,4 @@ FORWARDED_ALLOW_IPS='*' # DO NOT TRACK SCARF_NO_ANALYTICS=true DO_NOT_TRACK=true -ANONYMIZED_TELEMETRY=false \ No newline at end of file +ANONYMIZED_TELEMETRY=false diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 420633a0f6e9..b6fee82f2990 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -143,7 +143,7 @@ body: 3. Clone the Open WebUI repo (git clone ...). 4. Use the Docker Compose file without modifications. 5. Open browser Chrome 115.0 in incognito mode. - 6. Go to http://localhost:8080 and log in with user "test@example.com". + 6. Go to http://localhost:8083 and log in with user "test@example.com". 7. Set the language to "English" and theme to "Dark". 8. Attempt to connect to Ollama at "http://localhost:11434". 9. Observe that the error message "Connection refused" appears at the top right. diff --git a/.github/workflows/deploy-to-hf-spaces.yml b/.github/workflows/deploy-to-hf-spaces.yml index a30046af8954..1cabcaeb7694 100644 --- a/.github/workflows/deploy-to-hf-spaces.yml +++ b/.github/workflows/deploy-to-hf-spaces.yml @@ -42,7 +42,7 @@ jobs: echo "colorFrom: purple" >> temp_readme.md echo "colorTo: gray" >> temp_readme.md echo "sdk: docker" >> temp_readme.md - echo "app_port: 8080" >> temp_readme.md + echo "app_port: 8083" >> temp_readme.md echo "---" >> temp_readme.md cat README.md >> temp_readme.md mv temp_readme.md README.md diff --git a/.github/workflows/integration-test.disabled b/.github/workflows/integration-test.disabled index b248df4b5dc1..2fa23232d7f7 100644 --- a/.github/workflows/integration-test.disabled +++ b/.github/workflows/integration-test.disabled @@ -159,11 +159,11 @@ jobs: GLOBAL_LOG_LEVEL: debug run: | cd backend - uvicorn open_webui.main:app --port "8080" --forwarded-allow-ips '*' & + uvicorn open_webui.main:app --port "8083" --forwarded-allow-ips '*' & UVICORN_PID=$! # Wait up to 40 seconds for the server to start for i in {1..40}; do - curl -s http://localhost:8080/api/config > /dev/null && break + curl -s http://localhost:8083/api/config > /dev/null && break sleep 1 if [ $i -eq 40 ]; then echo "Server failed to start" diff --git a/Dockerfile b/Dockerfile index ad393338d813..d1fe096565c8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ ARG USE_PERMISSION_HARDENING=false # Tested with cu117 for CUDA 11 and cu121 for CUDA 12 (default) ARG USE_CUDA_VER=cu128 # any sentence transformer model; models to use can be found at https://huggingface.co/models?library=sentence-transformers -# Leaderboard: https://huggingface.co/spaces/mteb/leaderboard +# Leaderboard: https://huggingface.co/spaces/mteb/leaderboard # for better performance and multilangauge support use "intfloat/multilingual-e5-large" (~2.5GB) or "intfloat/multilingual-e5-base" (~1.5GB) # IMPORTANT: If you change the embedding model (sentence-transformers/all-MiniLM-L6-v2) and vice versa, you aren't able to use RAG Chat with your previous documents loaded in the WebUI! You need to re-embed them. ARG USE_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2 @@ -57,7 +57,7 @@ ARG GID ## Basis ## ENV ENV=prod \ - PORT=8080 \ + PORT=8083 \ # pass build args to the build USE_OLLAMA_DOCKER=${USE_OLLAMA} \ USE_CUDA_DOCKER=${USE_CUDA} \ @@ -167,9 +167,9 @@ COPY --chown=$UID:$GID --from=build /app/package.json /app/package.json # copy backend files COPY --chown=$UID:$GID ./backend . -EXPOSE 8080 +EXPOSE 8083 -HEALTHCHECK CMD curl --silent --fail http://localhost:${PORT:-8080}/health | jq -ne 'input.status == true' || exit 1 +HEALTHCHECK CMD curl --silent --fail http://localhost:${PORT:-8083}/health | jq -ne 'input.status == true' || exit 1 # Minimal, atomic permission hardening for OpenShift (arbitrary UID): # - Group 0 owns /app and /root diff --git a/README.md b/README.md index 52a3821aa5a4..5d846c2dd1f7 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Open WebUI can be installed using pip, the Python package installer. Before proc open-webui serve ``` -This will start the Open WebUI server, which you can access at [http://localhost:8080](http://localhost:8080) +This will start the Open WebUI server, which you can access at [http://localhost:8083](http://localhost:8083) ### Quick Start with Docker 🐳 @@ -107,7 +107,7 @@ This will start the Open WebUI server, which you can access at [http://localhost - **If Ollama is on your computer**, use this command: ```bash - docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p 3000:8083 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main ``` - **If Ollama is on a Different Server**, use this command: @@ -115,13 +115,13 @@ This will start the Open WebUI server, which you can access at [http://localhost To connect to Ollama on another server, change the `OLLAMA_BASE_URL` to the server's URL: ```bash - docker run -d -p 3000:8080 -e OLLAMA_BASE_URL=https://example.com -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p 3000:8083 -e OLLAMA_BASE_URL=https://example.com -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main ``` - **To run Open WebUI with Nvidia GPU support**, use this command: ```bash - docker run -d -p 3000:8080 --gpus all --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:cuda + docker run -d -p 3000:8083 --gpus all --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:cuda ``` ### Installation for OpenAI API Usage Only @@ -129,7 +129,7 @@ This will start the Open WebUI server, which you can access at [http://localhost - **If you're only using OpenAI API**, use this command: ```bash - docker run -d -p 3000:8080 -e OPENAI_API_KEY=your_secret_key -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main + docker run -d -p 3000:8083 -e OPENAI_API_KEY=your_secret_key -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main ``` ### Installing Open WebUI with Bundled Ollama Support @@ -140,14 +140,14 @@ This installation method uses a single container image that bundles Open WebUI w Utilize GPU resources by running the following command: ```bash - docker run -d -p 3000:8080 --gpus=all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p 3000:8083 --gpus=all -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama ``` - **For CPU Only**: If you're not using a GPU, use this command instead: ```bash - docker run -d -p 3000:8080 -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama + docker run -d -p 3000:8083 -v ollama:/root/.ollama -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:ollama ``` Both commands facilitate a built-in, hassle-free installation of both Open WebUI and Ollama, ensuring that you can get everything up and running swiftly. @@ -166,7 +166,7 @@ Encountering connection issues? Our [Open WebUI Documentation](https://docs.open #### Open WebUI: Server Connection Error -If you're experiencing connection issues, it’s often due to the WebUI docker container not being able to reach the Ollama server at 127.0.0.1:11434 (host.docker.internal:11434) inside the container . Use the `--network=host` flag in your docker command to resolve this. Note that the port changes from 3000 to 8080, resulting in the link: `http://localhost:8080`. +If you're experiencing connection issues, it’s often due to the WebUI docker container not being able to reach the Ollama server at 127.0.0.1:11434 (host.docker.internal:11434) inside the container . Use the `--network=host` flag in your docker command to resolve this. Note that the port changes from 3000 to 8083, resulting in the link: `http://localhost:8083`. **Example Docker Command**: @@ -194,7 +194,7 @@ Check our Updating Guide available in our [Open WebUI Documentation](https://doc If you want to try out the latest bleeding-edge features and are okay with occasional instability, you can use the `:dev` tag like this: ```bash -docker run -d -p 3000:8080 -v open-webui:/app/backend/data --name open-webui --add-host=host.docker.internal:host-gateway --restart always ghcr.io/open-webui/open-webui:dev +docker run -d -p 3000:8083 -v open-webui:/app/backend/data --name open-webui --add-host=host.docker.internal:host-gateway --restart always ghcr.io/open-webui/open-webui:dev ``` ### Offline Mode diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 83251a3a91ee..4508c6f8d0bd 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -10,7 +10,7 @@ The Open WebUI system is designed to streamline interactions between the client ## Open WebUI: Server Connection Error -If you're experiencing connection issues, it’s often due to the WebUI docker container not being able to reach the Ollama server at 127.0.0.1:11434 (host.docker.internal:11434) inside the container . Use the `--network=host` flag in your docker command to resolve this. Note that the port changes from 3000 to 8080, resulting in the link: `http://localhost:8080`. +If you're experiencing connection issues, it’s often due to the WebUI docker container not being able to reach the Ollama server at 127.0.0.1:11434 (host.docker.internal:11434) inside the container . Use the `--network=host` flag in your docker command to resolve this. Note that the port changes from 3000 to 8083, resulting in the link: `http://localhost:8083`. **Example Docker Command**: diff --git a/backend/dev.sh b/backend/dev.sh index 042fbd9efa1d..661294f2859b 100755 --- a/backend/dev.sh +++ b/backend/dev.sh @@ -1,3 +1,3 @@ -export CORS_ALLOW_ORIGIN="http://localhost:5173;http://localhost:8080" -PORT="${PORT:-8080}" +export CORS_ALLOW_ORIGIN="http://localhost:5173;http://localhost:8083" +PORT="${PORT:-8083}" uvicorn open_webui.main:app --port $PORT --host 0.0.0.0 --forwarded-allow-ips '*' --reload diff --git a/backend/open_webui/__init__.py b/backend/open_webui/__init__.py index 967a49de8ffa..bb80c310f1b3 100644 --- a/backend/open_webui/__init__.py +++ b/backend/open_webui/__init__.py @@ -33,7 +33,7 @@ def main( @app.command() def serve( host: str = "0.0.0.0", - port: int = 8080, + port: int = 8083, ): os.environ["FROM_INIT_PY"] = "true" if os.getenv("WEBUI_SECRET_KEY") is None: @@ -87,7 +87,7 @@ def serve( @app.command() def dev( host: str = "0.0.0.0", - port: int = 8080, + port: int = 8083, reload: bool = True, ): uvicorn.run( diff --git a/backend/open_webui/app.py b/backend/open_webui/app.py new file mode 100644 index 000000000000..b24e32116b40 --- /dev/null +++ b/backend/open_webui/app.py @@ -0,0 +1,894 @@ +import logging + +from open_webui.routers.retrieval import ( + get_embedding_function, + get_reranking_function, + get_ef, + get_rf, +) + +from open_webui.internal.db import engine + +from open_webui.config import ( + # Ollama + ENABLE_OLLAMA_API, + OLLAMA_BASE_URLS, + OLLAMA_API_CONFIGS, + # OpenAI + ENABLE_OPENAI_API, + OPENAI_API_BASE_URLS, + OPENAI_API_KEYS, + OPENAI_API_CONFIGS, + # Direct Connections + ENABLE_DIRECT_CONNECTIONS, + # Model list + ENABLE_BASE_MODELS_CACHE, + # Thread pool size for FastAPI/AnyIO + # Tool Server Configs + TOOL_SERVER_CONNECTIONS, + # Code Execution + ENABLE_CODE_EXECUTION, + CODE_EXECUTION_ENGINE, + CODE_EXECUTION_JUPYTER_URL, + CODE_EXECUTION_JUPYTER_AUTH, + CODE_EXECUTION_JUPYTER_AUTH_TOKEN, + CODE_EXECUTION_JUPYTER_AUTH_PASSWORD, + CODE_EXECUTION_JUPYTER_TIMEOUT, + ENABLE_CODE_INTERPRETER, + CODE_INTERPRETER_ENGINE, + CODE_INTERPRETER_PROMPT_TEMPLATE, + CODE_INTERPRETER_JUPYTER_URL, + CODE_INTERPRETER_JUPYTER_AUTH, + CODE_INTERPRETER_JUPYTER_AUTH_TOKEN, + CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD, + CODE_INTERPRETER_JUPYTER_TIMEOUT, + # Image + AUTOMATIC1111_API_AUTH, + AUTOMATIC1111_BASE_URL, + AUTOMATIC1111_PARAMS, + COMFYUI_BASE_URL, + COMFYUI_API_KEY, + COMFYUI_WORKFLOW, + COMFYUI_WORKFLOW_NODES, + ENABLE_IMAGE_GENERATION, + ENABLE_IMAGE_PROMPT_GENERATION, + IMAGE_GENERATION_ENGINE, + IMAGE_GENERATION_MODEL, + IMAGE_SIZE, + IMAGE_STEPS, + IMAGES_OPENAI_API_BASE_URL, + IMAGES_OPENAI_API_VERSION, + IMAGES_OPENAI_API_KEY, + IMAGES_GEMINI_API_BASE_URL, + IMAGES_GEMINI_API_KEY, + IMAGES_GEMINI_ENDPOINT_METHOD, + IMAGE_EDIT_ENGINE, + IMAGE_EDIT_MODEL, + IMAGE_EDIT_SIZE, + IMAGES_EDIT_OPENAI_API_BASE_URL, + IMAGES_EDIT_OPENAI_API_KEY, + IMAGES_EDIT_OPENAI_API_VERSION, + IMAGES_EDIT_GEMINI_API_BASE_URL, + IMAGES_EDIT_GEMINI_API_KEY, + IMAGES_EDIT_COMFYUI_BASE_URL, + IMAGES_EDIT_COMFYUI_API_KEY, + IMAGES_EDIT_COMFYUI_WORKFLOW, + IMAGES_EDIT_COMFYUI_WORKFLOW_NODES, + # Audio + AUDIO_STT_ENGINE, + AUDIO_STT_MODEL, + AUDIO_STT_SUPPORTED_CONTENT_TYPES, + AUDIO_STT_OPENAI_API_BASE_URL, + AUDIO_STT_OPENAI_API_KEY, + AUDIO_STT_AZURE_API_KEY, + AUDIO_STT_AZURE_REGION, + AUDIO_STT_AZURE_LOCALES, + AUDIO_STT_AZURE_BASE_URL, + AUDIO_STT_AZURE_MAX_SPEAKERS, + AUDIO_STT_MISTRAL_API_KEY, + AUDIO_STT_MISTRAL_API_BASE_URL, + AUDIO_STT_MISTRAL_USE_CHAT_COMPLETIONS, + AUDIO_TTS_ENGINE, + AUDIO_TTS_MODEL, + AUDIO_TTS_VOICE, + AUDIO_TTS_OPENAI_API_BASE_URL, + AUDIO_TTS_OPENAI_API_KEY, + AUDIO_TTS_OPENAI_PARAMS, + AUDIO_TTS_API_KEY, + AUDIO_TTS_SPLIT_ON, + AUDIO_TTS_AZURE_SPEECH_REGION, + AUDIO_TTS_AZURE_SPEECH_BASE_URL, + AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT, + PLAYWRIGHT_WS_URL, + PLAYWRIGHT_TIMEOUT, + FIRECRAWL_API_BASE_URL, + FIRECRAWL_API_KEY, + WEB_LOADER_ENGINE, + WEB_LOADER_CONCURRENT_REQUESTS, + WHISPER_MODEL, + WHISPER_VAD_FILTER, + DEEPGRAM_API_KEY, + # Retrieval + RAG_TEMPLATE, + RAG_FULL_CONTEXT, + BYPASS_EMBEDDING_AND_RETRIEVAL, + RAG_EMBEDDING_MODEL, + RAG_EMBEDDING_MODEL_AUTO_UPDATE, + RAG_RERANKING_ENGINE, + RAG_RERANKING_MODEL, + RAG_EXTERNAL_RERANKER_URL, + RAG_EXTERNAL_RERANKER_API_KEY, + RAG_RERANKING_MODEL_AUTO_UPDATE, + RAG_EMBEDDING_ENGINE, + RAG_EMBEDDING_BATCH_SIZE, + RAG_TOP_K, + RAG_TOP_K_RERANKER, + RAG_RELEVANCE_THRESHOLD, + RAG_HYBRID_BM25_WEIGHT, + RAG_ALLOWED_FILE_EXTENSIONS, + RAG_FILE_MAX_COUNT, + RAG_FILE_MAX_SIZE, + FILE_IMAGE_COMPRESSION_WIDTH, + FILE_IMAGE_COMPRESSION_HEIGHT, + RAG_OPENAI_API_BASE_URL, + RAG_OPENAI_API_KEY, + RAG_AZURE_OPENAI_BASE_URL, + RAG_AZURE_OPENAI_API_KEY, + RAG_AZURE_OPENAI_API_VERSION, + RAG_OLLAMA_BASE_URL, + RAG_OLLAMA_API_KEY, + CHUNK_OVERLAP, + CHUNK_SIZE, + CONTENT_EXTRACTION_ENGINE, + DATALAB_MARKER_API_KEY, + DATALAB_MARKER_API_BASE_URL, + DATALAB_MARKER_ADDITIONAL_CONFIG, + DATALAB_MARKER_SKIP_CACHE, + DATALAB_MARKER_FORCE_OCR, + DATALAB_MARKER_PAGINATE, + DATALAB_MARKER_STRIP_EXISTING_OCR, + DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION, + DATALAB_MARKER_FORMAT_LINES, + DATALAB_MARKER_OUTPUT_FORMAT, + MINERU_API_MODE, + MINERU_API_URL, + MINERU_API_KEY, + MINERU_PARAMS, + DATALAB_MARKER_USE_LLM, + EXTERNAL_DOCUMENT_LOADER_URL, + EXTERNAL_DOCUMENT_LOADER_API_KEY, + TIKA_SERVER_URL, + DOCLING_SERVER_URL, + DOCLING_PARAMS, + DOCLING_DO_OCR, + DOCLING_FORCE_OCR, + DOCLING_OCR_ENGINE, + DOCLING_OCR_LANG, + DOCLING_PDF_BACKEND, + DOCLING_TABLE_MODE, + DOCLING_PIPELINE, + DOCLING_DO_PICTURE_DESCRIPTION, + DOCLING_PICTURE_DESCRIPTION_MODE, + DOCLING_PICTURE_DESCRIPTION_LOCAL, + DOCLING_PICTURE_DESCRIPTION_API, + DOCUMENT_INTELLIGENCE_ENDPOINT, + DOCUMENT_INTELLIGENCE_KEY, + MISTRAL_OCR_API_BASE_URL, + MISTRAL_OCR_API_KEY, + RAG_TEXT_SPLITTER, + TIKTOKEN_ENCODING_NAME, + PDF_EXTRACT_IMAGES, + YOUTUBE_LOADER_LANGUAGE, + YOUTUBE_LOADER_PROXY_URL, + # Retrieval (Web Search) + ENABLE_WEB_SEARCH, + WEB_SEARCH_ENGINE, + BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL, + BYPASS_WEB_SEARCH_WEB_LOADER, + WEB_SEARCH_RESULT_COUNT, + WEB_SEARCH_CONCURRENT_REQUESTS, + WEB_SEARCH_TRUST_ENV, + WEB_SEARCH_DOMAIN_FILTER_LIST, + OLLAMA_CLOUD_WEB_SEARCH_API_KEY, + JINA_API_KEY, + SEARCHAPI_API_KEY, + SEARCHAPI_ENGINE, + SERPAPI_API_KEY, + SERPAPI_ENGINE, + SEARXNG_QUERY_URL, + YACY_QUERY_URL, + YACY_USERNAME, + YACY_PASSWORD, + SERPER_API_KEY, + SERPLY_API_KEY, + SERPSTACK_API_KEY, + SERPSTACK_HTTPS, + TAVILY_API_KEY, + TAVILY_EXTRACT_DEPTH, + BING_SEARCH_V7_ENDPOINT, + BING_SEARCH_V7_SUBSCRIPTION_KEY, + BRAVE_SEARCH_API_KEY, + EXA_API_KEY, + PERPLEXITY_API_KEY, + PERPLEXITY_MODEL, + PERPLEXITY_SEARCH_CONTEXT_USAGE, + SOUGOU_API_SID, + SOUGOU_API_SK, + KAGI_SEARCH_API_KEY, + MOJEEK_SEARCH_API_KEY, + BOCHA_SEARCH_API_KEY, + GOOGLE_PSE_API_KEY, + GOOGLE_PSE_ENGINE_ID, + ENABLE_ONEDRIVE_INTEGRATION, + ENABLE_RAG_HYBRID_SEARCH, + ENABLE_WEB_LOADER_SSL_VERIFICATION, + ENABLE_GOOGLE_DRIVE_INTEGRATION, + UPLOAD_DIR, + EXTERNAL_WEB_SEARCH_URL, + EXTERNAL_WEB_SEARCH_API_KEY, + EXTERNAL_WEB_LOADER_URL, + EXTERNAL_WEB_LOADER_API_KEY, + # WebUI + WEBUI_NAME, + WEBUI_BANNERS, + WEBHOOK_URL, + ADMIN_EMAIL, + SHOW_ADMIN_DETAILS, + JWT_EXPIRES_IN, + ENABLE_SIGNUP, + ENABLE_LOGIN_FORM, + ENABLE_API_KEY, + ENABLE_API_KEY_ENDPOINT_RESTRICTIONS, + API_KEY_ALLOWED_ENDPOINTS, + ENABLE_CHANNELS, + ENABLE_NOTES, + ENABLE_COMMUNITY_SHARING, + ENABLE_MESSAGE_RATING, + ENABLE_USER_WEBHOOKS, + ENABLE_EVALUATION_ARENA_MODELS, + USER_PERMISSIONS, + DEFAULT_USER_ROLE, + PENDING_USER_OVERLAY_CONTENT, + PENDING_USER_OVERLAY_TITLE, + DEFAULT_PROMPT_SUGGESTIONS, + DEFAULT_MODELS, + DEFAULT_ARENA_MODEL, + MODEL_ORDER_LIST, + EVALUATION_ARENA_MODELS, + # WebUI (OAuth) + ENABLE_OAUTH_ROLE_MANAGEMENT, + OAUTH_ROLES_CLAIM, + OAUTH_EMAIL_CLAIM, + OAUTH_PICTURE_CLAIM, + OAUTH_USERNAME_CLAIM, + OAUTH_ALLOWED_ROLES, + OAUTH_ADMIN_ROLES, + # WebUI (LDAP) + ENABLE_LDAP, + LDAP_SERVER_LABEL, + LDAP_SERVER_HOST, + LDAP_SERVER_PORT, + LDAP_ATTRIBUTE_FOR_MAIL, + LDAP_ATTRIBUTE_FOR_USERNAME, + LDAP_SEARCH_FILTERS, + LDAP_SEARCH_BASE, + LDAP_APP_DN, + LDAP_APP_PASSWORD, + LDAP_USE_TLS, + LDAP_CA_CERT_FILE, + LDAP_VALIDATE_CERT, + LDAP_CIPHERS, + # LDAP Group Management + ENABLE_LDAP_GROUP_MANAGEMENT, + ENABLE_LDAP_GROUP_CREATION, + LDAP_ATTRIBUTE_FOR_GROUPS, + WEBUI_URL, + RESPONSE_WATERMARK, + # Tasks + TASK_MODEL, + TASK_MODEL_EXTERNAL, + ENABLE_TAGS_GENERATION, + ENABLE_TITLE_GENERATION, + ENABLE_FOLLOW_UP_GENERATION, + ENABLE_SEARCH_QUERY_GENERATION, + ENABLE_RETRIEVAL_QUERY_GENERATION, + ENABLE_AUTOCOMPLETE_GENERATION, + TITLE_GENERATION_PROMPT_TEMPLATE, + FOLLOW_UP_GENERATION_PROMPT_TEMPLATE, + TAGS_GENERATION_PROMPT_TEMPLATE, + IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE, + TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE, + QUERY_GENERATION_PROMPT_TEMPLATE, + AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE, + AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH, + AppConfig, +) +from open_webui.env import ( + REDIS_URL, + REDIS_CLUSTER, + REDIS_KEY_PREFIX, + REDIS_SENTINEL_HOSTS, + REDIS_SENTINEL_PORT, + WEBUI_AUTH_TRUSTED_EMAIL_HEADER, + WEBUI_AUTH_TRUSTED_NAME_HEADER, + WEBUI_AUTH_SIGNOUT_REDIRECT_URL, + # SCIM + SCIM_ENABLED, + SCIM_TOKEN, + ENABLE_OTEL, + EXTERNAL_PWA_MANIFEST_URL, + SRC_LOG_LEVELS, +) + +from open_webui.utils.oauth import ( + OAuthManager, + OAuthClientManager, +) + +from open_webui.utils.redis import get_sentinels_from_env + +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MAIN"]) + + +def init_app_config(app): + # For Open WebUI OIDC/OAuth2 + oauth_manager = OAuthManager(app) + app.state.oauth_manager = oauth_manager + + # For Integrations + oauth_client_manager = OAuthClientManager(app) + app.state.oauth_client_manager = oauth_client_manager + + app.state.instance_id = None + app.state.config = AppConfig( + redis_url=REDIS_URL, + redis_sentinels=get_sentinels_from_env(REDIS_SENTINEL_HOSTS, REDIS_SENTINEL_PORT), + redis_cluster=REDIS_CLUSTER, + redis_key_prefix=REDIS_KEY_PREFIX, + ) + app.state.redis = None + + app.state.WEBUI_NAME = WEBUI_NAME + app.state.LICENSE_METADATA = None + + ######################################## + # + # OPENTELEMETRY + # + ######################################## + + if ENABLE_OTEL: + from open_webui.utils.telemetry.setup import setup as setup_opentelemetry + + setup_opentelemetry(app=app, db_engine=engine) + + ######################################## + # + # OLLAMA + # + ######################################## + + app.state.config.ENABLE_OLLAMA_API = ENABLE_OLLAMA_API + app.state.config.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS + app.state.config.OLLAMA_API_CONFIGS = OLLAMA_API_CONFIGS + + app.state.OLLAMA_MODELS = {} + + ######################################## + # + # OPENAI + # + ######################################## + + app.state.config.ENABLE_OPENAI_API = ENABLE_OPENAI_API + app.state.config.OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS + app.state.config.OPENAI_API_KEYS = OPENAI_API_KEYS + app.state.config.OPENAI_API_CONFIGS = OPENAI_API_CONFIGS + + app.state.OPENAI_MODELS = {} + + ######################################## + # + # TOOL SERVERS + # + ######################################## + + app.state.config.TOOL_SERVER_CONNECTIONS = TOOL_SERVER_CONNECTIONS + app.state.TOOL_SERVERS = [] + + ######################################## + # + # DIRECT CONNECTIONS + # + ######################################## + + app.state.config.ENABLE_DIRECT_CONNECTIONS = ENABLE_DIRECT_CONNECTIONS + + ######################################## + # + # SCIM + # + ######################################## + + app.state.SCIM_ENABLED = SCIM_ENABLED + app.state.SCIM_TOKEN = SCIM_TOKEN + + ######################################## + # + # MODELS + # + ######################################## + + app.state.config.ENABLE_BASE_MODELS_CACHE = ENABLE_BASE_MODELS_CACHE + app.state.BASE_MODELS = [] + + ######################################## + # + # WEBUI + # + ######################################## + + app.state.config.WEBUI_URL = WEBUI_URL + app.state.config.ENABLE_SIGNUP = ENABLE_SIGNUP + app.state.config.ENABLE_LOGIN_FORM = ENABLE_LOGIN_FORM + + app.state.config.ENABLE_API_KEY = ENABLE_API_KEY + app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS = ( + ENABLE_API_KEY_ENDPOINT_RESTRICTIONS + ) + app.state.config.API_KEY_ALLOWED_ENDPOINTS = API_KEY_ALLOWED_ENDPOINTS + + app.state.config.JWT_EXPIRES_IN = JWT_EXPIRES_IN + + app.state.config.SHOW_ADMIN_DETAILS = SHOW_ADMIN_DETAILS + app.state.config.ADMIN_EMAIL = ADMIN_EMAIL + + app.state.config.DEFAULT_MODELS = DEFAULT_MODELS + app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS + app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE + + app.state.config.PENDING_USER_OVERLAY_CONTENT = PENDING_USER_OVERLAY_CONTENT + app.state.config.PENDING_USER_OVERLAY_TITLE = PENDING_USER_OVERLAY_TITLE + + app.state.config.RESPONSE_WATERMARK = RESPONSE_WATERMARK + + app.state.config.USER_PERMISSIONS = USER_PERMISSIONS + app.state.config.WEBHOOK_URL = WEBHOOK_URL + app.state.config.BANNERS = WEBUI_BANNERS + app.state.config.MODEL_ORDER_LIST = MODEL_ORDER_LIST + + app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS + app.state.config.ENABLE_NOTES = ENABLE_NOTES + app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING + app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING + app.state.config.ENABLE_USER_WEBHOOKS = ENABLE_USER_WEBHOOKS + + app.state.config.ENABLE_EVALUATION_ARENA_MODELS = ENABLE_EVALUATION_ARENA_MODELS + app.state.config.EVALUATION_ARENA_MODELS = EVALUATION_ARENA_MODELS + + app.state.config.OAUTH_USERNAME_CLAIM = OAUTH_USERNAME_CLAIM + app.state.config.OAUTH_PICTURE_CLAIM = OAUTH_PICTURE_CLAIM + app.state.config.OAUTH_EMAIL_CLAIM = OAUTH_EMAIL_CLAIM + + app.state.config.ENABLE_OAUTH_ROLE_MANAGEMENT = ENABLE_OAUTH_ROLE_MANAGEMENT + app.state.config.OAUTH_ROLES_CLAIM = OAUTH_ROLES_CLAIM + app.state.config.OAUTH_ALLOWED_ROLES = OAUTH_ALLOWED_ROLES + app.state.config.OAUTH_ADMIN_ROLES = OAUTH_ADMIN_ROLES + + app.state.config.ENABLE_LDAP = ENABLE_LDAP + app.state.config.LDAP_SERVER_LABEL = LDAP_SERVER_LABEL + app.state.config.LDAP_SERVER_HOST = LDAP_SERVER_HOST + app.state.config.LDAP_SERVER_PORT = LDAP_SERVER_PORT + app.state.config.LDAP_ATTRIBUTE_FOR_MAIL = LDAP_ATTRIBUTE_FOR_MAIL + app.state.config.LDAP_ATTRIBUTE_FOR_USERNAME = LDAP_ATTRIBUTE_FOR_USERNAME + app.state.config.LDAP_APP_DN = LDAP_APP_DN + app.state.config.LDAP_APP_PASSWORD = LDAP_APP_PASSWORD + app.state.config.LDAP_SEARCH_BASE = LDAP_SEARCH_BASE + app.state.config.LDAP_SEARCH_FILTERS = LDAP_SEARCH_FILTERS + app.state.config.LDAP_USE_TLS = LDAP_USE_TLS + app.state.config.LDAP_CA_CERT_FILE = LDAP_CA_CERT_FILE + app.state.config.LDAP_VALIDATE_CERT = LDAP_VALIDATE_CERT + app.state.config.LDAP_CIPHERS = LDAP_CIPHERS + + # For LDAP Group Management + app.state.config.ENABLE_LDAP_GROUP_MANAGEMENT = ENABLE_LDAP_GROUP_MANAGEMENT + app.state.config.ENABLE_LDAP_GROUP_CREATION = ENABLE_LDAP_GROUP_CREATION + app.state.config.LDAP_ATTRIBUTE_FOR_GROUPS = LDAP_ATTRIBUTE_FOR_GROUPS + + app.state.AUTH_TRUSTED_EMAIL_HEADER = WEBUI_AUTH_TRUSTED_EMAIL_HEADER + app.state.AUTH_TRUSTED_NAME_HEADER = WEBUI_AUTH_TRUSTED_NAME_HEADER + app.state.WEBUI_AUTH_SIGNOUT_REDIRECT_URL = WEBUI_AUTH_SIGNOUT_REDIRECT_URL + app.state.EXTERNAL_PWA_MANIFEST_URL = EXTERNAL_PWA_MANIFEST_URL + + app.state.USER_COUNT = None + + app.state.TOOLS = {} + app.state.TOOL_CONTENTS = {} + + app.state.FUNCTIONS = {} + app.state.FUNCTION_CONTENTS = {} + + ######################################## + # + # RETRIEVAL + # + ######################################## + + app.state.config.TOP_K = RAG_TOP_K + app.state.config.TOP_K_RERANKER = RAG_TOP_K_RERANKER + app.state.config.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD + app.state.config.HYBRID_BM25_WEIGHT = RAG_HYBRID_BM25_WEIGHT + + app.state.config.ALLOWED_FILE_EXTENSIONS = RAG_ALLOWED_FILE_EXTENSIONS + app.state.config.FILE_MAX_SIZE = RAG_FILE_MAX_SIZE + app.state.config.FILE_MAX_COUNT = RAG_FILE_MAX_COUNT + app.state.config.FILE_IMAGE_COMPRESSION_WIDTH = FILE_IMAGE_COMPRESSION_WIDTH + app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT = FILE_IMAGE_COMPRESSION_HEIGHT + + app.state.config.RAG_FULL_CONTEXT = RAG_FULL_CONTEXT + app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL = BYPASS_EMBEDDING_AND_RETRIEVAL + app.state.config.ENABLE_RAG_HYBRID_SEARCH = ENABLE_RAG_HYBRID_SEARCH + app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION = ENABLE_WEB_LOADER_SSL_VERIFICATION + + app.state.config.CONTENT_EXTRACTION_ENGINE = CONTENT_EXTRACTION_ENGINE + app.state.config.DATALAB_MARKER_API_KEY = DATALAB_MARKER_API_KEY + app.state.config.DATALAB_MARKER_API_BASE_URL = DATALAB_MARKER_API_BASE_URL + app.state.config.DATALAB_MARKER_ADDITIONAL_CONFIG = DATALAB_MARKER_ADDITIONAL_CONFIG + app.state.config.DATALAB_MARKER_SKIP_CACHE = DATALAB_MARKER_SKIP_CACHE + app.state.config.DATALAB_MARKER_FORCE_OCR = DATALAB_MARKER_FORCE_OCR + app.state.config.DATALAB_MARKER_PAGINATE = DATALAB_MARKER_PAGINATE + app.state.config.DATALAB_MARKER_STRIP_EXISTING_OCR = DATALAB_MARKER_STRIP_EXISTING_OCR + app.state.config.DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION = ( + DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION + ) + app.state.config.DATALAB_MARKER_FORMAT_LINES = DATALAB_MARKER_FORMAT_LINES + app.state.config.DATALAB_MARKER_USE_LLM = DATALAB_MARKER_USE_LLM + app.state.config.DATALAB_MARKER_OUTPUT_FORMAT = DATALAB_MARKER_OUTPUT_FORMAT + app.state.config.EXTERNAL_DOCUMENT_LOADER_URL = EXTERNAL_DOCUMENT_LOADER_URL + app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY = EXTERNAL_DOCUMENT_LOADER_API_KEY + app.state.config.TIKA_SERVER_URL = TIKA_SERVER_URL + app.state.config.DOCLING_SERVER_URL = DOCLING_SERVER_URL + app.state.config.DOCLING_PARAMS = DOCLING_PARAMS + app.state.config.DOCLING_DO_OCR = DOCLING_DO_OCR + app.state.config.DOCLING_FORCE_OCR = DOCLING_FORCE_OCR + app.state.config.DOCLING_OCR_ENGINE = DOCLING_OCR_ENGINE + app.state.config.DOCLING_OCR_LANG = DOCLING_OCR_LANG + app.state.config.DOCLING_PDF_BACKEND = DOCLING_PDF_BACKEND + app.state.config.DOCLING_TABLE_MODE = DOCLING_TABLE_MODE + app.state.config.DOCLING_PIPELINE = DOCLING_PIPELINE + app.state.config.DOCLING_DO_PICTURE_DESCRIPTION = DOCLING_DO_PICTURE_DESCRIPTION + app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE = DOCLING_PICTURE_DESCRIPTION_MODE + app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL = DOCLING_PICTURE_DESCRIPTION_LOCAL + app.state.config.DOCLING_PICTURE_DESCRIPTION_API = DOCLING_PICTURE_DESCRIPTION_API + app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = DOCUMENT_INTELLIGENCE_ENDPOINT + app.state.config.DOCUMENT_INTELLIGENCE_KEY = DOCUMENT_INTELLIGENCE_KEY + app.state.config.MISTRAL_OCR_API_BASE_URL = MISTRAL_OCR_API_BASE_URL + app.state.config.MISTRAL_OCR_API_KEY = MISTRAL_OCR_API_KEY + app.state.config.MINERU_API_MODE = MINERU_API_MODE + app.state.config.MINERU_API_URL = MINERU_API_URL + app.state.config.MINERU_API_KEY = MINERU_API_KEY + app.state.config.MINERU_PARAMS = MINERU_PARAMS + + app.state.config.TEXT_SPLITTER = RAG_TEXT_SPLITTER + app.state.config.TIKTOKEN_ENCODING_NAME = TIKTOKEN_ENCODING_NAME + + app.state.config.CHUNK_SIZE = CHUNK_SIZE + app.state.config.CHUNK_OVERLAP = CHUNK_OVERLAP + + app.state.config.RAG_EMBEDDING_ENGINE = RAG_EMBEDDING_ENGINE + app.state.config.RAG_EMBEDDING_MODEL = RAG_EMBEDDING_MODEL + app.state.config.RAG_EMBEDDING_BATCH_SIZE = RAG_EMBEDDING_BATCH_SIZE + + app.state.config.RAG_RERANKING_ENGINE = RAG_RERANKING_ENGINE + app.state.config.RAG_RERANKING_MODEL = RAG_RERANKING_MODEL + app.state.config.RAG_EXTERNAL_RERANKER_URL = RAG_EXTERNAL_RERANKER_URL + app.state.config.RAG_EXTERNAL_RERANKER_API_KEY = RAG_EXTERNAL_RERANKER_API_KEY + + app.state.config.RAG_TEMPLATE = RAG_TEMPLATE + + app.state.config.RAG_OPENAI_API_BASE_URL = RAG_OPENAI_API_BASE_URL + app.state.config.RAG_OPENAI_API_KEY = RAG_OPENAI_API_KEY + + app.state.config.RAG_AZURE_OPENAI_BASE_URL = RAG_AZURE_OPENAI_BASE_URL + app.state.config.RAG_AZURE_OPENAI_API_KEY = RAG_AZURE_OPENAI_API_KEY + app.state.config.RAG_AZURE_OPENAI_API_VERSION = RAG_AZURE_OPENAI_API_VERSION + + app.state.config.RAG_OLLAMA_BASE_URL = RAG_OLLAMA_BASE_URL + app.state.config.RAG_OLLAMA_API_KEY = RAG_OLLAMA_API_KEY + + app.state.config.PDF_EXTRACT_IMAGES = PDF_EXTRACT_IMAGES + + app.state.config.YOUTUBE_LOADER_LANGUAGE = YOUTUBE_LOADER_LANGUAGE + app.state.config.YOUTUBE_LOADER_PROXY_URL = YOUTUBE_LOADER_PROXY_URL + + app.state.config.ENABLE_WEB_SEARCH = ENABLE_WEB_SEARCH + app.state.config.WEB_SEARCH_ENGINE = WEB_SEARCH_ENGINE + app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST = WEB_SEARCH_DOMAIN_FILTER_LIST + app.state.config.WEB_SEARCH_RESULT_COUNT = WEB_SEARCH_RESULT_COUNT + app.state.config.WEB_SEARCH_CONCURRENT_REQUESTS = WEB_SEARCH_CONCURRENT_REQUESTS + + app.state.config.WEB_LOADER_ENGINE = WEB_LOADER_ENGINE + app.state.config.WEB_LOADER_CONCURRENT_REQUESTS = WEB_LOADER_CONCURRENT_REQUESTS + + app.state.config.WEB_SEARCH_TRUST_ENV = WEB_SEARCH_TRUST_ENV + app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL = ( + BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL + ) + app.state.config.BYPASS_WEB_SEARCH_WEB_LOADER = BYPASS_WEB_SEARCH_WEB_LOADER + + app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION = ENABLE_GOOGLE_DRIVE_INTEGRATION + app.state.config.ENABLE_ONEDRIVE_INTEGRATION = ENABLE_ONEDRIVE_INTEGRATION + + app.state.config.OLLAMA_CLOUD_WEB_SEARCH_API_KEY = OLLAMA_CLOUD_WEB_SEARCH_API_KEY + app.state.config.SEARXNG_QUERY_URL = SEARXNG_QUERY_URL + app.state.config.YACY_QUERY_URL = YACY_QUERY_URL + app.state.config.YACY_USERNAME = YACY_USERNAME + app.state.config.YACY_PASSWORD = YACY_PASSWORD + app.state.config.GOOGLE_PSE_API_KEY = GOOGLE_PSE_API_KEY + app.state.config.GOOGLE_PSE_ENGINE_ID = GOOGLE_PSE_ENGINE_ID + app.state.config.BRAVE_SEARCH_API_KEY = BRAVE_SEARCH_API_KEY + app.state.config.KAGI_SEARCH_API_KEY = KAGI_SEARCH_API_KEY + app.state.config.MOJEEK_SEARCH_API_KEY = MOJEEK_SEARCH_API_KEY + app.state.config.BOCHA_SEARCH_API_KEY = BOCHA_SEARCH_API_KEY + app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY + app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS + app.state.config.SERPER_API_KEY = SERPER_API_KEY + app.state.config.SERPLY_API_KEY = SERPLY_API_KEY + app.state.config.TAVILY_API_KEY = TAVILY_API_KEY + app.state.config.SEARCHAPI_API_KEY = SEARCHAPI_API_KEY + app.state.config.SEARCHAPI_ENGINE = SEARCHAPI_ENGINE + app.state.config.SERPAPI_API_KEY = SERPAPI_API_KEY + app.state.config.SERPAPI_ENGINE = SERPAPI_ENGINE + app.state.config.JINA_API_KEY = JINA_API_KEY + app.state.config.BING_SEARCH_V7_ENDPOINT = BING_SEARCH_V7_ENDPOINT + app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY = BING_SEARCH_V7_SUBSCRIPTION_KEY + app.state.config.EXA_API_KEY = EXA_API_KEY + app.state.config.PERPLEXITY_API_KEY = PERPLEXITY_API_KEY + app.state.config.PERPLEXITY_MODEL = PERPLEXITY_MODEL + app.state.config.PERPLEXITY_SEARCH_CONTEXT_USAGE = PERPLEXITY_SEARCH_CONTEXT_USAGE + app.state.config.SOUGOU_API_SID = SOUGOU_API_SID + app.state.config.SOUGOU_API_SK = SOUGOU_API_SK + app.state.config.EXTERNAL_WEB_SEARCH_URL = EXTERNAL_WEB_SEARCH_URL + app.state.config.EXTERNAL_WEB_SEARCH_API_KEY = EXTERNAL_WEB_SEARCH_API_KEY + app.state.config.EXTERNAL_WEB_LOADER_URL = EXTERNAL_WEB_LOADER_URL + app.state.config.EXTERNAL_WEB_LOADER_API_KEY = EXTERNAL_WEB_LOADER_API_KEY + + app.state.config.PLAYWRIGHT_WS_URL = PLAYWRIGHT_WS_URL + app.state.config.PLAYWRIGHT_TIMEOUT = PLAYWRIGHT_TIMEOUT + app.state.config.FIRECRAWL_API_BASE_URL = FIRECRAWL_API_BASE_URL + app.state.config.FIRECRAWL_API_KEY = FIRECRAWL_API_KEY + app.state.config.TAVILY_EXTRACT_DEPTH = TAVILY_EXTRACT_DEPTH + + app.state.EMBEDDING_FUNCTION = None + app.state.RERANKING_FUNCTION = None + app.state.ef = None + app.state.rf = None + + app.state.YOUTUBE_LOADER_TRANSLATION = None + + try: + app.state.ef = get_ef( + app.state.config.RAG_EMBEDDING_ENGINE, + app.state.config.RAG_EMBEDDING_MODEL, + RAG_EMBEDDING_MODEL_AUTO_UPDATE, + ) + if ( + app.state.config.ENABLE_RAG_HYBRID_SEARCH + and not app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL + ): + app.state.rf = get_rf( + app.state.config.RAG_RERANKING_ENGINE, + app.state.config.RAG_RERANKING_MODEL, + app.state.config.RAG_EXTERNAL_RERANKER_URL, + app.state.config.RAG_EXTERNAL_RERANKER_API_KEY, + RAG_RERANKING_MODEL_AUTO_UPDATE, + ) + else: + app.state.rf = None + except Exception as e: + log.error(f"Error updating models: {e}") + pass + + app.state.EMBEDDING_FUNCTION = get_embedding_function( + app.state.config.RAG_EMBEDDING_ENGINE, + app.state.config.RAG_EMBEDDING_MODEL, + embedding_function=app.state.ef, + url=( + app.state.config.RAG_OPENAI_API_BASE_URL + if app.state.config.RAG_EMBEDDING_ENGINE == "openai" + else ( + app.state.config.RAG_OLLAMA_BASE_URL + if app.state.config.RAG_EMBEDDING_ENGINE == "ollama" + else app.state.config.RAG_AZURE_OPENAI_BASE_URL + ) + ), + key=( + app.state.config.RAG_OPENAI_API_KEY + if app.state.config.RAG_EMBEDDING_ENGINE == "openai" + else ( + app.state.config.RAG_OLLAMA_API_KEY + if app.state.config.RAG_EMBEDDING_ENGINE == "ollama" + else app.state.config.RAG_AZURE_OPENAI_API_KEY + ) + ), + embedding_batch_size=app.state.config.RAG_EMBEDDING_BATCH_SIZE, + azure_api_version=( + app.state.config.RAG_AZURE_OPENAI_API_VERSION + if app.state.config.RAG_EMBEDDING_ENGINE == "azure_openai" + else None + ), + ) + + app.state.RERANKING_FUNCTION = get_reranking_function( + app.state.config.RAG_RERANKING_ENGINE, + app.state.config.RAG_RERANKING_MODEL, + reranking_function=app.state.rf, + ) + + ######################################## + # + # CODE EXECUTION + # + ######################################## + + app.state.config.ENABLE_CODE_EXECUTION = ENABLE_CODE_EXECUTION + app.state.config.CODE_EXECUTION_ENGINE = CODE_EXECUTION_ENGINE + app.state.config.CODE_EXECUTION_JUPYTER_URL = CODE_EXECUTION_JUPYTER_URL + app.state.config.CODE_EXECUTION_JUPYTER_AUTH = CODE_EXECUTION_JUPYTER_AUTH + app.state.config.CODE_EXECUTION_JUPYTER_AUTH_TOKEN = CODE_EXECUTION_JUPYTER_AUTH_TOKEN + app.state.config.CODE_EXECUTION_JUPYTER_AUTH_PASSWORD = ( + CODE_EXECUTION_JUPYTER_AUTH_PASSWORD + ) + app.state.config.CODE_EXECUTION_JUPYTER_TIMEOUT = CODE_EXECUTION_JUPYTER_TIMEOUT + + app.state.config.ENABLE_CODE_INTERPRETER = ENABLE_CODE_INTERPRETER + app.state.config.CODE_INTERPRETER_ENGINE = CODE_INTERPRETER_ENGINE + app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE = CODE_INTERPRETER_PROMPT_TEMPLATE + + app.state.config.CODE_INTERPRETER_JUPYTER_URL = CODE_INTERPRETER_JUPYTER_URL + app.state.config.CODE_INTERPRETER_JUPYTER_AUTH = CODE_INTERPRETER_JUPYTER_AUTH + app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = ( + CODE_INTERPRETER_JUPYTER_AUTH_TOKEN + ) + app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = ( + CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD + ) + app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT = CODE_INTERPRETER_JUPYTER_TIMEOUT + + ######################################## + # + # IMAGES + # + ######################################## + + app.state.config.IMAGE_GENERATION_ENGINE = IMAGE_GENERATION_ENGINE + app.state.config.ENABLE_IMAGE_GENERATION = ENABLE_IMAGE_GENERATION + app.state.config.ENABLE_IMAGE_PROMPT_GENERATION = ENABLE_IMAGE_PROMPT_GENERATION + + app.state.config.IMAGE_GENERATION_MODEL = IMAGE_GENERATION_MODEL + app.state.config.IMAGE_SIZE = IMAGE_SIZE + app.state.config.IMAGE_STEPS = IMAGE_STEPS + + app.state.config.IMAGES_OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL + app.state.config.IMAGES_OPENAI_API_VERSION = IMAGES_OPENAI_API_VERSION + app.state.config.IMAGES_OPENAI_API_KEY = IMAGES_OPENAI_API_KEY + + app.state.config.IMAGES_GEMINI_API_BASE_URL = IMAGES_GEMINI_API_BASE_URL + app.state.config.IMAGES_GEMINI_API_KEY = IMAGES_GEMINI_API_KEY + app.state.config.IMAGES_GEMINI_ENDPOINT_METHOD = IMAGES_GEMINI_ENDPOINT_METHOD + + app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL + app.state.config.AUTOMATIC1111_API_AUTH = AUTOMATIC1111_API_AUTH + app.state.config.AUTOMATIC1111_PARAMS = AUTOMATIC1111_PARAMS + + app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL + app.state.config.COMFYUI_API_KEY = COMFYUI_API_KEY + app.state.config.COMFYUI_WORKFLOW = COMFYUI_WORKFLOW + app.state.config.COMFYUI_WORKFLOW_NODES = COMFYUI_WORKFLOW_NODES + + app.state.config.IMAGE_EDIT_ENGINE = IMAGE_EDIT_ENGINE + app.state.config.IMAGE_EDIT_MODEL = IMAGE_EDIT_MODEL + app.state.config.IMAGE_EDIT_SIZE = IMAGE_EDIT_SIZE + app.state.config.IMAGES_EDIT_OPENAI_API_BASE_URL = IMAGES_EDIT_OPENAI_API_BASE_URL + app.state.config.IMAGES_EDIT_OPENAI_API_KEY = IMAGES_EDIT_OPENAI_API_KEY + app.state.config.IMAGES_EDIT_OPENAI_API_VERSION = IMAGES_EDIT_OPENAI_API_VERSION + app.state.config.IMAGES_EDIT_GEMINI_API_BASE_URL = IMAGES_EDIT_GEMINI_API_BASE_URL + app.state.config.IMAGES_EDIT_GEMINI_API_KEY = IMAGES_EDIT_GEMINI_API_KEY + app.state.config.IMAGES_EDIT_COMFYUI_BASE_URL = IMAGES_EDIT_COMFYUI_BASE_URL + app.state.config.IMAGES_EDIT_COMFYUI_API_KEY = IMAGES_EDIT_COMFYUI_API_KEY + app.state.config.IMAGES_EDIT_COMFYUI_WORKFLOW = IMAGES_EDIT_COMFYUI_WORKFLOW + app.state.config.IMAGES_EDIT_COMFYUI_WORKFLOW_NODES = IMAGES_EDIT_COMFYUI_WORKFLOW_NODES + + ######################################## + # + # AUDIO + # + ######################################## + + app.state.config.STT_ENGINE = AUDIO_STT_ENGINE + app.state.config.STT_MODEL = AUDIO_STT_MODEL + app.state.config.STT_SUPPORTED_CONTENT_TYPES = AUDIO_STT_SUPPORTED_CONTENT_TYPES + + app.state.config.STT_OPENAI_API_BASE_URL = AUDIO_STT_OPENAI_API_BASE_URL + app.state.config.STT_OPENAI_API_KEY = AUDIO_STT_OPENAI_API_KEY + + app.state.config.WHISPER_MODEL = WHISPER_MODEL + app.state.config.WHISPER_VAD_FILTER = WHISPER_VAD_FILTER + app.state.config.DEEPGRAM_API_KEY = DEEPGRAM_API_KEY + + app.state.config.AUDIO_STT_AZURE_API_KEY = AUDIO_STT_AZURE_API_KEY + app.state.config.AUDIO_STT_AZURE_REGION = AUDIO_STT_AZURE_REGION + app.state.config.AUDIO_STT_AZURE_LOCALES = AUDIO_STT_AZURE_LOCALES + app.state.config.AUDIO_STT_AZURE_BASE_URL = AUDIO_STT_AZURE_BASE_URL + app.state.config.AUDIO_STT_AZURE_MAX_SPEAKERS = AUDIO_STT_AZURE_MAX_SPEAKERS + + app.state.config.AUDIO_STT_MISTRAL_API_KEY = AUDIO_STT_MISTRAL_API_KEY + app.state.config.AUDIO_STT_MISTRAL_API_BASE_URL = AUDIO_STT_MISTRAL_API_BASE_URL + app.state.config.AUDIO_STT_MISTRAL_USE_CHAT_COMPLETIONS = ( + AUDIO_STT_MISTRAL_USE_CHAT_COMPLETIONS + ) + + app.state.config.TTS_ENGINE = AUDIO_TTS_ENGINE + + app.state.config.TTS_MODEL = AUDIO_TTS_MODEL + app.state.config.TTS_VOICE = AUDIO_TTS_VOICE + + app.state.config.TTS_OPENAI_API_BASE_URL = AUDIO_TTS_OPENAI_API_BASE_URL + app.state.config.TTS_OPENAI_API_KEY = AUDIO_TTS_OPENAI_API_KEY + app.state.config.TTS_OPENAI_PARAMS = AUDIO_TTS_OPENAI_PARAMS + + app.state.config.TTS_API_KEY = AUDIO_TTS_API_KEY + app.state.config.TTS_SPLIT_ON = AUDIO_TTS_SPLIT_ON + + app.state.config.TTS_AZURE_SPEECH_REGION = AUDIO_TTS_AZURE_SPEECH_REGION + app.state.config.TTS_AZURE_SPEECH_BASE_URL = AUDIO_TTS_AZURE_SPEECH_BASE_URL + app.state.config.TTS_AZURE_SPEECH_OUTPUT_FORMAT = AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT + + app.state.faster_whisper_model = None + app.state.speech_synthesiser = None + app.state.speech_speaker_embeddings_dataset = None + + ######################################## + # + # TASKS + # + ######################################## + + app.state.config.TASK_MODEL = TASK_MODEL + app.state.config.TASK_MODEL_EXTERNAL = TASK_MODEL_EXTERNAL + + app.state.config.ENABLE_SEARCH_QUERY_GENERATION = ENABLE_SEARCH_QUERY_GENERATION + app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION = ENABLE_RETRIEVAL_QUERY_GENERATION + app.state.config.ENABLE_AUTOCOMPLETE_GENERATION = ENABLE_AUTOCOMPLETE_GENERATION + app.state.config.ENABLE_TAGS_GENERATION = ENABLE_TAGS_GENERATION + app.state.config.ENABLE_TITLE_GENERATION = ENABLE_TITLE_GENERATION + app.state.config.ENABLE_FOLLOW_UP_GENERATION = ENABLE_FOLLOW_UP_GENERATION + + app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE = TITLE_GENERATION_PROMPT_TEMPLATE + app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE = TAGS_GENERATION_PROMPT_TEMPLATE + app.state.config.IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE = ( + IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE + ) + app.state.config.FOLLOW_UP_GENERATION_PROMPT_TEMPLATE = ( + FOLLOW_UP_GENERATION_PROMPT_TEMPLATE + ) + + app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = ( + TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE + ) + app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE = QUERY_GENERATION_PROMPT_TEMPLATE + app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE = ( + AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE + ) + app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH = ( + AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH + ) + + ######################################## + # + # WEBUI + # + ######################################## + + app.state.MODELS = {} diff --git a/backend/open_webui/config.py b/backend/open_webui/config.py index 8d5b6829dcbd..bdef4417bb5c 100644 --- a/backend/open_webui/config.py +++ b/backend/open_webui/config.py @@ -1521,7 +1521,7 @@ def validate_cors_origin(origin): # For production, you should only need one host as # fastapi serves the svelte-kit built frontend and backend from the same host and port. # To test CORS_ALLOW_ORIGIN locally, you can set something like -# CORS_ALLOW_ORIGIN=http://localhost:5173;http://localhost:8080 +# CORS_ALLOW_ORIGIN=http://localhost:5173;http://localhost:8083 # in your .env file depending on your frontend port, 5173 in this case. CORS_ALLOW_ORIGIN = os.environ.get("CORS_ALLOW_ORIGIN", "*").split(";") @@ -1595,13 +1595,36 @@ class BannerModel(BaseModel): "task.title.prompt_template", os.environ.get("TITLE_GENERATION_PROMPT_TEMPLATE", ""), ) +# TODO: re-enable examples after testing +# DEFAULT_TITLE_GENERATION_PROMPT_TEMPLATE = """### Task: +# Generate a concise, 3-5 word title with an emoji summarizing the chat history. +# ### Guidelines: +# - The title should clearly represent the main theme or subject of the conversation. +# - Use emojis that enhance understanding of the topic, but avoid quotation marks or special formatting. +# - Write the title in the chat's primary language; default to English if multilingual. +# - Prioritize accuracy over excessive creativity; keep it clear and simple. +# - Your entire response must consist solely of the JSON object, without any introductory or concluding text. +# - The output must be a single, raw JSON object, without any markdown code fences or other encapsulating text. +# - Ensure no conversational text, affirmations, or explanations precede or follow the raw JSON output, as this will cause direct parsing failure. +# ### Output: +# JSON format: { "title": "your concise title here" } +# ### Examples: +# - { "title": "📉 Stock Market Trends" }, +# - { "title": "🍪 Perfect Chocolate Chip Recipe" }, +# - { "title": "Evolution of Music Streaming" }, +# - { "title": "Remote Work Productivity Tips" }, +# - { "title": "Artificial Intelligence in Healthcare" }, +# - { "title": "🎮 Video Game Development Insights" } +# ### Chat History: +# +# {{MESSAGES:END:2}} +# """ DEFAULT_TITLE_GENERATION_PROMPT_TEMPLATE = """### Task: -Generate a concise, 3-5 word title with an emoji summarizing the chat history. +Generate a concise, 3-5 word title. ### Guidelines: - The title should clearly represent the main theme or subject of the conversation. -- Use emojis that enhance understanding of the topic, but avoid quotation marks or special formatting. -- Write the title in the chat's primary language; default to English if multilingual. +- Use the primary language of the chat to write the title; if the chat contains multiple languages, generate the title in the primary language used. - Prioritize accuracy over excessive creativity; keep it clear and simple. - Your entire response must consist solely of the JSON object, without any introductory or concluding text. - The output must be a single, raw JSON object, without any markdown code fences or other encapsulating text. @@ -1609,12 +1632,12 @@ class BannerModel(BaseModel): ### Output: JSON format: { "title": "your concise title here" } ### Examples: -- { "title": "📉 Stock Market Trends" }, -- { "title": "🍪 Perfect Chocolate Chip Recipe" }, +- { "title": "Stock Market Trends" }, +- { "title": "Perfect Chocolate Chip Recipe" }, - { "title": "Evolution of Music Streaming" }, - { "title": "Remote Work Productivity Tips" }, - { "title": "Artificial Intelligence in Healthcare" }, -- { "title": "🎮 Video Game Development Insights" } +- { "title": "Video Game Development Insights" } ### Chat History: {{MESSAGES:END:2}} @@ -1744,7 +1767,7 @@ class BannerModel(BaseModel): - Always prioritize providing actionable and broad queries that maximize informational coverage. ### Output: -Strictly return in JSON format: +Strictly return in JSON format: { "queries": ["query1", "query2"] } @@ -1775,44 +1798,44 @@ class BannerModel(BaseModel): DEFAULT_AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE = """### Task: -You are an autocompletion system. Continue the text in `` based on the **completion type** in `` and the given language. +You are an autocompletion system. Continue the text in `` based on the **completion type** in `` and the given language. ### **Instructions**: -1. Analyze `` for context and meaning. -2. Use `` to guide your output: - - **General**: Provide a natural, concise continuation. - - **Search Query**: Complete as if generating a realistic search query. -3. Start as if you are directly continuing ``. Do **not** repeat, paraphrase, or respond as a model. Simply complete the text. +1. Analyze `` for context and meaning. +2. Use `` to guide your output: + - **General**: Provide a natural, concise continuation. + - **Search Query**: Complete as if generating a realistic search query. +3. Start as if you are directly continuing ``. Do **not** repeat, paraphrase, or respond as a model. Simply complete the text. 4. Ensure the continuation: - - Flows naturally from ``. - - Avoids repetition, overexplaining, or unrelated ideas. -5. If unsure, return: `{ "text": "" }`. + - Flows naturally from ``. + - Avoids repetition, overexplaining, or unrelated ideas. +5. If unsure, return: `{ "text": "" }`. ### **Output Rules**: - Respond only in JSON format: `{ "text": "" }`. ### **Examples**: -#### Example 1: -Input: -General -The sun was setting over the horizon, painting the sky -Output: +#### Example 1: +Input: +General +The sun was setting over the horizon, painting the sky +Output: { "text": "with vibrant shades of orange and pink." } -#### Example 2: -Input: -Search Query -Top-rated restaurants in -Output: -{ "text": "New York City for Italian cuisine." } +#### Example 2: +Input: +Search Query +Top-rated restaurants in +Output: +{ "text": "New York City for Italian cuisine." } --- ### Context: {{MESSAGES:END:6}} -{{TYPE}} -{{PROMPT}} +{{TYPE}} +{{PROMPT}} #### Output: """ @@ -1829,7 +1852,7 @@ class BannerModel(BaseModel): - Return only the JSON object, without any additional text or explanation. -- If no tools match the query, return an empty array: +- If no tools match the query, return an empty array: { "tool_calls": [] } @@ -1982,11 +2005,11 @@ class BannerModel(BaseModel): 1. **Code Interpreter**: `` - You have access to a Python shell that runs directly in the user's browser, enabling fast execution of code for analysis, calculations, or problem-solving. Use it in this response. - The Python code you write can incorporate a wide array of libraries, handle data manipulation or visualization, perform API calls for web-related tasks, or tackle virtually any computational challenge. Use this flexibility to **think outside the box, craft elegant solutions, and harness Python's full potential**. - - To use it, **you must enclose your code within `` XML tags** and stop right away. If you don't, the code won't execute. + - To use it, **you must enclose your code within `` XML tags** and stop right away. If you don't, the code won't execute. - When writing code in the code_interpreter XML tag, Do NOT use the triple backticks code block for markdown formatting, example: ```py # python code ``` will cause an error because it is markdown formatting, it is not python code. - - When coding, **always aim to print meaningful outputs** (e.g., results, tables, summaries, or visuals) to better interpret and verify the findings. Avoid relying on implicit outputs; prioritize explicit and clear print statements so the results are effectively communicated to the user. - - After obtaining the printed output, **always provide a concise analysis, interpretation, or next steps to help the user understand the findings or refine the outcome further.** - - If the results are unclear, unexpected, or require validation, refine the code and execute it again as needed. Always aim to deliver meaningful insights from the results, iterating if necessary. + - When coding, **always aim to print meaningful outputs** (e.g., results, tables, summaries, or visuals) to better interpret and verify the findings. Avoid relying on implicit outputs; prioritize explicit and clear print statements so the results are effectively communicated to the user. + - After obtaining the printed output, **always provide a concise analysis, interpretation, or next steps to help the user understand the findings or refine the outcome further.** + - If the results are unclear, unexpected, or require validation, refine the code and execute it again as needed. Always aim to deliver meaningful insights from the results, iterating if necessary. - **If a link to an image, audio, or any file is provided in markdown format in the output, ALWAYS regurgitate word for word, explicitly display it as part of the response to ensure the user can access it easily, do NOT change the link.** - All responses should be communicated in the chat's primary language, ensuring seamless understanding. If the chat is multilingual, default to English for clarity. diff --git a/backend/open_webui/env.py b/backend/open_webui/env.py index 8f9c1fbc4452..87f8ef12f3c7 100644 --- a/backend/open_webui/env.py +++ b/backend/open_webui/env.py @@ -97,6 +97,7 @@ "WEBHOOK", "SOCKET", "OAUTH", + "WISP", ] SRC_LOG_LEVELS = {} diff --git a/backend/open_webui/jms/__init__.py b/backend/open_webui/jms/__init__.py new file mode 100644 index 000000000000..da15fc009fc2 --- /dev/null +++ b/backend/open_webui/jms/__init__.py @@ -0,0 +1,6 @@ +from .command import * +from .replay import * +from .session import * +from .poll import * +from .account import * +from .chat import * diff --git a/backend/open_webui/jms/account.py b/backend/open_webui/jms/account.py new file mode 100644 index 000000000000..932c47271326 --- /dev/null +++ b/backend/open_webui/jms/account.py @@ -0,0 +1,22 @@ +import logging +from typing import Any + +from open_webui.jms.wisp.exceptions import WispError +from open_webui.env import SRC_LOG_LEVELS +from open_webui.jms.wisp.protobuf import service_pb2 + +from .base import BaseWisp + +logger = logging.getLogger(__name__) +logger.setLevel(SRC_LOG_LEVELS["WISP"]) + + +class AccountChatHandler(BaseWisp): + + def get_account(self) -> dict[Any, Any] | dict[str, Any] | dict[str, str] | dict[bytes, bytes]: + resp = self.stub.GetAccountChat(service_pb2.Empty()) + if not resp.status.ok: + error_message = f'Failed to get account info: {resp.status.err}' + logger.error(error_message) + raise WispError(error_message) + return dict(resp.payload) diff --git a/backend/open_webui/jms/base.py b/backend/open_webui/jms/base.py new file mode 100644 index 000000000000..c70e38bd92eb --- /dev/null +++ b/backend/open_webui/jms/base.py @@ -0,0 +1,8 @@ +from open_webui.jms.wisp import grpc_channel +from open_webui.jms.wisp.protobuf import service_pb2_grpc + + +class BaseWisp: + + def __init__(self): + self.stub = service_pb2_grpc.ServiceStub(grpc_channel) diff --git a/backend/open_webui/jms/chat.py b/backend/open_webui/jms/chat.py new file mode 100644 index 000000000000..8f4d56a524ae --- /dev/null +++ b/backend/open_webui/jms/chat.py @@ -0,0 +1,125 @@ +import json +import logging +from typing import Any, Dict, List, Optional + +from open_webui.jms.wisp.exceptions import WispError +from open_webui.env import SRC_LOG_LEVELS + +from .base import BaseWisp +from .wisp.protobuf.service_pb2 import HTTPRequest + +logger = logging.getLogger(__name__) +logger.setLevel(SRC_LOG_LEVELS["WISP"]) + +CHAT_URL = "/api/v1/terminal/chats/" + + +class ChatHandler(BaseWisp): + def list(self, query: Optional[Dict[str, Any]] = None) -> List[dict]: + query = self._normalize_query(query) + resp = self._request("GET", CHAT_URL, query=query, action="list chats") + return self._loads(CHAT_URL, resp.body) + + def retrieve(self, chat_id: str) -> dict: + self._ensure_id(chat_id) + path = f"{CHAT_URL}{chat_id}/" + resp = self._request("GET", path, action=f"retrieve chat {chat_id}") + return self._loads(path, resp.body) + + def create(self, data: Dict[str, Any]) -> dict: + body = self._dumps(data) + resp = self._request("POST", CHAT_URL, body=body, action="create chat") + return self._loads(CHAT_URL, resp.body) + + def update(self, chat_id: Optional[str] = None, data: Dict[str, Any] = None, query: Dict[str, Any] = None) -> dict: + self._ensure_id(chat_id) + path = f"{CHAT_URL}{chat_id}/" + body = self._dumps(data) + resp = self._request("PATCH", path, query=query, body=body, action=f"update chat {chat_id}") + return self._loads(path, resp.body) + + def destroy(self, chat_id: Optional[str] = None, query: Dict[str, Any] = None) -> None: + """ + If chat_id is provided, DELETE /chats/{id}/ + Else if query is provided, bulk DELETE /chats/ with query params + """ + if chat_id: + path, body, action = f"{CHAT_URL}{chat_id}/", None, f"delete chat {chat_id}" + elif query is not None: + path, query, action = CHAT_URL, query, "bulk delete chats" + else: + raise ValueError("Either chat_id or data must be provided") + + self._request("DELETE", path, query=query, action=action) + + def _request( + self, + method: str, + path: str, + *, + query: Optional[Dict[str, str]] = None, + body: Optional[bytes] = None, + action: str = "call API", + ): + """ + Centralized request with optional retries and better error surfacing. + """ + req = HTTPRequest( + method=method, + path=path, + query=query, + body=body + ) + + resp = self.stub.CallAPI(req) + if resp.status.ok: + return resp + + status_code = getattr(resp.status, "code", None) + + err_body = self._safe_decode(resp.body) + err_msg = ( + f"Failed to {action}: " + f"status={status_code}, err={resp.status.err}, body={err_body!r}" + ) + + logger.error(err_msg) + raise WispError(err_msg) + + @staticmethod + def _normalize_query(query: Optional[Dict[str, Any]]) -> Dict[str, str]: + if not query: + return {} + return {str(k): ('' if v is None else str(v)) for k, v in query.items()} + + @staticmethod + def _dumps(data: Dict[str, Any]) -> bytes: + try: + return json.dumps(data, separators=(",", ":"), ensure_ascii=False).encode("utf-8") + except (TypeError, ValueError) as e: + raise WispError(f"Failed to serialize request body: {e}") from e + + @staticmethod + def _loads(path: str, b: bytes) -> Any: + try: + return json.loads(b.decode("utf-8")) if b else None + except (UnicodeDecodeError, json.JSONDecodeError) as e: + raise WispError(f"Failed to parse response body: {e} path {path}") from e + + @staticmethod + def _safe_decode(b: Optional[bytes]) -> str: + if not b: + return "" + try: + text = b.decode("utf-8", errors="replace") + return text if len(text) <= 1000 else text[:1000] + "…" + except Exception: + return "" + + @staticmethod + def _ensure_id(chat_id: Optional[str]) -> None: + if not chat_id or not str(chat_id).strip(): + raise ValueError("chat_id must be a non-empty string") + + +chat_manager = ChatHandler() diff --git a/backend/open_webui/jms/check_user.py b/backend/open_webui/jms/check_user.py new file mode 100644 index 000000000000..e163cdaa1290 --- /dev/null +++ b/backend/open_webui/jms/check_user.py @@ -0,0 +1,50 @@ +import logging +from http.cookies import SimpleCookie +from typing import Mapping + +from fastapi import Request +from open_webui.jms.wisp.protobuf import service_pb2 +from open_webui.jms.wisp.exceptions import WispError +from open_webui.jms.wisp.protobuf.common_pb2 import User +from open_webui.env import SRC_LOG_LEVELS + +from .base import BaseWisp + +logger = logging.getLogger(__name__) +logger.setLevel(SRC_LOG_LEVELS["WISP"]) + + +class CheckUserHandler(BaseWisp): + + def check_user_by_cookies(self, request: Request) -> User: + req = service_pb2.CookiesRequest() + for name, value in request.cookies.items(): + c = req.cookies.add() + c.name = name + c.value = value + + user_resp = self.stub.CheckUserByCookies(req) + if not user_resp.status.ok: + error_message = f'Failed to check user: {user_resp.status.err}' + logger.error(error_message) + raise WispError(error_message) + return user_resp.data + + def check_user_by_cookie_map(self, cookies: Mapping[str, str]) -> User: + req = service_pb2.CookiesRequest() + for name, value in cookies.items(): + c = req.cookies.add() + c.name = name + c.value = value + user_resp = self.stub.CheckUserByCookies(req) + if not user_resp.status.ok: + error_message = f'Failed to check user: {user_resp.status.err}' + logger.error(error_message) + raise WispError(error_message) + return user_resp.data + + def check_user_by_cookie_header(self, cookie_header: str) -> User: + cookie = SimpleCookie() + cookie.load(cookie_header or "") + cookies = {k: morsel.value for k, morsel in cookie.items()} + return self.check_user_by_cookie_map(cookies) diff --git a/backend/open_webui/jms/command.py b/backend/open_webui/jms/command.py new file mode 100644 index 000000000000..2cc370120a30 --- /dev/null +++ b/backend/open_webui/jms/command.py @@ -0,0 +1,41 @@ +import logging +from typing import Optional +from datetime import datetime + +from open_webui.env import SRC_LOG_LEVELS +from open_webui.jms.wisp.protobuf import service_pb2 +from open_webui.jms.wisp.exceptions import WispError +from open_webui.jms.base import BaseWisp +from open_webui.jms.schemas import CommandRecord + +logger = logging.getLogger(__name__) +logger.setLevel(SRC_LOG_LEVELS["WISP"]) + + +class CommandHandler(BaseWisp): + + def __init__(self, session_id: str, session_info: dict): + super().__init__() + self.session_id = session_id + self.session_info = session_info + self.command_record: Optional[CommandRecord] = None + + async def record_command(self): + req = service_pb2.CommandRequest( + sid=self.session_id, + org_id=self.session_info['org_id'], + asset=self.session_info['asset'], + account=self.session_info['account'], + user=self.session_info['user'], + timestamp=int(datetime.timestamp(datetime.now())), + input=self.command_record.input, + output=self.command_record.output, + risk_level=self.command_record.risk_level, + cmd_acl_id='', + cmd_group_id='', + ) + resp = self.stub.UploadCommand(req) + if not resp.status.ok: + error_message = f'Failed to upload command: {resp.status.err}' + logger.error(error_message) + raise WispError(error_message) diff --git a/backend/open_webui/jms/poll.py b/backend/open_webui/jms/poll.py new file mode 100644 index 000000000000..0b1694e1dab7 --- /dev/null +++ b/backend/open_webui/jms/poll.py @@ -0,0 +1,62 @@ +import os +import queue +import logging +import asyncio +import threading + +from open_webui.env import SRC_LOG_LEVELS +from open_webui.jms.wisp import PROJECT_DIR +from open_webui.jms.wisp.protobuf import service_pb2 +from open_webui.jms.wisp.exceptions import WispError +from open_webui.jms.wisp.protobuf.common_pb2 import KillSession +from .base import BaseWisp +from .session import JMSSession + +logger = logging.getLogger(__name__) +logger.setLevel(SRC_LOG_LEVELS["WISP"]) + + +class PollJMSEvent(BaseWisp): + @staticmethod + async def close_session(target_session: JMSSession): + await target_session.close() + + def clear_zombie_session(self): + replay_dir = os.path.join(PROJECT_DIR, 'data/replay') + req = service_pb2.RemainReplayRequest(replay_dir=replay_dir) + resp = self.stub.ScanRemainReplays(req) + if not resp.status.ok: + error_message = f'Failed to scan remain replay: {resp.status.err}' + logger.error(error_message) + raise WispError(error_message) + else: + logger.info('Scan remain replay success') + + def wait_for_kill_session_message(self): + from open_webui.jms import chat_manager + q = queue.Queue(maxsize=1000) + for resp in self.stub.DispatchTask(iter(q.get, None)): + task = resp.task + session_id = task.session_id + task_action = task.action + + if task_action == KillSession: + filtered = chat_manager.list(query={'ids': session_id}) + for chat in filtered: + asyncio.run(self.close_session(JMSSession(chat))) + + req = service_pb2.FinishedTaskRequest(task_id=session_id) + self.stub.FinishSession(req) + + def start_session_killer(self): + self.wait_for_kill_session_message() + + def start(self): + self.clear_zombie_session() + self.start_session_killer() + + +def setup_poll_jms_event(): + jms_event = PollJMSEvent() + thread = threading.Thread(target=jms_event.start) + thread.start() diff --git a/backend/open_webui/jms/replay/__init__.py b/backend/open_webui/jms/replay/__init__.py new file mode 100644 index 000000000000..cacb003b8cce --- /dev/null +++ b/backend/open_webui/jms/replay/__init__.py @@ -0,0 +1,122 @@ +import os +import textwrap +import logging +from pathlib import Path +from datetime import datetime + +from open_webui.jms.wisp import PROJECT_DIR +from open_webui.jms.wisp.protobuf import service_pb2 +from open_webui.jms.wisp.exceptions import WispError +from open_webui.env import SRC_LOG_LEVELS +from .asciinema import AsciinemaWriter +from ..base import BaseWisp + +logger = logging.getLogger(__name__) +logger.setLevel(SRC_LOG_LEVELS["WISP"]) + + +class ReplayHandler(BaseWisp): + DEFAULT_ENCODING = "utf-8" + REPLAY_DIR = os.path.join(PROJECT_DIR, 'data/replay') + + def __init__(self, session_id: str): + super().__init__() + self.session_id = session_id + self.replay_writer: AsciinemaWriter | None = None + self.file_writer = None + self.file: Path | None = None + + async def _prepare(self): + self.ensure_replay_dir() + path = self._replay_path() + + if self.file is None: + self.file = path + + if not path.exists(): + try: + path.touch() + except Exception as e: + logger.error(f"Failed to create replay file: {path.name} -> {e}") + raise + + try: + self.file_writer = path.open(mode="w", encoding=self.DEFAULT_ENCODING, buffering=1) + self.replay_writer = AsciinemaWriter(self.file_writer) + self.replay_writer.write_header() + except Exception as e: + logger.error(f"Failed to init writer for new file {path.name}: {e}") + self.file_writer = None + self.replay_writer = None + raise + return + + if self.file_writer and not self.file_writer.closed and self.replay_writer is not None: + return + + try: + self.file_writer = path.open(mode="a", encoding=self.DEFAULT_ENCODING, buffering=1) + self.replay_writer = AsciinemaWriter(self.file_writer) + except Exception as e: + logger.error(f"Failed to reopen writer for {path.name}: {e}") + self.file_writer = None + self.replay_writer = None + + def ensure_replay_dir(self): + os.makedirs(self.REPLAY_DIR, exist_ok=True) + + def _replay_path(self) -> Path: + return Path(os.path.join(self.REPLAY_DIR, f"{self.session_id}.cast")) + + def _write_row(self, row): + row = row.replace("\n", "\r\n") + row = row.replace("\r\r\n", "\r\n") + row = f"{row} \r\n" + + try: + self.replay_writer.write_row(row.encode(self.DEFAULT_ENCODING)) + except Exception as e: + logger.error(f"Failed to write replay row: {e}") + + async def write_input(self, input_str): + await self._prepare() + current_time = datetime.now() + formatted_time = current_time.strftime("%Y-%m-%d %H:%M:%S") + input_str = f"[{formatted_time}]#: {input_str}" + self._write_row(input_str) + + async def write_output(self, output_str): + await self._prepare() + wrapper = textwrap.TextWrapper(width=self.replay_writer.WIDTH) + output_str = wrapper.fill(output_str) + output_str = f"\r\n {output_str} \r\n" + self._write_row(output_str) + + async def upload(self): + await self._prepare() + try: + if self.file_writer and not self.file_writer.closed: + try: + self.file_writer.flush() + except Exception: + pass + self.file_writer.close() + except Exception as e: + logger.warning(f"Failed to flush/close before upload: {e}") + + try: + replay_request = service_pb2.ReplayRequest( + session_id=self.session_id, + replay_file_path=self.file.absolute().as_posix() + ) + resp = self.stub.UploadReplayFile(replay_request) + + if not resp.status.ok: + error_message = f'Failed to upload replay file: {self.file.name} {resp.status.err}' + logger.error(error_message) + raise WispError(error_message) + except Exception as e: + logger.error(f'Failed to upload replay file upload {e}') + finally: + self.replay_writer = None + self.file_writer = None diff --git a/backend/open_webui/jms/replay/asciinema.py b/backend/open_webui/jms/replay/asciinema.py new file mode 100644 index 000000000000..74f0d1b4b4e6 --- /dev/null +++ b/backend/open_webui/jms/replay/asciinema.py @@ -0,0 +1,49 @@ +import json +import time +from datetime import datetime + + +class AsciinemaWriter: + VERSION = 2 + WIDTH = 80 + HEIGHT = 40 + DEFAULT_SHELL = "/bin/bash" + DEFAULT_TERM = "xterm" + NEW_LINE = "\n" + + def __init__(self, writer): + self.config = { + "width": self.WIDTH, + "height": self.HEIGHT, + "envShell": self.DEFAULT_SHELL, + "envTerm": self.DEFAULT_TERM, + "timestamp": int(datetime.timestamp(datetime.now())), + "title": None + } + self.writer = writer + self.timestampNano = time.time_ns() + + def write_header(self): + header = { + "version": self.VERSION, + "width": self.config["width"], + "height": self.config["height"], + "timestamp": self.config["timestamp"], + "title": self.config["title"], + "env": { + "shell": self.config["envShell"], + "term": self.config["envTerm"] + } + } + json_data = json.dumps(header) + self.NEW_LINE + self.writer.write(json_data) + + def write_row(self, p): + now = time.time_ns() + ts = (now - self.timestampNano) / 1_000_000_000.0 + self.write_stdout(ts, p) + + def write_stdout(self, ts, data): + row = [ts, "o", data.decode("utf-8")] + json_data = json.dumps(row) + self.NEW_LINE + self.writer.write(json_data) diff --git a/backend/open_webui/jms/schemas.py b/backend/open_webui/jms/schemas.py new file mode 100644 index 000000000000..e877d17b191b --- /dev/null +++ b/backend/open_webui/jms/schemas.py @@ -0,0 +1,10 @@ +from pydantic import BaseModel +from typing import Optional + +from open_webui.jms.wisp.protobuf.common_pb2 import RiskLevel + + +class CommandRecord(BaseModel): + input: Optional[str] = None + output: Optional[str] = None + risk_level: str = RiskLevel.Normal diff --git a/backend/open_webui/jms/session/__init__.py b/backend/open_webui/jms/session/__init__.py new file mode 100644 index 000000000000..98745a0fed50 --- /dev/null +++ b/backend/open_webui/jms/session/__init__.py @@ -0,0 +1 @@ +from .handler import * diff --git a/backend/open_webui/jms/session/handler.py b/backend/open_webui/jms/session/handler.py new file mode 100644 index 000000000000..740d3297bcef --- /dev/null +++ b/backend/open_webui/jms/session/handler.py @@ -0,0 +1,74 @@ +import asyncio +import logging +from datetime import datetime + +from open_webui.jms.wisp.protobuf import service_pb2 +from open_webui.jms.wisp.exceptions import WispError +from open_webui.jms.wisp.protobuf.common_pb2 import Session, User +from open_webui.jms import CommandHandler, ReplayHandler +from open_webui.env import SRC_LOG_LEVELS +from ..account import AccountChatHandler +from ..base import BaseWisp + +logger = logging.getLogger(__name__) +logger.setLevel(SRC_LOG_LEVELS["WISP"]) + + +class JMSSession(BaseWisp): + def __init__(self, chat: dict): + super().__init__() + self.chat_id = chat['id'] + + self.command_handler = CommandHandler(self.chat_id, chat['session_info']) + self.replay_handler = ReplayHandler(self.chat_id) + + async def close_session(self) -> None: + req = service_pb2.SessionFinishRequest( + id=self.chat_id, + date_end=int(datetime.now().timestamp()) + ) + resp = self.stub.FinishSession(req) + + if not resp.status.ok: + error_message = f'Failed to close session: {resp.status.err}' + logger.error(error_message) + raise WispError(error_message) + + async def close(self) -> None: + await asyncio.sleep(1) + await self.replay_handler.upload() + await self.close_session() + + +class SessionHandler(BaseWisp): + + def __init__(self, sid: str, ip: str, user: User): + super().__init__() + self.sid = sid + self.remote_address = ip + self.user = user + + def create_session(self, chat_model: str) -> Session: + account_handler = AccountChatHandler() + account_data = account_handler.get_account() + + req_session = Session( + user_id=self.user.id, + user=f'{self.user.name}({self.user.username})', + account_id=account_data['id'], + account=f'{account_data["name"]}({account_data["username"]})', + org_id=account_data['org_id'], + asset_id=account_data['asset']['id'], + asset=account_data['asset']['name'], + login_from=Session.LoginFrom.WT, + protocol=chat_model, + date_start=int(datetime.now().timestamp()), + remote_addr=self.remote_address, + ) + req = service_pb2.SessionCreateRequest(data=req_session) + resp = self.stub.CreateSession(req) + if not resp.status.ok: + error_message = f'Failed to create session: {resp.status.err}' + logger.error(error_message) + raise WispError(error_message) + return resp.data diff --git a/backend/open_webui/jms/wisp/__init__.py b/backend/open_webui/jms/wisp/__init__.py new file mode 100644 index 000000000000..e6973e461814 --- /dev/null +++ b/backend/open_webui/jms/wisp/__init__.py @@ -0,0 +1,30 @@ +import os +import sys +import grpc +from typing import Optional + +grpc_channel: Optional[grpc.Channel] = None +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +PROJECT_DIR = os.path.dirname(BASE_DIR) + + +def setup_protobuf(): + global grpc_channel + current_dir = os.path.dirname(os.path.abspath(__file__)) + protobuf_path = os.path.join(current_dir, 'protobuf') + if protobuf_path not in sys.path: + sys.path.insert(0, protobuf_path) + + grpc_channel = grpc.insecure_channel('localhost:9090') + + +def shutdown_protobuf(): + global grpc_channel + ch = grpc_channel + if ch is None: + return + ch.close() + grpc_channel = None + + +setup_protobuf() diff --git a/backend/open_webui/jms/wisp/exceptions.py b/backend/open_webui/jms/wisp/exceptions.py new file mode 100644 index 000000000000..8de2d408708f --- /dev/null +++ b/backend/open_webui/jms/wisp/exceptions.py @@ -0,0 +1,2 @@ +class WispError(Exception): + pass diff --git a/backend/open_webui/jms/wisp/protobuf/common_pb2.py b/backend/open_webui/jms/wisp/protobuf/common_pb2.py new file mode 100644 index 000000000000..13cb0e95ca48 --- /dev/null +++ b/backend/open_webui/jms/wisp/protobuf/common_pb2.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: common.proto +# Protobuf Python Version: 5.29.0 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 29, + 0, + '', + 'common.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x63ommon.proto\x12\x07message\"e\n\x04User\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08username\x18\x03 \x01(\t\x12\x0c\n\x04role\x18\x04 \x01(\t\x12\x10\n\x08is_valid\x18\x05 \x01(\x08\x12\x11\n\tis_active\x18\x06 \x01(\x08\"n\n\x07\x41\x63\x63ount\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08username\x18\x04 \x01(\t\x12\x0e\n\x06secret\x18\x05 \x01(\t\x12\'\n\nsecretType\x18\x06 \x01(\x0b\x32\x13.message.LabelValue\"*\n\nLabelValue\x12\r\n\x05label\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xc5\x03\n\x05\x41sset\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\x03 \x01(\t\x12\x0e\n\x06org_id\x18\x04 \x01(\t\x12\x10\n\x08org_name\x18\x05 \x01(\t\x12$\n\tprotocols\x18\x06 \x03(\x0b\x32\x11.message.Protocol\x12)\n\x08specific\x18\x07 \x01(\x0b\x32\x17.message.Asset.Specific\x1a\x9d\x02\n\x08Specific\x12\x0f\n\x07\x64\x62_name\x18\x01 \x01(\t\x12\x0f\n\x07use_ssl\x18\x02 \x01(\x08\x12\x0f\n\x07\x63\x61_cert\x18\x03 \x01(\t\x12\x13\n\x0b\x63lient_cert\x18\x04 \x01(\t\x12\x12\n\nclient_key\x18\x05 \x01(\t\x12\x1a\n\x12\x61llow_invalid_cert\x18\x06 \x01(\x08\x12\x11\n\tauto_fill\x18\x07 \x01(\t\x12\x19\n\x11username_selector\x18\x08 \x01(\t\x12\x19\n\x11password_selector\x18\t \x01(\t\x12\x17\n\x0fsubmit_selector\x18\n \x01(\t\x12\x0e\n\x06script\x18\x0b \x01(\t\x12\x12\n\nhttp_proxy\x18\x0c \x01(\t\x12\x13\n\x0bpg_ssl_mode\x18\r \x01(\t\"2\n\x08Protocol\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04port\x18\x03 \x01(\x05\"\x88\x01\n\x07Gateway\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\n\n\x02ip\x18\x03 \x01(\t\x12\x0c\n\x04port\x18\x04 \x01(\x05\x12\x10\n\x08protocol\x18\x05 \x01(\t\x12\x10\n\x08username\x18\x06 \x01(\t\x12\x10\n\x08password\x18\x07 \x01(\t\x12\x13\n\x0bprivate_key\x18\x08 \x01(\t\"\x7f\n\nPermission\x12\x16\n\x0e\x65nable_connect\x18\x01 \x01(\x08\x12\x17\n\x0f\x65nable_download\x18\x02 \x01(\x08\x12\x15\n\renable_upload\x18\x03 \x01(\x08\x12\x13\n\x0b\x65nable_copy\x18\x04 \x01(\x08\x12\x14\n\x0c\x65nable_paste\x18\x05 \x01(\x08\"\x81\x02\n\nCommandACL\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08priority\x18\x03 \x01(\x05\x12*\n\x06\x61\x63tion\x18\x05 \x01(\x0e\x32\x1a.message.CommandACL.Action\x12\x11\n\tis_active\x18\x06 \x01(\x08\x12-\n\x0e\x63ommand_groups\x18\x07 \x03(\x0b\x32\x15.message.CommandGroup\"Y\n\x06\x41\x63tion\x12\n\n\x06Reject\x10\x00\x12\n\n\x06\x41\x63\x63\x65pt\x10\x01\x12\n\n\x06Review\x10\x02\x12\x0b\n\x07Warning\x10\x03\x12\x11\n\rNotifyWarning\x10\x04\x12\x0b\n\x07Unknown\x10\x05\"\x96\x01\n\x0f\x44\x61taMaskingRule\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08priority\x18\x03 \x01(\x05\x12\x11\n\tis_active\x18\x04 \x01(\x08\x12\x16\n\x0emasking_method\x18\x05 \x01(\t\x12\x14\n\x0cmask_pattern\x18\x06 \x01(\t\x12\x16\n\x0e\x66ields_pattern\x18\x07 \x01(\t\"m\n\x0c\x43ommandGroup\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\t\x12\x0c\n\x04Type\x18\x04 \x01(\t\x12\x0f\n\x07pattern\x18\x05 \x01(\t\x12\x13\n\x0bignore_case\x18\x06 \x01(\x08\"\x1f\n\nExpireInfo\x12\x11\n\texpire_at\x18\x01 \x01(\x03\"\xb4\x02\n\x07Session\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\x12\r\n\x05\x61sset\x18\x03 \x01(\t\x12\x0f\n\x07\x61\x63\x63ount\x18\x04 \x01(\t\x12.\n\nlogin_from\x18\x05 \x01(\x0e\x32\x1a.message.Session.LoginFrom\x12\x13\n\x0bremote_addr\x18\x06 \x01(\t\x12\x10\n\x08protocol\x18\x07 \x01(\t\x12\x12\n\ndate_start\x18\x08 \x01(\x03\x12\x0e\n\x06org_id\x18\t \x01(\t\x12\x0f\n\x07user_id\x18\n \x01(\t\x12\x10\n\x08\x61sset_id\x18\x0b \x01(\t\x12\x12\n\naccount_id\x18\x0c \x01(\t\x12\x10\n\x08token_id\x18\r \x01(\t\"+\n\tLoginFrom\x12\x06\n\x02WT\x10\x00\x12\x06\n\x02ST\x10\x01\x12\x06\n\x02RT\x10\x02\x12\x06\n\x02\x44T\x10\x03\"?\n\x0bTokenStatus\x12\x0c\n\x04\x63ode\x18\x01 \x01(\t\x12\x0e\n\x06\x64\x65tail\x18\x02 \x01(\t\x12\x12\n\nis_expired\x18\x03 \x01(\x08\"\xaa\x01\n\x0cTerminalTask\x12\n\n\x02id\x18\x01 \x01(\t\x12#\n\x06\x61\x63tion\x18\x02 \x01(\x0e\x32\x13.message.TaskAction\x12\x12\n\nsession_id\x18\x03 \x01(\t\x12\x15\n\rterminated_by\x18\x04 \x01(\t\x12\x12\n\ncreated_by\x18\x05 \x01(\t\x12*\n\x0ctoken_status\x18\x06 \x01(\x0b\x32\x14.message.TokenStatus\"\xd5\x03\n\rTokenAuthInfo\x12\x0e\n\x06key_id\x18\x01 \x01(\t\x12\x12\n\nsecrete_id\x18\x02 \x01(\t\x12\x1d\n\x05\x61sset\x18\x03 \x01(\x0b\x32\x0e.message.Asset\x12\x1b\n\x04user\x18\x04 \x01(\x0b\x32\r.message.User\x12!\n\x07\x61\x63\x63ount\x18\x05 \x01(\x0b\x32\x10.message.Account\x12\'\n\npermission\x18\x06 \x01(\x0b\x32\x13.message.Permission\x12(\n\x0b\x65xpire_info\x18\x07 \x01(\x0b\x32\x13.message.ExpireInfo\x12)\n\x0c\x66ilter_rules\x18\x08 \x03(\x0b\x32\x13.message.CommandACL\x12\"\n\x08gateways\x18\t \x03(\x0b\x32\x10.message.Gateway\x12*\n\x07setting\x18\n \x01(\x0b\x32\x19.message.ComponentSetting\x12#\n\x08platform\x18\x0b \x01(\x0b\x32\x11.message.Platform\x12\x18\n\x10\x46\x61\x63\x65MonitorToken\x18\x0c \x01(\t\x12\x34\n\x12\x64\x61ta_masking_rules\x18\r \x03(\x0b\x32\x18.message.DataMaskingRule\"\x83\x01\n\x08Platform\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x10\n\x08\x63\x61tegory\x18\x03 \x01(\t\x12\x0f\n\x07\x63harset\x18\x04 \x01(\t\x12\x0c\n\x04type\x18\x05 \x01(\t\x12,\n\tprotocols\x18\x06 \x03(\x0b\x32\x19.message.PlatformProtocol\"\xa6\x01\n\x10PlatformProtocol\x12\n\n\x02id\x18\x01 \x01(\x05\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\x05\x12\x39\n\x08settings\x18\x04 \x03(\x0b\x32\'.message.PlatformProtocol.SettingsEntry\x1a/\n\rSettingsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"C\n\x10\x43omponentSetting\x12\x15\n\rmax_idle_time\x18\x01 \x01(\x05\x12\x18\n\x10max_session_time\x18\x02 \x01(\x05\"1\n\x07\x46orward\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04Host\x18\x02 \x01(\t\x12\x0c\n\x04port\x18\x03 \x01(\x05\"\xa7\x01\n\rPublicSetting\x12\x15\n\rxpack_enabled\x18\x01 \x01(\x08\x12\x15\n\rvalid_license\x18\x02 \x01(\x08\x12\x14\n\x0cgpt_base_url\x18\x03 \x01(\t\x12\x13\n\x0bgpt_api_key\x18\x04 \x01(\t\x12\x11\n\tgpt_proxy\x18\x05 \x01(\t\x12\x11\n\tgpt_model\x18\x06 \x01(\t\x12\x17\n\x0flicense_content\x18\x07 \x01(\t\"%\n\x06\x43ookie\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xa8\x03\n\x10LifecycleLogData\x12\x33\n\x05\x65vent\x18\x01 \x01(\x0e\x32$.message.LifecycleLogData.event_type\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x0c\n\x04user\x18\x03 \x01(\t\"\xc0\x02\n\nevent_type\x12\x17\n\x13\x41ssetConnectSuccess\x10\x00\x12\x18\n\x14\x41ssetConnectFinished\x10\x01\x12\x13\n\x0f\x43reateShareLink\x10\x02\x12\x13\n\x0fUserJoinSession\x10\x03\x12\x14\n\x10UserLeaveSession\x10\x04\x12\x14\n\x10\x41\x64minJoinMonitor\x10\x05\x12\x14\n\x10\x41\x64minExitMonitor\x10\x06\x12\x16\n\x12ReplayConvertStart\x10\x07\x12\x18\n\x14ReplayConvertSuccess\x10\x08\x12\x18\n\x14ReplayConvertFailure\x10\t\x12\x15\n\x11ReplayUploadStart\x10\n\x12\x17\n\x13ReplayUploadSuccess\x10\x0b\x12\x17\n\x13ReplayUploadFailure\x10\x0c*k\n\nTaskAction\x12\x0f\n\x0bKillSession\x10\x00\x12\x0f\n\x0bLockSession\x10\x01\x12\x11\n\rUnlockSession\x10\x02\x12\x14\n\x10TokenPermExpired\x10\x03\x12\x12\n\x0eTokenPermValid\x10\x04*f\n\tRiskLevel\x12\n\n\x06Normal\x10\x00\x12\x0b\n\x07Warning\x10\x01\x12\n\n\x06Reject\x10\x02\x12\x10\n\x0cReviewReject\x10\x03\x12\x10\n\x0cReviewAccept\x10\x04\x12\x10\n\x0cReviewCancel\x10\x05\x42 \n\x13org.jumpserver.wispZ\t/protobufb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'common_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\023org.jumpserver.wispZ\t/protobuf' + _globals['_PLATFORMPROTOCOL_SETTINGSENTRY']._loaded_options = None + _globals['_PLATFORMPROTOCOL_SETTINGSENTRY']._serialized_options = b'8\001' + _globals['_TASKACTION']._serialized_start=3697 + _globals['_TASKACTION']._serialized_end=3804 + _globals['_RISKLEVEL']._serialized_start=3806 + _globals['_RISKLEVEL']._serialized_end=3908 + _globals['_USER']._serialized_start=25 + _globals['_USER']._serialized_end=126 + _globals['_ACCOUNT']._serialized_start=128 + _globals['_ACCOUNT']._serialized_end=238 + _globals['_LABELVALUE']._serialized_start=240 + _globals['_LABELVALUE']._serialized_end=282 + _globals['_ASSET']._serialized_start=285 + _globals['_ASSET']._serialized_end=738 + _globals['_ASSET_SPECIFIC']._serialized_start=453 + _globals['_ASSET_SPECIFIC']._serialized_end=738 + _globals['_PROTOCOL']._serialized_start=740 + _globals['_PROTOCOL']._serialized_end=790 + _globals['_GATEWAY']._serialized_start=793 + _globals['_GATEWAY']._serialized_end=929 + _globals['_PERMISSION']._serialized_start=931 + _globals['_PERMISSION']._serialized_end=1058 + _globals['_COMMANDACL']._serialized_start=1061 + _globals['_COMMANDACL']._serialized_end=1318 + _globals['_COMMANDACL_ACTION']._serialized_start=1229 + _globals['_COMMANDACL_ACTION']._serialized_end=1318 + _globals['_DATAMASKINGRULE']._serialized_start=1321 + _globals['_DATAMASKINGRULE']._serialized_end=1471 + _globals['_COMMANDGROUP']._serialized_start=1473 + _globals['_COMMANDGROUP']._serialized_end=1582 + _globals['_EXPIREINFO']._serialized_start=1584 + _globals['_EXPIREINFO']._serialized_end=1615 + _globals['_SESSION']._serialized_start=1618 + _globals['_SESSION']._serialized_end=1926 + _globals['_SESSION_LOGINFROM']._serialized_start=1883 + _globals['_SESSION_LOGINFROM']._serialized_end=1926 + _globals['_TOKENSTATUS']._serialized_start=1928 + _globals['_TOKENSTATUS']._serialized_end=1991 + _globals['_TERMINALTASK']._serialized_start=1994 + _globals['_TERMINALTASK']._serialized_end=2164 + _globals['_TOKENAUTHINFO']._serialized_start=2167 + _globals['_TOKENAUTHINFO']._serialized_end=2636 + _globals['_PLATFORM']._serialized_start=2639 + _globals['_PLATFORM']._serialized_end=2770 + _globals['_PLATFORMPROTOCOL']._serialized_start=2773 + _globals['_PLATFORMPROTOCOL']._serialized_end=2939 + _globals['_PLATFORMPROTOCOL_SETTINGSENTRY']._serialized_start=2892 + _globals['_PLATFORMPROTOCOL_SETTINGSENTRY']._serialized_end=2939 + _globals['_COMPONENTSETTING']._serialized_start=2941 + _globals['_COMPONENTSETTING']._serialized_end=3008 + _globals['_FORWARD']._serialized_start=3010 + _globals['_FORWARD']._serialized_end=3059 + _globals['_PUBLICSETTING']._serialized_start=3062 + _globals['_PUBLICSETTING']._serialized_end=3229 + _globals['_COOKIE']._serialized_start=3231 + _globals['_COOKIE']._serialized_end=3268 + _globals['_LIFECYCLELOGDATA']._serialized_start=3271 + _globals['_LIFECYCLELOGDATA']._serialized_end=3695 + _globals['_LIFECYCLELOGDATA_EVENT_TYPE']._serialized_start=3375 + _globals['_LIFECYCLELOGDATA_EVENT_TYPE']._serialized_end=3695 +# @@protoc_insertion_point(module_scope) diff --git a/backend/open_webui/jms/wisp/protobuf/common_pb2.pyi b/backend/open_webui/jms/wisp/protobuf/common_pb2.pyi new file mode 100644 index 000000000000..016e0a3b986f --- /dev/null +++ b/backend/open_webui/jms/wisp/protobuf/common_pb2.pyi @@ -0,0 +1,447 @@ +from google.protobuf.internal import containers as _containers +from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union + +DESCRIPTOR: _descriptor.FileDescriptor + +class TaskAction(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + KillSession: _ClassVar[TaskAction] + LockSession: _ClassVar[TaskAction] + UnlockSession: _ClassVar[TaskAction] + TokenPermExpired: _ClassVar[TaskAction] + TokenPermValid: _ClassVar[TaskAction] + +class RiskLevel(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + Normal: _ClassVar[RiskLevel] + Warning: _ClassVar[RiskLevel] + Reject: _ClassVar[RiskLevel] + ReviewReject: _ClassVar[RiskLevel] + ReviewAccept: _ClassVar[RiskLevel] + ReviewCancel: _ClassVar[RiskLevel] +KillSession: TaskAction +LockSession: TaskAction +UnlockSession: TaskAction +TokenPermExpired: TaskAction +TokenPermValid: TaskAction +Normal: RiskLevel +Warning: RiskLevel +Reject: RiskLevel +ReviewReject: RiskLevel +ReviewAccept: RiskLevel +ReviewCancel: RiskLevel + +class User(_message.Message): + __slots__ = ("id", "name", "username", "role", "is_valid", "is_active") + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + USERNAME_FIELD_NUMBER: _ClassVar[int] + ROLE_FIELD_NUMBER: _ClassVar[int] + IS_VALID_FIELD_NUMBER: _ClassVar[int] + IS_ACTIVE_FIELD_NUMBER: _ClassVar[int] + id: str + name: str + username: str + role: str + is_valid: bool + is_active: bool + def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., username: _Optional[str] = ..., role: _Optional[str] = ..., is_valid: bool = ..., is_active: bool = ...) -> None: ... + +class Account(_message.Message): + __slots__ = ("id", "name", "username", "secret", "secretType") + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + USERNAME_FIELD_NUMBER: _ClassVar[int] + SECRET_FIELD_NUMBER: _ClassVar[int] + SECRETTYPE_FIELD_NUMBER: _ClassVar[int] + id: str + name: str + username: str + secret: str + secretType: LabelValue + def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., username: _Optional[str] = ..., secret: _Optional[str] = ..., secretType: _Optional[_Union[LabelValue, _Mapping]] = ...) -> None: ... + +class LabelValue(_message.Message): + __slots__ = ("label", "value") + LABEL_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + label: str + value: str + def __init__(self, label: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + +class Asset(_message.Message): + __slots__ = ("id", "name", "address", "org_id", "org_name", "protocols", "specific") + class Specific(_message.Message): + __slots__ = ("db_name", "use_ssl", "ca_cert", "client_cert", "client_key", "allow_invalid_cert", "auto_fill", "username_selector", "password_selector", "submit_selector", "script", "http_proxy", "pg_ssl_mode") + DB_NAME_FIELD_NUMBER: _ClassVar[int] + USE_SSL_FIELD_NUMBER: _ClassVar[int] + CA_CERT_FIELD_NUMBER: _ClassVar[int] + CLIENT_CERT_FIELD_NUMBER: _ClassVar[int] + CLIENT_KEY_FIELD_NUMBER: _ClassVar[int] + ALLOW_INVALID_CERT_FIELD_NUMBER: _ClassVar[int] + AUTO_FILL_FIELD_NUMBER: _ClassVar[int] + USERNAME_SELECTOR_FIELD_NUMBER: _ClassVar[int] + PASSWORD_SELECTOR_FIELD_NUMBER: _ClassVar[int] + SUBMIT_SELECTOR_FIELD_NUMBER: _ClassVar[int] + SCRIPT_FIELD_NUMBER: _ClassVar[int] + HTTP_PROXY_FIELD_NUMBER: _ClassVar[int] + PG_SSL_MODE_FIELD_NUMBER: _ClassVar[int] + db_name: str + use_ssl: bool + ca_cert: str + client_cert: str + client_key: str + allow_invalid_cert: bool + auto_fill: str + username_selector: str + password_selector: str + submit_selector: str + script: str + http_proxy: str + pg_ssl_mode: str + def __init__(self, db_name: _Optional[str] = ..., use_ssl: bool = ..., ca_cert: _Optional[str] = ..., client_cert: _Optional[str] = ..., client_key: _Optional[str] = ..., allow_invalid_cert: bool = ..., auto_fill: _Optional[str] = ..., username_selector: _Optional[str] = ..., password_selector: _Optional[str] = ..., submit_selector: _Optional[str] = ..., script: _Optional[str] = ..., http_proxy: _Optional[str] = ..., pg_ssl_mode: _Optional[str] = ...) -> None: ... + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + ADDRESS_FIELD_NUMBER: _ClassVar[int] + ORG_ID_FIELD_NUMBER: _ClassVar[int] + ORG_NAME_FIELD_NUMBER: _ClassVar[int] + PROTOCOLS_FIELD_NUMBER: _ClassVar[int] + SPECIFIC_FIELD_NUMBER: _ClassVar[int] + id: str + name: str + address: str + org_id: str + org_name: str + protocols: _containers.RepeatedCompositeFieldContainer[Protocol] + specific: Asset.Specific + def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., address: _Optional[str] = ..., org_id: _Optional[str] = ..., org_name: _Optional[str] = ..., protocols: _Optional[_Iterable[_Union[Protocol, _Mapping]]] = ..., specific: _Optional[_Union[Asset.Specific, _Mapping]] = ...) -> None: ... + +class Protocol(_message.Message): + __slots__ = ("name", "id", "port") + NAME_FIELD_NUMBER: _ClassVar[int] + ID_FIELD_NUMBER: _ClassVar[int] + PORT_FIELD_NUMBER: _ClassVar[int] + name: str + id: int + port: int + def __init__(self, name: _Optional[str] = ..., id: _Optional[int] = ..., port: _Optional[int] = ...) -> None: ... + +class Gateway(_message.Message): + __slots__ = ("id", "name", "ip", "port", "protocol", "username", "password", "private_key") + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + IP_FIELD_NUMBER: _ClassVar[int] + PORT_FIELD_NUMBER: _ClassVar[int] + PROTOCOL_FIELD_NUMBER: _ClassVar[int] + USERNAME_FIELD_NUMBER: _ClassVar[int] + PASSWORD_FIELD_NUMBER: _ClassVar[int] + PRIVATE_KEY_FIELD_NUMBER: _ClassVar[int] + id: str + name: str + ip: str + port: int + protocol: str + username: str + password: str + private_key: str + def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., ip: _Optional[str] = ..., port: _Optional[int] = ..., protocol: _Optional[str] = ..., username: _Optional[str] = ..., password: _Optional[str] = ..., private_key: _Optional[str] = ...) -> None: ... + +class Permission(_message.Message): + __slots__ = ("enable_connect", "enable_download", "enable_upload", "enable_copy", "enable_paste") + ENABLE_CONNECT_FIELD_NUMBER: _ClassVar[int] + ENABLE_DOWNLOAD_FIELD_NUMBER: _ClassVar[int] + ENABLE_UPLOAD_FIELD_NUMBER: _ClassVar[int] + ENABLE_COPY_FIELD_NUMBER: _ClassVar[int] + ENABLE_PASTE_FIELD_NUMBER: _ClassVar[int] + enable_connect: bool + enable_download: bool + enable_upload: bool + enable_copy: bool + enable_paste: bool + def __init__(self, enable_connect: bool = ..., enable_download: bool = ..., enable_upload: bool = ..., enable_copy: bool = ..., enable_paste: bool = ...) -> None: ... + +class CommandACL(_message.Message): + __slots__ = ("id", "name", "priority", "action", "is_active", "command_groups") + class Action(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + Reject: _ClassVar[CommandACL.Action] + Accept: _ClassVar[CommandACL.Action] + Review: _ClassVar[CommandACL.Action] + Warning: _ClassVar[CommandACL.Action] + NotifyWarning: _ClassVar[CommandACL.Action] + Unknown: _ClassVar[CommandACL.Action] + Reject: CommandACL.Action + Accept: CommandACL.Action + Review: CommandACL.Action + Warning: CommandACL.Action + NotifyWarning: CommandACL.Action + Unknown: CommandACL.Action + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + PRIORITY_FIELD_NUMBER: _ClassVar[int] + ACTION_FIELD_NUMBER: _ClassVar[int] + IS_ACTIVE_FIELD_NUMBER: _ClassVar[int] + COMMAND_GROUPS_FIELD_NUMBER: _ClassVar[int] + id: str + name: str + priority: int + action: CommandACL.Action + is_active: bool + command_groups: _containers.RepeatedCompositeFieldContainer[CommandGroup] + def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., priority: _Optional[int] = ..., action: _Optional[_Union[CommandACL.Action, str]] = ..., is_active: bool = ..., command_groups: _Optional[_Iterable[_Union[CommandGroup, _Mapping]]] = ...) -> None: ... + +class DataMaskingRule(_message.Message): + __slots__ = ("id", "name", "priority", "is_active", "masking_method", "mask_pattern", "fields_pattern") + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + PRIORITY_FIELD_NUMBER: _ClassVar[int] + IS_ACTIVE_FIELD_NUMBER: _ClassVar[int] + MASKING_METHOD_FIELD_NUMBER: _ClassVar[int] + MASK_PATTERN_FIELD_NUMBER: _ClassVar[int] + FIELDS_PATTERN_FIELD_NUMBER: _ClassVar[int] + id: str + name: str + priority: int + is_active: bool + masking_method: str + mask_pattern: str + fields_pattern: str + def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., priority: _Optional[int] = ..., is_active: bool = ..., masking_method: _Optional[str] = ..., mask_pattern: _Optional[str] = ..., fields_pattern: _Optional[str] = ...) -> None: ... + +class CommandGroup(_message.Message): + __slots__ = ("id", "name", "content", "Type", "pattern", "ignore_case") + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + CONTENT_FIELD_NUMBER: _ClassVar[int] + TYPE_FIELD_NUMBER: _ClassVar[int] + PATTERN_FIELD_NUMBER: _ClassVar[int] + IGNORE_CASE_FIELD_NUMBER: _ClassVar[int] + id: str + name: str + content: str + Type: str + pattern: str + ignore_case: bool + def __init__(self, id: _Optional[str] = ..., name: _Optional[str] = ..., content: _Optional[str] = ..., Type: _Optional[str] = ..., pattern: _Optional[str] = ..., ignore_case: bool = ...) -> None: ... + +class ExpireInfo(_message.Message): + __slots__ = ("expire_at",) + EXPIRE_AT_FIELD_NUMBER: _ClassVar[int] + expire_at: int + def __init__(self, expire_at: _Optional[int] = ...) -> None: ... + +class Session(_message.Message): + __slots__ = ("id", "user", "asset", "account", "login_from", "remote_addr", "protocol", "date_start", "org_id", "user_id", "asset_id", "account_id", "token_id") + class LoginFrom(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + WT: _ClassVar[Session.LoginFrom] + ST: _ClassVar[Session.LoginFrom] + RT: _ClassVar[Session.LoginFrom] + DT: _ClassVar[Session.LoginFrom] + WT: Session.LoginFrom + ST: Session.LoginFrom + RT: Session.LoginFrom + DT: Session.LoginFrom + ID_FIELD_NUMBER: _ClassVar[int] + USER_FIELD_NUMBER: _ClassVar[int] + ASSET_FIELD_NUMBER: _ClassVar[int] + ACCOUNT_FIELD_NUMBER: _ClassVar[int] + LOGIN_FROM_FIELD_NUMBER: _ClassVar[int] + REMOTE_ADDR_FIELD_NUMBER: _ClassVar[int] + PROTOCOL_FIELD_NUMBER: _ClassVar[int] + DATE_START_FIELD_NUMBER: _ClassVar[int] + ORG_ID_FIELD_NUMBER: _ClassVar[int] + USER_ID_FIELD_NUMBER: _ClassVar[int] + ASSET_ID_FIELD_NUMBER: _ClassVar[int] + ACCOUNT_ID_FIELD_NUMBER: _ClassVar[int] + TOKEN_ID_FIELD_NUMBER: _ClassVar[int] + id: str + user: str + asset: str + account: str + login_from: Session.LoginFrom + remote_addr: str + protocol: str + date_start: int + org_id: str + user_id: str + asset_id: str + account_id: str + token_id: str + def __init__(self, id: _Optional[str] = ..., user: _Optional[str] = ..., asset: _Optional[str] = ..., account: _Optional[str] = ..., login_from: _Optional[_Union[Session.LoginFrom, str]] = ..., remote_addr: _Optional[str] = ..., protocol: _Optional[str] = ..., date_start: _Optional[int] = ..., org_id: _Optional[str] = ..., user_id: _Optional[str] = ..., asset_id: _Optional[str] = ..., account_id: _Optional[str] = ..., token_id: _Optional[str] = ...) -> None: ... + +class TokenStatus(_message.Message): + __slots__ = ("code", "detail", "is_expired") + CODE_FIELD_NUMBER: _ClassVar[int] + DETAIL_FIELD_NUMBER: _ClassVar[int] + IS_EXPIRED_FIELD_NUMBER: _ClassVar[int] + code: str + detail: str + is_expired: bool + def __init__(self, code: _Optional[str] = ..., detail: _Optional[str] = ..., is_expired: bool = ...) -> None: ... + +class TerminalTask(_message.Message): + __slots__ = ("id", "action", "session_id", "terminated_by", "created_by", "token_status") + ID_FIELD_NUMBER: _ClassVar[int] + ACTION_FIELD_NUMBER: _ClassVar[int] + SESSION_ID_FIELD_NUMBER: _ClassVar[int] + TERMINATED_BY_FIELD_NUMBER: _ClassVar[int] + CREATED_BY_FIELD_NUMBER: _ClassVar[int] + TOKEN_STATUS_FIELD_NUMBER: _ClassVar[int] + id: str + action: TaskAction + session_id: str + terminated_by: str + created_by: str + token_status: TokenStatus + def __init__(self, id: _Optional[str] = ..., action: _Optional[_Union[TaskAction, str]] = ..., session_id: _Optional[str] = ..., terminated_by: _Optional[str] = ..., created_by: _Optional[str] = ..., token_status: _Optional[_Union[TokenStatus, _Mapping]] = ...) -> None: ... + +class TokenAuthInfo(_message.Message): + __slots__ = ("key_id", "secrete_id", "asset", "user", "account", "permission", "expire_info", "filter_rules", "gateways", "setting", "platform", "FaceMonitorToken", "data_masking_rules") + KEY_ID_FIELD_NUMBER: _ClassVar[int] + SECRETE_ID_FIELD_NUMBER: _ClassVar[int] + ASSET_FIELD_NUMBER: _ClassVar[int] + USER_FIELD_NUMBER: _ClassVar[int] + ACCOUNT_FIELD_NUMBER: _ClassVar[int] + PERMISSION_FIELD_NUMBER: _ClassVar[int] + EXPIRE_INFO_FIELD_NUMBER: _ClassVar[int] + FILTER_RULES_FIELD_NUMBER: _ClassVar[int] + GATEWAYS_FIELD_NUMBER: _ClassVar[int] + SETTING_FIELD_NUMBER: _ClassVar[int] + PLATFORM_FIELD_NUMBER: _ClassVar[int] + FACEMONITORTOKEN_FIELD_NUMBER: _ClassVar[int] + DATA_MASKING_RULES_FIELD_NUMBER: _ClassVar[int] + key_id: str + secrete_id: str + asset: Asset + user: User + account: Account + permission: Permission + expire_info: ExpireInfo + filter_rules: _containers.RepeatedCompositeFieldContainer[CommandACL] + gateways: _containers.RepeatedCompositeFieldContainer[Gateway] + setting: ComponentSetting + platform: Platform + FaceMonitorToken: str + data_masking_rules: _containers.RepeatedCompositeFieldContainer[DataMaskingRule] + def __init__(self, key_id: _Optional[str] = ..., secrete_id: _Optional[str] = ..., asset: _Optional[_Union[Asset, _Mapping]] = ..., user: _Optional[_Union[User, _Mapping]] = ..., account: _Optional[_Union[Account, _Mapping]] = ..., permission: _Optional[_Union[Permission, _Mapping]] = ..., expire_info: _Optional[_Union[ExpireInfo, _Mapping]] = ..., filter_rules: _Optional[_Iterable[_Union[CommandACL, _Mapping]]] = ..., gateways: _Optional[_Iterable[_Union[Gateway, _Mapping]]] = ..., setting: _Optional[_Union[ComponentSetting, _Mapping]] = ..., platform: _Optional[_Union[Platform, _Mapping]] = ..., FaceMonitorToken: _Optional[str] = ..., data_masking_rules: _Optional[_Iterable[_Union[DataMaskingRule, _Mapping]]] = ...) -> None: ... + +class Platform(_message.Message): + __slots__ = ("id", "name", "category", "charset", "type", "protocols") + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + CATEGORY_FIELD_NUMBER: _ClassVar[int] + CHARSET_FIELD_NUMBER: _ClassVar[int] + TYPE_FIELD_NUMBER: _ClassVar[int] + PROTOCOLS_FIELD_NUMBER: _ClassVar[int] + id: int + name: str + category: str + charset: str + type: str + protocols: _containers.RepeatedCompositeFieldContainer[PlatformProtocol] + def __init__(self, id: _Optional[int] = ..., name: _Optional[str] = ..., category: _Optional[str] = ..., charset: _Optional[str] = ..., type: _Optional[str] = ..., protocols: _Optional[_Iterable[_Union[PlatformProtocol, _Mapping]]] = ...) -> None: ... + +class PlatformProtocol(_message.Message): + __slots__ = ("id", "name", "port", "settings") + class SettingsEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: str + def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + ID_FIELD_NUMBER: _ClassVar[int] + NAME_FIELD_NUMBER: _ClassVar[int] + PORT_FIELD_NUMBER: _ClassVar[int] + SETTINGS_FIELD_NUMBER: _ClassVar[int] + id: int + name: str + port: int + settings: _containers.ScalarMap[str, str] + def __init__(self, id: _Optional[int] = ..., name: _Optional[str] = ..., port: _Optional[int] = ..., settings: _Optional[_Mapping[str, str]] = ...) -> None: ... + +class ComponentSetting(_message.Message): + __slots__ = ("max_idle_time", "max_session_time") + MAX_IDLE_TIME_FIELD_NUMBER: _ClassVar[int] + MAX_SESSION_TIME_FIELD_NUMBER: _ClassVar[int] + max_idle_time: int + max_session_time: int + def __init__(self, max_idle_time: _Optional[int] = ..., max_session_time: _Optional[int] = ...) -> None: ... + +class Forward(_message.Message): + __slots__ = ("id", "Host", "port") + ID_FIELD_NUMBER: _ClassVar[int] + HOST_FIELD_NUMBER: _ClassVar[int] + PORT_FIELD_NUMBER: _ClassVar[int] + id: str + Host: str + port: int + def __init__(self, id: _Optional[str] = ..., Host: _Optional[str] = ..., port: _Optional[int] = ...) -> None: ... + +class PublicSetting(_message.Message): + __slots__ = ("xpack_enabled", "valid_license", "gpt_base_url", "gpt_api_key", "gpt_proxy", "gpt_model", "license_content") + XPACK_ENABLED_FIELD_NUMBER: _ClassVar[int] + VALID_LICENSE_FIELD_NUMBER: _ClassVar[int] + GPT_BASE_URL_FIELD_NUMBER: _ClassVar[int] + GPT_API_KEY_FIELD_NUMBER: _ClassVar[int] + GPT_PROXY_FIELD_NUMBER: _ClassVar[int] + GPT_MODEL_FIELD_NUMBER: _ClassVar[int] + LICENSE_CONTENT_FIELD_NUMBER: _ClassVar[int] + xpack_enabled: bool + valid_license: bool + gpt_base_url: str + gpt_api_key: str + gpt_proxy: str + gpt_model: str + license_content: str + def __init__(self, xpack_enabled: bool = ..., valid_license: bool = ..., gpt_base_url: _Optional[str] = ..., gpt_api_key: _Optional[str] = ..., gpt_proxy: _Optional[str] = ..., gpt_model: _Optional[str] = ..., license_content: _Optional[str] = ...) -> None: ... + +class Cookie(_message.Message): + __slots__ = ("name", "value") + NAME_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + name: str + value: str + def __init__(self, name: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + +class LifecycleLogData(_message.Message): + __slots__ = ("event", "reason", "user") + class event_type(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + AssetConnectSuccess: _ClassVar[LifecycleLogData.event_type] + AssetConnectFinished: _ClassVar[LifecycleLogData.event_type] + CreateShareLink: _ClassVar[LifecycleLogData.event_type] + UserJoinSession: _ClassVar[LifecycleLogData.event_type] + UserLeaveSession: _ClassVar[LifecycleLogData.event_type] + AdminJoinMonitor: _ClassVar[LifecycleLogData.event_type] + AdminExitMonitor: _ClassVar[LifecycleLogData.event_type] + ReplayConvertStart: _ClassVar[LifecycleLogData.event_type] + ReplayConvertSuccess: _ClassVar[LifecycleLogData.event_type] + ReplayConvertFailure: _ClassVar[LifecycleLogData.event_type] + ReplayUploadStart: _ClassVar[LifecycleLogData.event_type] + ReplayUploadSuccess: _ClassVar[LifecycleLogData.event_type] + ReplayUploadFailure: _ClassVar[LifecycleLogData.event_type] + AssetConnectSuccess: LifecycleLogData.event_type + AssetConnectFinished: LifecycleLogData.event_type + CreateShareLink: LifecycleLogData.event_type + UserJoinSession: LifecycleLogData.event_type + UserLeaveSession: LifecycleLogData.event_type + AdminJoinMonitor: LifecycleLogData.event_type + AdminExitMonitor: LifecycleLogData.event_type + ReplayConvertStart: LifecycleLogData.event_type + ReplayConvertSuccess: LifecycleLogData.event_type + ReplayConvertFailure: LifecycleLogData.event_type + ReplayUploadStart: LifecycleLogData.event_type + ReplayUploadSuccess: LifecycleLogData.event_type + ReplayUploadFailure: LifecycleLogData.event_type + EVENT_FIELD_NUMBER: _ClassVar[int] + REASON_FIELD_NUMBER: _ClassVar[int] + USER_FIELD_NUMBER: _ClassVar[int] + event: LifecycleLogData.event_type + reason: str + user: str + def __init__(self, event: _Optional[_Union[LifecycleLogData.event_type, str]] = ..., reason: _Optional[str] = ..., user: _Optional[str] = ...) -> None: ... diff --git a/backend/open_webui/jms/wisp/protobuf/common_pb2_grpc.py b/backend/open_webui/jms/wisp/protobuf/common_pb2_grpc.py new file mode 100644 index 000000000000..f80da210ff0d --- /dev/null +++ b/backend/open_webui/jms/wisp/protobuf/common_pb2_grpc.py @@ -0,0 +1,24 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + + +GRPC_GENERATED_VERSION = '1.69.0' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in common_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) diff --git a/backend/open_webui/jms/wisp/protobuf/service_pb2.py b/backend/open_webui/jms/wisp/protobuf/service_pb2.py new file mode 100644 index 000000000000..ca51901bbda2 --- /dev/null +++ b/backend/open_webui/jms/wisp/protobuf/service_pb2.py @@ -0,0 +1,147 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# NO CHECKED-IN PROTOBUF GENCODE +# source: service.proto +# Protobuf Python Version: 5.29.0 +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import runtime_version as _runtime_version +from google.protobuf import symbol_database as _symbol_database +from google.protobuf.internal import builder as _builder +_runtime_version.ValidateProtobufRuntimeVersion( + _runtime_version.Domain.PUBLIC, + 5, + 29, + 0, + '', + 'service.proto' +) +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +import common_pb2 as common__pb2 +from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2 + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rservice.proto\x12\x07message\x1a\x0c\x63ommon.proto\x1a\x1cgoogle/protobuf/struct.proto\"H\n\x16JoinFaceMonitorRequest\x12\x1a\n\x12\x66\x61\x63\x65_monitor_token\x18\x01 \x01(\t\x12\x12\n\nsession_id\x18\x02 \x01(\t\":\n\x17JoinFaceMonitorResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\"\x8c\x01\n\x1a\x46\x61\x63\x65MonitorCallbackRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x15\n\rerror_message\x18\x03 \x01(\t\x12\x13\n\x0bis_finished\x18\x04 \x01(\x08\x12\x0e\n\x06\x61\x63tion\x18\x05 \x01(\t\x12\x12\n\nface_codes\x18\x06 \x03(\t\">\n\x1b\x46\x61\x63\x65MonitorCallbackResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\"j\n\x1e\x46\x61\x63\x65RecognitionCallbackRequest\x12\r\n\x05token\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x15\n\rerror_message\x18\x03 \x01(\t\x12\x11\n\tface_code\x18\x04 \x01(\t\"B\n\x1f\x46\x61\x63\x65RecognitionCallbackResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\"V\n\x17\x41ssetLoginTicketRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x10\n\x08\x61sset_id\x18\x02 \x01(\t\x12\x18\n\x10\x61\x63\x63ount_username\x18\x04 \x01(\t\"\x8e\x01\n\x18\x41ssetLoginTicketResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12(\n\x0bticket_info\x18\x02 \x01(\x0b\x32\x13.message.TicketInfo\x12\x14\n\x0cneed_confirm\x18\x03 \x01(\x08\x12\x11\n\tticket_id\x18\x04 \x01(\t\"!\n\x06Status\x12\n\n\x02ok\x18\x01 \x01(\x08\x12\x0b\n\x03\x65rr\x18\x02 \x01(\t\"\x1d\n\x0cTokenRequest\x12\r\n\x05token\x18\x01 \x01(\t\"V\n\rTokenResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12$\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x16.message.TokenAuthInfo\"6\n\x14SessionCreateRequest\x12\x1e\n\x04\x64\x61ta\x18\x01 \x01(\x0b\x32\x10.message.Session\"X\n\x15SessionCreateResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12\x1e\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x10.message.Session\"R\n\x14SessionFinishRequest\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x10\n\x08\x64\x61te_end\x18\x03 \x01(\x03\x12\x0b\n\x03\x65rr\x18\x04 \x01(\t\"4\n\x11SessionFinishResp\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\"=\n\rReplayRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x18\n\x10replay_file_path\x18\x02 \x01(\t\"1\n\x0eReplayResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\"\xdf\x01\n\x0e\x43ommandRequest\x12\x0b\n\x03sid\x18\x01 \x01(\t\x12\x0e\n\x06org_id\x18\x02 \x01(\t\x12\r\n\x05input\x18\x03 \x01(\t\x12\x0e\n\x06output\x18\x04 \x01(\t\x12\x0c\n\x04user\x18\x05 \x01(\t\x12\r\n\x05\x61sset\x18\x06 \x01(\t\x12\x0f\n\x07\x61\x63\x63ount\x18\x07 \x01(\t\x12\x11\n\ttimestamp\x18\x08 \x01(\x03\x12&\n\nrisk_level\x18\t \x01(\x0e\x32\x12.message.RiskLevel\x12\x12\n\ncmd_acl_id\x18\n \x01(\t\x12\x14\n\x0c\x63md_group_id\x18\x0b \x01(\t\"2\n\x0f\x43ommandResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\"&\n\x13\x46inishedTaskRequest\x12\x0f\n\x07task_id\x18\x01 \x01(\t\"3\n\x0cTaskResponse\x12#\n\x04task\x18\x01 \x01(\x0b\x32\x15.message.TerminalTask\")\n\x13RemainReplayRequest\x12\x12\n\nreplay_dir\x18\x01 \x01(\t\"{\n\x14RemainReplayResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12\x15\n\rsuccess_files\x18\x02 \x03(\t\x12\x15\n\rfailure_files\x18\x03 \x03(\t\x12\x14\n\x0c\x66\x61ilure_errs\x18\x04 \x03(\t\"1\n\x0eStatusResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\"L\n\x15\x43ommandConfirmRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12\x12\n\ncmd_acl_id\x18\x02 \x01(\t\x12\x0b\n\x03\x63md\x18\x03 \x01(\t\"&\n\x07ReqInfo\x12\x0e\n\x06method\x18\x01 \x01(\t\x12\x0b\n\x03url\x18\x02 \x01(\t\"\\\n\x16\x43ommandConfirmResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12!\n\x04info\x18\x02 \x01(\x0b\x32\x13.message.TicketInfo\"\x85\x01\n\nTicketInfo\x12#\n\tcheck_req\x18\x01 \x01(\x0b\x32\x10.message.ReqInfo\x12$\n\ncancel_req\x18\x02 \x01(\x0b\x32\x10.message.ReqInfo\x12\x19\n\x11ticket_detail_url\x18\x03 \x01(\t\x12\x11\n\treviewers\x18\x04 \x03(\t\".\n\rTicketRequest\x12\x1d\n\x03req\x18\x01 \x01(\x0b\x32\x10.message.ReqInfo\"Z\n\x13TicketStateResponse\x12\"\n\x04\x44\x61ta\x18\x01 \x01(\x0b\x32\x14.message.TicketState\x12\x1f\n\x06status\x18\x02 \x01(\x0b\x32\x0f.message.Status\"\x86\x01\n\x0bTicketState\x12)\n\x05state\x18\x01 \x01(\x0e\x32\x1a.message.TicketState.State\x12\x11\n\tprocessor\x18\x02 \x01(\t\"9\n\x05State\x12\x08\n\x04Open\x10\x00\x12\x0c\n\x08\x41pproved\x10\x01\x12\x0c\n\x08Rejected\x10\x02\x12\n\n\x06\x43losed\x10\x03\"P\n\x0e\x46orwardRequest\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\x12\"\n\x08gateways\x18\x03 \x03(\x0b\x32\x10.message.Gateway\"\"\n\x14\x46orwardDeleteRequest\x12\n\n\x02id\x18\x01 \x01(\t\"Z\n\x0f\x46orwardResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12\n\n\x02id\x18\x02 \x01(\t\x12\x0c\n\x04host\x18\x03 \x01(\t\x12\x0c\n\x04port\x18\x04 \x01(\x05\"^\n\x15PublicSettingResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12$\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x16.message.PublicSetting\"\x07\n\x05\x45mpty\"D\n\x12ListenPortResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12\r\n\x05ports\x18\x02 \x03(\x05\"\x1f\n\x0fPortInfoRequest\x12\x0c\n\x04port\x18\x01 \x01(\x05\"T\n\x10PortInfoResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12\x1f\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x11.message.PortInfo\"M\n\x08PortInfo\x12\x1d\n\x05\x61sset\x18\x01 \x01(\x0b\x32\x0e.message.Asset\x12\"\n\x08gateways\x18\x02 \x03(\x0b\x32\x10.message.Gateway\"+\n\x0bPortFailure\x12\x0c\n\x04port\x18\x01 \x01(\x05\x12\x0e\n\x06reason\x18\x02 \x01(\t\"8\n\x12PortFailureRequest\x12\"\n\x04\x64\x61ta\x18\x01 \x03(\x0b\x32\x14.message.PortFailure\"2\n\x0e\x43ookiesRequest\x12 \n\x07\x63ookies\x18\x01 \x03(\x0b\x32\x0f.message.Cookie\"L\n\x0cUserResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12\x1b\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\r.message.User\"\xce\x03\n\x1aSessionLifecycleLogRequest\x12\x12\n\nsession_id\x18\x01 \x01(\t\x12<\n\x05\x65vent\x18\x02 \x01(\x0e\x32-.message.SessionLifecycleLogRequest.EventType\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x0c\n\x04user\x18\x04 \x01(\t\"\xbf\x02\n\tEventType\x12\x17\n\x13\x41ssetConnectSuccess\x10\x00\x12\x18\n\x14\x41ssetConnectFinished\x10\x01\x12\x13\n\x0f\x43reateShareLink\x10\x02\x12\x13\n\x0fUserJoinSession\x10\x03\x12\x14\n\x10UserLeaveSession\x10\x04\x12\x14\n\x10\x41\x64minJoinMonitor\x10\x05\x12\x14\n\x10\x41\x64minExitMonitor\x10\x06\x12\x16\n\x12ReplayConvertStart\x10\x07\x12\x18\n\x14ReplayConvertSuccess\x10\x08\x12\x18\n\x14ReplayConvertFailure\x10\t\x12\x15\n\x11ReplayUploadStart\x10\n\x12\x17\n\x13ReplayUploadSuccess\x10\x0b\x12\x17\n\x13ReplayUploadFailure\x10\x0c\"b\n\x15\x41\x63\x63ountDetailResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12(\n\x07payload\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\"\xf8\x01\n\x0bHTTPRequest\x12\x0e\n\x06method\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\x12.\n\x05query\x18\x03 \x03(\x0b\x32\x1f.message.HTTPRequest.QueryEntry\x12\x30\n\x06header\x18\x04 \x03(\x0b\x32 .message.HTTPRequest.HeaderEntry\x12\x0c\n\x04\x62ody\x18\x05 \x01(\x0c\x1a,\n\nQueryEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a-\n\x0bHeaderEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"=\n\x0cHTTPResponse\x12\x1f\n\x06status\x18\x01 \x01(\x0b\x32\x0f.message.Status\x12\x0c\n\x04\x62ody\x18\x02 \x01(\x0c\x32\xa5\x0f\n\x07Service\x12\x43\n\x10GetTokenAuthInfo\x12\x15.message.TokenRequest\x1a\x16.message.TokenResponse\"\x00\x12>\n\nRenewToken\x12\x15.message.TokenRequest\x1a\x17.message.StatusResponse\"\x00\x12P\n\rCreateSession\x12\x1d.message.SessionCreateRequest\x1a\x1e.message.SessionCreateResponse\"\x00\x12L\n\rFinishSession\x12\x1d.message.SessionFinishRequest\x1a\x1a.message.SessionFinishResp\"\x00\x12\x45\n\x10UploadReplayFile\x12\x16.message.ReplayRequest\x1a\x17.message.ReplayResponse\"\x00\x12\x44\n\rUploadCommand\x12\x17.message.CommandRequest\x1a\x18.message.CommandResponse\"\x00\x12I\n\x0c\x44ispatchTask\x12\x1c.message.FinishedTaskRequest\x1a\x15.message.TaskResponse\"\x00(\x01\x30\x01\x12R\n\x11ScanRemainReplays\x12\x1c.message.RemainReplayRequest\x1a\x1d.message.RemainReplayResponse\"\x00\x12X\n\x13\x43reateCommandTicket\x12\x1e.message.CommandConfirmRequest\x1a\x1f.message.CommandConfirmResponse\"\x00\x12\x66\n\x1d\x43heckOrCreateAssetLoginTicket\x12 .message.AssetLoginTicketRequest\x1a!.message.AssetLoginTicketResponse\"\x00\x12J\n\x10\x43heckTicketState\x12\x16.message.TicketRequest\x1a\x1c.message.TicketStateResponse\"\x00\x12\x41\n\x0c\x43\x61ncelTicket\x12\x16.message.TicketRequest\x1a\x17.message.StatusResponse\"\x00\x12\x44\n\rCreateForward\x12\x17.message.ForwardRequest\x1a\x18.message.ForwardResponse\"\x00\x12I\n\rDeleteForward\x12\x1d.message.ForwardDeleteRequest\x1a\x17.message.StatusResponse\"\x00\x12\x44\n\x10GetPublicSetting\x12\x0e.message.Empty\x1a\x1e.message.PublicSettingResponse\"\x00\x12?\n\x0eGetListenPorts\x12\x0e.message.Empty\x1a\x1b.message.ListenPortResponse\"\x00\x12\x44\n\x0bGetPortInfo\x12\x18.message.PortInfoRequest\x1a\x19.message.PortInfoResponse\"\x00\x12K\n\x11HandlePortFailure\x12\x1b.message.PortFailureRequest\x1a\x17.message.StatusResponse\"\x00\x12\x46\n\x12\x43heckUserByCookies\x12\x17.message.CookiesRequest\x1a\x15.message.UserResponse\"\x00\x12[\n\x19RecordSessionLifecycleLog\x12#.message.SessionLifecycleLogRequest\x1a\x17.message.StatusResponse\"\x00\x12n\n\x17\x46\x61\x63\x65RecognitionCallback\x12\'.message.FaceRecognitionCallbackRequest\x1a(.message.FaceRecognitionCallbackResponse\"\x00\x12\x62\n\x13\x46\x61\x63\x65MonitorCallback\x12#.message.FaceMonitorCallbackRequest\x1a$.message.FaceMonitorCallbackResponse\"\x00\x12V\n\x0fJoinFaceMonitor\x12\x1f.message.JoinFaceMonitorRequest\x1a .message.JoinFaceMonitorResponse\"\x00\x12\x42\n\x0eGetAccountChat\x12\x0e.message.Empty\x1a\x1e.message.AccountDetailResponse\"\x00\x12\x38\n\x07\x43\x61llAPI\x12\x14.message.HTTPRequest\x1a\x15.message.HTTPResponse\"\x00\x42 \n\x13org.jumpserver.wispZ\t/protobufb\x06proto3') + +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'service_pb2', _globals) +if not _descriptor._USE_C_DESCRIPTORS: + _globals['DESCRIPTOR']._loaded_options = None + _globals['DESCRIPTOR']._serialized_options = b'\n\023org.jumpserver.wispZ\t/protobuf' + _globals['_HTTPREQUEST_QUERYENTRY']._loaded_options = None + _globals['_HTTPREQUEST_QUERYENTRY']._serialized_options = b'8\001' + _globals['_HTTPREQUEST_HEADERENTRY']._loaded_options = None + _globals['_HTTPREQUEST_HEADERENTRY']._serialized_options = b'8\001' + _globals['_JOINFACEMONITORREQUEST']._serialized_start=70 + _globals['_JOINFACEMONITORREQUEST']._serialized_end=142 + _globals['_JOINFACEMONITORRESPONSE']._serialized_start=144 + _globals['_JOINFACEMONITORRESPONSE']._serialized_end=202 + _globals['_FACEMONITORCALLBACKREQUEST']._serialized_start=205 + _globals['_FACEMONITORCALLBACKREQUEST']._serialized_end=345 + _globals['_FACEMONITORCALLBACKRESPONSE']._serialized_start=347 + _globals['_FACEMONITORCALLBACKRESPONSE']._serialized_end=409 + _globals['_FACERECOGNITIONCALLBACKREQUEST']._serialized_start=411 + _globals['_FACERECOGNITIONCALLBACKREQUEST']._serialized_end=517 + _globals['_FACERECOGNITIONCALLBACKRESPONSE']._serialized_start=519 + _globals['_FACERECOGNITIONCALLBACKRESPONSE']._serialized_end=585 + _globals['_ASSETLOGINTICKETREQUEST']._serialized_start=587 + _globals['_ASSETLOGINTICKETREQUEST']._serialized_end=673 + _globals['_ASSETLOGINTICKETRESPONSE']._serialized_start=676 + _globals['_ASSETLOGINTICKETRESPONSE']._serialized_end=818 + _globals['_STATUS']._serialized_start=820 + _globals['_STATUS']._serialized_end=853 + _globals['_TOKENREQUEST']._serialized_start=855 + _globals['_TOKENREQUEST']._serialized_end=884 + _globals['_TOKENRESPONSE']._serialized_start=886 + _globals['_TOKENRESPONSE']._serialized_end=972 + _globals['_SESSIONCREATEREQUEST']._serialized_start=974 + _globals['_SESSIONCREATEREQUEST']._serialized_end=1028 + _globals['_SESSIONCREATERESPONSE']._serialized_start=1030 + _globals['_SESSIONCREATERESPONSE']._serialized_end=1118 + _globals['_SESSIONFINISHREQUEST']._serialized_start=1120 + _globals['_SESSIONFINISHREQUEST']._serialized_end=1202 + _globals['_SESSIONFINISHRESP']._serialized_start=1204 + _globals['_SESSIONFINISHRESP']._serialized_end=1256 + _globals['_REPLAYREQUEST']._serialized_start=1258 + _globals['_REPLAYREQUEST']._serialized_end=1319 + _globals['_REPLAYRESPONSE']._serialized_start=1321 + _globals['_REPLAYRESPONSE']._serialized_end=1370 + _globals['_COMMANDREQUEST']._serialized_start=1373 + _globals['_COMMANDREQUEST']._serialized_end=1596 + _globals['_COMMANDRESPONSE']._serialized_start=1598 + _globals['_COMMANDRESPONSE']._serialized_end=1648 + _globals['_FINISHEDTASKREQUEST']._serialized_start=1650 + _globals['_FINISHEDTASKREQUEST']._serialized_end=1688 + _globals['_TASKRESPONSE']._serialized_start=1690 + _globals['_TASKRESPONSE']._serialized_end=1741 + _globals['_REMAINREPLAYREQUEST']._serialized_start=1743 + _globals['_REMAINREPLAYREQUEST']._serialized_end=1784 + _globals['_REMAINREPLAYRESPONSE']._serialized_start=1786 + _globals['_REMAINREPLAYRESPONSE']._serialized_end=1909 + _globals['_STATUSRESPONSE']._serialized_start=1911 + _globals['_STATUSRESPONSE']._serialized_end=1960 + _globals['_COMMANDCONFIRMREQUEST']._serialized_start=1962 + _globals['_COMMANDCONFIRMREQUEST']._serialized_end=2038 + _globals['_REQINFO']._serialized_start=2040 + _globals['_REQINFO']._serialized_end=2078 + _globals['_COMMANDCONFIRMRESPONSE']._serialized_start=2080 + _globals['_COMMANDCONFIRMRESPONSE']._serialized_end=2172 + _globals['_TICKETINFO']._serialized_start=2175 + _globals['_TICKETINFO']._serialized_end=2308 + _globals['_TICKETREQUEST']._serialized_start=2310 + _globals['_TICKETREQUEST']._serialized_end=2356 + _globals['_TICKETSTATERESPONSE']._serialized_start=2358 + _globals['_TICKETSTATERESPONSE']._serialized_end=2448 + _globals['_TICKETSTATE']._serialized_start=2451 + _globals['_TICKETSTATE']._serialized_end=2585 + _globals['_TICKETSTATE_STATE']._serialized_start=2528 + _globals['_TICKETSTATE_STATE']._serialized_end=2585 + _globals['_FORWARDREQUEST']._serialized_start=2587 + _globals['_FORWARDREQUEST']._serialized_end=2667 + _globals['_FORWARDDELETEREQUEST']._serialized_start=2669 + _globals['_FORWARDDELETEREQUEST']._serialized_end=2703 + _globals['_FORWARDRESPONSE']._serialized_start=2705 + _globals['_FORWARDRESPONSE']._serialized_end=2795 + _globals['_PUBLICSETTINGRESPONSE']._serialized_start=2797 + _globals['_PUBLICSETTINGRESPONSE']._serialized_end=2891 + _globals['_EMPTY']._serialized_start=2893 + _globals['_EMPTY']._serialized_end=2900 + _globals['_LISTENPORTRESPONSE']._serialized_start=2902 + _globals['_LISTENPORTRESPONSE']._serialized_end=2970 + _globals['_PORTINFOREQUEST']._serialized_start=2972 + _globals['_PORTINFOREQUEST']._serialized_end=3003 + _globals['_PORTINFORESPONSE']._serialized_start=3005 + _globals['_PORTINFORESPONSE']._serialized_end=3089 + _globals['_PORTINFO']._serialized_start=3091 + _globals['_PORTINFO']._serialized_end=3168 + _globals['_PORTFAILURE']._serialized_start=3170 + _globals['_PORTFAILURE']._serialized_end=3213 + _globals['_PORTFAILUREREQUEST']._serialized_start=3215 + _globals['_PORTFAILUREREQUEST']._serialized_end=3271 + _globals['_COOKIESREQUEST']._serialized_start=3273 + _globals['_COOKIESREQUEST']._serialized_end=3323 + _globals['_USERRESPONSE']._serialized_start=3325 + _globals['_USERRESPONSE']._serialized_end=3401 + _globals['_SESSIONLIFECYCLELOGREQUEST']._serialized_start=3404 + _globals['_SESSIONLIFECYCLELOGREQUEST']._serialized_end=3866 + _globals['_SESSIONLIFECYCLELOGREQUEST_EVENTTYPE']._serialized_start=3547 + _globals['_SESSIONLIFECYCLELOGREQUEST_EVENTTYPE']._serialized_end=3866 + _globals['_ACCOUNTDETAILRESPONSE']._serialized_start=3868 + _globals['_ACCOUNTDETAILRESPONSE']._serialized_end=3966 + _globals['_HTTPREQUEST']._serialized_start=3969 + _globals['_HTTPREQUEST']._serialized_end=4217 + _globals['_HTTPREQUEST_QUERYENTRY']._serialized_start=4126 + _globals['_HTTPREQUEST_QUERYENTRY']._serialized_end=4170 + _globals['_HTTPREQUEST_HEADERENTRY']._serialized_start=4172 + _globals['_HTTPREQUEST_HEADERENTRY']._serialized_end=4217 + _globals['_HTTPRESPONSE']._serialized_start=4219 + _globals['_HTTPRESPONSE']._serialized_end=4280 + _globals['_SERVICE']._serialized_start=4283 + _globals['_SERVICE']._serialized_end=6240 +# @@protoc_insertion_point(module_scope) diff --git a/backend/open_webui/jms/wisp/protobuf/service_pb2.pyi b/backend/open_webui/jms/wisp/protobuf/service_pb2.pyi new file mode 100644 index 000000000000..8c1dcbe835aa --- /dev/null +++ b/backend/open_webui/jms/wisp/protobuf/service_pb2.pyi @@ -0,0 +1,473 @@ +import common_pb2 as _common_pb2 +from google.protobuf import struct_pb2 as _struct_pb2 +from google.protobuf.internal import containers as _containers +from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Iterable as _Iterable, Mapping as _Mapping, Optional as _Optional, Union as _Union + +DESCRIPTOR: _descriptor.FileDescriptor + +class JoinFaceMonitorRequest(_message.Message): + __slots__ = ("face_monitor_token", "session_id") + FACE_MONITOR_TOKEN_FIELD_NUMBER: _ClassVar[int] + SESSION_ID_FIELD_NUMBER: _ClassVar[int] + face_monitor_token: str + session_id: str + def __init__(self, face_monitor_token: _Optional[str] = ..., session_id: _Optional[str] = ...) -> None: ... + +class JoinFaceMonitorResponse(_message.Message): + __slots__ = ("status",) + STATUS_FIELD_NUMBER: _ClassVar[int] + status: Status + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class FaceMonitorCallbackRequest(_message.Message): + __slots__ = ("token", "success", "error_message", "is_finished", "action", "face_codes") + TOKEN_FIELD_NUMBER: _ClassVar[int] + SUCCESS_FIELD_NUMBER: _ClassVar[int] + ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int] + IS_FINISHED_FIELD_NUMBER: _ClassVar[int] + ACTION_FIELD_NUMBER: _ClassVar[int] + FACE_CODES_FIELD_NUMBER: _ClassVar[int] + token: str + success: bool + error_message: str + is_finished: bool + action: str + face_codes: _containers.RepeatedScalarFieldContainer[str] + def __init__(self, token: _Optional[str] = ..., success: bool = ..., error_message: _Optional[str] = ..., is_finished: bool = ..., action: _Optional[str] = ..., face_codes: _Optional[_Iterable[str]] = ...) -> None: ... + +class FaceMonitorCallbackResponse(_message.Message): + __slots__ = ("status",) + STATUS_FIELD_NUMBER: _ClassVar[int] + status: Status + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class FaceRecognitionCallbackRequest(_message.Message): + __slots__ = ("token", "success", "error_message", "face_code") + TOKEN_FIELD_NUMBER: _ClassVar[int] + SUCCESS_FIELD_NUMBER: _ClassVar[int] + ERROR_MESSAGE_FIELD_NUMBER: _ClassVar[int] + FACE_CODE_FIELD_NUMBER: _ClassVar[int] + token: str + success: bool + error_message: str + face_code: str + def __init__(self, token: _Optional[str] = ..., success: bool = ..., error_message: _Optional[str] = ..., face_code: _Optional[str] = ...) -> None: ... + +class FaceRecognitionCallbackResponse(_message.Message): + __slots__ = ("status",) + STATUS_FIELD_NUMBER: _ClassVar[int] + status: Status + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class AssetLoginTicketRequest(_message.Message): + __slots__ = ("user_id", "asset_id", "account_username") + USER_ID_FIELD_NUMBER: _ClassVar[int] + ASSET_ID_FIELD_NUMBER: _ClassVar[int] + ACCOUNT_USERNAME_FIELD_NUMBER: _ClassVar[int] + user_id: str + asset_id: str + account_username: str + def __init__(self, user_id: _Optional[str] = ..., asset_id: _Optional[str] = ..., account_username: _Optional[str] = ...) -> None: ... + +class AssetLoginTicketResponse(_message.Message): + __slots__ = ("status", "ticket_info", "need_confirm", "ticket_id") + STATUS_FIELD_NUMBER: _ClassVar[int] + TICKET_INFO_FIELD_NUMBER: _ClassVar[int] + NEED_CONFIRM_FIELD_NUMBER: _ClassVar[int] + TICKET_ID_FIELD_NUMBER: _ClassVar[int] + status: Status + ticket_info: TicketInfo + need_confirm: bool + ticket_id: str + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., ticket_info: _Optional[_Union[TicketInfo, _Mapping]] = ..., need_confirm: bool = ..., ticket_id: _Optional[str] = ...) -> None: ... + +class Status(_message.Message): + __slots__ = ("ok", "err") + OK_FIELD_NUMBER: _ClassVar[int] + ERR_FIELD_NUMBER: _ClassVar[int] + ok: bool + err: str + def __init__(self, ok: bool = ..., err: _Optional[str] = ...) -> None: ... + +class TokenRequest(_message.Message): + __slots__ = ("token",) + TOKEN_FIELD_NUMBER: _ClassVar[int] + token: str + def __init__(self, token: _Optional[str] = ...) -> None: ... + +class TokenResponse(_message.Message): + __slots__ = ("status", "data") + STATUS_FIELD_NUMBER: _ClassVar[int] + DATA_FIELD_NUMBER: _ClassVar[int] + status: Status + data: _common_pb2.TokenAuthInfo + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., data: _Optional[_Union[_common_pb2.TokenAuthInfo, _Mapping]] = ...) -> None: ... + +class SessionCreateRequest(_message.Message): + __slots__ = ("data",) + DATA_FIELD_NUMBER: _ClassVar[int] + data: _common_pb2.Session + def __init__(self, data: _Optional[_Union[_common_pb2.Session, _Mapping]] = ...) -> None: ... + +class SessionCreateResponse(_message.Message): + __slots__ = ("status", "data") + STATUS_FIELD_NUMBER: _ClassVar[int] + DATA_FIELD_NUMBER: _ClassVar[int] + status: Status + data: _common_pb2.Session + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., data: _Optional[_Union[_common_pb2.Session, _Mapping]] = ...) -> None: ... + +class SessionFinishRequest(_message.Message): + __slots__ = ("id", "success", "date_end", "err") + ID_FIELD_NUMBER: _ClassVar[int] + SUCCESS_FIELD_NUMBER: _ClassVar[int] + DATE_END_FIELD_NUMBER: _ClassVar[int] + ERR_FIELD_NUMBER: _ClassVar[int] + id: str + success: bool + date_end: int + err: str + def __init__(self, id: _Optional[str] = ..., success: bool = ..., date_end: _Optional[int] = ..., err: _Optional[str] = ...) -> None: ... + +class SessionFinishResp(_message.Message): + __slots__ = ("status",) + STATUS_FIELD_NUMBER: _ClassVar[int] + status: Status + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class ReplayRequest(_message.Message): + __slots__ = ("session_id", "replay_file_path") + SESSION_ID_FIELD_NUMBER: _ClassVar[int] + REPLAY_FILE_PATH_FIELD_NUMBER: _ClassVar[int] + session_id: str + replay_file_path: str + def __init__(self, session_id: _Optional[str] = ..., replay_file_path: _Optional[str] = ...) -> None: ... + +class ReplayResponse(_message.Message): + __slots__ = ("status",) + STATUS_FIELD_NUMBER: _ClassVar[int] + status: Status + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class CommandRequest(_message.Message): + __slots__ = ("sid", "org_id", "input", "output", "user", "asset", "account", "timestamp", "risk_level", "cmd_acl_id", "cmd_group_id") + SID_FIELD_NUMBER: _ClassVar[int] + ORG_ID_FIELD_NUMBER: _ClassVar[int] + INPUT_FIELD_NUMBER: _ClassVar[int] + OUTPUT_FIELD_NUMBER: _ClassVar[int] + USER_FIELD_NUMBER: _ClassVar[int] + ASSET_FIELD_NUMBER: _ClassVar[int] + ACCOUNT_FIELD_NUMBER: _ClassVar[int] + TIMESTAMP_FIELD_NUMBER: _ClassVar[int] + RISK_LEVEL_FIELD_NUMBER: _ClassVar[int] + CMD_ACL_ID_FIELD_NUMBER: _ClassVar[int] + CMD_GROUP_ID_FIELD_NUMBER: _ClassVar[int] + sid: str + org_id: str + input: str + output: str + user: str + asset: str + account: str + timestamp: int + risk_level: _common_pb2.RiskLevel + cmd_acl_id: str + cmd_group_id: str + def __init__(self, sid: _Optional[str] = ..., org_id: _Optional[str] = ..., input: _Optional[str] = ..., output: _Optional[str] = ..., user: _Optional[str] = ..., asset: _Optional[str] = ..., account: _Optional[str] = ..., timestamp: _Optional[int] = ..., risk_level: _Optional[_Union[_common_pb2.RiskLevel, str]] = ..., cmd_acl_id: _Optional[str] = ..., cmd_group_id: _Optional[str] = ...) -> None: ... + +class CommandResponse(_message.Message): + __slots__ = ("status",) + STATUS_FIELD_NUMBER: _ClassVar[int] + status: Status + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class FinishedTaskRequest(_message.Message): + __slots__ = ("task_id",) + TASK_ID_FIELD_NUMBER: _ClassVar[int] + task_id: str + def __init__(self, task_id: _Optional[str] = ...) -> None: ... + +class TaskResponse(_message.Message): + __slots__ = ("task",) + TASK_FIELD_NUMBER: _ClassVar[int] + task: _common_pb2.TerminalTask + def __init__(self, task: _Optional[_Union[_common_pb2.TerminalTask, _Mapping]] = ...) -> None: ... + +class RemainReplayRequest(_message.Message): + __slots__ = ("replay_dir",) + REPLAY_DIR_FIELD_NUMBER: _ClassVar[int] + replay_dir: str + def __init__(self, replay_dir: _Optional[str] = ...) -> None: ... + +class RemainReplayResponse(_message.Message): + __slots__ = ("status", "success_files", "failure_files", "failure_errs") + STATUS_FIELD_NUMBER: _ClassVar[int] + SUCCESS_FILES_FIELD_NUMBER: _ClassVar[int] + FAILURE_FILES_FIELD_NUMBER: _ClassVar[int] + FAILURE_ERRS_FIELD_NUMBER: _ClassVar[int] + status: Status + success_files: _containers.RepeatedScalarFieldContainer[str] + failure_files: _containers.RepeatedScalarFieldContainer[str] + failure_errs: _containers.RepeatedScalarFieldContainer[str] + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., success_files: _Optional[_Iterable[str]] = ..., failure_files: _Optional[_Iterable[str]] = ..., failure_errs: _Optional[_Iterable[str]] = ...) -> None: ... + +class StatusResponse(_message.Message): + __slots__ = ("status",) + STATUS_FIELD_NUMBER: _ClassVar[int] + status: Status + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class CommandConfirmRequest(_message.Message): + __slots__ = ("session_id", "cmd_acl_id", "cmd") + SESSION_ID_FIELD_NUMBER: _ClassVar[int] + CMD_ACL_ID_FIELD_NUMBER: _ClassVar[int] + CMD_FIELD_NUMBER: _ClassVar[int] + session_id: str + cmd_acl_id: str + cmd: str + def __init__(self, session_id: _Optional[str] = ..., cmd_acl_id: _Optional[str] = ..., cmd: _Optional[str] = ...) -> None: ... + +class ReqInfo(_message.Message): + __slots__ = ("method", "url") + METHOD_FIELD_NUMBER: _ClassVar[int] + URL_FIELD_NUMBER: _ClassVar[int] + method: str + url: str + def __init__(self, method: _Optional[str] = ..., url: _Optional[str] = ...) -> None: ... + +class CommandConfirmResponse(_message.Message): + __slots__ = ("status", "info") + STATUS_FIELD_NUMBER: _ClassVar[int] + INFO_FIELD_NUMBER: _ClassVar[int] + status: Status + info: TicketInfo + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., info: _Optional[_Union[TicketInfo, _Mapping]] = ...) -> None: ... + +class TicketInfo(_message.Message): + __slots__ = ("check_req", "cancel_req", "ticket_detail_url", "reviewers") + CHECK_REQ_FIELD_NUMBER: _ClassVar[int] + CANCEL_REQ_FIELD_NUMBER: _ClassVar[int] + TICKET_DETAIL_URL_FIELD_NUMBER: _ClassVar[int] + REVIEWERS_FIELD_NUMBER: _ClassVar[int] + check_req: ReqInfo + cancel_req: ReqInfo + ticket_detail_url: str + reviewers: _containers.RepeatedScalarFieldContainer[str] + def __init__(self, check_req: _Optional[_Union[ReqInfo, _Mapping]] = ..., cancel_req: _Optional[_Union[ReqInfo, _Mapping]] = ..., ticket_detail_url: _Optional[str] = ..., reviewers: _Optional[_Iterable[str]] = ...) -> None: ... + +class TicketRequest(_message.Message): + __slots__ = ("req",) + REQ_FIELD_NUMBER: _ClassVar[int] + req: ReqInfo + def __init__(self, req: _Optional[_Union[ReqInfo, _Mapping]] = ...) -> None: ... + +class TicketStateResponse(_message.Message): + __slots__ = ("Data", "status") + DATA_FIELD_NUMBER: _ClassVar[int] + STATUS_FIELD_NUMBER: _ClassVar[int] + Data: TicketState + status: Status + def __init__(self, Data: _Optional[_Union[TicketState, _Mapping]] = ..., status: _Optional[_Union[Status, _Mapping]] = ...) -> None: ... + +class TicketState(_message.Message): + __slots__ = ("state", "processor") + class State(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + Open: _ClassVar[TicketState.State] + Approved: _ClassVar[TicketState.State] + Rejected: _ClassVar[TicketState.State] + Closed: _ClassVar[TicketState.State] + Open: TicketState.State + Approved: TicketState.State + Rejected: TicketState.State + Closed: TicketState.State + STATE_FIELD_NUMBER: _ClassVar[int] + PROCESSOR_FIELD_NUMBER: _ClassVar[int] + state: TicketState.State + processor: str + def __init__(self, state: _Optional[_Union[TicketState.State, str]] = ..., processor: _Optional[str] = ...) -> None: ... + +class ForwardRequest(_message.Message): + __slots__ = ("host", "port", "gateways") + HOST_FIELD_NUMBER: _ClassVar[int] + PORT_FIELD_NUMBER: _ClassVar[int] + GATEWAYS_FIELD_NUMBER: _ClassVar[int] + host: str + port: int + gateways: _containers.RepeatedCompositeFieldContainer[_common_pb2.Gateway] + def __init__(self, host: _Optional[str] = ..., port: _Optional[int] = ..., gateways: _Optional[_Iterable[_Union[_common_pb2.Gateway, _Mapping]]] = ...) -> None: ... + +class ForwardDeleteRequest(_message.Message): + __slots__ = ("id",) + ID_FIELD_NUMBER: _ClassVar[int] + id: str + def __init__(self, id: _Optional[str] = ...) -> None: ... + +class ForwardResponse(_message.Message): + __slots__ = ("status", "id", "host", "port") + STATUS_FIELD_NUMBER: _ClassVar[int] + ID_FIELD_NUMBER: _ClassVar[int] + HOST_FIELD_NUMBER: _ClassVar[int] + PORT_FIELD_NUMBER: _ClassVar[int] + status: Status + id: str + host: str + port: int + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., id: _Optional[str] = ..., host: _Optional[str] = ..., port: _Optional[int] = ...) -> None: ... + +class PublicSettingResponse(_message.Message): + __slots__ = ("status", "data") + STATUS_FIELD_NUMBER: _ClassVar[int] + DATA_FIELD_NUMBER: _ClassVar[int] + status: Status + data: _common_pb2.PublicSetting + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., data: _Optional[_Union[_common_pb2.PublicSetting, _Mapping]] = ...) -> None: ... + +class Empty(_message.Message): + __slots__ = () + def __init__(self) -> None: ... + +class ListenPortResponse(_message.Message): + __slots__ = ("status", "ports") + STATUS_FIELD_NUMBER: _ClassVar[int] + PORTS_FIELD_NUMBER: _ClassVar[int] + status: Status + ports: _containers.RepeatedScalarFieldContainer[int] + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., ports: _Optional[_Iterable[int]] = ...) -> None: ... + +class PortInfoRequest(_message.Message): + __slots__ = ("port",) + PORT_FIELD_NUMBER: _ClassVar[int] + port: int + def __init__(self, port: _Optional[int] = ...) -> None: ... + +class PortInfoResponse(_message.Message): + __slots__ = ("status", "data") + STATUS_FIELD_NUMBER: _ClassVar[int] + DATA_FIELD_NUMBER: _ClassVar[int] + status: Status + data: PortInfo + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., data: _Optional[_Union[PortInfo, _Mapping]] = ...) -> None: ... + +class PortInfo(_message.Message): + __slots__ = ("asset", "gateways") + ASSET_FIELD_NUMBER: _ClassVar[int] + GATEWAYS_FIELD_NUMBER: _ClassVar[int] + asset: _common_pb2.Asset + gateways: _containers.RepeatedCompositeFieldContainer[_common_pb2.Gateway] + def __init__(self, asset: _Optional[_Union[_common_pb2.Asset, _Mapping]] = ..., gateways: _Optional[_Iterable[_Union[_common_pb2.Gateway, _Mapping]]] = ...) -> None: ... + +class PortFailure(_message.Message): + __slots__ = ("port", "reason") + PORT_FIELD_NUMBER: _ClassVar[int] + REASON_FIELD_NUMBER: _ClassVar[int] + port: int + reason: str + def __init__(self, port: _Optional[int] = ..., reason: _Optional[str] = ...) -> None: ... + +class PortFailureRequest(_message.Message): + __slots__ = ("data",) + DATA_FIELD_NUMBER: _ClassVar[int] + data: _containers.RepeatedCompositeFieldContainer[PortFailure] + def __init__(self, data: _Optional[_Iterable[_Union[PortFailure, _Mapping]]] = ...) -> None: ... + +class CookiesRequest(_message.Message): + __slots__ = ("cookies",) + COOKIES_FIELD_NUMBER: _ClassVar[int] + cookies: _containers.RepeatedCompositeFieldContainer[_common_pb2.Cookie] + def __init__(self, cookies: _Optional[_Iterable[_Union[_common_pb2.Cookie, _Mapping]]] = ...) -> None: ... + +class UserResponse(_message.Message): + __slots__ = ("status", "data") + STATUS_FIELD_NUMBER: _ClassVar[int] + DATA_FIELD_NUMBER: _ClassVar[int] + status: Status + data: _common_pb2.User + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., data: _Optional[_Union[_common_pb2.User, _Mapping]] = ...) -> None: ... + +class SessionLifecycleLogRequest(_message.Message): + __slots__ = ("session_id", "event", "reason", "user") + class EventType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + AssetConnectSuccess: _ClassVar[SessionLifecycleLogRequest.EventType] + AssetConnectFinished: _ClassVar[SessionLifecycleLogRequest.EventType] + CreateShareLink: _ClassVar[SessionLifecycleLogRequest.EventType] + UserJoinSession: _ClassVar[SessionLifecycleLogRequest.EventType] + UserLeaveSession: _ClassVar[SessionLifecycleLogRequest.EventType] + AdminJoinMonitor: _ClassVar[SessionLifecycleLogRequest.EventType] + AdminExitMonitor: _ClassVar[SessionLifecycleLogRequest.EventType] + ReplayConvertStart: _ClassVar[SessionLifecycleLogRequest.EventType] + ReplayConvertSuccess: _ClassVar[SessionLifecycleLogRequest.EventType] + ReplayConvertFailure: _ClassVar[SessionLifecycleLogRequest.EventType] + ReplayUploadStart: _ClassVar[SessionLifecycleLogRequest.EventType] + ReplayUploadSuccess: _ClassVar[SessionLifecycleLogRequest.EventType] + ReplayUploadFailure: _ClassVar[SessionLifecycleLogRequest.EventType] + AssetConnectSuccess: SessionLifecycleLogRequest.EventType + AssetConnectFinished: SessionLifecycleLogRequest.EventType + CreateShareLink: SessionLifecycleLogRequest.EventType + UserJoinSession: SessionLifecycleLogRequest.EventType + UserLeaveSession: SessionLifecycleLogRequest.EventType + AdminJoinMonitor: SessionLifecycleLogRequest.EventType + AdminExitMonitor: SessionLifecycleLogRequest.EventType + ReplayConvertStart: SessionLifecycleLogRequest.EventType + ReplayConvertSuccess: SessionLifecycleLogRequest.EventType + ReplayConvertFailure: SessionLifecycleLogRequest.EventType + ReplayUploadStart: SessionLifecycleLogRequest.EventType + ReplayUploadSuccess: SessionLifecycleLogRequest.EventType + ReplayUploadFailure: SessionLifecycleLogRequest.EventType + SESSION_ID_FIELD_NUMBER: _ClassVar[int] + EVENT_FIELD_NUMBER: _ClassVar[int] + REASON_FIELD_NUMBER: _ClassVar[int] + USER_FIELD_NUMBER: _ClassVar[int] + session_id: str + event: SessionLifecycleLogRequest.EventType + reason: str + user: str + def __init__(self, session_id: _Optional[str] = ..., event: _Optional[_Union[SessionLifecycleLogRequest.EventType, str]] = ..., reason: _Optional[str] = ..., user: _Optional[str] = ...) -> None: ... + +class AccountDetailResponse(_message.Message): + __slots__ = ("status", "payload") + STATUS_FIELD_NUMBER: _ClassVar[int] + PAYLOAD_FIELD_NUMBER: _ClassVar[int] + status: Status + payload: _struct_pb2.Struct + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., payload: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ...) -> None: ... + +class HTTPRequest(_message.Message): + __slots__ = ("method", "path", "query", "header", "body") + class QueryEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: str + def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + class HeaderEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: str + def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + METHOD_FIELD_NUMBER: _ClassVar[int] + PATH_FIELD_NUMBER: _ClassVar[int] + QUERY_FIELD_NUMBER: _ClassVar[int] + HEADER_FIELD_NUMBER: _ClassVar[int] + BODY_FIELD_NUMBER: _ClassVar[int] + method: str + path: str + query: _containers.ScalarMap[str, str] + header: _containers.ScalarMap[str, str] + body: bytes + def __init__(self, method: _Optional[str] = ..., path: _Optional[str] = ..., query: _Optional[_Mapping[str, str]] = ..., header: _Optional[_Mapping[str, str]] = ..., body: _Optional[bytes] = ...) -> None: ... + +class HTTPResponse(_message.Message): + __slots__ = ("status", "body") + STATUS_FIELD_NUMBER: _ClassVar[int] + BODY_FIELD_NUMBER: _ClassVar[int] + status: Status + body: bytes + def __init__(self, status: _Optional[_Union[Status, _Mapping]] = ..., body: _Optional[bytes] = ...) -> None: ... diff --git a/backend/open_webui/jms/wisp/protobuf/service_pb2_grpc.py b/backend/open_webui/jms/wisp/protobuf/service_pb2_grpc.py new file mode 100644 index 000000000000..98bdde67d8ce --- /dev/null +++ b/backend/open_webui/jms/wisp/protobuf/service_pb2_grpc.py @@ -0,0 +1,1129 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc +import warnings + +import service_pb2 as service__pb2 + +GRPC_GENERATED_VERSION = '1.69.0' +GRPC_VERSION = grpc.__version__ +_version_not_supported = False + +try: + from grpc._utilities import first_version_is_lower + _version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION) +except ImportError: + _version_not_supported = True + +if _version_not_supported: + raise RuntimeError( + f'The grpc package installed is at version {GRPC_VERSION},' + + f' but the generated code in service_pb2_grpc.py depends on' + + f' grpcio>={GRPC_GENERATED_VERSION}.' + + f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}' + + f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.' + ) + + +class ServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetTokenAuthInfo = channel.unary_unary( + '/message.Service/GetTokenAuthInfo', + request_serializer=service__pb2.TokenRequest.SerializeToString, + response_deserializer=service__pb2.TokenResponse.FromString, + _registered_method=True) + self.RenewToken = channel.unary_unary( + '/message.Service/RenewToken', + request_serializer=service__pb2.TokenRequest.SerializeToString, + response_deserializer=service__pb2.StatusResponse.FromString, + _registered_method=True) + self.CreateSession = channel.unary_unary( + '/message.Service/CreateSession', + request_serializer=service__pb2.SessionCreateRequest.SerializeToString, + response_deserializer=service__pb2.SessionCreateResponse.FromString, + _registered_method=True) + self.FinishSession = channel.unary_unary( + '/message.Service/FinishSession', + request_serializer=service__pb2.SessionFinishRequest.SerializeToString, + response_deserializer=service__pb2.SessionFinishResp.FromString, + _registered_method=True) + self.UploadReplayFile = channel.unary_unary( + '/message.Service/UploadReplayFile', + request_serializer=service__pb2.ReplayRequest.SerializeToString, + response_deserializer=service__pb2.ReplayResponse.FromString, + _registered_method=True) + self.UploadCommand = channel.unary_unary( + '/message.Service/UploadCommand', + request_serializer=service__pb2.CommandRequest.SerializeToString, + response_deserializer=service__pb2.CommandResponse.FromString, + _registered_method=True) + self.DispatchTask = channel.stream_stream( + '/message.Service/DispatchTask', + request_serializer=service__pb2.FinishedTaskRequest.SerializeToString, + response_deserializer=service__pb2.TaskResponse.FromString, + _registered_method=True) + self.ScanRemainReplays = channel.unary_unary( + '/message.Service/ScanRemainReplays', + request_serializer=service__pb2.RemainReplayRequest.SerializeToString, + response_deserializer=service__pb2.RemainReplayResponse.FromString, + _registered_method=True) + self.CreateCommandTicket = channel.unary_unary( + '/message.Service/CreateCommandTicket', + request_serializer=service__pb2.CommandConfirmRequest.SerializeToString, + response_deserializer=service__pb2.CommandConfirmResponse.FromString, + _registered_method=True) + self.CheckOrCreateAssetLoginTicket = channel.unary_unary( + '/message.Service/CheckOrCreateAssetLoginTicket', + request_serializer=service__pb2.AssetLoginTicketRequest.SerializeToString, + response_deserializer=service__pb2.AssetLoginTicketResponse.FromString, + _registered_method=True) + self.CheckTicketState = channel.unary_unary( + '/message.Service/CheckTicketState', + request_serializer=service__pb2.TicketRequest.SerializeToString, + response_deserializer=service__pb2.TicketStateResponse.FromString, + _registered_method=True) + self.CancelTicket = channel.unary_unary( + '/message.Service/CancelTicket', + request_serializer=service__pb2.TicketRequest.SerializeToString, + response_deserializer=service__pb2.StatusResponse.FromString, + _registered_method=True) + self.CreateForward = channel.unary_unary( + '/message.Service/CreateForward', + request_serializer=service__pb2.ForwardRequest.SerializeToString, + response_deserializer=service__pb2.ForwardResponse.FromString, + _registered_method=True) + self.DeleteForward = channel.unary_unary( + '/message.Service/DeleteForward', + request_serializer=service__pb2.ForwardDeleteRequest.SerializeToString, + response_deserializer=service__pb2.StatusResponse.FromString, + _registered_method=True) + self.GetPublicSetting = channel.unary_unary( + '/message.Service/GetPublicSetting', + request_serializer=service__pb2.Empty.SerializeToString, + response_deserializer=service__pb2.PublicSettingResponse.FromString, + _registered_method=True) + self.GetListenPorts = channel.unary_unary( + '/message.Service/GetListenPorts', + request_serializer=service__pb2.Empty.SerializeToString, + response_deserializer=service__pb2.ListenPortResponse.FromString, + _registered_method=True) + self.GetPortInfo = channel.unary_unary( + '/message.Service/GetPortInfo', + request_serializer=service__pb2.PortInfoRequest.SerializeToString, + response_deserializer=service__pb2.PortInfoResponse.FromString, + _registered_method=True) + self.HandlePortFailure = channel.unary_unary( + '/message.Service/HandlePortFailure', + request_serializer=service__pb2.PortFailureRequest.SerializeToString, + response_deserializer=service__pb2.StatusResponse.FromString, + _registered_method=True) + self.CheckUserByCookies = channel.unary_unary( + '/message.Service/CheckUserByCookies', + request_serializer=service__pb2.CookiesRequest.SerializeToString, + response_deserializer=service__pb2.UserResponse.FromString, + _registered_method=True) + self.RecordSessionLifecycleLog = channel.unary_unary( + '/message.Service/RecordSessionLifecycleLog', + request_serializer=service__pb2.SessionLifecycleLogRequest.SerializeToString, + response_deserializer=service__pb2.StatusResponse.FromString, + _registered_method=True) + self.FaceRecognitionCallback = channel.unary_unary( + '/message.Service/FaceRecognitionCallback', + request_serializer=service__pb2.FaceRecognitionCallbackRequest.SerializeToString, + response_deserializer=service__pb2.FaceRecognitionCallbackResponse.FromString, + _registered_method=True) + self.FaceMonitorCallback = channel.unary_unary( + '/message.Service/FaceMonitorCallback', + request_serializer=service__pb2.FaceMonitorCallbackRequest.SerializeToString, + response_deserializer=service__pb2.FaceMonitorCallbackResponse.FromString, + _registered_method=True) + self.JoinFaceMonitor = channel.unary_unary( + '/message.Service/JoinFaceMonitor', + request_serializer=service__pb2.JoinFaceMonitorRequest.SerializeToString, + response_deserializer=service__pb2.JoinFaceMonitorResponse.FromString, + _registered_method=True) + self.GetAccountChat = channel.unary_unary( + '/message.Service/GetAccountChat', + request_serializer=service__pb2.Empty.SerializeToString, + response_deserializer=service__pb2.AccountDetailResponse.FromString, + _registered_method=True) + self.CallAPI = channel.unary_unary( + '/message.Service/CallAPI', + request_serializer=service__pb2.HTTPRequest.SerializeToString, + response_deserializer=service__pb2.HTTPResponse.FromString, + _registered_method=True) + + +class ServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def GetTokenAuthInfo(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def RenewToken(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CreateSession(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FinishSession(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UploadReplayFile(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UploadCommand(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DispatchTask(self, request_iterator, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ScanRemainReplays(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CreateCommandTicket(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CheckOrCreateAssetLoginTicket(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CheckTicketState(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CancelTicket(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CreateForward(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DeleteForward(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetPublicSetting(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetListenPorts(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetPortInfo(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def HandlePortFailure(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CheckUserByCookies(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def RecordSessionLifecycleLog(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FaceRecognitionCallback(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def FaceMonitorCallback(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def JoinFaceMonitor(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetAccountChat(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def CallAPI(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_ServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetTokenAuthInfo': grpc.unary_unary_rpc_method_handler( + servicer.GetTokenAuthInfo, + request_deserializer=service__pb2.TokenRequest.FromString, + response_serializer=service__pb2.TokenResponse.SerializeToString, + ), + 'RenewToken': grpc.unary_unary_rpc_method_handler( + servicer.RenewToken, + request_deserializer=service__pb2.TokenRequest.FromString, + response_serializer=service__pb2.StatusResponse.SerializeToString, + ), + 'CreateSession': grpc.unary_unary_rpc_method_handler( + servicer.CreateSession, + request_deserializer=service__pb2.SessionCreateRequest.FromString, + response_serializer=service__pb2.SessionCreateResponse.SerializeToString, + ), + 'FinishSession': grpc.unary_unary_rpc_method_handler( + servicer.FinishSession, + request_deserializer=service__pb2.SessionFinishRequest.FromString, + response_serializer=service__pb2.SessionFinishResp.SerializeToString, + ), + 'UploadReplayFile': grpc.unary_unary_rpc_method_handler( + servicer.UploadReplayFile, + request_deserializer=service__pb2.ReplayRequest.FromString, + response_serializer=service__pb2.ReplayResponse.SerializeToString, + ), + 'UploadCommand': grpc.unary_unary_rpc_method_handler( + servicer.UploadCommand, + request_deserializer=service__pb2.CommandRequest.FromString, + response_serializer=service__pb2.CommandResponse.SerializeToString, + ), + 'DispatchTask': grpc.stream_stream_rpc_method_handler( + servicer.DispatchTask, + request_deserializer=service__pb2.FinishedTaskRequest.FromString, + response_serializer=service__pb2.TaskResponse.SerializeToString, + ), + 'ScanRemainReplays': grpc.unary_unary_rpc_method_handler( + servicer.ScanRemainReplays, + request_deserializer=service__pb2.RemainReplayRequest.FromString, + response_serializer=service__pb2.RemainReplayResponse.SerializeToString, + ), + 'CreateCommandTicket': grpc.unary_unary_rpc_method_handler( + servicer.CreateCommandTicket, + request_deserializer=service__pb2.CommandConfirmRequest.FromString, + response_serializer=service__pb2.CommandConfirmResponse.SerializeToString, + ), + 'CheckOrCreateAssetLoginTicket': grpc.unary_unary_rpc_method_handler( + servicer.CheckOrCreateAssetLoginTicket, + request_deserializer=service__pb2.AssetLoginTicketRequest.FromString, + response_serializer=service__pb2.AssetLoginTicketResponse.SerializeToString, + ), + 'CheckTicketState': grpc.unary_unary_rpc_method_handler( + servicer.CheckTicketState, + request_deserializer=service__pb2.TicketRequest.FromString, + response_serializer=service__pb2.TicketStateResponse.SerializeToString, + ), + 'CancelTicket': grpc.unary_unary_rpc_method_handler( + servicer.CancelTicket, + request_deserializer=service__pb2.TicketRequest.FromString, + response_serializer=service__pb2.StatusResponse.SerializeToString, + ), + 'CreateForward': grpc.unary_unary_rpc_method_handler( + servicer.CreateForward, + request_deserializer=service__pb2.ForwardRequest.FromString, + response_serializer=service__pb2.ForwardResponse.SerializeToString, + ), + 'DeleteForward': grpc.unary_unary_rpc_method_handler( + servicer.DeleteForward, + request_deserializer=service__pb2.ForwardDeleteRequest.FromString, + response_serializer=service__pb2.StatusResponse.SerializeToString, + ), + 'GetPublicSetting': grpc.unary_unary_rpc_method_handler( + servicer.GetPublicSetting, + request_deserializer=service__pb2.Empty.FromString, + response_serializer=service__pb2.PublicSettingResponse.SerializeToString, + ), + 'GetListenPorts': grpc.unary_unary_rpc_method_handler( + servicer.GetListenPorts, + request_deserializer=service__pb2.Empty.FromString, + response_serializer=service__pb2.ListenPortResponse.SerializeToString, + ), + 'GetPortInfo': grpc.unary_unary_rpc_method_handler( + servicer.GetPortInfo, + request_deserializer=service__pb2.PortInfoRequest.FromString, + response_serializer=service__pb2.PortInfoResponse.SerializeToString, + ), + 'HandlePortFailure': grpc.unary_unary_rpc_method_handler( + servicer.HandlePortFailure, + request_deserializer=service__pb2.PortFailureRequest.FromString, + response_serializer=service__pb2.StatusResponse.SerializeToString, + ), + 'CheckUserByCookies': grpc.unary_unary_rpc_method_handler( + servicer.CheckUserByCookies, + request_deserializer=service__pb2.CookiesRequest.FromString, + response_serializer=service__pb2.UserResponse.SerializeToString, + ), + 'RecordSessionLifecycleLog': grpc.unary_unary_rpc_method_handler( + servicer.RecordSessionLifecycleLog, + request_deserializer=service__pb2.SessionLifecycleLogRequest.FromString, + response_serializer=service__pb2.StatusResponse.SerializeToString, + ), + 'FaceRecognitionCallback': grpc.unary_unary_rpc_method_handler( + servicer.FaceRecognitionCallback, + request_deserializer=service__pb2.FaceRecognitionCallbackRequest.FromString, + response_serializer=service__pb2.FaceRecognitionCallbackResponse.SerializeToString, + ), + 'FaceMonitorCallback': grpc.unary_unary_rpc_method_handler( + servicer.FaceMonitorCallback, + request_deserializer=service__pb2.FaceMonitorCallbackRequest.FromString, + response_serializer=service__pb2.FaceMonitorCallbackResponse.SerializeToString, + ), + 'JoinFaceMonitor': grpc.unary_unary_rpc_method_handler( + servicer.JoinFaceMonitor, + request_deserializer=service__pb2.JoinFaceMonitorRequest.FromString, + response_serializer=service__pb2.JoinFaceMonitorResponse.SerializeToString, + ), + 'GetAccountChat': grpc.unary_unary_rpc_method_handler( + servicer.GetAccountChat, + request_deserializer=service__pb2.Empty.FromString, + response_serializer=service__pb2.AccountDetailResponse.SerializeToString, + ), + 'CallAPI': grpc.unary_unary_rpc_method_handler( + servicer.CallAPI, + request_deserializer=service__pb2.HTTPRequest.FromString, + response_serializer=service__pb2.HTTPResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'message.Service', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + server.add_registered_method_handlers('message.Service', rpc_method_handlers) + + + # This class is part of an EXPERIMENTAL API. +class Service(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def GetTokenAuthInfo(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/GetTokenAuthInfo', + service__pb2.TokenRequest.SerializeToString, + service__pb2.TokenResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def RenewToken(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/RenewToken', + service__pb2.TokenRequest.SerializeToString, + service__pb2.StatusResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CreateSession(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CreateSession', + service__pb2.SessionCreateRequest.SerializeToString, + service__pb2.SessionCreateResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FinishSession(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/FinishSession', + service__pb2.SessionFinishRequest.SerializeToString, + service__pb2.SessionFinishResp.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def UploadReplayFile(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/UploadReplayFile', + service__pb2.ReplayRequest.SerializeToString, + service__pb2.ReplayResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def UploadCommand(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/UploadCommand', + service__pb2.CommandRequest.SerializeToString, + service__pb2.CommandResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def DispatchTask(request_iterator, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.stream_stream( + request_iterator, + target, + '/message.Service/DispatchTask', + service__pb2.FinishedTaskRequest.SerializeToString, + service__pb2.TaskResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ScanRemainReplays(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/ScanRemainReplays', + service__pb2.RemainReplayRequest.SerializeToString, + service__pb2.RemainReplayResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CreateCommandTicket(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CreateCommandTicket', + service__pb2.CommandConfirmRequest.SerializeToString, + service__pb2.CommandConfirmResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CheckOrCreateAssetLoginTicket(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CheckOrCreateAssetLoginTicket', + service__pb2.AssetLoginTicketRequest.SerializeToString, + service__pb2.AssetLoginTicketResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CheckTicketState(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CheckTicketState', + service__pb2.TicketRequest.SerializeToString, + service__pb2.TicketStateResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CancelTicket(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CancelTicket', + service__pb2.TicketRequest.SerializeToString, + service__pb2.StatusResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CreateForward(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CreateForward', + service__pb2.ForwardRequest.SerializeToString, + service__pb2.ForwardResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def DeleteForward(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/DeleteForward', + service__pb2.ForwardDeleteRequest.SerializeToString, + service__pb2.StatusResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetPublicSetting(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/GetPublicSetting', + service__pb2.Empty.SerializeToString, + service__pb2.PublicSettingResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetListenPorts(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/GetListenPorts', + service__pb2.Empty.SerializeToString, + service__pb2.ListenPortResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetPortInfo(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/GetPortInfo', + service__pb2.PortInfoRequest.SerializeToString, + service__pb2.PortInfoResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def HandlePortFailure(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/HandlePortFailure', + service__pb2.PortFailureRequest.SerializeToString, + service__pb2.StatusResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CheckUserByCookies(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CheckUserByCookies', + service__pb2.CookiesRequest.SerializeToString, + service__pb2.UserResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def RecordSessionLifecycleLog(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/RecordSessionLifecycleLog', + service__pb2.SessionLifecycleLogRequest.SerializeToString, + service__pb2.StatusResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FaceRecognitionCallback(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/FaceRecognitionCallback', + service__pb2.FaceRecognitionCallbackRequest.SerializeToString, + service__pb2.FaceRecognitionCallbackResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def FaceMonitorCallback(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/FaceMonitorCallback', + service__pb2.FaceMonitorCallbackRequest.SerializeToString, + service__pb2.FaceMonitorCallbackResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def JoinFaceMonitor(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/JoinFaceMonitor', + service__pb2.JoinFaceMonitorRequest.SerializeToString, + service__pb2.JoinFaceMonitorResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def GetAccountChat(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/GetAccountChat', + service__pb2.Empty.SerializeToString, + service__pb2.AccountDetailResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def CallAPI(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/message.Service/CallAPI', + service__pb2.HTTPRequest.SerializeToString, + service__pb2.HTTPResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) diff --git a/backend/open_webui/main.py b/backend/open_webui/main.py index f0aeeab02a53..12048d33f7ff 100644 --- a/backend/open_webui/main.py +++ b/backend/open_webui/main.py @@ -1,525 +1,71 @@ import asyncio -import inspect -import json import logging import mimetypes import os -import shutil import sys -import time -import random -import re -from uuid import uuid4 - from contextlib import asynccontextmanager -from urllib.parse import urlencode, parse_qs, urlparse -from pydantic import BaseModel -from sqlalchemy import text - -from typing import Optional -from aiocache import cached -import aiohttp import anyio.to_thread -import requests -from redis import Redis - from fastapi import ( - Depends, FastAPI, - File, - Form, HTTPException, Request, - UploadFile, - status, - applications, - BackgroundTasks, + applications ) -from fastapi.openapi.docs import get_swagger_ui_html - -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import FileResponse, JSONResponse, RedirectResponse from fastapi.staticfiles import StaticFiles - -from starlette_compress import CompressMiddleware +from fastapi.openapi.docs import get_swagger_ui_html from starlette.exceptions import HTTPException as StarletteHTTPException -from starlette.middleware.base import BaseHTTPMiddleware -from starlette.middleware.sessions import SessionMiddleware -from starlette.responses import Response, StreamingResponse from starlette.datastructures import Headers -from starsessions import ( - SessionMiddleware as StarSessionsMiddleware, - SessionAutoloadMiddleware, -) -from starsessions.stores.redis import RedisStore - -from open_webui.utils import logger -from open_webui.utils.audit import AuditLevel, AuditLoggingMiddleware +from open_webui.jms import setup_poll_jms_event from open_webui.utils.logger import start_logger from open_webui.socket.main import ( app as socket_app, periodic_usage_pool_cleanup, - get_event_emitter, - get_models_in_use, - get_active_user_ids, -) -from open_webui.routers import ( - audio, - images, - ollama, - openai, - retrieval, - pipelines, - tasks, - auths, - channels, - chats, - notes, - folders, - configs, - groups, - files, - functions, - memories, - models, - knowledge, - prompts, - evaluations, - tools, - users, - utils, - scim, -) - -from open_webui.routers.retrieval import ( - get_embedding_function, - get_reranking_function, - get_ef, - get_rf, ) -from open_webui.internal.db import Session, engine - from open_webui.models.functions import Functions -from open_webui.models.models import Models -from open_webui.models.users import UserModel, Users -from open_webui.models.chats import Chats from open_webui.config import ( - # Ollama - ENABLE_OLLAMA_API, - OLLAMA_BASE_URLS, - OLLAMA_API_CONFIGS, - # OpenAI - ENABLE_OPENAI_API, - OPENAI_API_BASE_URLS, - OPENAI_API_KEYS, - OPENAI_API_CONFIGS, - # Direct Connections - ENABLE_DIRECT_CONNECTIONS, - # Model list - ENABLE_BASE_MODELS_CACHE, - # Thread pool size for FastAPI/AnyIO THREAD_POOL_SIZE, - # Tool Server Configs - TOOL_SERVER_CONNECTIONS, - # Code Execution - ENABLE_CODE_EXECUTION, - CODE_EXECUTION_ENGINE, - CODE_EXECUTION_JUPYTER_URL, - CODE_EXECUTION_JUPYTER_AUTH, - CODE_EXECUTION_JUPYTER_AUTH_TOKEN, - CODE_EXECUTION_JUPYTER_AUTH_PASSWORD, - CODE_EXECUTION_JUPYTER_TIMEOUT, - ENABLE_CODE_INTERPRETER, - CODE_INTERPRETER_ENGINE, - CODE_INTERPRETER_PROMPT_TEMPLATE, - CODE_INTERPRETER_JUPYTER_URL, - CODE_INTERPRETER_JUPYTER_AUTH, - CODE_INTERPRETER_JUPYTER_AUTH_TOKEN, - CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD, - CODE_INTERPRETER_JUPYTER_TIMEOUT, - # Image - AUTOMATIC1111_API_AUTH, - AUTOMATIC1111_BASE_URL, - AUTOMATIC1111_PARAMS, - COMFYUI_BASE_URL, - COMFYUI_API_KEY, - COMFYUI_WORKFLOW, - COMFYUI_WORKFLOW_NODES, - ENABLE_IMAGE_GENERATION, - ENABLE_IMAGE_PROMPT_GENERATION, - IMAGE_GENERATION_ENGINE, - IMAGE_GENERATION_MODEL, - IMAGE_SIZE, - IMAGE_STEPS, - IMAGES_OPENAI_API_BASE_URL, - IMAGES_OPENAI_API_VERSION, - IMAGES_OPENAI_API_KEY, - IMAGES_GEMINI_API_BASE_URL, - IMAGES_GEMINI_API_KEY, - IMAGES_GEMINI_ENDPOINT_METHOD, - IMAGE_EDIT_ENGINE, - IMAGE_EDIT_MODEL, - IMAGE_EDIT_SIZE, - IMAGES_EDIT_OPENAI_API_BASE_URL, - IMAGES_EDIT_OPENAI_API_KEY, - IMAGES_EDIT_OPENAI_API_VERSION, - IMAGES_EDIT_GEMINI_API_BASE_URL, - IMAGES_EDIT_GEMINI_API_KEY, - IMAGES_EDIT_COMFYUI_BASE_URL, - IMAGES_EDIT_COMFYUI_API_KEY, - IMAGES_EDIT_COMFYUI_WORKFLOW, - IMAGES_EDIT_COMFYUI_WORKFLOW_NODES, - # Audio - AUDIO_STT_ENGINE, - AUDIO_STT_MODEL, - AUDIO_STT_SUPPORTED_CONTENT_TYPES, - AUDIO_STT_OPENAI_API_BASE_URL, - AUDIO_STT_OPENAI_API_KEY, - AUDIO_STT_AZURE_API_KEY, - AUDIO_STT_AZURE_REGION, - AUDIO_STT_AZURE_LOCALES, - AUDIO_STT_AZURE_BASE_URL, - AUDIO_STT_AZURE_MAX_SPEAKERS, - AUDIO_STT_MISTRAL_API_KEY, - AUDIO_STT_MISTRAL_API_BASE_URL, - AUDIO_STT_MISTRAL_USE_CHAT_COMPLETIONS, - AUDIO_TTS_ENGINE, - AUDIO_TTS_MODEL, - AUDIO_TTS_VOICE, - AUDIO_TTS_OPENAI_API_BASE_URL, - AUDIO_TTS_OPENAI_API_KEY, - AUDIO_TTS_OPENAI_PARAMS, - AUDIO_TTS_API_KEY, - AUDIO_TTS_SPLIT_ON, - AUDIO_TTS_AZURE_SPEECH_REGION, - AUDIO_TTS_AZURE_SPEECH_BASE_URL, - AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT, - PLAYWRIGHT_WS_URL, - PLAYWRIGHT_TIMEOUT, - FIRECRAWL_API_BASE_URL, - FIRECRAWL_API_KEY, - WEB_LOADER_ENGINE, - WEB_LOADER_CONCURRENT_REQUESTS, - WHISPER_MODEL, - WHISPER_VAD_FILTER, - WHISPER_LANGUAGE, - DEEPGRAM_API_KEY, - WHISPER_MODEL_AUTO_UPDATE, - WHISPER_MODEL_DIR, - # Retrieval - RAG_TEMPLATE, - DEFAULT_RAG_TEMPLATE, - RAG_FULL_CONTEXT, - BYPASS_EMBEDDING_AND_RETRIEVAL, - RAG_EMBEDDING_MODEL, - RAG_EMBEDDING_MODEL_AUTO_UPDATE, - RAG_EMBEDDING_MODEL_TRUST_REMOTE_CODE, - RAG_RERANKING_ENGINE, - RAG_RERANKING_MODEL, - RAG_EXTERNAL_RERANKER_URL, - RAG_EXTERNAL_RERANKER_API_KEY, - RAG_RERANKING_MODEL_AUTO_UPDATE, - RAG_RERANKING_MODEL_TRUST_REMOTE_CODE, - RAG_EMBEDDING_ENGINE, - RAG_EMBEDDING_BATCH_SIZE, - RAG_TOP_K, - RAG_TOP_K_RERANKER, - RAG_RELEVANCE_THRESHOLD, - RAG_HYBRID_BM25_WEIGHT, - RAG_ALLOWED_FILE_EXTENSIONS, - RAG_FILE_MAX_COUNT, - RAG_FILE_MAX_SIZE, - FILE_IMAGE_COMPRESSION_WIDTH, - FILE_IMAGE_COMPRESSION_HEIGHT, - RAG_OPENAI_API_BASE_URL, - RAG_OPENAI_API_KEY, - RAG_AZURE_OPENAI_BASE_URL, - RAG_AZURE_OPENAI_API_KEY, - RAG_AZURE_OPENAI_API_VERSION, - RAG_OLLAMA_BASE_URL, - RAG_OLLAMA_API_KEY, - CHUNK_OVERLAP, - CHUNK_SIZE, - CONTENT_EXTRACTION_ENGINE, - DATALAB_MARKER_API_KEY, - DATALAB_MARKER_API_BASE_URL, - DATALAB_MARKER_ADDITIONAL_CONFIG, - DATALAB_MARKER_SKIP_CACHE, - DATALAB_MARKER_FORCE_OCR, - DATALAB_MARKER_PAGINATE, - DATALAB_MARKER_STRIP_EXISTING_OCR, - DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION, - DATALAB_MARKER_FORMAT_LINES, - DATALAB_MARKER_OUTPUT_FORMAT, - MINERU_API_MODE, - MINERU_API_URL, - MINERU_API_KEY, - MINERU_PARAMS, - DATALAB_MARKER_USE_LLM, - EXTERNAL_DOCUMENT_LOADER_URL, - EXTERNAL_DOCUMENT_LOADER_API_KEY, - TIKA_SERVER_URL, - DOCLING_SERVER_URL, - DOCLING_PARAMS, - DOCLING_DO_OCR, - DOCLING_FORCE_OCR, - DOCLING_OCR_ENGINE, - DOCLING_OCR_LANG, - DOCLING_PDF_BACKEND, - DOCLING_TABLE_MODE, - DOCLING_PIPELINE, - DOCLING_DO_PICTURE_DESCRIPTION, - DOCLING_PICTURE_DESCRIPTION_MODE, - DOCLING_PICTURE_DESCRIPTION_LOCAL, - DOCLING_PICTURE_DESCRIPTION_API, - DOCUMENT_INTELLIGENCE_ENDPOINT, - DOCUMENT_INTELLIGENCE_KEY, - MISTRAL_OCR_API_BASE_URL, - MISTRAL_OCR_API_KEY, - RAG_TEXT_SPLITTER, - TIKTOKEN_ENCODING_NAME, - PDF_EXTRACT_IMAGES, - YOUTUBE_LOADER_LANGUAGE, - YOUTUBE_LOADER_PROXY_URL, - # Retrieval (Web Search) - ENABLE_WEB_SEARCH, - WEB_SEARCH_ENGINE, - BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL, - BYPASS_WEB_SEARCH_WEB_LOADER, - WEB_SEARCH_RESULT_COUNT, - WEB_SEARCH_CONCURRENT_REQUESTS, - WEB_SEARCH_TRUST_ENV, - WEB_SEARCH_DOMAIN_FILTER_LIST, - OLLAMA_CLOUD_WEB_SEARCH_API_KEY, - JINA_API_KEY, - SEARCHAPI_API_KEY, - SEARCHAPI_ENGINE, - SERPAPI_API_KEY, - SERPAPI_ENGINE, - SEARXNG_QUERY_URL, - YACY_QUERY_URL, - YACY_USERNAME, - YACY_PASSWORD, - SERPER_API_KEY, - SERPLY_API_KEY, - SERPSTACK_API_KEY, - SERPSTACK_HTTPS, - TAVILY_API_KEY, - TAVILY_EXTRACT_DEPTH, - BING_SEARCH_V7_ENDPOINT, - BING_SEARCH_V7_SUBSCRIPTION_KEY, - BRAVE_SEARCH_API_KEY, - EXA_API_KEY, - PERPLEXITY_API_KEY, - PERPLEXITY_MODEL, - PERPLEXITY_SEARCH_CONTEXT_USAGE, - SOUGOU_API_SID, - SOUGOU_API_SK, - KAGI_SEARCH_API_KEY, - MOJEEK_SEARCH_API_KEY, - BOCHA_SEARCH_API_KEY, - GOOGLE_PSE_API_KEY, - GOOGLE_PSE_ENGINE_ID, - GOOGLE_DRIVE_CLIENT_ID, - GOOGLE_DRIVE_API_KEY, - ENABLE_ONEDRIVE_INTEGRATION, - ONEDRIVE_CLIENT_ID_PERSONAL, - ONEDRIVE_CLIENT_ID_BUSINESS, - ONEDRIVE_SHAREPOINT_URL, - ONEDRIVE_SHAREPOINT_TENANT_ID, - ENABLE_ONEDRIVE_PERSONAL, - ENABLE_ONEDRIVE_BUSINESS, - ENABLE_RAG_HYBRID_SEARCH, - ENABLE_RAG_LOCAL_WEB_FETCH, - ENABLE_WEB_LOADER_SSL_VERIFICATION, - ENABLE_GOOGLE_DRIVE_INTEGRATION, - UPLOAD_DIR, - EXTERNAL_WEB_SEARCH_URL, - EXTERNAL_WEB_SEARCH_API_KEY, - EXTERNAL_WEB_LOADER_URL, - EXTERNAL_WEB_LOADER_API_KEY, - # WebUI - WEBUI_AUTH, - WEBUI_NAME, - WEBUI_BANNERS, - WEBHOOK_URL, - ADMIN_EMAIL, - SHOW_ADMIN_DETAILS, - JWT_EXPIRES_IN, - ENABLE_SIGNUP, - ENABLE_LOGIN_FORM, - ENABLE_API_KEY, - ENABLE_API_KEY_ENDPOINT_RESTRICTIONS, - API_KEY_ALLOWED_ENDPOINTS, - ENABLE_CHANNELS, - ENABLE_NOTES, - ENABLE_COMMUNITY_SHARING, - ENABLE_MESSAGE_RATING, - ENABLE_USER_WEBHOOKS, - ENABLE_EVALUATION_ARENA_MODELS, - BYPASS_ADMIN_ACCESS_CONTROL, - USER_PERMISSIONS, - DEFAULT_USER_ROLE, - PENDING_USER_OVERLAY_CONTENT, - PENDING_USER_OVERLAY_TITLE, - DEFAULT_PROMPT_SUGGESTIONS, - DEFAULT_MODELS, - DEFAULT_ARENA_MODEL, - MODEL_ORDER_LIST, - EVALUATION_ARENA_MODELS, - # WebUI (OAuth) - ENABLE_OAUTH_ROLE_MANAGEMENT, - OAUTH_ROLES_CLAIM, - OAUTH_EMAIL_CLAIM, - OAUTH_PICTURE_CLAIM, - OAUTH_USERNAME_CLAIM, - OAUTH_ALLOWED_ROLES, - OAUTH_ADMIN_ROLES, - # WebUI (LDAP) - ENABLE_LDAP, - LDAP_SERVER_LABEL, - LDAP_SERVER_HOST, - LDAP_SERVER_PORT, - LDAP_ATTRIBUTE_FOR_MAIL, - LDAP_ATTRIBUTE_FOR_USERNAME, - LDAP_SEARCH_FILTERS, - LDAP_SEARCH_BASE, - LDAP_APP_DN, - LDAP_APP_PASSWORD, - LDAP_USE_TLS, - LDAP_CA_CERT_FILE, - LDAP_VALIDATE_CERT, - LDAP_CIPHERS, - # LDAP Group Management - ENABLE_LDAP_GROUP_MANAGEMENT, - ENABLE_LDAP_GROUP_CREATION, - LDAP_ATTRIBUTE_FOR_GROUPS, - # Misc ENV, - CACHE_DIR, - STATIC_DIR, - FRONTEND_BUILD_DIR, - CORS_ALLOW_ORIGIN, - DEFAULT_LOCALE, - OAUTH_PROVIDERS, - WEBUI_URL, - RESPONSE_WATERMARK, - # Admin - ENABLE_ADMIN_CHAT_ACCESS, - BYPASS_ADMIN_ACCESS_CONTROL, - ENABLE_ADMIN_EXPORT, - # Tasks - TASK_MODEL, - TASK_MODEL_EXTERNAL, - ENABLE_TAGS_GENERATION, - ENABLE_TITLE_GENERATION, - ENABLE_FOLLOW_UP_GENERATION, - ENABLE_SEARCH_QUERY_GENERATION, - ENABLE_RETRIEVAL_QUERY_GENERATION, - ENABLE_AUTOCOMPLETE_GENERATION, - TITLE_GENERATION_PROMPT_TEMPLATE, - FOLLOW_UP_GENERATION_PROMPT_TEMPLATE, - TAGS_GENERATION_PROMPT_TEMPLATE, - IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE, - TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE, - QUERY_GENERATION_PROMPT_TEMPLATE, - AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE, - AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH, - AppConfig, reset_config, ) from open_webui.env import ( LICENSE_KEY, - AUDIT_EXCLUDED_PATHS, - AUDIT_LOG_LEVEL, - CHANGELOG, REDIS_URL, REDIS_CLUSTER, - REDIS_KEY_PREFIX, REDIS_SENTINEL_HOSTS, REDIS_SENTINEL_PORT, GLOBAL_LOG_LEVEL, - MAX_BODY_LOG_SIZE, SAFE_MODE, SRC_LOG_LEVELS, VERSION, INSTANCE_ID, WEBUI_BUILD_HASH, - WEBUI_SECRET_KEY, - WEBUI_SESSION_COOKIE_SAME_SITE, - WEBUI_SESSION_COOKIE_SECURE, - ENABLE_SIGNUP_PASSWORD_CONFIRMATION, - WEBUI_AUTH_TRUSTED_EMAIL_HEADER, - WEBUI_AUTH_TRUSTED_NAME_HEADER, - WEBUI_AUTH_SIGNOUT_REDIRECT_URL, - # SCIM - SCIM_ENABLED, - SCIM_TOKEN, - ENABLE_COMPRESSION_MIDDLEWARE, - ENABLE_WEBSOCKET_SUPPORT, - BYPASS_MODEL_ACCESS_CONTROL, - RESET_CONFIG_ON_START, - ENABLE_VERSION_UPDATE_CHECK, - ENABLE_OTEL, - EXTERNAL_PWA_MANIFEST_URL, - AIOHTTP_CLIENT_SESSION_SSL, - ENABLE_STAR_SESSIONS_MIDDLEWARE, + RESET_CONFIG_ON_START, FRONTEND_BUILD_DIR, ) - from open_webui.utils.models import ( get_all_models, - get_all_base_models, - check_model_access, - get_filtered_models, ) -from open_webui.utils.chat import ( - generate_chat_completion as chat_completion_handler, - chat_completed as chat_completed_handler, - chat_action as chat_action_handler, -) -from open_webui.utils.embeddings import generate_embeddings -from open_webui.utils.middleware import process_chat_payload, process_chat_response -from open_webui.utils.access_control import has_access from open_webui.utils.auth import ( get_license_data, - get_http_authorization_cred, - decode_token, - get_admin_user, - get_verified_user, ) from open_webui.utils.plugin import install_tool_and_function_dependencies -from open_webui.utils.oauth import ( - get_oauth_client_info_with_dynamic_client_registration, - encrypt_data, - decrypt_data, - OAuthManager, - OAuthClientManager, - OAuthClientInformationFull, -) -from open_webui.utils.security_headers import SecurityHeadersMiddleware from open_webui.utils.redis import get_redis_connection from open_webui.tasks import ( redis_task_command_listener, - list_task_ids_by_item_id, - create_task, - stop_task, - list_tasks, ) # Import from tasks.py from open_webui.utils.redis import get_sentinels_from_env - - -from open_webui.constants import ERROR_MESSAGES - +from open_webui.app import init_app_config +from open_webui.middlewares import init_middlewares +from open_webui.urls import setup_routes if SAFE_MODE: print("SAFE MODE ENABLED") @@ -619,6 +165,7 @@ async def lifespan(app: FastAPI): None, ) + setup_poll_jms_event() yield if hasattr(app.state, "redis_task_command_listener"): @@ -626,1614 +173,17 @@ async def lifespan(app: FastAPI): app = FastAPI( - title="Open WebUI", + title="JumpServer Chat && Open WebUI", docs_url="/docs" if ENV == "dev" else None, openapi_url="/openapi.json" if ENV == "dev" else None, redoc_url=None, lifespan=lifespan, ) -# For Open WebUI OIDC/OAuth2 -oauth_manager = OAuthManager(app) -app.state.oauth_manager = oauth_manager - -# For Integrations -oauth_client_manager = OAuthClientManager(app) -app.state.oauth_client_manager = oauth_client_manager - -app.state.instance_id = None -app.state.config = AppConfig( - redis_url=REDIS_URL, - redis_sentinels=get_sentinels_from_env(REDIS_SENTINEL_HOSTS, REDIS_SENTINEL_PORT), - redis_cluster=REDIS_CLUSTER, - redis_key_prefix=REDIS_KEY_PREFIX, -) -app.state.redis = None - -app.state.WEBUI_NAME = WEBUI_NAME -app.state.LICENSE_METADATA = None - - -######################################## -# -# OPENTELEMETRY -# -######################################## - -if ENABLE_OTEL: - from open_webui.utils.telemetry.setup import setup as setup_opentelemetry - - setup_opentelemetry(app=app, db_engine=engine) - - -######################################## -# -# OLLAMA -# -######################################## - - -app.state.config.ENABLE_OLLAMA_API = ENABLE_OLLAMA_API -app.state.config.OLLAMA_BASE_URLS = OLLAMA_BASE_URLS -app.state.config.OLLAMA_API_CONFIGS = OLLAMA_API_CONFIGS - -app.state.OLLAMA_MODELS = {} - -######################################## -# -# OPENAI -# -######################################## - -app.state.config.ENABLE_OPENAI_API = ENABLE_OPENAI_API -app.state.config.OPENAI_API_BASE_URLS = OPENAI_API_BASE_URLS -app.state.config.OPENAI_API_KEYS = OPENAI_API_KEYS -app.state.config.OPENAI_API_CONFIGS = OPENAI_API_CONFIGS - -app.state.OPENAI_MODELS = {} - -######################################## -# -# TOOL SERVERS -# -######################################## - -app.state.config.TOOL_SERVER_CONNECTIONS = TOOL_SERVER_CONNECTIONS -app.state.TOOL_SERVERS = [] - -######################################## -# -# DIRECT CONNECTIONS -# -######################################## - -app.state.config.ENABLE_DIRECT_CONNECTIONS = ENABLE_DIRECT_CONNECTIONS - -######################################## -# -# SCIM -# -######################################## - -app.state.SCIM_ENABLED = SCIM_ENABLED -app.state.SCIM_TOKEN = SCIM_TOKEN - -######################################## -# -# MODELS -# -######################################## - -app.state.config.ENABLE_BASE_MODELS_CACHE = ENABLE_BASE_MODELS_CACHE -app.state.BASE_MODELS = [] - -######################################## -# -# WEBUI -# -######################################## - -app.state.config.WEBUI_URL = WEBUI_URL -app.state.config.ENABLE_SIGNUP = ENABLE_SIGNUP -app.state.config.ENABLE_LOGIN_FORM = ENABLE_LOGIN_FORM - -app.state.config.ENABLE_API_KEY = ENABLE_API_KEY -app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS = ( - ENABLE_API_KEY_ENDPOINT_RESTRICTIONS -) -app.state.config.API_KEY_ALLOWED_ENDPOINTS = API_KEY_ALLOWED_ENDPOINTS - -app.state.config.JWT_EXPIRES_IN = JWT_EXPIRES_IN - -app.state.config.SHOW_ADMIN_DETAILS = SHOW_ADMIN_DETAILS -app.state.config.ADMIN_EMAIL = ADMIN_EMAIL - - -app.state.config.DEFAULT_MODELS = DEFAULT_MODELS -app.state.config.DEFAULT_PROMPT_SUGGESTIONS = DEFAULT_PROMPT_SUGGESTIONS -app.state.config.DEFAULT_USER_ROLE = DEFAULT_USER_ROLE - -app.state.config.PENDING_USER_OVERLAY_CONTENT = PENDING_USER_OVERLAY_CONTENT -app.state.config.PENDING_USER_OVERLAY_TITLE = PENDING_USER_OVERLAY_TITLE - -app.state.config.RESPONSE_WATERMARK = RESPONSE_WATERMARK - -app.state.config.USER_PERMISSIONS = USER_PERMISSIONS -app.state.config.WEBHOOK_URL = WEBHOOK_URL -app.state.config.BANNERS = WEBUI_BANNERS -app.state.config.MODEL_ORDER_LIST = MODEL_ORDER_LIST - - -app.state.config.ENABLE_CHANNELS = ENABLE_CHANNELS -app.state.config.ENABLE_NOTES = ENABLE_NOTES -app.state.config.ENABLE_COMMUNITY_SHARING = ENABLE_COMMUNITY_SHARING -app.state.config.ENABLE_MESSAGE_RATING = ENABLE_MESSAGE_RATING -app.state.config.ENABLE_USER_WEBHOOKS = ENABLE_USER_WEBHOOKS - -app.state.config.ENABLE_EVALUATION_ARENA_MODELS = ENABLE_EVALUATION_ARENA_MODELS -app.state.config.EVALUATION_ARENA_MODELS = EVALUATION_ARENA_MODELS - -app.state.config.OAUTH_USERNAME_CLAIM = OAUTH_USERNAME_CLAIM -app.state.config.OAUTH_PICTURE_CLAIM = OAUTH_PICTURE_CLAIM -app.state.config.OAUTH_EMAIL_CLAIM = OAUTH_EMAIL_CLAIM - -app.state.config.ENABLE_OAUTH_ROLE_MANAGEMENT = ENABLE_OAUTH_ROLE_MANAGEMENT -app.state.config.OAUTH_ROLES_CLAIM = OAUTH_ROLES_CLAIM -app.state.config.OAUTH_ALLOWED_ROLES = OAUTH_ALLOWED_ROLES -app.state.config.OAUTH_ADMIN_ROLES = OAUTH_ADMIN_ROLES - -app.state.config.ENABLE_LDAP = ENABLE_LDAP -app.state.config.LDAP_SERVER_LABEL = LDAP_SERVER_LABEL -app.state.config.LDAP_SERVER_HOST = LDAP_SERVER_HOST -app.state.config.LDAP_SERVER_PORT = LDAP_SERVER_PORT -app.state.config.LDAP_ATTRIBUTE_FOR_MAIL = LDAP_ATTRIBUTE_FOR_MAIL -app.state.config.LDAP_ATTRIBUTE_FOR_USERNAME = LDAP_ATTRIBUTE_FOR_USERNAME -app.state.config.LDAP_APP_DN = LDAP_APP_DN -app.state.config.LDAP_APP_PASSWORD = LDAP_APP_PASSWORD -app.state.config.LDAP_SEARCH_BASE = LDAP_SEARCH_BASE -app.state.config.LDAP_SEARCH_FILTERS = LDAP_SEARCH_FILTERS -app.state.config.LDAP_USE_TLS = LDAP_USE_TLS -app.state.config.LDAP_CA_CERT_FILE = LDAP_CA_CERT_FILE -app.state.config.LDAP_VALIDATE_CERT = LDAP_VALIDATE_CERT -app.state.config.LDAP_CIPHERS = LDAP_CIPHERS - -# For LDAP Group Management -app.state.config.ENABLE_LDAP_GROUP_MANAGEMENT = ENABLE_LDAP_GROUP_MANAGEMENT -app.state.config.ENABLE_LDAP_GROUP_CREATION = ENABLE_LDAP_GROUP_CREATION -app.state.config.LDAP_ATTRIBUTE_FOR_GROUPS = LDAP_ATTRIBUTE_FOR_GROUPS - - -app.state.AUTH_TRUSTED_EMAIL_HEADER = WEBUI_AUTH_TRUSTED_EMAIL_HEADER -app.state.AUTH_TRUSTED_NAME_HEADER = WEBUI_AUTH_TRUSTED_NAME_HEADER -app.state.WEBUI_AUTH_SIGNOUT_REDIRECT_URL = WEBUI_AUTH_SIGNOUT_REDIRECT_URL -app.state.EXTERNAL_PWA_MANIFEST_URL = EXTERNAL_PWA_MANIFEST_URL - -app.state.USER_COUNT = None - -app.state.TOOLS = {} -app.state.TOOL_CONTENTS = {} - -app.state.FUNCTIONS = {} -app.state.FUNCTION_CONTENTS = {} - -######################################## -# -# RETRIEVAL -# -######################################## - - -app.state.config.TOP_K = RAG_TOP_K -app.state.config.TOP_K_RERANKER = RAG_TOP_K_RERANKER -app.state.config.RELEVANCE_THRESHOLD = RAG_RELEVANCE_THRESHOLD -app.state.config.HYBRID_BM25_WEIGHT = RAG_HYBRID_BM25_WEIGHT - - -app.state.config.ALLOWED_FILE_EXTENSIONS = RAG_ALLOWED_FILE_EXTENSIONS -app.state.config.FILE_MAX_SIZE = RAG_FILE_MAX_SIZE -app.state.config.FILE_MAX_COUNT = RAG_FILE_MAX_COUNT -app.state.config.FILE_IMAGE_COMPRESSION_WIDTH = FILE_IMAGE_COMPRESSION_WIDTH -app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT = FILE_IMAGE_COMPRESSION_HEIGHT - - -app.state.config.RAG_FULL_CONTEXT = RAG_FULL_CONTEXT -app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL = BYPASS_EMBEDDING_AND_RETRIEVAL -app.state.config.ENABLE_RAG_HYBRID_SEARCH = ENABLE_RAG_HYBRID_SEARCH -app.state.config.ENABLE_WEB_LOADER_SSL_VERIFICATION = ENABLE_WEB_LOADER_SSL_VERIFICATION - -app.state.config.CONTENT_EXTRACTION_ENGINE = CONTENT_EXTRACTION_ENGINE -app.state.config.DATALAB_MARKER_API_KEY = DATALAB_MARKER_API_KEY -app.state.config.DATALAB_MARKER_API_BASE_URL = DATALAB_MARKER_API_BASE_URL -app.state.config.DATALAB_MARKER_ADDITIONAL_CONFIG = DATALAB_MARKER_ADDITIONAL_CONFIG -app.state.config.DATALAB_MARKER_SKIP_CACHE = DATALAB_MARKER_SKIP_CACHE -app.state.config.DATALAB_MARKER_FORCE_OCR = DATALAB_MARKER_FORCE_OCR -app.state.config.DATALAB_MARKER_PAGINATE = DATALAB_MARKER_PAGINATE -app.state.config.DATALAB_MARKER_STRIP_EXISTING_OCR = DATALAB_MARKER_STRIP_EXISTING_OCR -app.state.config.DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION = ( - DATALAB_MARKER_DISABLE_IMAGE_EXTRACTION -) -app.state.config.DATALAB_MARKER_FORMAT_LINES = DATALAB_MARKER_FORMAT_LINES -app.state.config.DATALAB_MARKER_USE_LLM = DATALAB_MARKER_USE_LLM -app.state.config.DATALAB_MARKER_OUTPUT_FORMAT = DATALAB_MARKER_OUTPUT_FORMAT -app.state.config.EXTERNAL_DOCUMENT_LOADER_URL = EXTERNAL_DOCUMENT_LOADER_URL -app.state.config.EXTERNAL_DOCUMENT_LOADER_API_KEY = EXTERNAL_DOCUMENT_LOADER_API_KEY -app.state.config.TIKA_SERVER_URL = TIKA_SERVER_URL -app.state.config.DOCLING_SERVER_URL = DOCLING_SERVER_URL -app.state.config.DOCLING_PARAMS = DOCLING_PARAMS -app.state.config.DOCLING_DO_OCR = DOCLING_DO_OCR -app.state.config.DOCLING_FORCE_OCR = DOCLING_FORCE_OCR -app.state.config.DOCLING_OCR_ENGINE = DOCLING_OCR_ENGINE -app.state.config.DOCLING_OCR_LANG = DOCLING_OCR_LANG -app.state.config.DOCLING_PDF_BACKEND = DOCLING_PDF_BACKEND -app.state.config.DOCLING_TABLE_MODE = DOCLING_TABLE_MODE -app.state.config.DOCLING_PIPELINE = DOCLING_PIPELINE -app.state.config.DOCLING_DO_PICTURE_DESCRIPTION = DOCLING_DO_PICTURE_DESCRIPTION -app.state.config.DOCLING_PICTURE_DESCRIPTION_MODE = DOCLING_PICTURE_DESCRIPTION_MODE -app.state.config.DOCLING_PICTURE_DESCRIPTION_LOCAL = DOCLING_PICTURE_DESCRIPTION_LOCAL -app.state.config.DOCLING_PICTURE_DESCRIPTION_API = DOCLING_PICTURE_DESCRIPTION_API -app.state.config.DOCUMENT_INTELLIGENCE_ENDPOINT = DOCUMENT_INTELLIGENCE_ENDPOINT -app.state.config.DOCUMENT_INTELLIGENCE_KEY = DOCUMENT_INTELLIGENCE_KEY -app.state.config.MISTRAL_OCR_API_BASE_URL = MISTRAL_OCR_API_BASE_URL -app.state.config.MISTRAL_OCR_API_KEY = MISTRAL_OCR_API_KEY -app.state.config.MINERU_API_MODE = MINERU_API_MODE -app.state.config.MINERU_API_URL = MINERU_API_URL -app.state.config.MINERU_API_KEY = MINERU_API_KEY -app.state.config.MINERU_PARAMS = MINERU_PARAMS - -app.state.config.TEXT_SPLITTER = RAG_TEXT_SPLITTER -app.state.config.TIKTOKEN_ENCODING_NAME = TIKTOKEN_ENCODING_NAME - -app.state.config.CHUNK_SIZE = CHUNK_SIZE -app.state.config.CHUNK_OVERLAP = CHUNK_OVERLAP - -app.state.config.RAG_EMBEDDING_ENGINE = RAG_EMBEDDING_ENGINE -app.state.config.RAG_EMBEDDING_MODEL = RAG_EMBEDDING_MODEL -app.state.config.RAG_EMBEDDING_BATCH_SIZE = RAG_EMBEDDING_BATCH_SIZE - -app.state.config.RAG_RERANKING_ENGINE = RAG_RERANKING_ENGINE -app.state.config.RAG_RERANKING_MODEL = RAG_RERANKING_MODEL -app.state.config.RAG_EXTERNAL_RERANKER_URL = RAG_EXTERNAL_RERANKER_URL -app.state.config.RAG_EXTERNAL_RERANKER_API_KEY = RAG_EXTERNAL_RERANKER_API_KEY - -app.state.config.RAG_TEMPLATE = RAG_TEMPLATE - -app.state.config.RAG_OPENAI_API_BASE_URL = RAG_OPENAI_API_BASE_URL -app.state.config.RAG_OPENAI_API_KEY = RAG_OPENAI_API_KEY - -app.state.config.RAG_AZURE_OPENAI_BASE_URL = RAG_AZURE_OPENAI_BASE_URL -app.state.config.RAG_AZURE_OPENAI_API_KEY = RAG_AZURE_OPENAI_API_KEY -app.state.config.RAG_AZURE_OPENAI_API_VERSION = RAG_AZURE_OPENAI_API_VERSION - -app.state.config.RAG_OLLAMA_BASE_URL = RAG_OLLAMA_BASE_URL -app.state.config.RAG_OLLAMA_API_KEY = RAG_OLLAMA_API_KEY - -app.state.config.PDF_EXTRACT_IMAGES = PDF_EXTRACT_IMAGES - -app.state.config.YOUTUBE_LOADER_LANGUAGE = YOUTUBE_LOADER_LANGUAGE -app.state.config.YOUTUBE_LOADER_PROXY_URL = YOUTUBE_LOADER_PROXY_URL - - -app.state.config.ENABLE_WEB_SEARCH = ENABLE_WEB_SEARCH -app.state.config.WEB_SEARCH_ENGINE = WEB_SEARCH_ENGINE -app.state.config.WEB_SEARCH_DOMAIN_FILTER_LIST = WEB_SEARCH_DOMAIN_FILTER_LIST -app.state.config.WEB_SEARCH_RESULT_COUNT = WEB_SEARCH_RESULT_COUNT -app.state.config.WEB_SEARCH_CONCURRENT_REQUESTS = WEB_SEARCH_CONCURRENT_REQUESTS - -app.state.config.WEB_LOADER_ENGINE = WEB_LOADER_ENGINE -app.state.config.WEB_LOADER_CONCURRENT_REQUESTS = WEB_LOADER_CONCURRENT_REQUESTS - -app.state.config.WEB_SEARCH_TRUST_ENV = WEB_SEARCH_TRUST_ENV -app.state.config.BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL = ( - BYPASS_WEB_SEARCH_EMBEDDING_AND_RETRIEVAL -) -app.state.config.BYPASS_WEB_SEARCH_WEB_LOADER = BYPASS_WEB_SEARCH_WEB_LOADER - -app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION = ENABLE_GOOGLE_DRIVE_INTEGRATION -app.state.config.ENABLE_ONEDRIVE_INTEGRATION = ENABLE_ONEDRIVE_INTEGRATION - -app.state.config.OLLAMA_CLOUD_WEB_SEARCH_API_KEY = OLLAMA_CLOUD_WEB_SEARCH_API_KEY -app.state.config.SEARXNG_QUERY_URL = SEARXNG_QUERY_URL -app.state.config.YACY_QUERY_URL = YACY_QUERY_URL -app.state.config.YACY_USERNAME = YACY_USERNAME -app.state.config.YACY_PASSWORD = YACY_PASSWORD -app.state.config.GOOGLE_PSE_API_KEY = GOOGLE_PSE_API_KEY -app.state.config.GOOGLE_PSE_ENGINE_ID = GOOGLE_PSE_ENGINE_ID -app.state.config.BRAVE_SEARCH_API_KEY = BRAVE_SEARCH_API_KEY -app.state.config.KAGI_SEARCH_API_KEY = KAGI_SEARCH_API_KEY -app.state.config.MOJEEK_SEARCH_API_KEY = MOJEEK_SEARCH_API_KEY -app.state.config.BOCHA_SEARCH_API_KEY = BOCHA_SEARCH_API_KEY -app.state.config.SERPSTACK_API_KEY = SERPSTACK_API_KEY -app.state.config.SERPSTACK_HTTPS = SERPSTACK_HTTPS -app.state.config.SERPER_API_KEY = SERPER_API_KEY -app.state.config.SERPLY_API_KEY = SERPLY_API_KEY -app.state.config.TAVILY_API_KEY = TAVILY_API_KEY -app.state.config.SEARCHAPI_API_KEY = SEARCHAPI_API_KEY -app.state.config.SEARCHAPI_ENGINE = SEARCHAPI_ENGINE -app.state.config.SERPAPI_API_KEY = SERPAPI_API_KEY -app.state.config.SERPAPI_ENGINE = SERPAPI_ENGINE -app.state.config.JINA_API_KEY = JINA_API_KEY -app.state.config.BING_SEARCH_V7_ENDPOINT = BING_SEARCH_V7_ENDPOINT -app.state.config.BING_SEARCH_V7_SUBSCRIPTION_KEY = BING_SEARCH_V7_SUBSCRIPTION_KEY -app.state.config.EXA_API_KEY = EXA_API_KEY -app.state.config.PERPLEXITY_API_KEY = PERPLEXITY_API_KEY -app.state.config.PERPLEXITY_MODEL = PERPLEXITY_MODEL -app.state.config.PERPLEXITY_SEARCH_CONTEXT_USAGE = PERPLEXITY_SEARCH_CONTEXT_USAGE -app.state.config.SOUGOU_API_SID = SOUGOU_API_SID -app.state.config.SOUGOU_API_SK = SOUGOU_API_SK -app.state.config.EXTERNAL_WEB_SEARCH_URL = EXTERNAL_WEB_SEARCH_URL -app.state.config.EXTERNAL_WEB_SEARCH_API_KEY = EXTERNAL_WEB_SEARCH_API_KEY -app.state.config.EXTERNAL_WEB_LOADER_URL = EXTERNAL_WEB_LOADER_URL -app.state.config.EXTERNAL_WEB_LOADER_API_KEY = EXTERNAL_WEB_LOADER_API_KEY - - -app.state.config.PLAYWRIGHT_WS_URL = PLAYWRIGHT_WS_URL -app.state.config.PLAYWRIGHT_TIMEOUT = PLAYWRIGHT_TIMEOUT -app.state.config.FIRECRAWL_API_BASE_URL = FIRECRAWL_API_BASE_URL -app.state.config.FIRECRAWL_API_KEY = FIRECRAWL_API_KEY -app.state.config.TAVILY_EXTRACT_DEPTH = TAVILY_EXTRACT_DEPTH - -app.state.EMBEDDING_FUNCTION = None -app.state.RERANKING_FUNCTION = None -app.state.ef = None -app.state.rf = None - -app.state.YOUTUBE_LOADER_TRANSLATION = None - - -try: - app.state.ef = get_ef( - app.state.config.RAG_EMBEDDING_ENGINE, - app.state.config.RAG_EMBEDDING_MODEL, - RAG_EMBEDDING_MODEL_AUTO_UPDATE, - ) - if ( - app.state.config.ENABLE_RAG_HYBRID_SEARCH - and not app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL - ): - app.state.rf = get_rf( - app.state.config.RAG_RERANKING_ENGINE, - app.state.config.RAG_RERANKING_MODEL, - app.state.config.RAG_EXTERNAL_RERANKER_URL, - app.state.config.RAG_EXTERNAL_RERANKER_API_KEY, - RAG_RERANKING_MODEL_AUTO_UPDATE, - ) - else: - app.state.rf = None -except Exception as e: - log.error(f"Error updating models: {e}") - pass - - -app.state.EMBEDDING_FUNCTION = get_embedding_function( - app.state.config.RAG_EMBEDDING_ENGINE, - app.state.config.RAG_EMBEDDING_MODEL, - embedding_function=app.state.ef, - url=( - app.state.config.RAG_OPENAI_API_BASE_URL - if app.state.config.RAG_EMBEDDING_ENGINE == "openai" - else ( - app.state.config.RAG_OLLAMA_BASE_URL - if app.state.config.RAG_EMBEDDING_ENGINE == "ollama" - else app.state.config.RAG_AZURE_OPENAI_BASE_URL - ) - ), - key=( - app.state.config.RAG_OPENAI_API_KEY - if app.state.config.RAG_EMBEDDING_ENGINE == "openai" - else ( - app.state.config.RAG_OLLAMA_API_KEY - if app.state.config.RAG_EMBEDDING_ENGINE == "ollama" - else app.state.config.RAG_AZURE_OPENAI_API_KEY - ) - ), - embedding_batch_size=app.state.config.RAG_EMBEDDING_BATCH_SIZE, - azure_api_version=( - app.state.config.RAG_AZURE_OPENAI_API_VERSION - if app.state.config.RAG_EMBEDDING_ENGINE == "azure_openai" - else None - ), -) - -app.state.RERANKING_FUNCTION = get_reranking_function( - app.state.config.RAG_RERANKING_ENGINE, - app.state.config.RAG_RERANKING_MODEL, - reranking_function=app.state.rf, -) - -######################################## -# -# CODE EXECUTION -# -######################################## - -app.state.config.ENABLE_CODE_EXECUTION = ENABLE_CODE_EXECUTION -app.state.config.CODE_EXECUTION_ENGINE = CODE_EXECUTION_ENGINE -app.state.config.CODE_EXECUTION_JUPYTER_URL = CODE_EXECUTION_JUPYTER_URL -app.state.config.CODE_EXECUTION_JUPYTER_AUTH = CODE_EXECUTION_JUPYTER_AUTH -app.state.config.CODE_EXECUTION_JUPYTER_AUTH_TOKEN = CODE_EXECUTION_JUPYTER_AUTH_TOKEN -app.state.config.CODE_EXECUTION_JUPYTER_AUTH_PASSWORD = ( - CODE_EXECUTION_JUPYTER_AUTH_PASSWORD -) -app.state.config.CODE_EXECUTION_JUPYTER_TIMEOUT = CODE_EXECUTION_JUPYTER_TIMEOUT - -app.state.config.ENABLE_CODE_INTERPRETER = ENABLE_CODE_INTERPRETER -app.state.config.CODE_INTERPRETER_ENGINE = CODE_INTERPRETER_ENGINE -app.state.config.CODE_INTERPRETER_PROMPT_TEMPLATE = CODE_INTERPRETER_PROMPT_TEMPLATE - -app.state.config.CODE_INTERPRETER_JUPYTER_URL = CODE_INTERPRETER_JUPYTER_URL -app.state.config.CODE_INTERPRETER_JUPYTER_AUTH = CODE_INTERPRETER_JUPYTER_AUTH -app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN = ( - CODE_INTERPRETER_JUPYTER_AUTH_TOKEN -) -app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD = ( - CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD -) -app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT = CODE_INTERPRETER_JUPYTER_TIMEOUT - -######################################## -# -# IMAGES -# -######################################## - -app.state.config.IMAGE_GENERATION_ENGINE = IMAGE_GENERATION_ENGINE -app.state.config.ENABLE_IMAGE_GENERATION = ENABLE_IMAGE_GENERATION -app.state.config.ENABLE_IMAGE_PROMPT_GENERATION = ENABLE_IMAGE_PROMPT_GENERATION - -app.state.config.IMAGE_GENERATION_MODEL = IMAGE_GENERATION_MODEL -app.state.config.IMAGE_SIZE = IMAGE_SIZE -app.state.config.IMAGE_STEPS = IMAGE_STEPS - -app.state.config.IMAGES_OPENAI_API_BASE_URL = IMAGES_OPENAI_API_BASE_URL -app.state.config.IMAGES_OPENAI_API_VERSION = IMAGES_OPENAI_API_VERSION -app.state.config.IMAGES_OPENAI_API_KEY = IMAGES_OPENAI_API_KEY - -app.state.config.IMAGES_GEMINI_API_BASE_URL = IMAGES_GEMINI_API_BASE_URL -app.state.config.IMAGES_GEMINI_API_KEY = IMAGES_GEMINI_API_KEY -app.state.config.IMAGES_GEMINI_ENDPOINT_METHOD = IMAGES_GEMINI_ENDPOINT_METHOD - -app.state.config.AUTOMATIC1111_BASE_URL = AUTOMATIC1111_BASE_URL -app.state.config.AUTOMATIC1111_API_AUTH = AUTOMATIC1111_API_AUTH -app.state.config.AUTOMATIC1111_PARAMS = AUTOMATIC1111_PARAMS - -app.state.config.COMFYUI_BASE_URL = COMFYUI_BASE_URL -app.state.config.COMFYUI_API_KEY = COMFYUI_API_KEY -app.state.config.COMFYUI_WORKFLOW = COMFYUI_WORKFLOW -app.state.config.COMFYUI_WORKFLOW_NODES = COMFYUI_WORKFLOW_NODES - - -app.state.config.IMAGE_EDIT_ENGINE = IMAGE_EDIT_ENGINE -app.state.config.IMAGE_EDIT_MODEL = IMAGE_EDIT_MODEL -app.state.config.IMAGE_EDIT_SIZE = IMAGE_EDIT_SIZE -app.state.config.IMAGES_EDIT_OPENAI_API_BASE_URL = IMAGES_EDIT_OPENAI_API_BASE_URL -app.state.config.IMAGES_EDIT_OPENAI_API_KEY = IMAGES_EDIT_OPENAI_API_KEY -app.state.config.IMAGES_EDIT_OPENAI_API_VERSION = IMAGES_EDIT_OPENAI_API_VERSION -app.state.config.IMAGES_EDIT_GEMINI_API_BASE_URL = IMAGES_EDIT_GEMINI_API_BASE_URL -app.state.config.IMAGES_EDIT_GEMINI_API_KEY = IMAGES_EDIT_GEMINI_API_KEY -app.state.config.IMAGES_EDIT_COMFYUI_BASE_URL = IMAGES_EDIT_COMFYUI_BASE_URL -app.state.config.IMAGES_EDIT_COMFYUI_API_KEY = IMAGES_EDIT_COMFYUI_API_KEY -app.state.config.IMAGES_EDIT_COMFYUI_WORKFLOW = IMAGES_EDIT_COMFYUI_WORKFLOW -app.state.config.IMAGES_EDIT_COMFYUI_WORKFLOW_NODES = IMAGES_EDIT_COMFYUI_WORKFLOW_NODES - - -######################################## -# -# AUDIO -# -######################################## - -app.state.config.STT_ENGINE = AUDIO_STT_ENGINE -app.state.config.STT_MODEL = AUDIO_STT_MODEL -app.state.config.STT_SUPPORTED_CONTENT_TYPES = AUDIO_STT_SUPPORTED_CONTENT_TYPES - -app.state.config.STT_OPENAI_API_BASE_URL = AUDIO_STT_OPENAI_API_BASE_URL -app.state.config.STT_OPENAI_API_KEY = AUDIO_STT_OPENAI_API_KEY - -app.state.config.WHISPER_MODEL = WHISPER_MODEL -app.state.config.WHISPER_VAD_FILTER = WHISPER_VAD_FILTER -app.state.config.DEEPGRAM_API_KEY = DEEPGRAM_API_KEY - -app.state.config.AUDIO_STT_AZURE_API_KEY = AUDIO_STT_AZURE_API_KEY -app.state.config.AUDIO_STT_AZURE_REGION = AUDIO_STT_AZURE_REGION -app.state.config.AUDIO_STT_AZURE_LOCALES = AUDIO_STT_AZURE_LOCALES -app.state.config.AUDIO_STT_AZURE_BASE_URL = AUDIO_STT_AZURE_BASE_URL -app.state.config.AUDIO_STT_AZURE_MAX_SPEAKERS = AUDIO_STT_AZURE_MAX_SPEAKERS - -app.state.config.AUDIO_STT_MISTRAL_API_KEY = AUDIO_STT_MISTRAL_API_KEY -app.state.config.AUDIO_STT_MISTRAL_API_BASE_URL = AUDIO_STT_MISTRAL_API_BASE_URL -app.state.config.AUDIO_STT_MISTRAL_USE_CHAT_COMPLETIONS = ( - AUDIO_STT_MISTRAL_USE_CHAT_COMPLETIONS -) - -app.state.config.TTS_ENGINE = AUDIO_TTS_ENGINE - -app.state.config.TTS_MODEL = AUDIO_TTS_MODEL -app.state.config.TTS_VOICE = AUDIO_TTS_VOICE - -app.state.config.TTS_OPENAI_API_BASE_URL = AUDIO_TTS_OPENAI_API_BASE_URL -app.state.config.TTS_OPENAI_API_KEY = AUDIO_TTS_OPENAI_API_KEY -app.state.config.TTS_OPENAI_PARAMS = AUDIO_TTS_OPENAI_PARAMS - -app.state.config.TTS_API_KEY = AUDIO_TTS_API_KEY -app.state.config.TTS_SPLIT_ON = AUDIO_TTS_SPLIT_ON - - -app.state.config.TTS_AZURE_SPEECH_REGION = AUDIO_TTS_AZURE_SPEECH_REGION -app.state.config.TTS_AZURE_SPEECH_BASE_URL = AUDIO_TTS_AZURE_SPEECH_BASE_URL -app.state.config.TTS_AZURE_SPEECH_OUTPUT_FORMAT = AUDIO_TTS_AZURE_SPEECH_OUTPUT_FORMAT - - -app.state.faster_whisper_model = None -app.state.speech_synthesiser = None -app.state.speech_speaker_embeddings_dataset = None - - -######################################## -# -# TASKS -# -######################################## - - -app.state.config.TASK_MODEL = TASK_MODEL -app.state.config.TASK_MODEL_EXTERNAL = TASK_MODEL_EXTERNAL - - -app.state.config.ENABLE_SEARCH_QUERY_GENERATION = ENABLE_SEARCH_QUERY_GENERATION -app.state.config.ENABLE_RETRIEVAL_QUERY_GENERATION = ENABLE_RETRIEVAL_QUERY_GENERATION -app.state.config.ENABLE_AUTOCOMPLETE_GENERATION = ENABLE_AUTOCOMPLETE_GENERATION -app.state.config.ENABLE_TAGS_GENERATION = ENABLE_TAGS_GENERATION -app.state.config.ENABLE_TITLE_GENERATION = ENABLE_TITLE_GENERATION -app.state.config.ENABLE_FOLLOW_UP_GENERATION = ENABLE_FOLLOW_UP_GENERATION - - -app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE = TITLE_GENERATION_PROMPT_TEMPLATE -app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE = TAGS_GENERATION_PROMPT_TEMPLATE -app.state.config.IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE = ( - IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE -) -app.state.config.FOLLOW_UP_GENERATION_PROMPT_TEMPLATE = ( - FOLLOW_UP_GENERATION_PROMPT_TEMPLATE -) - -app.state.config.TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE = ( - TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE -) -app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE = QUERY_GENERATION_PROMPT_TEMPLATE -app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE = ( - AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE -) -app.state.config.AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH = ( - AUTOCOMPLETE_GENERATION_INPUT_MAX_LENGTH -) - - -######################################## -# -# WEBUI -# -######################################## - -app.state.MODELS = {} - - -class RedirectMiddleware(BaseHTTPMiddleware): - async def dispatch(self, request: Request, call_next): - # Check if the request is a GET request - if request.method == "GET": - path = request.url.path - query_params = dict(parse_qs(urlparse(str(request.url)).query)) - - redirect_params = {} - - # Check for the specific watch path and the presence of 'v' parameter - if path.endswith("/watch") and "v" in query_params: - # Extract the first 'v' parameter - youtube_video_id = query_params["v"][0] - redirect_params["youtube"] = youtube_video_id - - if "shared" in query_params and len(query_params["shared"]) > 0: - # PWA share_target support - - text = query_params["shared"][0] - if text: - urls = re.match(r"https://\S+", text) - if urls: - from open_webui.retrieval.loaders.youtube import _parse_video_id - - if youtube_video_id := _parse_video_id(urls[0]): - redirect_params["youtube"] = youtube_video_id - else: - redirect_params["load-url"] = urls[0] - else: - redirect_params["q"] = text - - if redirect_params: - redirect_url = f"/?{urlencode(redirect_params)}" - return RedirectResponse(url=redirect_url) - - # Proceed with the normal flow of other requests - response = await call_next(request) - return response - - -# Add the middleware to the app -if ENABLE_COMPRESSION_MIDDLEWARE: - app.add_middleware(CompressMiddleware) - -app.add_middleware(RedirectMiddleware) -app.add_middleware(SecurityHeadersMiddleware) - - -@app.middleware("http") -async def commit_session_after_request(request: Request, call_next): - response = await call_next(request) - # log.debug("Commit session after request") - Session.commit() - return response - - -@app.middleware("http") -async def check_url(request: Request, call_next): - start_time = int(time.time()) - request.state.token = get_http_authorization_cred( - request.headers.get("Authorization") - ) - - request.state.enable_api_key = app.state.config.ENABLE_API_KEY - response = await call_next(request) - process_time = int(time.time()) - start_time - response.headers["X-Process-Time"] = str(process_time) - return response - - -@app.middleware("http") -async def inspect_websocket(request: Request, call_next): - if ( - "/ws/socket.io" in request.url.path - and request.query_params.get("transport") == "websocket" - ): - upgrade = (request.headers.get("Upgrade") or "").lower() - connection = (request.headers.get("Connection") or "").lower().split(",") - # Check that there's the correct headers for an upgrade, else reject the connection - # This is to work around this upstream issue: https://github.com/miguelgrinberg/python-engineio/issues/367 - if upgrade != "websocket" or "upgrade" not in connection: - return JSONResponse( - status_code=status.HTTP_400_BAD_REQUEST, - content={"detail": "Invalid WebSocket upgrade request"}, - ) - return await call_next(request) - - -app.add_middleware( - CORSMiddleware, - allow_origins=CORS_ALLOW_ORIGIN, - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - - -app.mount("/ws", socket_app) - - -app.include_router(ollama.router, prefix="/ollama", tags=["ollama"]) -app.include_router(openai.router, prefix="/openai", tags=["openai"]) - - -app.include_router(pipelines.router, prefix="/api/v1/pipelines", tags=["pipelines"]) -app.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"]) -app.include_router(images.router, prefix="/api/v1/images", tags=["images"]) - -app.include_router(audio.router, prefix="/api/v1/audio", tags=["audio"]) -app.include_router(retrieval.router, prefix="/api/v1/retrieval", tags=["retrieval"]) - -app.include_router(configs.router, prefix="/api/v1/configs", tags=["configs"]) - -app.include_router(auths.router, prefix="/api/v1/auths", tags=["auths"]) -app.include_router(users.router, prefix="/api/v1/users", tags=["users"]) - - -app.include_router(channels.router, prefix="/api/v1/channels", tags=["channels"]) -app.include_router(chats.router, prefix="/api/v1/chats", tags=["chats"]) -app.include_router(notes.router, prefix="/api/v1/notes", tags=["notes"]) - - -app.include_router(models.router, prefix="/api/v1/models", tags=["models"]) -app.include_router(knowledge.router, prefix="/api/v1/knowledge", tags=["knowledge"]) -app.include_router(prompts.router, prefix="/api/v1/prompts", tags=["prompts"]) -app.include_router(tools.router, prefix="/api/v1/tools", tags=["tools"]) - -app.include_router(memories.router, prefix="/api/v1/memories", tags=["memories"]) -app.include_router(folders.router, prefix="/api/v1/folders", tags=["folders"]) -app.include_router(groups.router, prefix="/api/v1/groups", tags=["groups"]) -app.include_router(files.router, prefix="/api/v1/files", tags=["files"]) -app.include_router(functions.router, prefix="/api/v1/functions", tags=["functions"]) -app.include_router( - evaluations.router, prefix="/api/v1/evaluations", tags=["evaluations"] -) -app.include_router(utils.router, prefix="/api/v1/utils", tags=["utils"]) - -# SCIM 2.0 API for identity management -if SCIM_ENABLED: - app.include_router(scim.router, prefix="/api/v1/scim/v2", tags=["scim"]) - - -try: - audit_level = AuditLevel(AUDIT_LOG_LEVEL) -except ValueError as e: - logger.error(f"Invalid audit level: {AUDIT_LOG_LEVEL}. Error: {e}") - audit_level = AuditLevel.NONE - -if audit_level != AuditLevel.NONE: - app.add_middleware( - AuditLoggingMiddleware, - audit_level=audit_level, - excluded_paths=AUDIT_EXCLUDED_PATHS, - max_body_size=MAX_BODY_LOG_SIZE, - ) -################################## -# -# Chat Endpoints -# -################################## - - -@app.get("/api/models") -@app.get("/api/v1/models") # Experimental: Compatibility with OpenAI API -async def get_models( - request: Request, refresh: bool = False, user=Depends(get_verified_user) -): - all_models = await get_all_models(request, refresh=refresh, user=user) - - models = [] - for model in all_models: - # Filter out filter pipelines - if "pipeline" in model and model["pipeline"].get("type", None) == "filter": - continue - - try: - model_tags = [ - tag.get("name") - for tag in model.get("info", {}).get("meta", {}).get("tags", []) - ] - tags = [tag.get("name") for tag in model.get("tags", [])] - - tags = list(set(model_tags + tags)) - model["tags"] = [{"name": tag} for tag in tags] - except Exception as e: - log.debug(f"Error processing model tags: {e}") - model["tags"] = [] - pass - - models.append(model) - - model_order_list = request.app.state.config.MODEL_ORDER_LIST - if model_order_list: - model_order_dict = {model_id: i for i, model_id in enumerate(model_order_list)} - # Sort models by order list priority, with fallback for those not in the list - models.sort( - key=lambda model: ( - model_order_dict.get(model.get("id", ""), float("inf")), - (model.get("name", "") or ""), - ) - ) - - models = get_filtered_models(models, user) - - log.debug( - f"/api/models returned filtered models accessible to the user: {json.dumps([model.get('id') for model in models])}" - ) - return {"data": models} - - -@app.get("/api/models/base") -async def get_base_models(request: Request, user=Depends(get_admin_user)): - models = await get_all_base_models(request, user=user) - return {"data": models} - - -################################## -# Embeddings -################################## - - -@app.post("/api/embeddings") -@app.post("/api/v1/embeddings") # Experimental: Compatibility with OpenAI API -async def embeddings( - request: Request, form_data: dict, user=Depends(get_verified_user) -): - """ - OpenAI-compatible embeddings endpoint. - - This handler: - - Performs user/model checks and dispatches to the correct backend. - - Supports OpenAI, Ollama, arena models, pipelines, and any compatible provider. - - Args: - request (Request): Request context. - form_data (dict): OpenAI-like payload (e.g., {"model": "...", "input": [...]}) - user (UserModel): Authenticated user. - - Returns: - dict: OpenAI-compatible embeddings response. - """ - # Make sure models are loaded in app state - if not request.app.state.MODELS: - await get_all_models(request, user=user) - # Use generic dispatcher in utils.embeddings - return await generate_embeddings(request, form_data, user) - - -@app.post("/api/chat/completions") -@app.post("/api/v1/chat/completions") # Experimental: Compatibility with OpenAI API -async def chat_completion( - request: Request, - form_data: dict, - user=Depends(get_verified_user), -): - if not request.app.state.MODELS: - await get_all_models(request, user=user) - - model_id = form_data.get("model", None) - model_item = form_data.pop("model_item", {}) - tasks = form_data.pop("background_tasks", None) - - metadata = {} - try: - if not model_item.get("direct", False): - if model_id not in request.app.state.MODELS: - raise Exception("Model not found") - - model = request.app.state.MODELS[model_id] - model_info = Models.get_model_by_id(model_id) - - # Check if user has access to the model - if not BYPASS_MODEL_ACCESS_CONTROL and ( - user.role != "admin" or not BYPASS_ADMIN_ACCESS_CONTROL - ): - try: - check_model_access(user, model) - except Exception as e: - raise e - else: - model = model_item - model_info = None - - request.state.direct = True - request.state.model = model - - model_info_params = ( - model_info.params.model_dump() if model_info and model_info.params else {} - ) - - # Chat Params - stream_delta_chunk_size = form_data.get("params", {}).get( - "stream_delta_chunk_size" - ) - reasoning_tags = form_data.get("params", {}).get("reasoning_tags") - - # Model Params - if model_info_params.get("stream_delta_chunk_size"): - stream_delta_chunk_size = model_info_params.get("stream_delta_chunk_size") - - if model_info_params.get("reasoning_tags") is not None: - reasoning_tags = model_info_params.get("reasoning_tags") - - metadata = { - "user_id": user.id, - "chat_id": form_data.pop("chat_id", None), - "message_id": form_data.pop("id", None), - "session_id": form_data.pop("session_id", None), - "filter_ids": form_data.pop("filter_ids", []), - "tool_ids": form_data.get("tool_ids", None), - "tool_servers": form_data.pop("tool_servers", None), - "files": form_data.get("files", None), - "features": form_data.get("features", {}), - "variables": form_data.get("variables", {}), - "model": model, - "direct": model_item.get("direct", False), - "params": { - "stream_delta_chunk_size": stream_delta_chunk_size, - "reasoning_tags": reasoning_tags, - "function_calling": ( - "native" - if ( - form_data.get("params", {}).get("function_calling") == "native" - or model_info_params.get("function_calling") == "native" - ) - else "default" - ), - }, - } - - if metadata.get("chat_id") and (user and user.role != "admin"): - if not metadata["chat_id"].startswith("local:"): - chat = Chats.get_chat_by_id_and_user_id(metadata["chat_id"], user.id) - if chat is None: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=ERROR_MESSAGES.DEFAULT(), - ) - - request.state.metadata = metadata - form_data["metadata"] = metadata - - except Exception as e: - log.debug(f"Error processing chat metadata: {e}") - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=str(e), - ) - - async def process_chat(request, form_data, user, metadata, model): - try: - form_data, metadata, events = await process_chat_payload( - request, form_data, user, metadata, model - ) - - response = await chat_completion_handler(request, form_data, user) - if metadata.get("chat_id") and metadata.get("message_id"): - try: - if not metadata["chat_id"].startswith("local:"): - Chats.upsert_message_to_chat_by_id_and_message_id( - metadata["chat_id"], - metadata["message_id"], - { - "model": model_id, - }, - ) - except: - pass - - return await process_chat_response( - request, response, form_data, user, metadata, model, events, tasks - ) - except asyncio.CancelledError: - log.info("Chat processing was cancelled") - try: - event_emitter = get_event_emitter(metadata) - await asyncio.shield( - event_emitter( - {"type": "chat:tasks:cancel"}, - ) - ) - except Exception as e: - pass - finally: - raise # re-raise to ensure proper task cancellation handling - except Exception as e: - log.debug(f"Error processing chat payload: {e}") - if metadata.get("chat_id") and metadata.get("message_id"): - # Update the chat message with the error - try: - if not metadata["chat_id"].startswith("local:"): - Chats.upsert_message_to_chat_by_id_and_message_id( - metadata["chat_id"], - metadata["message_id"], - { - "error": {"content": str(e)}, - }, - ) - - event_emitter = get_event_emitter(metadata) - await event_emitter( - { - "type": "chat:message:error", - "data": {"error": {"content": str(e)}}, - } - ) - await event_emitter( - {"type": "chat:tasks:cancel"}, - ) - - except: - pass - finally: - try: - if mcp_clients := metadata.get("mcp_clients"): - for client in reversed(mcp_clients.values()): - await client.disconnect() - except Exception as e: - log.debug(f"Error cleaning up: {e}") - pass - - if ( - metadata.get("session_id") - and metadata.get("chat_id") - and metadata.get("message_id") - ): - # Asynchronous Chat Processing - task_id, _ = await create_task( - request.app.state.redis, - process_chat(request, form_data, user, metadata, model), - id=metadata["chat_id"], - ) - return {"status": True, "task_id": task_id} - else: - return await process_chat(request, form_data, user, metadata, model) - - -# Alias for chat_completion (Legacy) -generate_chat_completions = chat_completion -generate_chat_completion = chat_completion - - -@app.post("/api/chat/completed") -async def chat_completed( - request: Request, form_data: dict, user=Depends(get_verified_user) -): - try: - model_item = form_data.pop("model_item", {}) - - if model_item.get("direct", False): - request.state.direct = True - request.state.model = model_item - - return await chat_completed_handler(request, form_data, user) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=str(e), - ) - - -@app.post("/api/chat/actions/{action_id}") -async def chat_action( - request: Request, action_id: str, form_data: dict, user=Depends(get_verified_user) -): - try: - model_item = form_data.pop("model_item", {}) - - if model_item.get("direct", False): - request.state.direct = True - request.state.model = model_item - - return await chat_action_handler(request, action_id, form_data, user) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail=str(e), - ) - - -@app.post("/api/tasks/stop/{task_id}") -async def stop_task_endpoint( - request: Request, task_id: str, user=Depends(get_verified_user) -): - try: - result = await stop_task(request.app.state.redis, task_id) - return result - except ValueError as e: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e)) - - -@app.get("/api/tasks") -async def list_tasks_endpoint(request: Request, user=Depends(get_verified_user)): - return {"tasks": await list_tasks(request.app.state.redis)} - - -@app.get("/api/tasks/chat/{chat_id}") -async def list_tasks_by_chat_id_endpoint( - request: Request, chat_id: str, user=Depends(get_verified_user) -): - chat = Chats.get_chat_by_id(chat_id) - if chat is None or chat.user_id != user.id: - return {"task_ids": []} - - task_ids = await list_task_ids_by_item_id(request.app.state.redis, chat_id) - - log.debug(f"Task IDs for chat {chat_id}: {task_ids}") - return {"task_ids": task_ids} - - -################################## -# -# Config Endpoints -# -################################## - - -@app.get("/api/config") -async def get_app_config(request: Request): - user = None - token = None - - auth_header = request.headers.get("Authorization") - if auth_header: - cred = get_http_authorization_cred(auth_header) - if cred: - token = cred.credentials - - if not token and "token" in request.cookies: - token = request.cookies.get("token") - - if token: - try: - data = decode_token(token) - except Exception as e: - log.debug(e) - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Invalid token", - ) - if data is not None and "id" in data: - user = Users.get_user_by_id(data["id"]) - - user_count = Users.get_num_users() - onboarding = False - - if user is None: - onboarding = user_count == 0 - - return { - **({"onboarding": True} if onboarding else {}), - "status": True, - "name": app.state.WEBUI_NAME, - "version": VERSION, - "default_locale": str(DEFAULT_LOCALE), - "oauth": { - "providers": { - name: config.get("name", name) - for name, config in OAUTH_PROVIDERS.items() - } - }, - "features": { - "auth": WEBUI_AUTH, - "auth_trusted_header": bool(app.state.AUTH_TRUSTED_EMAIL_HEADER), - "enable_signup_password_confirmation": ENABLE_SIGNUP_PASSWORD_CONFIRMATION, - "enable_ldap": app.state.config.ENABLE_LDAP, - "enable_api_key": app.state.config.ENABLE_API_KEY, - "enable_signup": app.state.config.ENABLE_SIGNUP, - "enable_login_form": app.state.config.ENABLE_LOGIN_FORM, - "enable_websocket": ENABLE_WEBSOCKET_SUPPORT, - "enable_version_update_check": ENABLE_VERSION_UPDATE_CHECK, - **( - { - "enable_direct_connections": app.state.config.ENABLE_DIRECT_CONNECTIONS, - "enable_channels": app.state.config.ENABLE_CHANNELS, - "enable_notes": app.state.config.ENABLE_NOTES, - "enable_web_search": app.state.config.ENABLE_WEB_SEARCH, - "enable_code_execution": app.state.config.ENABLE_CODE_EXECUTION, - "enable_code_interpreter": app.state.config.ENABLE_CODE_INTERPRETER, - "enable_image_generation": app.state.config.ENABLE_IMAGE_GENERATION, - "enable_autocomplete_generation": app.state.config.ENABLE_AUTOCOMPLETE_GENERATION, - "enable_community_sharing": app.state.config.ENABLE_COMMUNITY_SHARING, - "enable_message_rating": app.state.config.ENABLE_MESSAGE_RATING, - "enable_user_webhooks": app.state.config.ENABLE_USER_WEBHOOKS, - "enable_admin_export": ENABLE_ADMIN_EXPORT, - "enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS, - "enable_google_drive_integration": app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION, - "enable_onedrive_integration": app.state.config.ENABLE_ONEDRIVE_INTEGRATION, - **( - { - "enable_onedrive_personal": ENABLE_ONEDRIVE_PERSONAL, - "enable_onedrive_business": ENABLE_ONEDRIVE_BUSINESS, - } - if app.state.config.ENABLE_ONEDRIVE_INTEGRATION - else {} - ), - } - if user is not None - else {} - ), - }, - **( - { - "default_models": app.state.config.DEFAULT_MODELS, - "default_prompt_suggestions": app.state.config.DEFAULT_PROMPT_SUGGESTIONS, - "user_count": user_count, - "code": { - "engine": app.state.config.CODE_EXECUTION_ENGINE, - }, - "audio": { - "tts": { - "engine": app.state.config.TTS_ENGINE, - "voice": app.state.config.TTS_VOICE, - "split_on": app.state.config.TTS_SPLIT_ON, - }, - "stt": { - "engine": app.state.config.STT_ENGINE, - }, - }, - "file": { - "max_size": app.state.config.FILE_MAX_SIZE, - "max_count": app.state.config.FILE_MAX_COUNT, - "image_compression": { - "width": app.state.config.FILE_IMAGE_COMPRESSION_WIDTH, - "height": app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT, - }, - }, - "permissions": {**app.state.config.USER_PERMISSIONS}, - "google_drive": { - "client_id": GOOGLE_DRIVE_CLIENT_ID.value, - "api_key": GOOGLE_DRIVE_API_KEY.value, - }, - "onedrive": { - "client_id_personal": ONEDRIVE_CLIENT_ID_PERSONAL, - "client_id_business": ONEDRIVE_CLIENT_ID_BUSINESS, - "sharepoint_url": ONEDRIVE_SHAREPOINT_URL.value, - "sharepoint_tenant_id": ONEDRIVE_SHAREPOINT_TENANT_ID.value, - }, - "ui": { - "pending_user_overlay_title": app.state.config.PENDING_USER_OVERLAY_TITLE, - "pending_user_overlay_content": app.state.config.PENDING_USER_OVERLAY_CONTENT, - "response_watermark": app.state.config.RESPONSE_WATERMARK, - }, - "license_metadata": app.state.LICENSE_METADATA, - **( - { - "active_entries": app.state.USER_COUNT, - } - if user.role == "admin" - else {} - ), - } - if user is not None and (user.role in ["admin", "user"]) - else { - **( - { - "ui": { - "pending_user_overlay_title": app.state.config.PENDING_USER_OVERLAY_TITLE, - "pending_user_overlay_content": app.state.config.PENDING_USER_OVERLAY_CONTENT, - } - } - if user and user.role == "pending" - else {} - ), - **( - { - "metadata": { - "login_footer": app.state.LICENSE_METADATA.get( - "login_footer", "" - ), - "auth_logo_position": app.state.LICENSE_METADATA.get( - "auth_logo_position", "" - ), - } - } - if app.state.LICENSE_METADATA - else {} - ), - } - ), - } - - -class UrlForm(BaseModel): - url: str - - -@app.get("/api/webhook") -async def get_webhook_url(user=Depends(get_admin_user)): - return { - "url": app.state.config.WEBHOOK_URL, - } - - -@app.post("/api/webhook") -async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)): - app.state.config.WEBHOOK_URL = form_data.url - app.state.WEBHOOK_URL = app.state.config.WEBHOOK_URL - return {"url": app.state.config.WEBHOOK_URL} - - -@app.get("/api/version") -async def get_app_version(): - return { - "version": VERSION, - } - - -@app.get("/api/version/updates") -async def get_app_latest_release_version(user=Depends(get_verified_user)): - if not ENABLE_VERSION_UPDATE_CHECK: - log.debug( - f"Version update check is disabled, returning current version as latest version" - ) - return {"current": VERSION, "latest": VERSION} - try: - timeout = aiohttp.ClientTimeout(total=1) - async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: - async with session.get( - "https://api.github.com/repos/open-webui/open-webui/releases/latest", - ssl=AIOHTTP_CLIENT_SESSION_SSL, - ) as response: - response.raise_for_status() - data = await response.json() - latest_version = data["tag_name"] - - return {"current": VERSION, "latest": latest_version[1:]} - except Exception as e: - log.debug(e) - return {"current": VERSION, "latest": VERSION} - - -@app.get("/api/changelog") -async def get_app_changelog(): - return {key: CHANGELOG[key] for idx, key in enumerate(CHANGELOG) if idx < 5} - - -@app.get("/api/usage") -async def get_current_usage(user=Depends(get_verified_user)): - """ - Get current usage statistics for Open WebUI. - This is an experimental endpoint and subject to change. - """ - try: - return {"model_ids": get_models_in_use(), "user_ids": get_active_user_ids()} - except Exception as e: - log.error(f"Error getting usage statistics: {e}") - raise HTTPException(status_code=500, detail="Internal Server Error") - - -############################ -# OAuth Login & Callback -############################ - - -# Initialize OAuth client manager with any MCP tool servers using OAuth 2.1 -if len(app.state.config.TOOL_SERVER_CONNECTIONS) > 0: - for tool_server_connection in app.state.config.TOOL_SERVER_CONNECTIONS: - if tool_server_connection.get("type", "openapi") == "mcp": - server_id = tool_server_connection.get("info", {}).get("id") - auth_type = tool_server_connection.get("auth_type", "none") - - if server_id and auth_type == "oauth_2.1": - oauth_client_info = tool_server_connection.get("info", {}).get( - "oauth_client_info", "" - ) - - try: - oauth_client_info = decrypt_data(oauth_client_info) - app.state.oauth_client_manager.add_client( - f"mcp:{server_id}", - OAuthClientInformationFull(**oauth_client_info), - ) - except Exception as e: - log.error( - f"Error adding OAuth client for MCP tool server {server_id}: {e}" - ) - pass - -try: - if ENABLE_STAR_SESSIONS_MIDDLEWARE: - redis_session_store = RedisStore( - url=REDIS_URL, - prefix=(f"{REDIS_KEY_PREFIX}:session:" if REDIS_KEY_PREFIX else "session:"), - ) - - app.add_middleware(SessionAutoloadMiddleware) - app.add_middleware( - StarSessionsMiddleware, - store=redis_session_store, - cookie_name="owui-session", - cookie_same_site=WEBUI_SESSION_COOKIE_SAME_SITE, - cookie_https_only=WEBUI_SESSION_COOKIE_SECURE, - ) - log.info("Using Redis for session") - else: - raise ValueError("No Redis URL provided") -except Exception as e: - app.add_middleware( - SessionMiddleware, - secret_key=WEBUI_SECRET_KEY, - session_cookie="owui-session", - same_site=WEBUI_SESSION_COOKIE_SAME_SITE, - https_only=WEBUI_SESSION_COOKIE_SECURE, - ) - - -async def register_client(self, request, client_id: str) -> bool: - server_type, server_id = client_id.split(":", 1) - - connection = None - connection_idx = None - - for idx, conn in enumerate(request.app.state.config.TOOL_SERVER_CONNECTIONS or []): - if conn.get("type", "openapi") == server_type: - info = conn.get("info", {}) - if info.get("id") == server_id: - connection = conn - connection_idx = idx - break - - if connection is None or connection_idx is None: - log.warning( - f"Unable to locate MCP tool server configuration for client {client_id} during re-registration" - ) - return False - - server_url = connection.get("url") - oauth_server_key = (connection.get("config") or {}).get("oauth_server_key") - - try: - oauth_client_info = ( - await get_oauth_client_info_with_dynamic_client_registration( - request, - client_id, - server_url, - oauth_server_key, - ) - ) - except Exception as e: - log.error(f"Dynamic client re-registration failed for {client_id}: {e}") - return False - - try: - request.app.state.config.TOOL_SERVER_CONNECTIONS[connection_idx] = { - **connection, - "info": { - **connection.get("info", {}), - "oauth_client_info": encrypt_data( - oauth_client_info.model_dump(mode="json") - ), - }, - } - except Exception as e: - log.error( - f"Failed to persist updated OAuth client info for tool server {client_id}: {e}" - ) - return False - - oauth_client_manager.remove_client(client_id) - oauth_client_manager.add_client(client_id, oauth_client_info) - log.info(f"Re-registered OAuth client {client_id} for tool server") - return True - - -@app.get("/oauth/clients/{client_id}/authorize") -async def oauth_client_authorize( - client_id: str, - request: Request, - response: Response, - user=Depends(get_verified_user), -): - # ensure_valid_client_registration - client = oauth_client_manager.get_client(client_id) - client_info = oauth_client_manager.get_client_info(client_id) - if client is None or client_info is None: - raise HTTPException(status.HTTP_404_NOT_FOUND) - - if not await oauth_client_manager._preflight_authorization_url(client, client_info): - log.info( - "Detected invalid OAuth client %s; attempting re-registration", - client_id, - ) - - registered = await register_client(request, client_id) - if not registered: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="Failed to re-register OAuth client", - ) - - client = oauth_client_manager.get_client(client_id) - client_info = oauth_client_manager.get_client_info(client_id) - if client is None or client_info is None: - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="OAuth client unavailable after re-registration", - ) - - if not await oauth_client_manager._preflight_authorization_url( - client, client_info - ): - raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, - detail="OAuth client registration is still invalid after re-registration", - ) - - return await oauth_client_manager.handle_authorize(request, client_id=client_id) - - -@app.get("/oauth/clients/{client_id}/callback") -async def oauth_client_callback( - client_id: str, - request: Request, - response: Response, - user=Depends(get_verified_user), -): - return await oauth_client_manager.handle_callback( - request, - client_id=client_id, - user_id=user.id if user else None, - response=response, - ) - - -@app.get("/oauth/{provider}/login") -async def oauth_login(provider: str, request: Request): - return await oauth_manager.handle_login(request, provider) - - -# OAuth login logic is as follows: -# 1. Attempt to find a user with matching subject ID, tied to the provider -# 2. If OAUTH_MERGE_ACCOUNTS_BY_EMAIL is true, find a user with the email address provided via OAuth -# - This is considered insecure in general, as OAuth providers do not always verify email addresses -# 3. If there is no user, and ENABLE_OAUTH_SIGNUP is true, create a user -# - Email addresses are considered unique, so we fail registration if the email address is already taken -@app.get("/oauth/{provider}/login/callback") -@app.get("/oauth/{provider}/callback") # Legacy endpoint -async def oauth_login_callback(provider: str, request: Request, response: Response): - return await oauth_manager.handle_callback(request, provider, response) - - -@app.get("/manifest.json") -async def get_manifest_json(): - if app.state.EXTERNAL_PWA_MANIFEST_URL: - return requests.get(app.state.EXTERNAL_PWA_MANIFEST_URL).json() - else: - return { - "name": app.state.WEBUI_NAME, - "short_name": app.state.WEBUI_NAME, - "description": f"{app.state.WEBUI_NAME} is an open, extensible, user-friendly interface for AI that adapts to your workflow.", - "start_url": "/", - "display": "standalone", - "background_color": "#343541", - "icons": [ - { - "src": "/static/logo.png", - "type": "image/png", - "sizes": "500x500", - "purpose": "any", - }, - { - "src": "/static/logo.png", - "type": "image/png", - "sizes": "500x500", - "purpose": "maskable", - }, - ], - "share_target": { - "action": "/", - "method": "GET", - "params": {"text": "shared"}, - }, - } - - -@app.get("/opensearch.xml") -async def get_opensearch_xml(): - xml_content = rf""" - - {app.state.WEBUI_NAME} - Search {app.state.WEBUI_NAME} - UTF-8 - {app.state.config.WEBUI_URL}/static/favicon.png - - {app.state.config.WEBUI_URL} - - """ - return Response(content=xml_content, media_type="application/xml") - - -@app.get("/health") -async def healthcheck(): - return {"status": True} - - -@app.get("/health/db") -async def healthcheck_with_db(): - Session.execute(text("SELECT 1;")).all() - return {"status": True} - - -app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static") - - -@app.get("/cache/{path:path}") -async def serve_cache_file( - path: str, - user=Depends(get_verified_user), -): - file_path = os.path.abspath(os.path.join(CACHE_DIR, path)) - # prevent path traversal - if not file_path.startswith(os.path.abspath(CACHE_DIR)): - raise HTTPException(status_code=404, detail="File not found") - if not os.path.isfile(file_path): - raise HTTPException(status_code=404, detail="File not found") - return FileResponse(file_path) +init_app_config(app) +init_middlewares(app) +# Setup all routes +setup_routes(app, socket_app) def swagger_ui_html(*args, **kwargs): @@ -2247,11 +197,11 @@ def swagger_ui_html(*args, **kwargs): applications.get_swagger_ui_html = swagger_ui_html - +BASE_PATH = "/kael" if os.path.exists(FRONTEND_BUILD_DIR): mimetypes.add_type("text/javascript", ".js") app.mount( - "/", + BASE_PATH, SPAStaticFiles(directory=FRONTEND_BUILD_DIR, html=True), name="spa-static-files", ) diff --git a/backend/open_webui/middlewares.py b/backend/open_webui/middlewares.py new file mode 100644 index 000000000000..43fcd33b10b4 --- /dev/null +++ b/backend/open_webui/middlewares.py @@ -0,0 +1,219 @@ +import logging +import time +import re + +from urllib.parse import urlencode, parse_qs, urlparse + +from fastapi import ( + Request, + status, +) + +from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import JSONResponse, RedirectResponse + +from starlette_compress import CompressMiddleware + +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.middleware.sessions import SessionMiddleware + +from starsessions import ( + SessionMiddleware as StarSessionsMiddleware, + SessionAutoloadMiddleware, +) +from starsessions.stores.redis import RedisStore + +from open_webui.utils import logger +from open_webui.utils.audit import AuditLevel, AuditLoggingMiddleware +from open_webui.internal.db import Session + +from open_webui.config import CORS_ALLOW_ORIGIN +from open_webui.env import ( + AUDIT_EXCLUDED_PATHS, + AUDIT_LOG_LEVEL, + REDIS_URL, + REDIS_KEY_PREFIX, + MAX_BODY_LOG_SIZE, + WEBUI_SECRET_KEY, + WEBUI_SESSION_COOKIE_SAME_SITE, + WEBUI_SESSION_COOKIE_SECURE, + ENABLE_COMPRESSION_MIDDLEWARE, + ENABLE_STAR_SESSIONS_MIDDLEWARE, SRC_LOG_LEVELS, +) + +from open_webui.utils.auth import ( + get_http_authorization_cred, +) +from open_webui.utils.oauth import ( + decrypt_data, + OAuthClientInformationFull, +) +from open_webui.utils.security_headers import SecurityHeadersMiddleware + +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MAIN"]) + +BASE_PATH = "/kael" + + +class RedirectMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next): + # Check if the request is a GET request + if request.method == "GET": + path = request.url.path + query_params = dict(parse_qs(urlparse(str(request.url)).query)) + + redirect_params = {} + + # Check for the specific watch path and the presence of 'v' parameter + if path.endswith("/watch") and "v" in query_params: + # Extract the first 'v' parameter + youtube_video_id = query_params["v"][0] + redirect_params["youtube"] = youtube_video_id + + if "shared" in query_params and len(query_params["shared"]) > 0: + # PWA share_target support + + text = query_params["shared"][0] + if text: + urls = re.match(r"https://\S+", text) + if urls: + from open_webui.retrieval.loaders.youtube import _parse_video_id + + if youtube_video_id := _parse_video_id(urls[0]): + redirect_params["youtube"] = youtube_video_id + else: + redirect_params["load-url"] = urls[0] + else: + redirect_params["q"] = text + + if redirect_params: + redirect_url = f"/?{urlencode(redirect_params)}" + return RedirectResponse(url=redirect_url) + + # Proceed with the normal flow of other requests + response = await call_next(request) + return response + + +def init_middlewares(app): + # Add the middleware to the app + if ENABLE_COMPRESSION_MIDDLEWARE: + app.add_middleware(CompressMiddleware) + + app.add_middleware(RedirectMiddleware) + app.add_middleware(SecurityHeadersMiddleware) + + @app.middleware("http") + async def commit_session_after_request(request: Request, call_next): + response = await call_next(request) + # log.debug("Commit session after request") + Session.commit() + return response + + @app.middleware("http") + async def check_url(request: Request, call_next): + start_time = int(time.time()) + request.state.token = get_http_authorization_cred( + request.headers.get("Authorization") + ) + + request.state.enable_api_key = app.state.config.ENABLE_API_KEY + response = await call_next(request) + process_time = int(time.time()) - start_time + response.headers["X-Process-Time"] = str(process_time) + return response + + @app.middleware("http") + async def inspect_websocket(request: Request, call_next): + if ( + f"{BASE_PATH}/ws/socket.io" in request.url.path + and request.query_params.get("transport") == "websocket" + ): + upgrade = (request.headers.get("Upgrade") or "").lower() + connection = (request.headers.get("Connection") or "").lower().split(",") + # Check that there's the correct headers for an upgrade, else reject the connection + # This is to work around this upstream issue: https://github.com/miguelgrinberg/python-engineio/issues/367 + if upgrade != "websocket" or "upgrade" not in connection: + return JSONResponse( + status_code=status.HTTP_400_BAD_REQUEST, + content={"detail": "Invalid WebSocket upgrade request"}, + ) + return await call_next(request) + + app.add_middleware( + CORSMiddleware, + allow_origins=CORS_ALLOW_ORIGIN, + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], + ) + + try: + audit_level = AuditLevel(AUDIT_LOG_LEVEL) + except ValueError as e: + logger.error(f"Invalid audit level: {AUDIT_LOG_LEVEL}. Error: {e}") + audit_level = AuditLevel.NONE + + if audit_level != AuditLevel.NONE: + app.add_middleware( + AuditLoggingMiddleware, + audit_level=audit_level, + excluded_paths=AUDIT_EXCLUDED_PATHS, + max_body_size=MAX_BODY_LOG_SIZE, + ) + + ############################ + # OAuth Login & Callback + ############################ + + # Initialize OAuth client manager with any MCP tool servers using OAuth 2.1 + if len(app.state.config.TOOL_SERVER_CONNECTIONS) > 0: + for tool_server_connection in app.state.config.TOOL_SERVER_CONNECTIONS: + if tool_server_connection.get("type", "openapi") == "mcp": + server_id = tool_server_connection.get("info", {}).get("id") + auth_type = tool_server_connection.get("auth_type", "none") + + if server_id and auth_type == "oauth_2.1": + oauth_client_info = tool_server_connection.get("info", {}).get( + "oauth_client_info", "" + ) + + try: + oauth_client_info = decrypt_data(oauth_client_info) + app.state.oauth_client_manager.add_client( + f"mcp:{server_id}", + OAuthClientInformationFull(**oauth_client_info), + ) + except Exception as e: + log.error( + f"Error adding OAuth client for MCP tool server {server_id}: {e}" + ) + pass + + try: + if ENABLE_STAR_SESSIONS_MIDDLEWARE: + redis_session_store = RedisStore( + url=REDIS_URL, + prefix=(f"{REDIS_KEY_PREFIX}:session:" if REDIS_KEY_PREFIX else "session:"), + ) + + app.add_middleware(SessionAutoloadMiddleware) + app.add_middleware( + StarSessionsMiddleware, + store=redis_session_store, + cookie_name="owui-session", + cookie_same_site=WEBUI_SESSION_COOKIE_SAME_SITE, + cookie_https_only=WEBUI_SESSION_COOKIE_SECURE, + ) + log.info("Using Redis for session") + else: + raise ValueError("No Redis URL provided") + except Exception as e: + app.add_middleware( + SessionMiddleware, + secret_key=WEBUI_SECRET_KEY, + session_cookie="owui-session", + same_site=WEBUI_SESSION_COOKIE_SAME_SITE, + https_only=WEBUI_SESSION_COOKIE_SECURE, + ) diff --git a/backend/open_webui/models/chats.py b/backend/open_webui/models/chats.py index c559932bcdbc..de7bb737bdac 100644 --- a/backend/open_webui/models/chats.py +++ b/backend/open_webui/models/chats.py @@ -1,18 +1,20 @@ import logging -import json import time import uuid from typing import Optional +from fastapi import Request +from open_webui.jms import chat_manager +from open_webui.jms import SessionHandler +from open_webui.jms.wisp.protobuf.common_pb2 import User from open_webui.internal.db import Base, get_db -from open_webui.models.tags import TagModel, Tag, Tags +from open_webui.models.tags import TagModel, Tags from open_webui.models.folders import Folders from open_webui.env import SRC_LOG_LEVELS from pydantic import BaseModel, ConfigDict from sqlalchemy import BigInteger, Boolean, Column, String, Text, JSON, Index -from sqlalchemy import or_, func, select, and_, text -from sqlalchemy.sql import exists +from sqlalchemy import or_, and_, text from sqlalchemy.sql.expression import bindparam #################### @@ -112,6 +114,7 @@ class ChatResponse(BaseModel): archived: bool pinned: Optional[bool] = False meta: dict = {} + session_info: dict = {} folder_id: Optional[str] = None @@ -123,33 +126,46 @@ class ChatTitleIdResponse(BaseModel): class ChatTable: - def insert_new_chat(self, user_id: str, form_data: ChatForm) -> Optional[ChatModel]: - with get_db() as db: - id = str(uuid.uuid4()) - chat = ChatModel( - **{ - "id": id, - "user_id": user_id, - "title": ( - form_data.chat["title"] - if "title" in form_data.chat - else "New Chat" - ), - "chat": form_data.chat, - "folder_id": form_data.folder_id, - "created_at": int(time.time()), - "updated_at": int(time.time()), - } - ) + @staticmethod + def get_ip(request: Request): + client_host, client_port = request.client or (None, None) + ip = client_host + + xff = request.headers.get("x-forwarded-for") + xri = request.headers.get("x-real-ip") + if xff: + ip = xff.split(",")[0].strip() + elif xri: + ip = xri.strip() + return ip + + def insert_new_chat(self, form_data: ChatForm, sid: str, request: Request, user: User): + ip = self.get_ip(request) + session_handler = SessionHandler(sid=sid, ip=ip, user=user) + chat_model = form_data.chat.get("models", [None])[0] or '' + session = session_handler.create_session(chat_model) + + data = { + 'id': session.id, + 'user_id': session.user_id, + 'title': form_data.chat['title'] if 'title' in form_data.chat else 'New Chat', + 'chat': form_data.chat, + 'socket_id': sid, + 'folder_id': form_data.folder_id or '', + 'session_info': { + 'org_id': session.org_id, + 'asset': session.asset, + 'account': session.account, + 'user': session.user + } + } - result = Chat(**chat.model_dump()) - db.add(result) - db.commit() - db.refresh(result) - return ChatModel.model_validate(result) if result else None + chat = chat_manager.create(data) + return chat + # TODO def import_chat( - self, user_id: str, form_data: ChatImportForm + self, user_id: str, form_data: ChatImportForm ) -> Optional[ChatModel]: with get_db() as db: id = str(uuid.uuid4()) @@ -185,32 +201,29 @@ def import_chat( db.refresh(result) return ChatModel.model_validate(result) if result else None - def update_chat_by_id(self, id: str, chat: dict) -> Optional[ChatModel]: - try: - with get_db() as db: - chat_item = db.get(Chat, id) - chat_item.chat = chat - chat_item.title = chat["title"] if "title" in chat else "New Chat" - chat_item.updated_at = int(time.time()) - db.commit() - db.refresh(chat_item) - - return ChatModel.model_validate(chat_item) - except Exception: - return None + @staticmethod + def update_chat_by_id(_id: str, chat: dict) -> Optional[ChatModel]: + chat_dict = chat_manager.update( + _id, + { + 'chat': chat, + 'title': chat["title"] if "title" in chat else "New Chat", + } + ) + return chat_dict - def update_chat_title_by_id(self, id: str, title: str) -> Optional[ChatModel]: - chat = self.get_chat_by_id(id) - if chat is None: + def update_chat_title_by_id(self, _id: str, title: str) -> Optional[ChatModel]: + chat_dict = self.get_chat_by_id(_id) + if chat_dict is None: return None - chat = chat.chat + chat = chat_dict['chat'] chat["title"] = title + return self.update_chat_by_id(_id, chat) - return self.update_chat_by_id(id, chat) - + # TODO def update_chat_tags_by_id( - self, id: str, tags: list[str], user + self, id: str, tags: list[str], user ) -> Optional[ChatModel]: chat = self.get_chat_by_id(id) if chat is None: @@ -229,41 +242,41 @@ def update_chat_tags_by_id( self.add_chat_tag_by_id_and_user_id_and_tag_name(id, user.id, tag_name) return self.get_chat_by_id(id) - def get_chat_title_by_id(self, id: str) -> Optional[str]: - chat = self.get_chat_by_id(id) - if chat is None: + def get_chat_title_by_id(self, _id: str) -> Optional[str]: + chat_dict = self.get_chat_by_id(_id) + if chat_dict is None: return None - return chat.chat.get("title", "New Chat") + return chat_dict['chat'].get("title", "New Chat") - def get_messages_map_by_chat_id(self, id: str) -> Optional[dict]: - chat = self.get_chat_by_id(id) - if chat is None: + def get_messages_map_by_chat_id(self, _id: str) -> Optional[dict]: + chat_dict = self.get_chat_by_id(_id) + if chat_dict is None: return None - return chat.chat.get("history", {}).get("messages", {}) or {} + return chat_dict['chat'].get("history", {}).get("messages", {}) or {} def get_message_by_id_and_message_id( - self, id: str, message_id: str + self, _id: str, message_id: str ) -> Optional[dict]: - chat = self.get_chat_by_id(id) - if chat is None: + chat_dict = self.get_chat_by_id(_id) + if chat_dict is None: return None - return chat.chat.get("history", {}).get("messages", {}).get(message_id, {}) + return chat_dict['chat'].get("history", {}).get("messages", {}).get(message_id, {}) def upsert_message_to_chat_by_id_and_message_id( - self, id: str, message_id: str, message: dict - ) -> Optional[ChatModel]: - chat = self.get_chat_by_id(id) - if chat is None: + self, _id: str, message_id: str, message: dict + ): + chat_dict = self.get_chat_by_id(_id) + if chat_dict is None: return None # Sanitize message content for null characters before upserting if isinstance(message.get("content"), str): message["content"] = message["content"].replace("\x00", "") - chat = chat.chat + chat = chat_dict['chat'] history = chat.get("history", {}) if message_id in history.get("messages", {}): @@ -277,16 +290,16 @@ def upsert_message_to_chat_by_id_and_message_id( history["currentId"] = message_id chat["history"] = history - return self.update_chat_by_id(id, chat) + return self.update_chat_by_id(_id, chat) def add_message_status_to_chat_by_id_and_message_id( - self, id: str, message_id: str, status: dict - ) -> Optional[ChatModel]: - chat = self.get_chat_by_id(id) - if chat is None: + self, _id: str, message_id: str, status: dict + ): + chat_dict = self.get_chat_by_id(_id) + if chat_dict is None: return None - chat = chat.chat + chat = chat_dict['chat'] history = chat.get("history", {}) if message_id in history.get("messages", {}): @@ -295,8 +308,9 @@ def add_message_status_to_chat_by_id_and_message_id( history["messages"][message_id]["statusHistory"] = status_history chat["history"] = history - return self.update_chat_by_id(id, chat) + return self.update_chat_by_id(_id, chat) + # TODO def insert_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: with get_db() as db: # Get the existing chat to share @@ -332,6 +346,7 @@ def insert_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: db.commit() return shared_chat if (shared_result and result) else None + # TODO def update_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: try: with get_db() as db: @@ -356,6 +371,7 @@ def update_shared_chat_by_chat_id(self, chat_id: str) -> Optional[ChatModel]: except Exception: return None + # TODO def delete_shared_chat_by_chat_id(self, chat_id: str) -> bool: try: with get_db() as db: @@ -366,206 +382,163 @@ def delete_shared_chat_by_chat_id(self, chat_id: str) -> bool: except Exception: return False - def unarchive_all_chats_by_user_id(self, user_id: str) -> bool: + @staticmethod + def unarchive_all_chats_by_user_id(user_id: str) -> bool: try: - with get_db() as db: - db.query(Chat).filter_by(user_id=user_id).update({"archived": False}) - db.commit() - return True + chat_manager.update(data={"archived": False}, query={"user_id": user_id}) + return True except Exception: return False + @staticmethod def update_chat_share_id_by_id( - self, id: str, share_id: Optional[str] - ) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.get(Chat, id) - chat.share_id = share_id - db.commit() - db.refresh(chat) - return ChatModel.model_validate(chat) - except Exception: - return None - - def toggle_chat_pinned_by_id(self, id: str) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.get(Chat, id) - chat.pinned = not chat.pinned - chat.updated_at = int(time.time()) - db.commit() - db.refresh(chat) - return ChatModel.model_validate(chat) - except Exception: - return None - - def toggle_chat_archive_by_id(self, id: str) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.get(Chat, id) - chat.archived = not chat.archived - chat.updated_at = int(time.time()) - db.commit() - db.refresh(chat) - return ChatModel.model_validate(chat) - except Exception: - return None - - def archive_all_chats_by_user_id(self, user_id: str) -> bool: + _id: str, share_id: Optional[str] + ): + data = {'share_id': share_id} + chat_dict = chat_manager.update(_id, data) + return chat_dict + + def toggle_chat_pinned_by_id(self, _id: str): + chat_dict = self.get_chat_by_id(_id) + pinned = not chat_dict.get('pinned', False) + data = {'pinned': pinned} + return chat_manager.update(_id, data) + + def toggle_chat_archive_by_id(self, _id: str): + chat_dict = self.get_chat_by_id(_id) + archived = not chat_dict.get('archived', False) + data = {'archived': archived} + chat_dict = chat_manager.update(_id, data) + return chat_dict + + @staticmethod + def archive_all_chats_by_user_id(user_id: str) -> bool: try: - with get_db() as db: - db.query(Chat).filter_by(user_id=user_id).update({"archived": True}) - db.commit() - return True + chat_manager.update(data={"archived": True}, query={"user_id": user_id}) + return True except Exception: return False + @staticmethod def get_archived_chat_list_by_user_id( - self, - user_id: str, - filter: Optional[dict] = None, - skip: int = 0, - limit: int = 50, - ) -> list[ChatModel]: - - with get_db() as db: - query = db.query(Chat).filter_by(user_id=user_id, archived=True) - - if filter: - query_key = filter.get("query") - if query_key: - query = query.filter(Chat.title.ilike(f"%{query_key}%")) - - order_by = filter.get("order_by") - direction = filter.get("direction") - - if order_by and direction: - if not getattr(Chat, order_by, None): - raise ValueError("Invalid order_by field") - - if direction.lower() == "asc": - query = query.order_by(getattr(Chat, order_by).asc()) - elif direction.lower() == "desc": - query = query.order_by(getattr(Chat, order_by).desc()) - else: - raise ValueError("Invalid direction for ordering") - else: - query = query.order_by(Chat.updated_at.desc()) - - if skip: - query = query.offset(skip) - if limit: - query = query.limit(limit) - - all_chats = query.all() - return [ChatModel.model_validate(chat) for chat in all_chats] - + user_id: str, + filter: Optional[dict] = None, + skip: int = 0, + limit: int = 50, + ) -> list: + query = { + 'user_id': user_id, + 'archived': True, + 'offset': skip, + 'limit': limit, + } + + if filter: + query_key = filter.get("query") + if query_key: + query['search'] = query_key + + order_by = filter.get("order_by") + direction = filter.get("direction") + + if order_by and direction: + if direction.lower() == "asc": + query['ordering'] = 'date_updated' + + resp = chat_manager.list(query=query) + return resp['results'] + + @staticmethod def get_chat_list_by_user_id( - self, - user_id: str, - include_archived: bool = False, - filter: Optional[dict] = None, - skip: int = 0, - limit: int = 50, - ) -> list[ChatModel]: - with get_db() as db: - query = db.query(Chat).filter_by(user_id=user_id) - if not include_archived: - query = query.filter_by(archived=False) - - if filter: - query_key = filter.get("query") - if query_key: - query = query.filter(Chat.title.ilike(f"%{query_key}%")) - - order_by = filter.get("order_by") - direction = filter.get("direction") - - if order_by and direction and getattr(Chat, order_by): - if direction.lower() == "asc": - query = query.order_by(getattr(Chat, order_by).asc()) - elif direction.lower() == "desc": - query = query.order_by(getattr(Chat, order_by).desc()) - else: - raise ValueError("Invalid direction for ordering") - else: - query = query.order_by(Chat.updated_at.desc()) - - if skip: - query = query.offset(skip) - if limit: - query = query.limit(limit) - - all_chats = query.all() - return [ChatModel.model_validate(chat) for chat in all_chats] - + user_id: str, + include_archived: bool = False, + filter: Optional[dict] = None, + skip: int = 0, + limit: int = 50, + ) -> list: + query = { + 'user_id': user_id, + 'offset': skip, + 'limit': limit, + } + + if not include_archived: + query['archived'] = False + + if filter: + query_key = filter.get("query") + if query_key: + query['search'] = query_key + + order_by = filter.get("order_by") + direction = filter.get("direction") + + if order_by and direction: + if direction.lower() == "asc": + query['ordering'] = 'date_updated' + + resp = chat_manager.list(query=query) + return resp['results'] + + @staticmethod def get_chat_title_id_list_by_user_id( - self, - user_id: str, - include_archived: bool = False, - include_folders: bool = False, - include_pinned: bool = False, - skip: Optional[int] = None, - limit: Optional[int] = None, + user_id: str, + include_archived: bool = False, + include_folders: bool = False, + include_pinned: bool = False, + skip: Optional[int] = 0, + limit: Optional[int] = 10, ) -> list[ChatTitleIdResponse]: - with get_db() as db: - query = db.query(Chat).filter_by(user_id=user_id) - - if not include_folders: - query = query.filter_by(folder_id=None) - - if not include_pinned: - query = query.filter(or_(Chat.pinned == False, Chat.pinned == None)) - - if not include_archived: - query = query.filter_by(archived=False) - - query = query.order_by(Chat.updated_at.desc()).with_entities( - Chat.id, Chat.title, Chat.updated_at, Chat.created_at + query = { + 'user_id': user_id, + 'offset': skip, + 'limit': limit, + 'fields_size': 'mini' + } + + if not include_folders: + query['folder_id'] = None + + if not include_pinned: + query['pinned'] = False + + if not include_archived: + query['archived'] = False + + resp = chat_manager.list(query=query) + filtered = resp['results'] + return [ + ChatTitleIdResponse.model_validate( + { + "id": chat['id'], + "title": chat['title'], + "updated_at": chat['updated_at'], + "created_at": chat['created_at'], + } ) + for chat in filtered + ] - if skip: - query = query.offset(skip) - if limit: - query = query.limit(limit) - - all_chats = query.all() - - # result has to be destructured from sqlalchemy `row` and mapped to a dict since the `ChatModel`is not the returned dataclass. - return [ - ChatTitleIdResponse.model_validate( - { - "id": chat[0], - "title": chat[1], - "updated_at": chat[2], - "created_at": chat[3], - } - ) - for chat in all_chats - ] - + @staticmethod def get_chat_list_by_chat_ids( - self, chat_ids: list[str], skip: int = 0, limit: int = 50 - ) -> list[ChatModel]: - with get_db() as db: - all_chats = ( - db.query(Chat) - .filter(Chat.id.in_(chat_ids)) - .filter_by(archived=False) - .order_by(Chat.updated_at.desc()) - .all() - ) - return [ChatModel.model_validate(chat) for chat in all_chats] - - def get_chat_by_id(self, id: str) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.get(Chat, id) - return ChatModel.model_validate(chat) - except Exception: - return None - + chat_ids: list[str], skip: int = 0, limit: int = 50 + ) -> list: + query = { + 'archived': False, + 'ids': ','.join(chat_ids), + 'offset': skip, + 'limit': limit, + } + + resp = chat_manager.list(query=query) + filtered = resp['results'] + return filtered + + @staticmethod + def get_chat_by_id(_id: str): + return chat_manager.retrieve(_id) + + # TODO def get_chat_by_share_id(self, id: str) -> Optional[ChatModel]: try: with get_db() as db: @@ -580,57 +553,50 @@ def get_chat_by_share_id(self, id: str) -> Optional[ChatModel]: except Exception: return None - def get_chat_by_id_and_user_id(self, id: str, user_id: str) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.query(Chat).filter_by(id=id, user_id=user_id).first() - return ChatModel.model_validate(chat) - except Exception: - return None - - def get_chats(self, skip: int = 0, limit: int = 50) -> list[ChatModel]: - with get_db() as db: - all_chats = ( - db.query(Chat) - # .limit(limit).offset(skip) - .order_by(Chat.updated_at.desc()) - ) - return [ChatModel.model_validate(chat) for chat in all_chats] - - def get_chats_by_user_id(self, user_id: str) -> list[ChatModel]: - with get_db() as db: - all_chats = ( - db.query(Chat) - .filter_by(user_id=user_id) - .order_by(Chat.updated_at.desc()) - ) - return [ChatModel.model_validate(chat) for chat in all_chats] - - def get_pinned_chats_by_user_id(self, user_id: str) -> list[ChatModel]: - with get_db() as db: - all_chats = ( - db.query(Chat) - .filter_by(user_id=user_id, pinned=True, archived=False) - .order_by(Chat.updated_at.desc()) - ) - return [ChatModel.model_validate(chat) for chat in all_chats] - - def get_archived_chats_by_user_id(self, user_id: str) -> list[ChatModel]: - with get_db() as db: - all_chats = ( - db.query(Chat) - .filter_by(user_id=user_id, archived=True) - .order_by(Chat.updated_at.desc()) - ) - return [ChatModel.model_validate(chat) for chat in all_chats] + def get_chat_by_id_and_user_id(self, _id: str, user_id: str): + return self.get_chat_by_id(_id) + # try: + # with get_db() as db: + # chat = db.query(Chat).filter_by(id=id, user_id=user_id).first() + # return ChatModel.model_validate(chat) + # except Exception: + # return None + + @staticmethod + def get_chats(skip: int = 0, limit: int = 50): + return chat_manager.list() + + @staticmethod + def get_chats_by_user_id(user_id: str): + query = { + 'user_id': user_id, + } + return chat_manager.list(query=query) + + @staticmethod + def get_pinned_chats_by_user_id(user_id: str): + query = { + 'user_id': user_id, + 'pinned': True, + 'archived': False, + } + return chat_manager.list(query=query) + + @staticmethod + def get_archived_chats_by_user_id(user_id: str): + query = { + 'user_id': user_id, + 'archived': True, + } + return chat_manager.list(query=query) def get_chats_by_user_id_and_search_text( - self, - user_id: str, - search_text: str, - include_archived: bool = False, - skip: int = 0, - limit: int = 60, + self, + user_id: str, + search_text: str, + include_archived: bool = False, + skip: int = 0, + limit: int = 60, ) -> list[ChatModel]: """ Filters chats based on a search query using Python, allowing pagination using skip and limit. @@ -644,24 +610,6 @@ def get_chats_by_user_id_and_search_text( search_text_words = search_text.split(" ") - # search_text might contain 'tag:tag_name' format so we need to extract the tag_name, split the search_text and remove the tags - tag_ids = [ - word.replace("tag:", "").replace(" ", "_").lower() - for word in search_text_words - if word.startswith("tag:") - ] - - # Extract folder names - handle spaces and case insensitivity - folders = Folders.search_folders_by_names( - user_id, - [ - word.replace("folder:", "") - for word in search_text_words - if word.startswith("folder:") - ], - ) - folder_ids = [folder.id for folder in folders] - is_pinned = None if "pinned:true" in search_text_words: is_pinned = True @@ -674,162 +622,41 @@ def get_chats_by_user_id_and_search_text( elif "archived:false" in search_text_words: is_archived = False - is_shared = None - if "shared:true" in search_text_words: - is_shared = True - elif "shared:false" in search_text_words: - is_shared = False - search_text_words = [ word for word in search_text_words if ( - not word.startswith("tag:") - and not word.startswith("folder:") - and not word.startswith("pinned:") - and not word.startswith("archived:") - and not word.startswith("shared:") + not word.startswith("tag:") + and not word.startswith("folder:") + and not word.startswith("pinned:") + and not word.startswith("archived:") + and not word.startswith("shared:") ) ] search_text = " ".join(search_text_words) + query = { + 'user_id': user_id, + 'skip': skip, + 'limit': limit, + } - with get_db() as db: - query = db.query(Chat).filter(Chat.user_id == user_id) - - if is_archived is not None: - query = query.filter(Chat.archived == is_archived) - elif not include_archived: - query = query.filter(Chat.archived == False) - - if is_pinned is not None: - query = query.filter(Chat.pinned == is_pinned) + if is_archived is not None: + query['archived'] = is_archived + elif not include_archived: + query['archived'] = False - if is_shared is not None: - if is_shared: - query = query.filter(Chat.share_id.isnot(None)) - else: - query = query.filter(Chat.share_id.is_(None)) - - if folder_ids: - query = query.filter(Chat.folder_id.in_(folder_ids)) + if is_pinned is not None: + query['pinned'] = is_pinned - query = query.order_by(Chat.updated_at.desc()) + query['search'] = search_text + resp = chat_manager.list(query=query) - # Check if the database dialect is either 'sqlite' or 'postgresql' - dialect_name = db.bind.dialect.name - if dialect_name == "sqlite": - # SQLite case: using JSON1 extension for JSON searching - sqlite_content_sql = ( - "EXISTS (" - " SELECT 1 " - " FROM json_each(Chat.chat, '$.messages') AS message " - " WHERE LOWER(message.value->>'content') LIKE '%' || :content_key || '%'" - ")" - ) - sqlite_content_clause = text(sqlite_content_sql) - query = query.filter( - or_( - Chat.title.ilike(bindparam("title_key")), sqlite_content_clause - ).params(title_key=f"%{search_text}%", content_key=search_text) - ) - - # Check if there are any tags to filter, it should have all the tags - if "none" in tag_ids: - query = query.filter( - text( - """ - NOT EXISTS ( - SELECT 1 - FROM json_each(Chat.meta, '$.tags') AS tag - ) - """ - ) - ) - elif tag_ids: - query = query.filter( - and_( - *[ - text( - f""" - EXISTS ( - SELECT 1 - FROM json_each(Chat.meta, '$.tags') AS tag - WHERE tag.value = :tag_id_{tag_idx} - ) - """ - ).params(**{f"tag_id_{tag_idx}": tag_id}) - for tag_idx, tag_id in enumerate(tag_ids) - ] - ) - ) - - elif dialect_name == "postgresql": - # PostgreSQL doesn't allow null bytes in text. We filter those out by checking - # the JSON representation for \u0000 before attempting text extraction - postgres_content_sql = ( - "EXISTS (" - " SELECT 1 " - " FROM json_array_elements(Chat.chat->'messages') AS message " - " WHERE message->'content' IS NOT NULL " - " AND (message->'content')::text NOT LIKE '%\\u0000%' " - " AND LOWER(message->>'content') LIKE '%' || :content_key || '%'" - ")" - ) - postgres_content_clause = text(postgres_content_sql) - # Also filter out chats with null bytes in title - query = query.filter(text("Chat.title::text NOT LIKE '%\\x00%'")) - query = query.filter( - or_( - Chat.title.ilike(bindparam("title_key")), - postgres_content_clause, - ).params(title_key=f"%{search_text}%", content_key=search_text) - ) - - # Check if there are any tags to filter, it should have all the tags - if "none" in tag_ids: - query = query.filter( - text( - """ - NOT EXISTS ( - SELECT 1 - FROM json_array_elements_text(Chat.meta->'tags') AS tag - ) - """ - ) - ) - elif tag_ids: - query = query.filter( - and_( - *[ - text( - f""" - EXISTS ( - SELECT 1 - FROM json_array_elements_text(Chat.meta->'tags') AS tag - WHERE tag = :tag_id_{tag_idx} - ) - """ - ).params(**{f"tag_id_{tag_idx}": tag_id}) - for tag_idx, tag_id in enumerate(tag_ids) - ] - ) - ) - else: - raise NotImplementedError( - f"Unsupported dialect: {db.bind.dialect.name}" - ) - - # Perform pagination at the SQL level - all_chats = query.offset(skip).limit(limit).all() - - log.info(f"The number of chats: {len(all_chats)}") - - # Validate and return chats - return [ChatModel.model_validate(chat) for chat in all_chats] + # Validate and return chats + return resp['results'] def get_chats_by_folder_id_and_user_id( - self, folder_id: str, user_id: str, skip: int = 0, limit: int = 60 + self, folder_id: str, user_id: str, skip: int = 0, limit: int = 60 ) -> list[ChatModel]: with get_db() as db: query = db.query(Chat).filter_by(folder_id=folder_id, user_id=user_id) @@ -846,8 +673,9 @@ def get_chats_by_folder_id_and_user_id( all_chats = query.all() return [ChatModel.model_validate(chat) for chat in all_chats] + # TODO def get_chats_by_folder_ids_and_user_id( - self, folder_ids: list[str], user_id: str + self, folder_ids: list[str], user_id: str ) -> list[ChatModel]: with get_db() as db: query = db.query(Chat).filter( @@ -861,29 +689,26 @@ def get_chats_by_folder_ids_and_user_id( all_chats = query.all() return [ChatModel.model_validate(chat) for chat in all_chats] + @staticmethod def update_chat_folder_id_by_id_and_user_id( - self, id: str, user_id: str, folder_id: str - ) -> Optional[ChatModel]: - try: - with get_db() as db: - chat = db.get(Chat, id) - chat.folder_id = folder_id - chat.updated_at = int(time.time()) - chat.pinned = False - db.commit() - db.refresh(chat) - return ChatModel.model_validate(chat) - except Exception: - return None - + _id: str, user_id: str, folder_id: str + ): + data = { + 'folder_id': folder_id, + 'pinned': False + } + return chat_manager.update(_id, data) + + # TODO def get_chat_tags_by_id_and_user_id(self, id: str, user_id: str) -> list[TagModel]: with get_db() as db: chat = db.get(Chat, id) tags = chat.meta.get("tags", []) return [Tags.get_tag_by_name_and_user_id(tag, user_id) for tag in tags] + # TODO def get_chat_list_by_user_id_and_tag_name( - self, user_id: str, tag_name: str, skip: int = 0, limit: int = 50 + self, user_id: str, tag_name: str, skip: int = 0, limit: int = 50 ) -> list[ChatModel]: with get_db() as db: query = db.query(Chat).filter_by(user_id=user_id) @@ -913,15 +738,16 @@ def get_chat_list_by_user_id_and_tag_name( log.debug(f"all_chats: {all_chats}") return [ChatModel.model_validate(chat) for chat in all_chats] + # TODO def add_chat_tag_by_id_and_user_id_and_tag_name( - self, id: str, user_id: str, tag_name: str + self, _id: str, user_id: str, tag_name: str ) -> Optional[ChatModel]: tag = Tags.get_tag_by_name_and_user_id(tag_name, user_id) if tag is None: tag = Tags.insert_new_tag(tag_name, user_id) try: with get_db() as db: - chat = db.get(Chat, id) + chat = db.get(Chat, _id) tag_id = tag.id if tag_id not in chat.meta.get("tags", []): @@ -936,41 +762,43 @@ def add_chat_tag_by_id_and_user_id_and_tag_name( except Exception: return None - def count_chats_by_tag_name_and_user_id(self, tag_name: str, user_id: str) -> int: - with get_db() as db: # Assuming `get_db()` returns a session object - query = db.query(Chat).filter_by(user_id=user_id, archived=False) - - # Normalize the tag_name for consistency - tag_id = tag_name.replace(" ", "_").lower() - - if db.bind.dialect.name == "sqlite": - # SQLite JSON1 support for querying the tags inside the `meta` JSON field - query = query.filter( - text( - f"EXISTS (SELECT 1 FROM json_each(Chat.meta, '$.tags') WHERE json_each.value = :tag_id)" - ) - ).params(tag_id=tag_id) - - elif db.bind.dialect.name == "postgresql": - # PostgreSQL JSONB support for querying the tags inside the `meta` JSON field - query = query.filter( - text( - "EXISTS (SELECT 1 FROM json_array_elements_text(Chat.meta->'tags') elem WHERE elem = :tag_id)" - ) - ).params(tag_id=tag_id) - - else: - raise NotImplementedError( - f"Unsupported dialect: {db.bind.dialect.name}" - ) - - # Get the count of matching records - count = query.count() - - # Debugging output for inspection - log.info(f"Count of chats for tag '{tag_name}': {count}") - - return count + @staticmethod + def count_chats_by_tag_name_and_user_id(tag_name: str, user_id: str) -> int: + return 0 + # with get_db() as db: # Assuming `get_db()` returns a session object + # query = db.query(Chat).filter_by(user_id=user_id, archived=False) + # + # # Normalize the tag_name for consistency + # tag_id = tag_name.replace(" ", "_").lower() + # + # if db.bind.dialect.name == "sqlite": + # # SQLite JSON1 support for querying the tags inside the `meta` JSON field + # query = query.filter( + # text( + # f"EXISTS (SELECT 1 FROM json_each(Chat.meta, '$.tags') WHERE json_each.value = :tag_id)" + # ) + # ).params(tag_id=tag_id) + # + # elif db.bind.dialect.name == "postgresql": + # # PostgreSQL JSONB support for querying the tags inside the `meta` JSON field + # query = query.filter( + # text( + # "EXISTS (SELECT 1 FROM json_array_elements_text(Chat.meta->'tags') elem WHERE elem = :tag_id)" + # ) + # ).params(tag_id=tag_id) + # + # else: + # raise NotImplementedError( + # f"Unsupported dialect: {db.bind.dialect.name}" + # ) + # + # # Get the count of matching records + # count = query.count() + # + # # Debugging output for inspection + # log.info(f"Count of chats for tag '{tag_name}': {count}") + # + # return count def count_chats_by_folder_id_and_user_id(self, folder_id: str, user_id: str) -> int: with get_db() as db: @@ -983,82 +811,74 @@ def count_chats_by_folder_id_and_user_id(self, folder_id: str, user_id: str) -> return count def delete_tag_by_id_and_user_id_and_tag_name( - self, id: str, user_id: str, tag_name: str + self, _id: str, user_id: str, tag_name: str ) -> bool: try: - with get_db() as db: - chat = db.get(Chat, id) - tags = chat.meta.get("tags", []) - tag_id = tag_name.replace(" ", "_").lower() - - tags = [tag for tag in tags if tag != tag_id] - chat.meta = { - **chat.meta, - "tags": list(set(tags)), - } - db.commit() - return True + chat_dict = self.get_chat_by_id(_id) + tags = chat_dict['meta'].get("tags", []) + tag_id = tag_name.replace(" ", "_").lower() + tags = [tag for tag in tags if tag != tag_id] + meta = { + **chat_dict['meta'], + "tags": list(set(tags)), + } + chat_manager.update(_id, {'meta': meta}) + return True except Exception: return False - def delete_all_tags_by_id_and_user_id(self, id: str, user_id: str) -> bool: + def delete_all_tags_by_id_and_user_id(self, _id: str, user_id: str) -> bool: try: - with get_db() as db: - chat = db.get(Chat, id) - chat.meta = { - **chat.meta, + chat_dict = self.get_chat_by_id(_id) + data = { + 'meta': { + **chat_dict['meta'], "tags": [], } - db.commit() - - return True + } + chat_manager.update(_id, data) + return True except Exception: return False - def delete_chat_by_id(self, id: str) -> bool: + @staticmethod + def delete_chat_by_id(self, _id: str) -> bool: try: - with get_db() as db: - db.query(Chat).filter_by(id=id).delete() - db.commit() - - return True and self.delete_shared_chat_by_chat_id(id) + chat_manager.destroy(_id) + return True + # return True and self.delete_shared_chat_by_chat_id(id) except Exception: return False - def delete_chat_by_id_and_user_id(self, id: str, user_id: str) -> bool: + @staticmethod + def delete_chat_by_id_and_user_id(_id: str, user_id: str) -> bool: try: - with get_db() as db: - db.query(Chat).filter_by(id=id, user_id=user_id).delete() - db.commit() - - return True and self.delete_shared_chat_by_chat_id(id) + chat_manager.destroy(_id, {'user_id': user_id}) + return True + # return True and self.delete_shared_chat_by_chat_id(id) except Exception: return False - def delete_chats_by_user_id(self, user_id: str) -> bool: + @staticmethod + def delete_chats_by_user_id(user_id: str) -> bool: try: - with get_db() as db: - self.delete_shared_chats_by_user_id(user_id) - - db.query(Chat).filter_by(user_id=user_id).delete() - db.commit() - - return True + # self.delete_shared_chats_by_user_id(user_id) + chat_manager.destroy('', {'user_id': user_id}) + return True except Exception: return False + @staticmethod def delete_chats_by_user_id_and_folder_id( - self, user_id: str, folder_id: str + user_id: str, folder_id: str ) -> bool: try: - with get_db() as db: - db.query(Chat).filter_by(user_id=user_id, folder_id=folder_id).delete() - db.commit() - - return True + chat_manager.destroy('', {'user_id': user_id, 'folder_id': folder_id}) + return True except Exception: return False + # TODO def delete_shared_chats_by_user_id(self, user_id: str) -> bool: try: with get_db() as db: diff --git a/backend/open_webui/retrieval/models/external.py b/backend/open_webui/retrieval/models/external.py index a9be526b6d18..6b3fbd5d271b 100644 --- a/backend/open_webui/retrieval/models/external.py +++ b/backend/open_webui/retrieval/models/external.py @@ -16,7 +16,7 @@ class ExternalReranker(BaseReranker): def __init__( self, api_key: str, - url: str = "http://localhost:8080/v1/rerank", + url: str = "http://localhost:8083/v1/rerank", model: str = "reranker", ): self.api_key = api_key @@ -49,8 +49,8 @@ def predict( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} diff --git a/backend/open_webui/retrieval/utils.py b/backend/open_webui/retrieval/utils.py index da570330b372..f56209f93da0 100644 --- a/backend/open_webui/retrieval/utils.py +++ b/backend/open_webui/retrieval/utils.py @@ -861,8 +861,8 @@ def generate_openai_batch_embeddings( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -910,8 +910,8 @@ def generate_azure_openai_batch_embeddings( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -960,8 +960,8 @@ def generate_ollama_batch_embeddings( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS else {} diff --git a/backend/open_webui/routers/audio.py b/backend/open_webui/routers/audio.py index 45b4f1e69233..3eac52cc9ad9 100644 --- a/backend/open_webui/routers/audio.py +++ b/backend/open_webui/routers/audio.py @@ -374,8 +374,8 @@ async def speech(request: Request, user=Depends(get_verified_user)): { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS else {} diff --git a/backend/open_webui/routers/auths.py b/backend/open_webui/routers/auths.py index f261673f3874..7d2efe864d42 100644 --- a/backend/open_webui/routers/auths.py +++ b/backend/open_webui/routers/auths.py @@ -80,58 +80,16 @@ class SessionUserInfoResponse(SessionUserResponse): date_of_birth: Optional[datetime.date] = None -@router.get("/", response_model=SessionUserInfoResponse) +@router.get("/") async def get_session_user( - request: Request, response: Response, user=Depends(get_current_user) + request: Request, user=Depends(get_current_user) ): - - auth_header = request.headers.get("Authorization") - auth_token = get_http_authorization_cred(auth_header) - token = auth_token.credentials - data = decode_token(token) - - expires_at = None - - if data: - expires_at = data.get("exp") - - if (expires_at is not None) and int(time.time()) > expires_at: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.INVALID_TOKEN, - ) - - # Set the cookie token - response.set_cookie( - key="token", - value=token, - expires=( - datetime.datetime.fromtimestamp(expires_at, datetime.timezone.utc) - if expires_at - else None - ), - httponly=True, # Ensures the cookie is not accessible via JavaScript - samesite=WEBUI_AUTH_COOKIE_SAME_SITE, - secure=WEBUI_AUTH_COOKIE_SECURE, - ) - - user_permissions = get_permissions( - user.id, request.app.state.config.USER_PERMISSIONS - ) - return { - "token": token, - "token_type": "Bearer", - "expires_at": expires_at, + "expires_at": None, "id": user.id, - "email": user.email, "name": user.name, - "role": user.role, - "profile_image_url": user.profile_image_url, - "bio": user.bio, - "gender": user.gender, - "date_of_birth": user.date_of_birth, - "permissions": user_permissions, + "role": 'admin', + "permissions": request.app.state.config.USER_PERMISSIONS, } diff --git a/backend/open_webui/routers/chats.py b/backend/open_webui/routers/chats.py index 2587c5ff8e5d..35c9e650ba17 100644 --- a/backend/open_webui/routers/chats.py +++ b/backend/open_webui/routers/chats.py @@ -17,7 +17,7 @@ from open_webui.config import ENABLE_ADMIN_CHAT_ACCESS, ENABLE_ADMIN_EXPORT from open_webui.constants import ERROR_MESSAGES from open_webui.env import SRC_LOG_LEVELS -from fastapi import APIRouter, Depends, HTTPException, Request, status +from fastapi import APIRouter, Depends, HTTPException, Request, status, Header from pydantic import BaseModel @@ -130,17 +130,22 @@ async def get_user_chat_list_by_user_id( @router.post("/new", response_model=Optional[ChatResponse]) -async def create_new_chat(form_data: ChatForm, user=Depends(get_verified_user)): +async def create_new_chat( + form_data: ChatForm, + sid: str = Header(...), + user=Depends(get_verified_user), + request: Request = None +): try: - chat = Chats.insert_new_chat(user.id, form_data) - return ChatResponse(**chat.model_dump()) + log.debug(f"Creating new chat with form_data: {form_data}, sid: {sid}, user: {user.id}") + chat = Chats.insert_new_chat(form_data, sid, request, user) + return ChatResponse(**chat) except Exception as e: - log.exception(e) + log.exception(f"Error creating new chat: {e}") raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, detail=ERROR_MESSAGES.DEFAULT() + status_code=status.HTTP_400_BAD_REQUEST, detail=f"Error creating chat: {str(e)}" ) - ############################ # ImportChat ############################ @@ -161,7 +166,7 @@ async def import_chat(form_data: ChatImportForm, user=Depends(get_verified_user) ): Tags.insert_new_tag(tag_name, user.id) - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) except Exception as e: log.exception(e) raise HTTPException( @@ -185,7 +190,7 @@ def search_user_chats( skip = (page - 1) * limit chat_list = [ - ChatTitleIdResponse(**chat.model_dump()) + ChatTitleIdResponse(**chat) for chat in Chats.get_chats_by_user_id_and_search_text( user.id, text, skip=skip, limit=limit ) @@ -218,7 +223,7 @@ async def get_chats_by_folder_id(folder_id: str, user=Depends(get_verified_user) folder_ids.extend([folder.id for folder in children_folders]) return [ - ChatResponse(**chat.model_dump()) + ChatResponse(**chat) for chat in Chats.get_chats_by_folder_ids_and_user_id(folder_ids, user.id) ] @@ -253,7 +258,7 @@ async def get_chat_list_by_folder_id( @router.get("/pinned", response_model=list[ChatTitleIdResponse]) async def get_user_pinned_chats(user=Depends(get_verified_user)): return [ - ChatTitleIdResponse(**chat.model_dump()) + ChatTitleIdResponse(**chat) for chat in Chats.get_pinned_chats_by_user_id(user.id) ] @@ -266,7 +271,7 @@ async def get_user_pinned_chats(user=Depends(get_verified_user)): @router.get("/all", response_model=list[ChatResponse]) async def get_user_chats(user=Depends(get_verified_user)): return [ - ChatResponse(**chat.model_dump()) + ChatResponse(**chat) for chat in Chats.get_chats_by_user_id(user.id) ] @@ -279,7 +284,7 @@ async def get_user_chats(user=Depends(get_verified_user)): @router.get("/all/archived", response_model=list[ChatResponse]) async def get_user_archived_chats(user=Depends(get_verified_user)): return [ - ChatResponse(**chat.model_dump()) + ChatResponse(**chat) for chat in Chats.get_archived_chats_by_user_id(user.id) ] @@ -313,7 +318,7 @@ async def get_all_user_chats_in_db(user=Depends(get_admin_user)): status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.ACCESS_PROHIBITED, ) - return [ChatResponse(**chat.model_dump()) for chat in Chats.get_chats()] + return [ChatResponse(**chat) for chat in Chats.get_chats()] ############################ @@ -344,7 +349,7 @@ async def get_archived_session_user_chat_list( filter["direction"] = direction chat_list = [ - ChatTitleIdResponse(**chat.model_dump()) + ChatTitleIdResponse(**chat) for chat in Chats.get_archived_chat_list_by_user_id( user.id, filter=filter, @@ -394,7 +399,7 @@ async def get_shared_chat_by_id(share_id: str, user=Depends(get_verified_user)): chat = Chats.get_chat_by_id(share_id) if chat: - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) else: raise HTTPException( @@ -434,12 +439,12 @@ async def get_user_chat_list_by_tag_name( ############################ -@router.get("/{id}", response_model=Optional[ChatResponse]) -async def get_chat_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +@router.get("/{_id}", response_model=Optional[ChatResponse]) +async def get_chat_by_id(_id: str, user=Depends(get_verified_user)): + chat = Chats.get_chat_by_id_and_user_id(_id, user.id) if chat: - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) else: raise HTTPException( @@ -458,9 +463,9 @@ async def update_chat_by_id( ): chat = Chats.get_chat_by_id_and_user_id(id, user.id) if chat: - updated_chat = {**chat.chat, **form_data.chat} + updated_chat = {**chat['chat'], **form_data.chat} chat = Chats.update_chat_by_id(id, updated_chat) - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, @@ -522,7 +527,7 @@ async def update_chat_message_by_id( } ) - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) ############################ @@ -561,7 +566,7 @@ async def send_chat_message_event_by_id( try: if event_emitter: - await event_emitter(form_data.model_dump()) + await event_emitter(form_data) else: return False return True @@ -670,7 +675,7 @@ async def clone_chat_by_id( ), ) - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() @@ -709,7 +714,7 @@ async def clone_shared_chat_by_id(id: str, user=Depends(get_verified_user)): } ), ) - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() @@ -740,7 +745,7 @@ async def archive_chat_by_id(id: str, user=Depends(get_verified_user)): log.debug(f"inserting tag: {tag_id}") tag = Tags.insert_new_tag(tag_id, user.id) - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() @@ -769,7 +774,7 @@ async def share_chat_by_id(request: Request, id: str, user=Depends(get_verified_ if chat: if chat.share_id: shared_chat = Chats.update_shared_chat_by_chat_id(chat.id) - return ChatResponse(**shared_chat.model_dump()) + return ChatResponse(**shared_chat) shared_chat = Chats.insert_shared_chat_by_chat_id(chat.id) if not shared_chat: @@ -777,7 +782,7 @@ async def share_chat_by_id(request: Request, id: str, user=Depends(get_verified_ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=ERROR_MESSAGES.DEFAULT(), ) - return ChatResponse(**shared_chat.model_dump()) + return ChatResponse(**shared_chat) else: raise HTTPException( @@ -827,7 +832,7 @@ async def update_chat_folder_id_by_id( chat = Chats.update_chat_folder_id_by_id_and_user_id( id, user.id, form_data.folder_id ) - return ChatResponse(**chat.model_dump()) + return ChatResponse(**chat) else: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail=ERROR_MESSAGES.DEFAULT() @@ -839,11 +844,11 @@ async def update_chat_folder_id_by_id( ############################ -@router.get("/{id}/tags", response_model=list[TagModel]) -async def get_chat_tags_by_id(id: str, user=Depends(get_verified_user)): - chat = Chats.get_chat_by_id_and_user_id(id, user.id) +@router.get("/{_id}/tags", response_model=list[TagModel]) +async def get_chat_tags_by_id(_id: str, user=Depends(get_verified_user)): + chat = Chats.get_chat_by_id_and_user_id(_id, user.id) if chat: - tags = chat.meta.get("tags", []) + tags = chat['meta'].get("tags", []) return Tags.get_tags_by_ids_and_user_id(tags, user.id) else: raise HTTPException( diff --git a/backend/open_webui/routers/common.py b/backend/open_webui/routers/common.py new file mode 100644 index 000000000000..46e39873b803 --- /dev/null +++ b/backend/open_webui/routers/common.py @@ -0,0 +1,856 @@ +import asyncio +import json +import logging +import os +import datetime as dt +from pydantic import BaseModel +from sqlalchemy import text +import aiohttp +import requests + +from fastapi import ( + Depends, + HTTPException, + Request, + status, +) + +from fastapi.responses import FileResponse + +from starlette.responses import Response + +from open_webui.socket.main import ( + get_event_emitter, + get_models_in_use, + get_active_user_ids, +) +from open_webui.internal.db import Session +from open_webui.models.models import Models +from open_webui.models.users import UserModel, Users +from open_webui.models.chats import Chats + +from open_webui.config import ( + # Retrieval (Web Search) + GOOGLE_DRIVE_CLIENT_ID, + GOOGLE_DRIVE_API_KEY, + ONEDRIVE_CLIENT_ID_PERSONAL, + ONEDRIVE_CLIENT_ID_BUSINESS, + ONEDRIVE_SHAREPOINT_URL, + ONEDRIVE_SHAREPOINT_TENANT_ID, + ENABLE_ONEDRIVE_PERSONAL, + ENABLE_ONEDRIVE_BUSINESS, + # WebUI + WEBUI_AUTH, + # Misc + CACHE_DIR, + DEFAULT_LOCALE, + OAUTH_PROVIDERS, + # Admin + ENABLE_ADMIN_CHAT_ACCESS, + BYPASS_ADMIN_ACCESS_CONTROL, + ENABLE_ADMIN_EXPORT, +) +from open_webui.env import ( + CHANGELOG, + VERSION, + ENABLE_SIGNUP_PASSWORD_CONFIRMATION, + # SCIM + ENABLE_WEBSOCKET_SUPPORT, + BYPASS_MODEL_ACCESS_CONTROL, + ENABLE_VERSION_UPDATE_CHECK, + AIOHTTP_CLIENT_SESSION_SSL, SRC_LOG_LEVELS, +) + +from open_webui.utils.models import ( + get_all_models, + get_all_base_models, + check_model_access, + get_filtered_models, +) +from open_webui.utils.chat import ( + generate_chat_completion as chat_completion_handler, + chat_completed as chat_completed_handler, + chat_action as chat_action_handler, +) +from open_webui.utils.embeddings import generate_embeddings +from open_webui.utils.middleware import process_chat_payload, process_chat_response + +from open_webui.utils.auth import ( + get_http_authorization_cred, + decode_token, + get_admin_user, + get_verified_user, +) +from open_webui.utils.oauth import ( + get_oauth_client_info_with_dynamic_client_registration, + encrypt_data, OAuthClientManager, OAuthManager, +) + +from open_webui.tasks import ( + list_task_ids_by_item_id, + create_task, + stop_task, + list_tasks, +) # Import from tasks.py + +from open_webui.constants import ERROR_MESSAGES + +log = logging.getLogger(__name__) +log.setLevel(SRC_LOG_LEVELS["MAIN"]) + +BASE_PATH = "/kael" + + +def setup_lazy_routes(app): + oauth_client_manager = OAuthClientManager(app) + oauth_manager = OAuthManager(app) + + ################################## + # + # Chat Endpoints + # + ################################## + + @app.get(f"{BASE_PATH}/api/models") + @app.get(f"{BASE_PATH}/api/v1/models") # Experimental: Compatibility with OpenAI API + async def get_models( + request: Request, refresh: bool = False, user=Depends(get_verified_user) + ): + all_models = await get_all_models(request, refresh=refresh, user=user) + + models = [] + for model in all_models: + # Filter out filter pipelines + if "pipeline" in model and model["pipeline"].get("type", None) == "filter": + continue + + try: + model_tags = [ + tag.get("name") + for tag in model.get("info", {}).get("meta", {}).get("tags", []) + ] + tags = [tag.get("name") for tag in model.get("tags", [])] + + tags = list(set(model_tags + tags)) + model["tags"] = [{"name": tag} for tag in tags] + except Exception as e: + log.debug(f"Error processing model tags: {e}") + model["tags"] = [] + pass + + models.append(model) + + model_order_list = request.app.state.config.MODEL_ORDER_LIST + if model_order_list: + model_order_dict = {model_id: i for i, model_id in enumerate(model_order_list)} + # Sort models by order list priority, with fallback for those not in the list + models.sort( + key=lambda model: ( + model_order_dict.get(model.get("id", ""), float("inf")), + (model.get("name", "") or ""), + ) + ) + + models = get_filtered_models(models, user) + + log.debug( + f"/api/models returned filtered models accessible to the user: {json.dumps([model.get('id') for model in models])}" + ) + return {"data": models} + + @app.get(f"{BASE_PATH}/api/models/base") + async def get_base_models(request: Request, user=Depends(get_admin_user)): + models = await get_all_base_models(request, user=user) + return {"data": models} + + ################################## + # Embeddings + ################################## + + @app.post(f"{BASE_PATH}/api/embeddings") + @app.post(f"{BASE_PATH}/api/v1/embeddings") # Experimental: Compatibility with OpenAI API + async def embeddings( + request: Request, form_data: dict, user=Depends(get_verified_user) + ): + """ + OpenAI-compatible embeddings endpoint. + + This handler: + - Performs user/model checks and dispatches to the correct backend. + - Supports OpenAI, Ollama, arena models, pipelines, and any compatible provider. + + Args: + request (Request): Request context. + form_data (dict): OpenAI-like payload (e.g., {"model": "...", "input": [...]}) + user (UserModel): Authenticated user. + + Returns: + dict: OpenAI-compatible embeddings response. + """ + # Make sure models are loaded in app state + if not request.app.state.MODELS: + await get_all_models(request, user=user) + # Use generic dispatcher in utils.embeddings + return await generate_embeddings(request, form_data, user) + + @app.post(f"{BASE_PATH}/api/chat/completions") + @app.post(f"{BASE_PATH}/api/v1/chat/completions") # Experimental: Compatibility with OpenAI API + async def chat_completion( + request: Request, + form_data: dict, + user=Depends(get_verified_user), + ): + if not request.app.state.MODELS: + await get_all_models(request, user=user) + + model_id = form_data.get("model", None) + model_item = form_data.pop("model_item", {}) + tasks = form_data.pop("background_tasks", None) + + metadata = {} + try: + if not model_item.get("direct", False): + if model_id not in request.app.state.MODELS: + raise Exception("Model not found") + + model = request.app.state.MODELS[model_id] + # model_info = Models.get_model_by_id(model_id) + model_info = None + + # Check if user has access to the model + # if not BYPASS_MODEL_ACCESS_CONTROL and ( + # user.role != "admin" or not BYPASS_ADMIN_ACCESS_CONTROL + # ): + # try: + # check_model_access(user, model) + # except Exception as e: + # raise e + else: + model = model_item + model_info = None + + request.state.direct = True + request.state.model = model + + model_info_params = ( + model_info.params.model_dump() if model_info and model_info.params else {} + ) + + # Chat Params + stream_delta_chunk_size = form_data.get("params", {}).get( + "stream_delta_chunk_size" + ) + reasoning_tags = form_data.get("params", {}).get("reasoning_tags") + + # Model Params + if model_info_params.get("stream_delta_chunk_size"): + stream_delta_chunk_size = model_info_params.get("stream_delta_chunk_size") + + if model_info_params.get("reasoning_tags") is not None: + reasoning_tags = model_info_params.get("reasoning_tags") + + metadata = { + "user_id": user.id, + "chat_id": form_data.pop("chat_id", None), + "message_id": form_data.pop("id", None), + "session_id": form_data.pop("session_id", None), + "filter_ids": form_data.pop("filter_ids", []), + "tool_ids": form_data.get("tool_ids", None), + "tool_servers": form_data.pop("tool_servers", None), + "files": form_data.get("files", None), + "features": form_data.get("features", {}), + "variables": form_data.get("variables", {}), + "model": model, + "direct": model_item.get("direct", False), + "params": { + "stream_delta_chunk_size": stream_delta_chunk_size, + "reasoning_tags": reasoning_tags, + "function_calling": ( + "native" + if ( + form_data.get("params", {}).get("function_calling") == "native" + or model_info_params.get("function_calling") == "native" + ) + else "default" + ), + }, + } + + if metadata.get("chat_id") and (user and user.role != "admin"): + if not metadata["chat_id"].startswith("local:"): + chat = Chats.get_chat_by_id_and_user_id(metadata["chat_id"], user.id) + if chat is None: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=ERROR_MESSAGES.DEFAULT(), + ) + + request.state.metadata = metadata + form_data["metadata"] = metadata + + except Exception as e: + log.debug(f"Error processing chat metadata: {e}") + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=str(e), + ) + + async def process_chat(request, form_data, user, metadata, model): + try: + form_data, metadata, events = await process_chat_payload( + request, form_data, user, metadata, model + ) + + response = await chat_completion_handler(request, form_data, user) + if metadata.get("chat_id") and metadata.get("message_id"): + try: + if not metadata["chat_id"].startswith("local:"): + Chats.upsert_message_to_chat_by_id_and_message_id( + metadata["chat_id"], + metadata["message_id"], + { + "model": model_id, + }, + ) + except: + pass + + return await process_chat_response( + request, response, form_data, user, metadata, model, events, tasks + ) + except asyncio.CancelledError: + log.info("Chat processing was cancelled") + try: + event_emitter = get_event_emitter(metadata) + await asyncio.shield( + event_emitter( + {"type": "chat:tasks:cancel"}, + ) + ) + except Exception as e: + pass + finally: + raise # re-raise to ensure proper task cancellation handling + except Exception as e: + log.debug(f"Error processing chat payload: {e}") + if metadata.get("chat_id") and metadata.get("message_id"): + # Update the chat message with the error + try: + if not metadata["chat_id"].startswith("local:"): + Chats.upsert_message_to_chat_by_id_and_message_id( + metadata["chat_id"], + metadata["message_id"], + { + "error": {"content": str(e)}, + }, + ) + + event_emitter = get_event_emitter(metadata) + await event_emitter( + { + "type": "chat:message:error", + "data": {"error": {"content": str(e)}}, + } + ) + await event_emitter( + {"type": "chat:tasks:cancel"}, + ) + + except: + pass + finally: + try: + if mcp_clients := metadata.get("mcp_clients"): + for client in reversed(mcp_clients.values()): + await client.disconnect() + except Exception as e: + log.debug(f"Error cleaning up: {e}") + pass + + if ( + metadata.get("session_id") + and metadata.get("chat_id") + and metadata.get("message_id") + ): + # Asynchronous Chat Processing + task_id, _ = await create_task( + request.app.state.redis, + process_chat(request, form_data, user, metadata, model), + id=metadata["chat_id"], + ) + return {"status": True, "task_id": task_id} + else: + return await process_chat(request, form_data, user, metadata, model) + + # Alias for chat_completion (Legacy) + generate_chat_completions = chat_completion + generate_chat_completion = chat_completion + + @app.post(f"{BASE_PATH}/api/chat/completed") + async def chat_completed( + request: Request, form_data: dict, user=Depends(get_verified_user) + ): + try: + model_item = form_data.pop("model_item", {}) + + if model_item.get("direct", False): + request.state.direct = True + request.state.model = model_item + + return await chat_completed_handler(request, form_data, user) + except Exception as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=str(e), + ) + + @app.post(BASE_PATH + "/api/chat/actions/{action_id}") + async def chat_action( + request: Request, action_id: str, form_data: dict, user=Depends(get_verified_user) + ): + try: + model_item = form_data.pop("model_item", {}) + + if model_item.get("direct", False): + request.state.direct = True + request.state.model = model_item + + return await chat_action_handler(request, action_id, form_data, user) + except Exception as e: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail=str(e), + ) + + @app.post(BASE_PATH + "/api/tasks/stop/{task_id}") + async def stop_task_endpoint( + request: Request, task_id: str, user=Depends(get_verified_user) + ): + try: + result = await stop_task(request.app.state.redis, task_id) + return result + except ValueError as e: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e)) + + @app.get(f"{BASE_PATH}/api/tasks") + async def list_tasks_endpoint(request: Request, user=Depends(get_verified_user)): + return {"tasks": await list_tasks(request.app.state.redis)} + + @app.get(BASE_PATH + "/api/tasks/chat/{chat_id}") + async def list_tasks_by_chat_id_endpoint( + request: Request, chat_id: str, user=Depends(get_verified_user) + ): + chat = Chats.get_chat_by_id(chat_id) + if chat is None or chat.user_id != user.id: + return {"task_ids": []} + + task_ids = await list_task_ids_by_item_id(request.app.state.redis, chat_id) + + log.debug(f"Task IDs for chat {chat_id}: {task_ids}") + return {"task_ids": task_ids} + + ################################## + # + # Config Endpoints + # + ################################## + + @app.get(f"{BASE_PATH}/api/config") + async def get_app_config(request: Request, user=Depends(get_verified_user)): + user_count = 1 + onboarding = False + + if user is None: + onboarding = user_count == 0 + + return { + **({"onboarding": True} if onboarding else {}), + "status": True, + "name": app.state.WEBUI_NAME, + "version": VERSION, + "default_locale": str(DEFAULT_LOCALE), + "oauth": { + "providers": { + name: config.get("name", name) + for name, config in OAUTH_PROVIDERS.items() + } + }, + "features": { + "auth": WEBUI_AUTH, + "auth_trusted_header": bool(app.state.AUTH_TRUSTED_EMAIL_HEADER), + "enable_signup_password_confirmation": ENABLE_SIGNUP_PASSWORD_CONFIRMATION, + "enable_ldap": app.state.config.ENABLE_LDAP, + "enable_api_key": app.state.config.ENABLE_API_KEY, + "enable_signup": app.state.config.ENABLE_SIGNUP, + "enable_login_form": app.state.config.ENABLE_LOGIN_FORM, + "enable_websocket": ENABLE_WEBSOCKET_SUPPORT, + "enable_version_update_check": ENABLE_VERSION_UPDATE_CHECK, + **( + { + "enable_direct_connections": app.state.config.ENABLE_DIRECT_CONNECTIONS, + "enable_channels": app.state.config.ENABLE_CHANNELS, + "enable_notes": app.state.config.ENABLE_NOTES, + "enable_web_search": app.state.config.ENABLE_WEB_SEARCH, + "enable_code_execution": app.state.config.ENABLE_CODE_EXECUTION, + "enable_code_interpreter": app.state.config.ENABLE_CODE_INTERPRETER, + "enable_image_generation": app.state.config.ENABLE_IMAGE_GENERATION, + "enable_autocomplete_generation": app.state.config.ENABLE_AUTOCOMPLETE_GENERATION, + "enable_community_sharing": app.state.config.ENABLE_COMMUNITY_SHARING, + "enable_message_rating": app.state.config.ENABLE_MESSAGE_RATING, + "enable_user_webhooks": app.state.config.ENABLE_USER_WEBHOOKS, + "enable_admin_export": ENABLE_ADMIN_EXPORT, + "enable_admin_chat_access": ENABLE_ADMIN_CHAT_ACCESS, + "enable_google_drive_integration": app.state.config.ENABLE_GOOGLE_DRIVE_INTEGRATION, + "enable_onedrive_integration": app.state.config.ENABLE_ONEDRIVE_INTEGRATION, + **( + { + "enable_onedrive_personal": ENABLE_ONEDRIVE_PERSONAL, + "enable_onedrive_business": ENABLE_ONEDRIVE_BUSINESS, + } + if app.state.config.ENABLE_ONEDRIVE_INTEGRATION + else {} + ), + } + if user is not None + else {} + ), + }, + **( + { + "default_models": app.state.config.DEFAULT_MODELS, + "default_prompt_suggestions": app.state.config.DEFAULT_PROMPT_SUGGESTIONS, + "user_count": user_count, + "code": { + "engine": app.state.config.CODE_EXECUTION_ENGINE, + }, + "audio": { + "tts": { + "engine": app.state.config.TTS_ENGINE, + "voice": app.state.config.TTS_VOICE, + "split_on": app.state.config.TTS_SPLIT_ON, + }, + "stt": { + "engine": app.state.config.STT_ENGINE, + }, + }, + "file": { + "max_size": app.state.config.FILE_MAX_SIZE, + "max_count": app.state.config.FILE_MAX_COUNT, + "image_compression": { + "width": app.state.config.FILE_IMAGE_COMPRESSION_WIDTH, + "height": app.state.config.FILE_IMAGE_COMPRESSION_HEIGHT, + }, + }, + "permissions": {**app.state.config.USER_PERMISSIONS}, + "google_drive": { + "client_id": GOOGLE_DRIVE_CLIENT_ID.value, + "api_key": GOOGLE_DRIVE_API_KEY.value, + }, + "onedrive": { + "client_id_personal": ONEDRIVE_CLIENT_ID_PERSONAL, + "client_id_business": ONEDRIVE_CLIENT_ID_BUSINESS, + "sharepoint_url": ONEDRIVE_SHAREPOINT_URL.value, + "sharepoint_tenant_id": ONEDRIVE_SHAREPOINT_TENANT_ID.value, + }, + "ui": { + "pending_user_overlay_title": app.state.config.PENDING_USER_OVERLAY_TITLE, + "pending_user_overlay_content": app.state.config.PENDING_USER_OVERLAY_CONTENT, + "response_watermark": app.state.config.RESPONSE_WATERMARK, + }, + "license_metadata": app.state.LICENSE_METADATA, + "active_entries": app.state.USER_COUNT, + } + if user is not None + else { + **( + { + "ui": { + "pending_user_overlay_title": app.state.config.PENDING_USER_OVERLAY_TITLE, + "pending_user_overlay_content": app.state.config.PENDING_USER_OVERLAY_CONTENT, + } + } + if user and user.role == "pending" + else {} + ), + **( + { + "metadata": { + "login_footer": app.state.LICENSE_METADATA.get( + "login_footer", "" + ), + "auth_logo_position": app.state.LICENSE_METADATA.get( + "auth_logo_position", "" + ), + } + } + if app.state.LICENSE_METADATA + else {} + ), + } + ), + } + + class UrlForm(BaseModel): + url: str + + @app.get(f"{BASE_PATH}/api/webhook") + async def get_webhook_url(user=Depends(get_admin_user)): + return { + "url": app.state.config.WEBHOOK_URL, + } + + @app.post(f"{BASE_PATH}/api/webhook") + async def update_webhook_url(form_data: UrlForm, user=Depends(get_admin_user)): + app.state.config.WEBHOOK_URL = form_data.url + app.state.WEBHOOK_URL = app.state.config.WEBHOOK_URL + return {"url": app.state.config.WEBHOOK_URL} + + @app.get(f"{BASE_PATH}/api/version") + async def get_app_version(): + return { + "version": VERSION, + } + + @app.get(f"{BASE_PATH}/api/version/updates") + async def get_app_latest_release_version(user=Depends(get_verified_user)): + if not ENABLE_VERSION_UPDATE_CHECK: + log.debug( + f"Version update check is disabled, returning current version as latest version" + ) + return {"current": VERSION, "latest": VERSION} + try: + timeout = aiohttp.ClientTimeout(total=1) + async with aiohttp.ClientSession(timeout=timeout, trust_env=True) as session: + async with session.get( + "https://api.github.com/repos/open-webui/open-webui/releases/latest", + ssl=AIOHTTP_CLIENT_SESSION_SSL, + ) as response: + response.raise_for_status() + data = await response.json() + latest_version = data["tag_name"] + + return {"current": VERSION, "latest": latest_version[1:]} + except Exception as e: + log.debug(e) + return {"current": VERSION, "latest": VERSION} + + @app.get(f"{BASE_PATH}/api/changelog") + async def get_app_changelog(): + return {key: CHANGELOG[key] for idx, key in enumerate(CHANGELOG) if idx < 5} + + @app.get(f"{BASE_PATH}/api/usage") + async def get_current_usage(user=Depends(get_verified_user)): + """ + Get current usage statistics for Open WebUI. + This is an experimental endpoint and subject to change. + """ + try: + return {"model_ids": get_models_in_use(), "user_ids": get_active_user_ids()} + except Exception as e: + log.error(f"Error getting usage statistics: {e}") + raise HTTPException(status_code=500, detail="Internal Server Error") + + async def register_client(self, request, client_id: str) -> bool: + server_type, server_id = client_id.split(":", 1) + + connection = None + connection_idx = None + + for idx, conn in enumerate(request.app.state.config.TOOL_SERVER_CONNECTIONS or []): + if conn.get("type", "openapi") == server_type: + info = conn.get("info", {}) + if info.get("id") == server_id: + connection = conn + connection_idx = idx + break + + if connection is None or connection_idx is None: + log.warning( + f"Unable to locate MCP tool server configuration for client {client_id} during re-registration" + ) + return False + + server_url = connection.get("url") + oauth_server_key = (connection.get("config") or {}).get("oauth_server_key") + + try: + oauth_client_info = ( + await get_oauth_client_info_with_dynamic_client_registration( + request, + client_id, + server_url, + oauth_server_key, + ) + ) + except Exception as e: + log.error(f"Dynamic client re-registration failed for {client_id}: {e}") + return False + + try: + request.app.state.config.TOOL_SERVER_CONNECTIONS[connection_idx] = { + **connection, + "info": { + **connection.get("info", {}), + "oauth_client_info": encrypt_data( + oauth_client_info.model_dump(mode="json") + ), + }, + } + except Exception as e: + log.error( + f"Failed to persist updated OAuth client info for tool server {client_id}: {e}" + ) + return False + + oauth_client_manager.remove_client(client_id) + oauth_client_manager.add_client(client_id, oauth_client_info) + log.info(f"Re-registered OAuth client {client_id} for tool server") + return True + + @app.get(BASE_PATH + "/oauth/clients/{client_id}/authorize") + async def oauth_client_authorize( + client_id: str, + request: Request, + response: Response, + user=Depends(get_verified_user), + ): + # ensure_valid_client_registration + client = oauth_client_manager.get_client(client_id) + client_info = oauth_client_manager.get_client_info(client_id) + if client is None or client_info is None: + raise HTTPException(status.HTTP_404_NOT_FOUND) + + if not await oauth_client_manager._preflight_authorization_url(client, client_info): + log.info( + "Detected invalid OAuth client %s; attempting re-registration", + client_id, + ) + + registered = await register_client(request, client_id) + if not registered: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Failed to re-register OAuth client", + ) + + client = oauth_client_manager.get_client(client_id) + client_info = oauth_client_manager.get_client_info(client_id) + if client is None or client_info is None: + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="OAuth client unavailable after re-registration", + ) + + if not await oauth_client_manager._preflight_authorization_url( + client, client_info + ): + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="OAuth client registration is still invalid after re-registration", + ) + + return await oauth_client_manager.handle_authorize(request, client_id=client_id) + + @app.get(BASE_PATH + "/oauth/clients/{client_id}/callback") + async def oauth_client_callback( + client_id: str, + request: Request, + response: Response, + user=Depends(get_verified_user), + ): + return await oauth_client_manager.handle_callback( + request, + client_id=client_id, + user_id=user.id if user else None, + response=response, + ) + + @app.get(BASE_PATH + "/oauth/{provider}/login") + async def oauth_login(provider: str, request: Request): + return await oauth_manager.handle_login(request, provider) + + # OAuth login logic is as follows: + # 1. Attempt to find a user with matching subject ID, tied to the provider + # 2. If OAUTH_MERGE_ACCOUNTS_BY_EMAIL is true, find a user with the email address provided via OAuth + # - This is considered insecure in general, as OAuth providers do not always verify email addresses + # 3. If there is no user, and ENABLE_OAUTH_SIGNUP is true, create a user + # - Email addresses are considered unique, so we fail registration if the email address is already taken + @app.get(BASE_PATH + "/oauth/{provider}/login/callback") + @app.get(BASE_PATH + "/oauth/{provider}/callback") # Legacy endpoint + async def oauth_login_callback(provider: str, request: Request, response: Response): + return await oauth_manager.handle_callback(request, provider, response) + + @app.get(f"{BASE_PATH}/manifest.json") + async def get_manifest_json(): + if app.state.EXTERNAL_PWA_MANIFEST_URL: + return requests.get(app.state.EXTERNAL_PWA_MANIFEST_URL).json() + else: + return { + "name": app.state.WEBUI_NAME, + "short_name": app.state.WEBUI_NAME, + "description": f"{app.state.WEBUI_NAME} is an open, extensible, user-friendly interface for AI that adapts to your workflow.", + "start_url": "/", + "display": "standalone", + "background_color": "#343541", + "icons": [ + { + "src": "/static/logo.png", + "type": "image/png", + "sizes": "500x500", + "purpose": "any", + }, + { + "src": "/static/logo.png", + "type": "image/png", + "sizes": "500x500", + "purpose": "maskable", + }, + ], + "share_target": { + "action": "/", + "method": "GET", + "params": {"text": "shared"}, + }, + } + + @app.get(f"{BASE_PATH}/opensearch.xml") + async def get_opensearch_xml(): + xml_content = rf""" + + {app.state.WEBUI_NAME} + Search {app.state.WEBUI_NAME} + UTF-8 + {app.state.config.WEBUI_URL}/static/favicon.png + + {app.state.config.WEBUI_URL} + + """ + return Response(content=xml_content, media_type="application/xml") + + @app.get(f"{BASE_PATH}/health") + async def healthcheck(): + UTC = getattr(dt, "UTC", dt.timezone.utc) + upTime = dt.datetime.now().astimezone().astimezone(UTC) + now_utc = dt.datetime.now(UTC) + return { + "timestamp": now_utc.isoformat().replace("+00:00", "Z"), # ISO8601 with Z + "uptime": str(now_utc - upTime), + } + + @app.get(f"{BASE_PATH}/health/db") + async def healthcheck_with_db(): + Session.execute(text("SELECT 1;")).all() + return {"status": True} + + @app.get(BASE_PATH + "/cache/{path:path}") + async def serve_cache_file( + path: str, + user=Depends(get_verified_user), + ): + file_path = os.path.abspath(os.path.join(CACHE_DIR, path)) + # prevent path traversal + if not file_path.startswith(os.path.abspath(CACHE_DIR)): + raise HTTPException(status_code=404, detail="File not found") + if not os.path.isfile(file_path): + raise HTTPException(status_code=404, detail="File not found") + return FileResponse(file_path) diff --git a/backend/open_webui/routers/files.py b/backend/open_webui/routers/files.py index 2a5c3e5bb169..f6993dd9f449 100644 --- a/backend/open_webui/routers/files.py +++ b/backend/open_webui/routers/files.py @@ -206,7 +206,7 @@ def upload_file_handler( file.file, filename, { - "OpenWebUI-User-Email": user.email, + "OpenWebUI-User-Username": user.username, "OpenWebUI-User-Id": user.id, "OpenWebUI-User-Name": user.name, "OpenWebUI-File-Id": id, diff --git a/backend/open_webui/routers/ollama.py b/backend/open_webui/routers/ollama.py index 64b0687afa09..c73564eae3ff 100644 --- a/backend/open_webui/routers/ollama.py +++ b/backend/open_webui/routers/ollama.py @@ -91,7 +91,7 @@ async def send_get_request(url, key=None, user: UserModel = None): { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, + "X-OpenWebUI-User-Username": user.username, "X-OpenWebUI-User-Role": user.role, } if ENABLE_FORWARD_USER_INFO_HEADERS and user @@ -143,7 +143,7 @@ async def send_post_request( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, + "X-OpenWebUI-User-Username": user.username, "X-OpenWebUI-User-Role": user.role, **( {"X-OpenWebUI-Chat-Id": metadata.get("chat_id")} @@ -254,7 +254,7 @@ async def verify_connection( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, + "X-OpenWebUI-User-Username": user.username, "X-OpenWebUI-User-Role": user.role, } if ENABLE_FORWARD_USER_INFO_HEADERS and user @@ -478,8 +478,8 @@ async def get_ollama_tags( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -848,8 +848,8 @@ async def copy_model( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -919,8 +919,8 @@ async def delete_model( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -983,8 +983,8 @@ async def show_model_info( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -1074,8 +1074,8 @@ async def embed( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -1161,8 +1161,8 @@ async def embeddings( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} diff --git a/backend/open_webui/routers/openai.py b/backend/open_webui/routers/openai.py index 9f94d67ee4ff..d42377b395b1 100644 --- a/backend/open_webui/routers/openai.py +++ b/backend/open_webui/routers/openai.py @@ -74,8 +74,8 @@ async def send_get_request(url, key=None, user: UserModel = None): { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } if ENABLE_FORWARD_USER_INFO_HEADERS and user else {} @@ -144,7 +144,7 @@ async def get_headers_and_cookies( { "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, + "X-OpenWebUI-User-Username": user.username, "X-OpenWebUI-User-Role": user.role, **( {"X-OpenWebUI-Chat-Id": metadata.get("chat_id")} @@ -822,40 +822,40 @@ async def generate_chat_completion( metadata = payload.pop("metadata", None) model_id = form_data.get("model") - model_info = Models.get_model_by_id(model_id) + # model_info = Models.get_model_by_id(model_id) # Check model info and override the payload - if model_info: - if model_info.base_model_id: - payload["model"] = model_info.base_model_id - model_id = model_info.base_model_id - - params = model_info.params.model_dump() - - if params: - system = params.pop("system", None) - - payload = apply_model_params_to_body_openai(params, payload) - payload = apply_system_prompt_to_body(system, payload, metadata, user) - - # Check if user has access to the model - if not bypass_filter and user.role == "user": - if not ( - user.id == model_info.user_id - or has_access( - user.id, type="read", access_control=model_info.access_control - ) - ): - raise HTTPException( - status_code=403, - detail="Model not found", - ) - elif not bypass_filter: - if user.role != "admin": - raise HTTPException( - status_code=403, - detail="Model not found", - ) + # if model_info: + # if model_info.base_model_id: + # payload["model"] = model_info.base_model_id + # model_id = model_info.base_model_id + # + # params = model_info.params.model_dump() + # + # if params: + # system = params.pop("system", None) + # + # payload = apply_model_params_to_body_openai(params, payload) + # payload = apply_system_prompt_to_body(system, payload, metadata, user) + # + # # Check if user has access to the model + # if not bypass_filter and user.role == "user": + # if not ( + # user.id == model_info.user_id + # or has_access( + # user.id, type="read", access_control=model_info.access_control + # ) + # ): + # raise HTTPException( + # status_code=403, + # detail="Model not found", + # ) + # elif not bypass_filter: + # if user.role != "admin": + # raise HTTPException( + # status_code=403, + # detail="Model not found", + # ) await get_all_models(request, user=user) model = request.app.state.OPENAI_MODELS.get(model_id) @@ -884,8 +884,8 @@ async def generate_chat_completion( payload["user"] = { "name": user.name, "id": user.id, - "email": user.email, - "role": user.role, + "username": user.username, + "role": 'admin', } url = request.app.state.config.OPENAI_API_BASE_URLS[idx] diff --git a/backend/open_webui/routers/pipelines.py b/backend/open_webui/routers/pipelines.py index f80ea91f848b..e7945a8e9905 100644 --- a/backend/open_webui/routers/pipelines.py +++ b/backend/open_webui/routers/pipelines.py @@ -58,7 +58,7 @@ def get_sorted_filters(model_id, models): async def process_pipeline_inlet_filter(request, payload, user, models): - user = {"id": user.id, "email": user.email, "name": user.name, "role": user.role} + user = {"id": user.id, "name": user.name, "role": user.role} model_id = payload["model"] sorted_filters = get_sorted_filters(model_id, models) model = models[model_id] @@ -111,7 +111,7 @@ async def process_pipeline_inlet_filter(request, payload, user, models): async def process_pipeline_outlet_filter(request, payload, user, models): - user = {"id": user.id, "email": user.email, "name": user.name, "role": user.role} + user = {"id": user.id, "name": user.name, "role": user.role} model_id = payload["model"] sorted_filters = get_sorted_filters(model_id, models) model = models[model_id] diff --git a/backend/open_webui/routers/tasks.py b/backend/open_webui/routers/tasks.py index 7585466f69c1..30bfe90830db 100644 --- a/backend/open_webui/routers/tasks.py +++ b/backend/open_webui/routers/tasks.py @@ -190,7 +190,7 @@ async def generate_title( ) log.debug( - f"generating chat title using model {task_model_id} for user {user.email} " + f"generating chat title using model {task_model_id} for user {user.username} " ) if request.app.state.config.TITLE_GENERATION_PROMPT_TEMPLATE != "": @@ -274,7 +274,7 @@ async def generate_follow_ups( ) log.debug( - f"generating chat title using model {task_model_id} for user {user.email} " + f"generating chat title using model {task_model_id} for user {user.username} " ) if request.app.state.config.FOLLOW_UP_GENERATION_PROMPT_TEMPLATE != "": @@ -347,7 +347,7 @@ async def generate_chat_tags( ) log.debug( - f"generating chat tags using model {task_model_id} for user {user.email} " + f"generating chat tags using model {task_model_id} for user {user.username} " ) if request.app.state.config.TAGS_GENERATION_PROMPT_TEMPLATE != "": @@ -413,7 +413,7 @@ async def generate_image_prompt( ) log.debug( - f"generating image prompt using model {task_model_id} for user {user.email} " + f"generating image prompt using model {task_model_id} for user {user.username} " ) if request.app.state.config.IMAGE_PROMPT_GENERATION_PROMPT_TEMPLATE != "": @@ -498,7 +498,7 @@ async def generate_queries( ) log.debug( - f"generating {type} queries using model {task_model_id} for user {user.email}" + f"generating {type} queries using model {task_model_id} for user {user.username}" ) if (request.app.state.config.QUERY_GENERATION_PROMPT_TEMPLATE).strip() != "": @@ -583,7 +583,7 @@ async def generate_autocompletion( ) log.debug( - f"generating autocompletion using model {task_model_id} for user {user.email}" + f"generating autocompletion using model {task_model_id} for user {user.username}" ) if (request.app.state.config.AUTOCOMPLETE_GENERATION_PROMPT_TEMPLATE).strip() != "": @@ -649,7 +649,7 @@ async def generate_emoji( models, ) - log.debug(f"generating emoji using model {task_model_id} for user {user.email} ") + log.debug(f"generating emoji using model {task_model_id} for user {user.username} ") template = DEFAULT_EMOJI_GENERATION_PROMPT_TEMPLATE diff --git a/backend/open_webui/socket/main.py b/backend/open_webui/socket/main.py index 818a57807f83..7d42c482c4c1 100644 --- a/backend/open_webui/socket/main.py +++ b/backend/open_webui/socket/main.py @@ -5,10 +5,10 @@ import logging import sys import time -from typing import Dict, Set -from redis import asyncio as aioredis import pycrdt as Y +from open_webui.jms import chat_manager, JMSSession +from open_webui.jms import check_user from open_webui.models.users import Users, UserNameResponse from open_webui.models.channels import Channels from open_webui.models.chats import Chats @@ -39,17 +39,20 @@ from open_webui.utils.redis import get_redis_connection from open_webui.utils.access_control import has_access, get_users_with_access - from open_webui.env import ( GLOBAL_LOG_LEVEL, SRC_LOG_LEVELS, ) - logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["SOCKET"]) +# Import BASE_PATH from main module +try: + from open_webui.main import BASE_PATH +except ImportError: + BASE_PATH = "/kael" REDIS = None @@ -82,7 +85,6 @@ always_connect=True, ) - # Timeout duration in seconds TIMEOUT_DURATION = 3 @@ -138,7 +140,6 @@ aquire_func = release_func = renew_func = lambda: True - YDOC_MANAGER = YdocManager( redis=REDIS, redis_key_prefix=f"{REDIS_KEY_PREFIX}:ydoc:documents", @@ -199,7 +200,7 @@ async def periodic_usage_pool_cleanup(): app = socketio.ASGIApp( sio, - socketio_path="/ws/socket.io", + socketio_path=f"{BASE_PATH}/ws/socket.io", ) @@ -266,26 +267,52 @@ async def usage(sid, data): @sio.event async def connect(sid, environ, auth): - user = None - if auth and "token" in auth: - data = decode_token(auth["token"]) + scope = environ.get("asgi.scope", {}) + handler = check_user.CheckUserHandler() - if data is not None and "id" in data: - user = Users.get_user_by_id(data["id"]) + cookie_header = "" + if scope and "headers" in scope: + for k, v in scope["headers"]: + if k == b"cookie": + cookie_header = v.decode("latin1") + break - if user: - SESSION_POOL[sid] = user.model_dump( - exclude=["date_of_birth", "bio", "gender"] - ) - if user.id in USER_POOL: - USER_POOL[user.id] = USER_POOL[user.id] + [sid] - else: - USER_POOL[user.id] = [sid] + if not cookie_header and "HTTP_COOKIE" in environ: + cookie_header = environ["HTTP_COOKIE"] + + user = handler.check_user_by_cookie_header(cookie_header) + + if user: + SESSION_POOL[sid] = { + "id": user.id, + "name": user.name, + "username": user.username, + "role": 'admin', + } + if user.id in USER_POOL: + USER_POOL[user.id] = USER_POOL[user.id] + [sid] + else: + USER_POOL[user.id] = [sid] + + # user = None + # if auth and "token" in auth: + # data = decode_token(auth["token"]) + # + # if data is not None and "id" in data: + # user = Users.get_user_by_id(data["id"]) + # + # if user: + # SESSION_POOL[sid] = user.model_dump( + # exclude=["date_of_birth", "bio", "gender"] + # ) + # if user.id in USER_POOL: + # USER_POOL[user.id] = USER_POOL[user.id] + [sid] + # else: + # USER_POOL[user.id] = [sid] @sio.on("user-join") async def user_join(sid, data): - auth = data["auth"] if "auth" in data else None if not auth or "token" not in auth: return @@ -353,9 +380,9 @@ async def join_note(sid, data): return if ( - user.role != "admin" - and user.id != note.user_id - and not has_access(user.id, type="read", access_control=note.access_control) + user.role != "admin" + and user.id != note.user_id + and not has_access(user.id, type="read", access_control=note.access_control) ): log.error(f"User {user.id} does not have access to note {data['note_id']}") return @@ -408,11 +435,11 @@ async def ydoc_document_join(sid, data): return if ( - user.get("role") != "admin" - and user.get("id") != note.user_id - and not has_access( - user.get("id"), type="read", access_control=note.access_control - ) + user.get("role") != "admin" + and user.get("id") != note.user_id + and not has_access( + user.get("id"), type="read", access_control=note.access_control + ) ): log.error( f"User {user.get('id')} does not have access to note {note_id}" @@ -478,11 +505,11 @@ async def document_save_handler(document_id, data, user): return if ( - user.get("role") != "admin" - and user.get("id") != note.user_id - and not has_access( - user.get("id"), type="read", access_control=note.access_control - ) + user.get("role") != "admin" + and user.get("id") != note.user_id + and not has_access( + user.get("id"), type="read", access_control=note.access_control + ) ): log.error(f"User {user.get('id')} does not have access to note {note_id}") return @@ -598,8 +625,8 @@ async def yjs_document_leave(sid, data): ) if ( - await YDOC_MANAGER.document_exists(document_id) - and len(await YDOC_MANAGER.get_users(document_id)) == 0 + await YDOC_MANAGER.document_exists(document_id) + and len(await YDOC_MANAGER.get_users(document_id)) == 0 ): log.info(f"Cleaning up document {document_id} as no users are left") await YDOC_MANAGER.clear_document(document_id) @@ -641,6 +668,12 @@ async def disconnect(sid): del USER_POOL[user_id] await YDOC_MANAGER.remove_user_from_all_documents(sid) + + chats = chat_manager.list(query={'socket_id': sid}) + + for chat in chats: + jms_session = JMSSession(chat) + await jms_session.close() else: pass # print(f"Unknown session ID {sid} disconnected") @@ -679,9 +712,9 @@ async def __event_emitter__(event_data): await asyncio.gather(*emit_tasks) if ( - update_db - and message_id - and not request_info.get("chat_id", "").startswith("local:") + update_db + and message_id + and not request_info.get("chat_id", "").startswith("local:") ): if "type" in event_data and event_data["type"] == "status": Chats.add_message_status_to_chat_by_id_and_message_id( diff --git a/backend/open_webui/urls.py b/backend/open_webui/urls.py new file mode 100644 index 000000000000..f0f6c55484dd --- /dev/null +++ b/backend/open_webui/urls.py @@ -0,0 +1,94 @@ +from fastapi import APIRouter +from fastapi.staticfiles import StaticFiles + +from open_webui.routers import ( + audio, + images, + ollama, + openai, + retrieval, + pipelines, + tasks, + auths, + channels, + chats, + notes, + folders, + configs, + groups, + files, + functions, + memories, + models, + knowledge, + prompts, + evaluations, + tools, + users, + utils, + scim, +) + +from open_webui.config import ( + # Misc + STATIC_DIR, +) +from open_webui.env import ( + # SCIM + SCIM_ENABLED, +) + +from open_webui.routers.common import setup_lazy_routes + +# Base path configuration - easily changeable +BASE_PATH = "/kael" + + +def setup_routes(app, socket_app): + # Create main API router + main_router = APIRouter() + + main_router.include_router(ollama.router, prefix="/ollama", tags=["ollama"]) + main_router.include_router(openai.router, prefix="/openai", tags=["openai"]) + + main_router.include_router(pipelines.router, prefix="/api/v1/pipelines", tags=["pipelines"]) + main_router.include_router(tasks.router, prefix="/api/v1/tasks", tags=["tasks"]) + main_router.include_router(images.router, prefix="/api/v1/images", tags=["images"]) + + main_router.include_router(audio.router, prefix="/api/v1/audio", tags=["audio"]) + main_router.include_router(retrieval.router, prefix="/api/v1/retrieval", tags=["retrieval"]) + + main_router.include_router(configs.router, prefix="/api/v1/configs", tags=["configs"]) + + main_router.include_router(auths.router, prefix="/api/v1/auths", tags=["auths"]) + main_router.include_router(users.router, prefix="/api/v1/users", tags=["users"]) + + main_router.include_router(channels.router, prefix="/api/v1/channels", tags=["channels"]) + main_router.include_router(chats.router, prefix="/api/v1/chats", tags=["chats"]) + main_router.include_router(notes.router, prefix="/api/v1/notes", tags=["notes"]) + + main_router.include_router(models.router, prefix="/api/v1/models", tags=["models"]) + main_router.include_router(knowledge.router, prefix="/api/v1/knowledge", tags=["knowledge"]) + main_router.include_router(prompts.router, prefix="/api/v1/prompts", tags=["prompts"]) + main_router.include_router(tools.router, prefix="/api/v1/tools", tags=["tools"]) + + main_router.include_router(memories.router, prefix="/api/v1/memories", tags=["memories"]) + main_router.include_router(folders.router, prefix="/api/v1/folders", tags=["folders"]) + main_router.include_router(groups.router, prefix="/api/v1/groups", tags=["groups"]) + main_router.include_router(files.router, prefix="/api/v1/files", tags=["files"]) + main_router.include_router(functions.router, prefix="/api/v1/functions", tags=["functions"]) + main_router.include_router( + evaluations.router, prefix="/api/v1/evaluations", tags=["evaluations"] + ) + main_router.include_router(utils.router, prefix="/api/v1/utils", tags=["utils"]) + + # SCIM 2.0 API for identity management + if SCIM_ENABLED: + main_router.include_router(scim.router, prefix="/api/v1/scim/v2", tags=["scim"]) + + setup_lazy_routes(app) + + app.include_router(main_router, prefix=BASE_PATH) + app.mount(f"{BASE_PATH}/ws", socket_app) + app.mount(f"{BASE_PATH}/kael", StaticFiles(directory=STATIC_DIR), name="kael") + app.mount(f"{BASE_PATH}/static", StaticFiles(directory=STATIC_DIR), name="static") diff --git a/backend/open_webui/utils/auth.py b/backend/open_webui/utils/auth.py index e34803ade1b1..a76fdd849c23 100644 --- a/backend/open_webui/utils/auth.py +++ b/backend/open_webui/utils/auth.py @@ -21,6 +21,7 @@ from opentelemetry import trace +from open_webui.jms import check_user from open_webui.models.users import Users from open_webui.constants import ERROR_MESSAGES @@ -213,118 +214,123 @@ def get_current_user( request: Request, response: Response, background_tasks: BackgroundTasks, - auth_token: HTTPAuthorizationCredentials = Depends(bearer_security), ): - token = None - - if auth_token is not None: - token = auth_token.credentials - - if token is None and "token" in request.cookies: - token = request.cookies.get("token") - - if token is None: - raise HTTPException(status_code=401, detail="Not authenticated") + # token = None + # + # if auth_token is not None: + # token = auth_token.credentials + # + # if token is None and "token" in request.cookies: + # token = request.cookies.get("token") + # + # if token is None: + # raise HTTPException(status_code=401, detail="Not authenticated") # auth by api key - if token.startswith("sk-"): - if not request.state.enable_api_key: - raise HTTPException( - status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_NOT_ALLOWED - ) - - if request.app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS: - allowed_paths = [ - path.strip() - for path in str( - request.app.state.config.API_KEY_ALLOWED_ENDPOINTS - ).split(",") - ] - - # Check if the request path matches any allowed endpoint. - if not any( - request.url.path == allowed - or request.url.path.startswith(allowed + "/") - for allowed in allowed_paths - ): - raise HTTPException( - status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_NOT_ALLOWED - ) - - user = get_current_user_by_api_key(token) - - # Add user info to current span - current_span = trace.get_current_span() - if current_span: - current_span.set_attribute("client.user.id", user.id) - current_span.set_attribute("client.user.email", user.email) - current_span.set_attribute("client.user.role", user.role) - current_span.set_attribute("client.auth.type", "api_key") - - return user - - # auth by jwt token - + # if token.startswith("sk-"): + # if not request.state.enable_api_key: + # raise HTTPException( + # status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_NOT_ALLOWED + # ) + # + # if request.app.state.config.ENABLE_API_KEY_ENDPOINT_RESTRICTIONS: + # allowed_paths = [ + # path.strip() + # for path in str( + # request.app.state.config.API_KEY_ALLOWED_ENDPOINTS + # ).split(",") + # ] + # + # # Check if the request path matches any allowed endpoint. + # if not any( + # request.url.path == allowed + # or request.url.path.startswith(allowed + "/") + # for allowed in allowed_paths + # ): + # raise HTTPException( + # status.HTTP_403_FORBIDDEN, detail=ERROR_MESSAGES.API_KEY_NOT_ALLOWED + # ) + check_user_handler = check_user.CheckUserHandler() try: - try: - data = decode_token(token) - except Exception as e: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Invalid token", - ) - - if data is not None and "id" in data: - user = Users.get_user_by_id(data["id"]) - if user is None: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.INVALID_TOKEN, - ) - else: - if WEBUI_AUTH_TRUSTED_EMAIL_HEADER: - trusted_email = request.headers.get( - WEBUI_AUTH_TRUSTED_EMAIL_HEADER, "" - ).lower() - if trusted_email and user.email != trusted_email: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="User mismatch. Please sign in again.", - ) - - # Add user info to current span - current_span = trace.get_current_span() - if current_span: - current_span.set_attribute("client.user.id", user.id) - current_span.set_attribute("client.user.email", user.email) - current_span.set_attribute("client.user.role", user.role) - current_span.set_attribute("client.auth.type", "jwt") - - # Refresh the user's last active timestamp asynchronously - # to prevent blocking the request - if background_tasks: - background_tasks.add_task( - Users.update_user_last_active_by_id, user.id - ) - return user - else: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.UNAUTHORIZED, - ) - except Exception as e: - # Delete the token cookie - if request.cookies.get("token"): - response.delete_cookie("token") + user = check_user_handler.check_user_by_cookies(request) + except Exception: + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail=ERROR_MESSAGES.UNAUTHORIZED, + ) - if request.cookies.get("oauth_id_token"): - response.delete_cookie("oauth_id_token") + # Add user info to current span + current_span = trace.get_current_span() + if current_span: + current_span.set_attribute("client.user.id", user.id) + current_span.set_attribute("client.user.name", user.name) + current_span.set_attribute("client.user.username", user.username) + current_span.set_attribute("client.user.role", user.role) + # current_span.set_attribute("client.auth.type", "api_key") - # Delete OAuth session if present - if request.cookies.get("oauth_session_id"): - response.delete_cookie("oauth_session_id") + return user - raise e + # # auth by jwt token + # try: + # try: + # data = decode_token(token) + # except Exception as e: + # raise HTTPException( + # status_code=status.HTTP_401_UNAUTHORIZED, + # detail="Invalid token", + # ) + # + # if data is not None and "id" in data: + # user = Users.get_user_by_id(data["id"]) + # if user is None: + # raise HTTPException( + # status_code=status.HTTP_401_UNAUTHORIZED, + # detail=ERROR_MESSAGES.INVALID_TOKEN, + # ) + # else: + # if WEBUI_AUTH_TRUSTED_EMAIL_HEADER: + # trusted_email = request.headers.get( + # WEBUI_AUTH_TRUSTED_EMAIL_HEADER, "" + # ).lower() + # if trusted_email and user.email != trusted_email: + # raise HTTPException( + # status_code=status.HTTP_401_UNAUTHORIZED, + # detail="User mismatch. Please sign in again.", + # ) + # + # # Add user info to current span + # current_span = trace.get_current_span() + # if current_span: + # current_span.set_attribute("client.user.id", user.id) + # current_span.set_attribute("client.user.email", user.email) + # current_span.set_attribute("client.user.role", user.role) + # current_span.set_attribute("client.auth.type", "jwt") + # + # # Refresh the user's last active timestamp asynchronously + # # to prevent blocking the request + # if background_tasks: + # background_tasks.add_task( + # Users.update_user_last_active_by_id, user.id + # ) + # return user + # else: + # raise HTTPException( + # status_code=status.HTTP_401_UNAUTHORIZED, + # detail=ERROR_MESSAGES.UNAUTHORIZED, + # ) + # except Exception as e: + # # Delete the token cookie + # if request.cookies.get("token"): + # response.delete_cookie("token") + # + # if request.cookies.get("oauth_id_token"): + # response.delete_cookie("oauth_id_token") + # + # # Delete OAuth session if present + # if request.cookies.get("oauth_session_id"): + # response.delete_cookie("oauth_session_id") + # + # raise e def get_current_user_by_api_key(api_key: str): @@ -350,11 +356,6 @@ def get_current_user_by_api_key(api_key: str): def get_verified_user(user=Depends(get_current_user)): - if user.role not in {"user", "admin"}: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail=ERROR_MESSAGES.ACCESS_PROHIBITED, - ) return user diff --git a/backend/open_webui/utils/headers.py b/backend/open_webui/utils/headers.py index 3caee5033407..d42ba661a409 100644 --- a/backend/open_webui/utils/headers.py +++ b/backend/open_webui/utils/headers.py @@ -6,6 +6,6 @@ def include_user_info_headers(headers, user): **headers, "X-OpenWebUI-User-Name": quote(user.name, safe=" "), "X-OpenWebUI-User-Id": user.id, - "X-OpenWebUI-User-Email": user.email, - "X-OpenWebUI-User-Role": user.role, + "X-OpenWebUI-User-Username": user.username, + "X-OpenWebUI-User-Role": 'admin', } diff --git a/backend/open_webui/utils/images/comfyui.py b/backend/open_webui/utils/images/comfyui.py index 506723bc9291..4434c3cb7bf2 100644 --- a/backend/open_webui/utils/images/comfyui.py +++ b/backend/open_webui/utils/images/comfyui.py @@ -196,7 +196,7 @@ async def comfyui_create_image( ws.connect(f"{ws_url}/ws?clientId={client_id}", header=headers) log.info("WebSocket connection established.") except Exception as e: - log.exception(f"Failed to connect to WebSocket server: {e}") + log.exception(f"Failed to connect to WebSocket {e}") return None try: diff --git a/backend/open_webui/utils/middleware.py b/backend/open_webui/utils/middleware.py index e5b84a3d792b..f875231e5e2e 100644 --- a/backend/open_webui/utils/middleware.py +++ b/backend/open_webui/utils/middleware.py @@ -1,30 +1,23 @@ import time import logging import sys -import os -import base64 import textwrap import asyncio -from aiocache import cached -from typing import Any, Optional -import random +from typing import Optional import json import html -import inspect import re import ast from uuid import uuid4 from concurrent.futures import ThreadPoolExecutor - from fastapi import Request, HTTPException from fastapi.responses import HTMLResponse -from starlette.responses import Response, StreamingResponse, JSONResponse - +from starlette.responses import StreamingResponse, JSONResponse -from open_webui.models.oauth_sessions import OAuthSessions +from open_webui.jms import chat_manager, CommandHandler, CommandRecord, ReplayHandler from open_webui.models.chats import Chats from open_webui.models.folders import Folders from open_webui.models.users import Users @@ -63,14 +56,12 @@ get_image_url_from_base64, ) - from open_webui.models.users import UserModel from open_webui.models.functions import Functions from open_webui.models.models import Models from open_webui.retrieval.utils import get_sources_from_items - from open_webui.utils.chat import generate_chat_completion from open_webui.utils.task import ( get_task_model_id, @@ -101,7 +92,6 @@ from open_webui.utils.payload import apply_system_prompt_to_body from open_webui.utils.mcp.client import MCPClient - from open_webui.config import ( CACHE_DIR, DEFAULT_TOOLS_FUNCTION_CALLING_PROMPT_TEMPLATE, @@ -119,12 +109,10 @@ ) from open_webui.constants import TASKS - logging.basicConfig(stream=sys.stdout, level=GLOBAL_LOG_LEVEL) log = logging.getLogger(__name__) log.setLevel(SRC_LOG_LEVELS["MAIN"]) - DEFAULT_REASONING_TAGS = [ ("", ""), ("", ""), @@ -140,13 +128,13 @@ def process_tool_result( - request, - tool_function_name, - tool_result, - tool_type, - direct_tool=False, - metadata=None, - user=None, + request, + tool_function_name, + tool_result, + tool_type, + direct_tool=False, + metadata=None, + user=None, ): tool_result_embeds = [] @@ -184,7 +172,7 @@ def process_tool_result( tool_result = tool_result.body.decode("utf-8", "replace") elif (tool_type == "external" and isinstance(tool_result, tuple)) or ( - direct_tool and isinstance(tool_result, list) and len(tool_result) == 2 + direct_tool and isinstance(tool_result, list) and len(tool_result) == 2 ): tool_result, tool_response_headers = tool_result @@ -283,7 +271,7 @@ def process_tool_result( async def chat_completion_tools_handler( - request: Request, body: dict, extra_params: dict, user: UserModel, models, tools + request: Request, body: dict, extra_params: dict, user: UserModel, models, tools ) -> tuple[dict, dict]: async def get_content_from_response(response) -> Optional[str]: content = None @@ -359,7 +347,7 @@ def get_tools_function_calling_payload(messages, task_model_id, content): return body, {} try: - content = content[content.find("{") : content.rfind("}") + 1] + content = content[content.find("{"): content.rfind("}") + 1] if not content: raise Exception("No JSON object found in the response") @@ -488,9 +476,9 @@ async def tool_call_handler(tool_call): ) if ( - tools[tool_function_name] - .get("metadata", {}) - .get("file_handler", False) + tools[tool_function_name] + .get("metadata", {}) + .get("file_handler", False) ): skip_files = True @@ -517,7 +505,7 @@ async def tool_call_handler(tool_call): async def chat_memory_handler( - request: Request, form_data: dict, extra_params: dict, user + request: Request, form_data: dict, extra_params: dict, user ): try: results = await query_memory( @@ -556,7 +544,7 @@ async def chat_memory_handler( async def chat_web_search_handler( - request: Request, form_data: dict, extra_params: dict, user + request: Request, form_data: dict, extra_params: dict, user ): event_emitter = extra_params["__event_emitter__"] await event_emitter( @@ -649,7 +637,7 @@ async def chat_web_search_handler( if results.get("collection_names"): for col_idx, collection_name in enumerate( - results.get("collection_names") + results.get("collection_names") ): files.append( { @@ -734,7 +722,7 @@ def get_last_images(message_list): async def chat_image_generation_handler( - request: Request, form_data: dict, extra_params: dict, user + request: Request, form_data: dict, extra_params: dict, user ): metadata = extra_params.get("__metadata__", {}) chat_id = metadata.get("chat_id", None) @@ -906,7 +894,7 @@ async def chat_image_generation_handler( async def chat_completion_files_handler( - request: Request, body: dict, extra_params: dict, user: UserModel + request: Request, body: dict, extra_params: dict, user: UserModel ) -> tuple[dict, dict[str, list]]: __event_emitter__ = extra_params["__event_emitter__"] sources = [] @@ -987,7 +975,7 @@ async def chat_completion_files_handler( hybrid_bm25_weight=request.app.state.config.HYBRID_BM25_WEIGHT, hybrid_search=request.app.state.config.ENABLE_RAG_HYBRID_SEARCH, full_context=all_full_context - or request.app.state.config.RAG_FULL_CONTEXT, + or request.app.state.config.RAG_FULL_CONTEXT, user=user, ), ) @@ -1008,9 +996,9 @@ async def chat_completion_files_handler( for index, _ in enumerate(documents): metadata = metadatas[index] if index < len(metadatas) else None _id = ( - (metadata or {}).get("source") - or (src_info or {}).get("id") - or "N/A" + (metadata or {}).get("source") + or (src_info or {}).get("id") + or "N/A" ) unique_ids.add(_id) @@ -1143,7 +1131,7 @@ async def process_chat_payload(request, form_data, user, metadata, model): chat_id = metadata.get("chat_id", None) if chat_id and user: chat = Chats.get_chat_by_id_and_user_id(chat_id, user.id) - if chat and chat.folder_id: + if chat and chat['folder_id']: folder = Folders.get_folder_by_id_and_user_id(chat.folder_id, user.id) if folder and folder.data: @@ -1305,15 +1293,15 @@ async def process_chat_payload(request, form_data, user, metadata, model): for tool_id in tool_ids: if tool_id.startswith("server:mcp:"): try: - server_id = tool_id[len("server:mcp:") :] + server_id = tool_id[len("server:mcp:"):] mcp_server_connection = None for ( - server_connection + server_connection ) in request.app.state.config.TOOL_SERVER_CONNECTIONS: if ( - server_connection.get("type", "") == "mcp" - and server_connection.get("info", {}).get("id") == server_id + server_connection.get("type", "") == "mcp" + and server_connection.get("info", {}).get("id") == server_id ): mcp_server_connection = server_connection break @@ -1367,7 +1355,6 @@ async def process_chat_payload(request, form_data, user, metadata, model): tool_specs = await mcp_clients[server_id].list_tool_specs() for tool_spec in tool_specs: - def make_tool_function(client, function_name): async def tool_function(**kwargs): return await client.call_tool( @@ -1468,22 +1455,22 @@ async def tool_function(**kwargs): for source in sources: if "document" in source: for document_text, document_metadata in zip( - source["document"], source["metadata"] + source["document"], source["metadata"] ): source_name = source.get("source", {}).get("name", None) source_id = ( - document_metadata.get("source", None) - or source.get("source", {}).get("id", None) - or "N/A" + document_metadata.get("source", None) + or source.get("source", {}).get("id", None) + or "N/A" ) if source_id not in citation_idx_map: citation_idx_map[source_id] = len(citation_idx_map) + 1 context_string += ( - f'{document_text}\n" + f'{document_text}\n" ) context_string = context_string.strip() @@ -1506,7 +1493,7 @@ async def tool_function(**kwargs): source for source in sources if source.get("source", {}).get("name", "") - or source.get("source", {}).get("id", "") + or source.get("source", {}).get("id", "") ] if len(sources) > 0: @@ -1525,11 +1512,13 @@ async def tool_function(**kwargs): } ) + chat_id = metadata.get("chat_id", '') + asyncio.create_task(ReplayHandler(chat_id).write_input(user_message)) return form_data, metadata, events async def process_chat_response( - request, response, form_data, user, metadata, model, events, tasks + request, response, form_data, user, metadata, model, events, tasks ): async def background_tasks_handler(): message = None @@ -1581,8 +1570,8 @@ async def background_tasks_handler(): if message and "model" in message: if tasks and messages: if ( - TASKS.FOLLOW_UP_GENERATION in tasks - and tasks[TASKS.FOLLOW_UP_GENERATION] + TASKS.FOLLOW_UP_GENERATION in tasks + and tasks[TASKS.FOLLOW_UP_GENERATION] ): res = await generate_follow_ups( request, @@ -1608,8 +1597,8 @@ async def background_tasks_handler(): follow_ups_string = "" follow_ups_string = follow_ups_string[ - follow_ups_string.find("{") : follow_ups_string.rfind("}") - + 1 + follow_ups_string.find("{"): follow_ups_string.rfind("}") + + 1 ] try: @@ -1638,7 +1627,7 @@ async def background_tasks_handler(): pass if not metadata.get("chat_id", "").startswith( - "local:" + "local:" ): # Only update titles and tags for non-temp chats if TASKS.TITLE_GENERATION in tasks: user_message = get_last_user_message(messages) @@ -1664,17 +1653,17 @@ async def background_tasks_handler(): ) title_string = ( - response_message.get("content") - or response_message.get( - "reasoning_content", - ) - or message.get("content", user_message) + response_message.get("content") + or response_message.get( + "reasoning_content", + ) + or message.get("content", user_message) ) else: title_string = "" title_string = title_string[ - title_string.find("{") : title_string.rfind("}") + 1 + title_string.find("{"): title_string.rfind("}") + 1 ] try: @@ -1734,7 +1723,7 @@ async def background_tasks_handler(): tags_string = "" tags_string = tags_string[ - tags_string.find("{") : tags_string.rfind("}") + 1 + tags_string.find("{"): tags_string.rfind("}") + 1 ] try: @@ -1755,12 +1744,12 @@ async def background_tasks_handler(): event_emitter = None event_caller = None if ( - "session_id" in metadata - and metadata["session_id"] - and "chat_id" in metadata - and metadata["chat_id"] - and "message_id" in metadata - and metadata["message_id"] + "session_id" in metadata + and metadata["session_id"] + and "chat_id" in metadata + and metadata["chat_id"] + and "message_id" in metadata + and metadata["message_id"] ): event_emitter = get_event_emitter(metadata) event_caller = get_event_call(metadata) @@ -1775,7 +1764,7 @@ async def background_tasks_handler(): response = response[0] if isinstance(response, JSONResponse) and isinstance( - response.body, bytes + response.body, bytes ): try: response_data = json.loads( @@ -1918,8 +1907,8 @@ async def background_tasks_handler(): # Non standard response if not any( - content_type in response.headers["Content-Type"] - for content_type in ["text/event-stream", "application/x-ndjson"] + content_type in response.headers["Content-Type"] + for content_type in ["text/event-stream", "application/x-ndjson"] ): return response @@ -1957,7 +1946,7 @@ async def background_tasks_handler(): def split_content_and_whitespace(content): content_stripped = content.rstrip() original_whitespace = ( - content[len(content_stripped) :] + content[len(content_stripped):] if len(content) > len(content_stripped) else "" ) @@ -2075,8 +2064,8 @@ def serialize_content_blocks(content_blocks, raw=False): if is_opening_code_block(content_stripped): # Remove trailing backticks that would open a new block content = ( - content_stripped.rstrip("`").rstrip() - + original_whitespace + content_stripped.rstrip("`").rstrip() + + original_whitespace ) else: # Keep content as is - either closing backticks or no backticks @@ -2189,7 +2178,7 @@ def extract_attributes(tag_content): : match.start() ] # Content before opening tag after_tag = content[ - match.end() : + match.end(): ] # Content after opening tag # Remove the start tag and after from the currently handling text block @@ -2358,8 +2347,8 @@ def extract_attributes(tag_content): reasoning_tags = [] if DETECT_REASONING_TAGS: if ( - isinstance(reasoning_tags_param, list) - and len(reasoning_tags_param) == 2 + isinstance(reasoning_tags_param, list) + and len(reasoning_tags_param) == 2 ): reasoning_tags = [ (reasoning_tags_param[0], reasoning_tags_param[1]) @@ -2432,7 +2421,7 @@ async def flush_pending_delta_data(threshold: int = 0): continue # Remove the prefix - data = data[len("data:") :].strip() + data = data[len("data:"):].strip() try: data = json.loads(data) @@ -2447,7 +2436,7 @@ async def flush_pending_delta_data(threshold: int = 0): if data: if "event" in data and not getattr( - request.state, "direct", False + request.state, "direct", False ): await event_emitter(data.get("event", {})) @@ -2508,11 +2497,11 @@ async def flush_pending_delta_data(threshold: int = 0): # Check if the tool call already exists current_response_tool_call = None for ( - response_tool_call + response_tool_call ) in response_tool_calls: if ( - response_tool_call.get("index") - == tool_call_index + response_tool_call.get("index") + == tool_call_index ): current_response_tool_call = ( response_tool_call @@ -2559,14 +2548,14 @@ async def flush_pending_delta_data(threshold: int = 0): value = delta.get("content") reasoning_content = ( - delta.get("reasoning_content") - or delta.get("reasoning") - or delta.get("thinking") + delta.get("reasoning_content") + or delta.get("reasoning") + or delta.get("thinking") ) if reasoning_content: if ( - not content_blocks - or content_blocks[-1]["type"] != "reasoning" + not content_blocks + or content_blocks[-1]["type"] != "reasoning" ): reasoning_block = { "type": "reasoning", @@ -2592,13 +2581,13 @@ async def flush_pending_delta_data(threshold: int = 0): if value: if ( - content_blocks - and content_blocks[-1]["type"] - == "reasoning" - and content_blocks[-1] - .get("attributes", {}) - .get("type") - == "reasoning_content" + content_blocks + and content_blocks[-1]["type"] + == "reasoning" + and content_blocks[-1] + .get("attributes", {}) + .get("type") + == "reasoning_content" ): reasoning_block = content_blocks[-1] reasoning_block["ended_at"] = time.time() @@ -2624,7 +2613,7 @@ async def flush_pending_delta_data(threshold: int = 0): ) content_blocks[-1]["content"] = ( - content_blocks[-1]["content"] + value + content_blocks[-1]["content"] + value ) if DETECT_REASONING_TAGS: @@ -2736,8 +2725,8 @@ async def flush_pending_delta_data(threshold: int = 0): tool_call_retries = 0 while ( - len(tool_calls) > 0 - and tool_call_retries < CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES + len(tool_calls) > 0 + and tool_call_retries < CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES ): tool_call_retries += 1 @@ -2934,8 +2923,8 @@ async def flush_pending_delta_data(threshold: int = 0): retries = 0 while ( - content_blocks[-1]["type"] == "code_interpreter" - and retries < MAX_RETRIES + content_blocks[-1]["type"] == "code_interpreter" + and retries < MAX_RETRIES ): await event_emitter( @@ -2977,8 +2966,8 @@ def restricted_import(name, globals=None, locals=None, fromlist=(), level=0): code = blocking_code + "\n" + code if ( - request.app.state.config.CODE_INTERPRETER_ENGINE - == "pyodide" + request.app.state.config.CODE_INTERPRETER_ENGINE + == "pyodide" ): output = await event_caller( { @@ -2993,8 +2982,8 @@ def restricted_import(name, globals=None, locals=None, fromlist=(), level=0): } ) elif ( - request.app.state.config.CODE_INTERPRETER_ENGINE - == "jupyter" + request.app.state.config.CODE_INTERPRETER_ENGINE + == "jupyter" ): output = await execute_code_jupyter( request.app.state.config.CODE_INTERPRETER_JUPYTER_URL, @@ -3002,13 +2991,13 @@ def restricted_import(name, globals=None, locals=None, fromlist=(), level=0): ( request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_TOKEN if request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH - == "token" + == "token" else None ), ( request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH_PASSWORD if request.app.state.config.CODE_INTERPRETER_JUPYTER_AUTH - == "password" + == "password" else None ), request.app.state.config.CODE_INTERPRETER_JUPYTER_TIMEOUT, @@ -3115,6 +3104,17 @@ def restricted_import(name, globals=None, locals=None, fromlist=(), level=0): "title": title, } + chat_id = metadata.get("chat_id", '') + + chat_data = chat_manager.retrieve(chat_id) + user_message = get_last_user_message(form_data["messages"]) + + command_handler = CommandHandler(chat_id, chat_data['session_info']) + command_handler.command_record = CommandRecord( + input=user_message, output=data['content'] + ) + asyncio.create_task(ReplayHandler(chat_id).write_input(data['content'])) + if not ENABLE_REALTIME_CHAT_SAVE: # Save message in the database Chats.upsert_message_to_chat_by_id_and_message_id( diff --git a/backend/start.sh b/backend/start.sh index 31e87c95577a..106fa23c9c7d 100755 --- a/backend/start.sh +++ b/backend/start.sh @@ -20,7 +20,7 @@ else KEY_FILE=".webui_secret_key" fi -PORT="${PORT:-8080}" +PORT="${PORT:-8083}" HOST="${HOST:-0.0.0.0}" if test "$WEBUI_SECRET_KEY $WEBUI_JWT_SECRET_KEY" = " "; then echo "Loading WEBUI_SECRET_KEY from file, not provided as an environment variable." @@ -84,4 +84,4 @@ WEBUI_SECRET_KEY="$WEBUI_SECRET_KEY" exec "$PYTHON_CMD" -m uvicorn open_webui.ma --host "$HOST" \ --port "$PORT" \ --forwarded-allow-ips '*' \ - "${ARGS[@]}" \ No newline at end of file + "${ARGS[@]}" diff --git a/backend/start_windows.bat b/backend/start_windows.bat index f350d11cd196..691632f022c0 100644 --- a/backend/start_windows.bat +++ b/backend/start_windows.bat @@ -22,7 +22,7 @@ IF NOT "%WEBUI_SECRET_KEY_FILE%" == "" ( SET "KEY_FILE=%WEBUI_SECRET_KEY_FILE%" ) -IF "%PORT%"=="" SET PORT=8080 +IF "%PORT%"=="" SET PORT=8083 IF "%HOST%"=="" SET HOST=0.0.0.0 SET "WEBUI_SECRET_KEY=%WEBUI_SECRET_KEY%" SET "WEBUI_JWT_SECRET_KEY=%WEBUI_JWT_SECRET_KEY%" diff --git a/cypress.config.ts b/cypress.config.ts index dbb538233809..d28819487c64 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from 'cypress'; export default defineConfig({ e2e: { - baseUrl: 'http://localhost:8080' + baseUrl: 'http://localhost:8083' }, video: true }); diff --git a/docker-compose.otel.yaml b/docker-compose.otel.yaml index 0ccadccddae0..01c070e72c01 100644 --- a/docker-compose.otel.yaml +++ b/docker-compose.otel.yaml @@ -20,7 +20,7 @@ services: depends_on: - grafana ports: - - ${OPEN_WEBUI_PORT-8088}:8080 + - ${OPEN_WEBUI_PORT-8088}:8083 environment: - ENABLE_OTEL=true - ENABLE_OTEL_METRICS=true diff --git a/docker-compose.yaml b/docker-compose.yaml index 349734a93921..522087e85623 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -19,7 +19,7 @@ services: depends_on: - ollama ports: - - ${OPEN_WEBUI_PORT-3000}:8080 + - ${OPEN_WEBUI_PORT-3000}:8083 environment: - 'OLLAMA_BASE_URL=http://ollama:11434' - 'WEBUI_SECRET_KEY=' diff --git a/kubernetes/manifest/base/webui-deployment.yaml b/kubernetes/manifest/base/webui-deployment.yaml index 79a0a9a23c96..0414eac239b5 100644 --- a/kubernetes/manifest/base/webui-deployment.yaml +++ b/kubernetes/manifest/base/webui-deployment.yaml @@ -17,7 +17,7 @@ spec: - name: open-webui image: ghcr.io/open-webui/open-webui:main ports: - - containerPort: 8080 + - containerPort: 8083 resources: requests: cpu: "500m" @@ -35,4 +35,4 @@ spec: volumes: - name: webui-volume persistentVolumeClaim: - claimName: open-webui-pvc \ No newline at end of file + claimName: open-webui-pvc diff --git a/kubernetes/manifest/base/webui-ingress.yaml b/kubernetes/manifest/base/webui-ingress.yaml index dc0b53ccd456..22474fb664b7 100644 --- a/kubernetes/manifest/base/webui-ingress.yaml +++ b/kubernetes/manifest/base/webui-ingress.yaml @@ -17,4 +17,4 @@ spec: service: name: open-webui-service port: - number: 8080 + number: 8083 diff --git a/kubernetes/manifest/base/webui-service.yaml b/kubernetes/manifest/base/webui-service.yaml index d73845f00a8e..64b71e8d0abb 100644 --- a/kubernetes/manifest/base/webui-service.yaml +++ b/kubernetes/manifest/base/webui-service.yaml @@ -9,7 +9,7 @@ spec: app: open-webui ports: - protocol: TCP - port: 8080 - targetPort: 8080 + port: 8083 + targetPort: 8083 # If using NodePort, you can optionally specify the nodePort: - # nodePort: 30000 \ No newline at end of file + # nodePort: 30000 diff --git a/package.json b/package.json index 9065bda0ce4b..023238ce84ca 100644 --- a/package.json +++ b/package.json @@ -3,10 +3,10 @@ "version": "0.6.36", "private": true, "scripts": { - "dev": "npm run pyodide:fetch && vite dev --host", - "dev:5050": "npm run pyodide:fetch && vite dev --port 5050", - "build": "npm run pyodide:fetch && vite build", - "build:watch": "npm run pyodide:fetch && vite build --watch", + "dev": "vite dev --host", + "dev:5050": "vite dev --port 5050", + "build": "vite build", + "build:watch": "vite build --watch", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", diff --git a/pyproject.toml b/pyproject.toml index 87e88a1b06bd..843d71263524 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ dependencies = [ "fake-useragent==2.2.0", "chromadb==1.0.20", "opensearch-py==2.8.0", - + "transformers", "sentence-transformers==5.1.1", "accelerate", @@ -111,8 +111,9 @@ dependencies = [ "azure-identity==1.25.0", "azure-storage-blob==12.24.1", - + "protobuf==5.29.5", "ldap3==2.9.1", + "grpcio==1.74.0", ] readme = "README.md" requires-python = ">= 3.11, < 3.13.0a1" @@ -127,16 +128,16 @@ classifiers = [ "Topic :: Multimedia", ] -[project.optional-dependencies] -postgres = [ - "psycopg2-binary==2.9.10", - "pgvector==0.4.1", -] +#[project.optional-dependencies] +#postgres = [ +# "psycopg2-binary==2.9.10", +# "pgvector==0.4.1", +#] all = [ "pymongo", - "psycopg2-binary==2.9.9", - "pgvector==0.4.0", +# "psycopg2-binary==2.9.9", +# "pgvector==0.4.0", "moto[s3]>=5.0.26", "gcp-storage-emulator>=2024.8.3", "docker~=7.1.0", @@ -154,8 +155,8 @@ all = [ "firecrawl-py==4.5.0", ] -[project.scripts] -open-webui = "open_webui:app" +#[project.scripts] +#open-webui = "open_webui:app" [build-system] requires = ["hatchling"] @@ -187,7 +188,7 @@ exclude = [ "webui.db", "chroma.sqlite3", ] -force-include = { "CHANGELOG.md" = "open_webui/CHANGELOG.md", build = "open_webui/frontend" } +#force-include = { "CHANGELOG.md" = "open_webui/CHANGELOG.md", build = "open_webui/frontend" } [tool.codespell] # Ref: https://github.com/codespell-project/codespell#using-a-config-file diff --git a/run.sh b/run.sh index 6793fe16271c..f6315589757a 100644 --- a/run.sh +++ b/run.sh @@ -3,7 +3,7 @@ image_name="open-webui" container_name="open-webui" host_port=3000 -container_port=8080 +container_port=8083 docker build -t "$image_name" . docker stop "$container_name" &>/dev/null || true diff --git a/src/app.html b/src/app.html index 9333dc8ba3de..7b2b7fa93a7b 100644 --- a/src/app.html +++ b/src/app.html @@ -2,28 +2,28 @@ - + - + - + - - + + - + + {#if version && compareVersion(version.latest, version.current) && ($settings?.showUpdateToast ?? true)}
diff --git a/src/routes/(app)/admin/+layout.svelte b/src/routes/(app)/admin/+layout.svelte index fb3395fb6fcc..680e77a3eea4 100644 --- a/src/routes/(app)/admin/+layout.svelte +++ b/src/routes/(app)/admin/+layout.svelte @@ -14,7 +14,7 @@ onMount(async () => { if ($user?.role !== 'admin') { - await goto('/'); + await goto('/kael/'); } loaded = true; }); diff --git a/src/routes/(app)/admin/+page.svelte b/src/routes/(app)/admin/+page.svelte index 2f12bbab8050..cac8a9bcf92f 100644 --- a/src/routes/(app)/admin/+page.svelte +++ b/src/routes/(app)/admin/+page.svelte @@ -3,6 +3,6 @@ import { onMount } from 'svelte'; onMount(() => { - goto('/admin/users'); + goto('/kael/admin/users'); }); diff --git a/src/routes/(app)/admin/analytics/+page.svelte b/src/routes/(app)/admin/analytics/+page.svelte index 176e3162f8eb..e8dc40c64c8b 100644 --- a/src/routes/(app)/admin/analytics/+page.svelte +++ b/src/routes/(app)/admin/analytics/+page.svelte @@ -5,7 +5,7 @@ import Evaluations from '$lib/components/admin/Evaluations.svelte'; onMount(() => { - goto('/admin/evaluations/leaderboard'); + goto('/kael/admin/evaluations/leaderboard'); }); diff --git a/src/routes/(app)/admin/evaluations/+page.svelte b/src/routes/(app)/admin/evaluations/+page.svelte index 176e3162f8eb..e8dc40c64c8b 100644 --- a/src/routes/(app)/admin/evaluations/+page.svelte +++ b/src/routes/(app)/admin/evaluations/+page.svelte @@ -5,7 +5,7 @@ import Evaluations from '$lib/components/admin/Evaluations.svelte'; onMount(() => { - goto('/admin/evaluations/leaderboard'); + goto('/kael/admin/evaluations/leaderboard'); }); diff --git a/src/routes/(app)/admin/functions/create/+page.svelte b/src/routes/(app)/admin/functions/create/+page.svelte index bb13a759fd93..b49d3450fdd4 100644 --- a/src/routes/(app)/admin/functions/create/+page.svelte +++ b/src/routes/(app)/admin/functions/create/+page.svelte @@ -56,7 +56,7 @@ ) ); - await goto('/admin/functions'); + await goto('/kael/admin/functions'); } }; diff --git a/src/routes/(app)/admin/functions/edit/+page.svelte b/src/routes/(app)/admin/functions/edit/+page.svelte index 6a456b983ec9..84302a67c8ea 100644 --- a/src/routes/(app)/admin/functions/edit/+page.svelte +++ b/src/routes/(app)/admin/functions/edit/+page.svelte @@ -66,7 +66,7 @@ if (id) { func = await getFunctionById(localStorage.token, id).catch((error) => { toast.error(`${error}`); - goto('/admin/functions'); + goto('/kael/admin/functions'); return null; }); diff --git a/src/routes/(app)/admin/settings/+page.svelte b/src/routes/(app)/admin/settings/+page.svelte index d8a497cb246b..0754768cbd2d 100644 --- a/src/routes/(app)/admin/settings/+page.svelte +++ b/src/routes/(app)/admin/settings/+page.svelte @@ -4,7 +4,7 @@ import Settings from '$lib/components/admin/Settings.svelte'; onMount(() => { - goto('/admin/settings/general'); + goto('/kael/admin/settings/general'); }); diff --git a/src/routes/(app)/admin/users/+page.svelte b/src/routes/(app)/admin/users/+page.svelte index 8a8e6be79fa4..9798be400158 100644 --- a/src/routes/(app)/admin/users/+page.svelte +++ b/src/routes/(app)/admin/users/+page.svelte @@ -5,7 +5,7 @@ import Users from '$lib/components/admin/Users.svelte'; onMount(() => { - goto('/admin/users/overview'); + goto('/kael/admin/users/overview'); }); diff --git a/src/routes/(app)/notes/+layout.svelte b/src/routes/(app)/notes/+layout.svelte index 2ee828796695..e4204942142d 100644 --- a/src/routes/(app)/notes/+layout.svelte +++ b/src/routes/(app)/notes/+layout.svelte @@ -15,7 +15,7 @@ ) ) { // If the feature is not enabled, redirect to the home page - goto('/'); + goto('/kael'); } loaded = true; diff --git a/src/routes/(app)/workspace/+layout.svelte b/src/routes/(app)/workspace/+layout.svelte index 4473a2bae333..8967a03e19ff 100644 --- a/src/routes/(app)/workspace/+layout.svelte +++ b/src/routes/(app)/workspace/+layout.svelte @@ -23,19 +23,19 @@ onMount(async () => { if ($user?.role !== 'admin') { if ($page.url.pathname.includes('/models') && !$user?.permissions?.workspace?.models) { - goto('/'); + goto('/kael'); } else if ( $page.url.pathname.includes('/knowledge') && !$user?.permissions?.workspace?.knowledge ) { - goto('/'); + goto('/kael'); } else if ( $page.url.pathname.includes('/prompts') && !$user?.permissions?.workspace?.prompts ) { - goto('/'); + goto('/kael'); } else if ($page.url.pathname.includes('/tools') && !$user?.permissions?.workspace?.tools) { - goto('/'); + goto('/kael'); } } diff --git a/src/routes/(app)/workspace/+page.svelte b/src/routes/(app)/workspace/+page.svelte index 65f9d4cef364..4249fd5bfa80 100644 --- a/src/routes/(app)/workspace/+page.svelte +++ b/src/routes/(app)/workspace/+page.svelte @@ -4,20 +4,20 @@ import { onMount } from 'svelte'; onMount(() => { - if ($user?.role !== 'admin') { - if ($user?.permissions?.workspace?.models) { - goto('/workspace/models'); - } else if ($user?.permissions?.workspace?.knowledge) { - goto('/workspace/knowledge'); - } else if ($user?.permissions?.workspace?.prompts) { - goto('/workspace/prompts'); - } else if ($user?.permissions?.workspace?.tools) { - goto('/workspace/tools'); - } else { - goto('/'); - } - } else { - goto('/workspace/models'); - } + // if ($user?.role !== 'admin') { + // if ($user?.permissions?.workspace?.models) { + // goto('/kael/workspace/models'); + // } else if ($user?.permissions?.workspace?.knowledge) { + // goto('/kael/workspace/knowledge'); + // } else if ($user?.permissions?.workspace?.prompts) { + // goto('/kael/workspace/prompts'); + // } else if ($user?.permissions?.workspace?.tools) { + // goto('/kael/workspace/tools'); + // } else { + // goto('/kael'); + // } + // } else { + goto('/kael/workspace/models'); + // } }); diff --git a/src/routes/(app)/workspace/models/create/+page.svelte b/src/routes/(app)/workspace/models/create/+page.svelte index 31bdd96c38e0..2d6f548ae91e 100644 --- a/src/routes/(app)/workspace/models/create/+page.svelte +++ b/src/routes/(app)/workspace/models/create/+page.svelte @@ -54,7 +54,7 @@ ) ); toast.success($i18n.t('Model created successfully!')); - await goto('/workspace/models'); + await goto('/kael/workspace/models'); } } }; diff --git a/src/routes/(app)/workspace/models/edit/+page.svelte b/src/routes/(app)/workspace/models/edit/+page.svelte index 1ff9652c6f60..17113ee87b01 100644 --- a/src/routes/(app)/workspace/models/edit/+page.svelte +++ b/src/routes/(app)/workspace/models/edit/+page.svelte @@ -23,10 +23,10 @@ }); if (!model) { - goto('/workspace/models'); + goto('/kael/workspace/models'); } } else { - goto('/workspace/models'); + goto('/kael/workspace/models'); } }); @@ -41,7 +41,7 @@ ) ); toast.success($i18n.t('Model updated successfully')); - await goto('/workspace/models'); + await goto('/kael/workspace/models'); } }; diff --git a/src/routes/(app)/workspace/prompts/create/+page.svelte b/src/routes/(app)/workspace/prompts/create/+page.svelte index 2fa25de6bd4c..74bc49f54e16 100644 --- a/src/routes/(app)/workspace/prompts/create/+page.svelte +++ b/src/routes/(app)/workspace/prompts/create/+page.svelte @@ -28,7 +28,7 @@ toast.success($i18n.t('Prompt created successfully')); await prompts.set(await getPrompts(localStorage.token)); - await goto('/workspace/prompts'); + await goto('/kael/workspace/prompts'); } }; diff --git a/src/routes/(app)/workspace/prompts/edit/+page.svelte b/src/routes/(app)/workspace/prompts/edit/+page.svelte index 9a317cc7c532..36b8309b9d3a 100644 --- a/src/routes/(app)/workspace/prompts/edit/+page.svelte +++ b/src/routes/(app)/workspace/prompts/edit/+page.svelte @@ -22,7 +22,7 @@ if (prompt) { toast.success($i18n.t('Prompt updated successfully')); await prompts.set(await getPrompts(localStorage.token)); - await goto('/workspace/prompts'); + await goto('/kael/workspace/prompts'); } }; diff --git a/src/routes/(app)/workspace/tools/create/+page.svelte b/src/routes/(app)/workspace/tools/create/+page.svelte index c50ca44cceb0..a91b64b3a3bb 100644 --- a/src/routes/(app)/workspace/tools/create/+page.svelte +++ b/src/routes/(app)/workspace/tools/create/+page.svelte @@ -47,7 +47,7 @@ toast.success($i18n.t('Tool created successfully')); tools.set(await getTools(localStorage.token)); - await goto('/workspace/tools'); + await goto('/kael/workspace/tools'); } }; diff --git a/src/routes/(app)/workspace/tools/edit/+page.svelte b/src/routes/(app)/workspace/tools/edit/+page.svelte index 8714a58c70f0..747a67b4ac55 100644 --- a/src/routes/(app)/workspace/tools/edit/+page.svelte +++ b/src/routes/(app)/workspace/tools/edit/+page.svelte @@ -58,7 +58,7 @@ if (id) { tool = await getToolById(localStorage.token, id).catch((error) => { toast.error(`${error}`); - goto('/workspace/tools'); + goto('/kael/workspace/tools'); return null; }); diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 3985413ebdc9..b2af361d81a4 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -71,14 +71,13 @@ const BREAKPOINT = 768; const setupSocket = async (enableWebsocket) => { - const _socket = io(`${WEBUI_BASE_URL}` || undefined, { + const _socket = io(undefined, { reconnection: true, reconnectionDelay: 1000, reconnectionDelayMax: 5000, randomizationFactor: 0.5, - path: '/ws/socket.io', + path: '/kael/ws/socket.io', transports: enableWebsocket ? ['websocket'] : ['polling', 'websocket'], - auth: { token: localStorage.token } }); await socket.set(_socket); @@ -87,7 +86,6 @@ }); _socket.on('connect', async () => { - console.log('connected', _socket.id); const version = await getVersion(localStorage.token); if (version !== null) { if ($WEBUI_VERSION !== null && version !== $WEBUI_VERSION) { @@ -313,7 +311,7 @@ toast.custom(NotificationToast, { componentProps: { onClick: () => { - goto(`/c/${event.chat_id}`); + goto(`/kael/c/${event.chat_id}`); }, content: content, title: title @@ -462,7 +460,7 @@ toast.custom(NotificationToast, { componentProps: { onClick: () => { - goto(`/channels/${event.channel_id}`); + goto(`/kael/channels/${event.channel_id}`); }, content: data?.content, title: `#${event?.channel?.name}` @@ -636,32 +634,22 @@ const currentUrl = `${window.location.pathname}${window.location.search}`; const encodedUrl = encodeURIComponent(currentUrl); - if (localStorage.token) { - // Get Session User Info - const sessionUser = await getSessionUser(localStorage.token).catch((error) => { - toast.error(`${error}`); - return null; - }); + // Get Session User Info + const sessionUser = await getSessionUser().catch((error) => { + toast.error(`${error}`); + return null; + }); - if (sessionUser) { - await user.set(sessionUser); - await config.set(await getBackendConfig()); - } else { - // Redirect Invalid Session User to /auth Page - localStorage.removeItem('token'); - await goto(`/auth?redirect=${encodedUrl}`); - } + if (sessionUser) { + await user.set(sessionUser); + await config.set(await getBackendConfig()); } else { - // Don't redirect if we're already on the auth page - // Needed because we pass in tokens from OAuth logins via URL fragments - if ($page.url.pathname !== '/auth') { - await goto(`/auth?redirect=${encodedUrl}`); - } + await goto(`/core/auth/login/?next=/kael?redirect=${encodedUrl}`); } } } else { // Redirect to /error when Backend Not Detected - await goto(`/error`); + await goto(`/kael/error`); } await tick(); diff --git a/src/routes/auth/+page.svelte b/src/routes/auth/+page.svelte index a6dd15f99794..ef95dfb2336d 100644 --- a/src/routes/auth/+page.svelte +++ b/src/routes/auth/+page.svelte @@ -38,7 +38,6 @@ const setSessionUser = async (sessionUser, redirectPath: string | null = null) => { if (sessionUser) { - console.log(sessionUser); toast.success($i18n.t(`You're now logged in.`)); if (sessionUser.token) { localStorage.token = sessionUser.token; @@ -48,7 +47,7 @@ await config.set(await getBackendConfig()); if (!redirectPath) { - redirectPath = $page.url.searchParams.get('redirect') || '/'; + redirectPath = $page.url.searchParams.get('redirect') || '/kael'; } goto(redirectPath); @@ -156,7 +155,8 @@ onMount(async () => { const redirectPath = $page.url.searchParams.get('redirect'); if ($user !== undefined) { - goto(redirectPath || '/'); + const redirectPath = "/core/auth/login/?next=/kael" + goto(redirectPath); } else { if (redirectPath) { localStorage.setItem('redirectPath', redirectPath); diff --git a/src/routes/error/+page.svelte b/src/routes/error/+page.svelte index 748b6d7d4454..8d0d6c943e62 100644 --- a/src/routes/error/+page.svelte +++ b/src/routes/error/+page.svelte @@ -9,7 +9,7 @@ onMount(async () => { if ($config) { - await goto('/'); + await goto('/kael/'); } loaded = true; diff --git a/src/routes/s/[id]/+page.svelte b/src/routes/s/[id]/+page.svelte index 02ed91389bfb..40a9a48e074f 100644 --- a/src/routes/s/[id]/+page.svelte +++ b/src/routes/s/[id]/+page.svelte @@ -50,7 +50,7 @@ await tick(); loaded = true; } else { - await goto('/'); + await goto('/kael/'); } })(); } @@ -87,7 +87,7 @@ ); await chatId.set($page.params.id); chat = await getChatByShareId(localStorage.token, $chatId).catch(async (error) => { - await goto('/'); + await goto('/kael/'); return null; }); @@ -136,7 +136,7 @@ }); if (res) { - goto(`/c/${res.id}`); + goto(`/kael/c/${res.id}`); } }; diff --git a/static/avatar.png b/static/avatar.png new file mode 100644 index 000000000000..8462a8a18b02 Binary files /dev/null and b/static/avatar.png differ diff --git a/svelte.config.js b/svelte.config.js index 82e05951f3f5..2d7d2e4b928c 100644 --- a/svelte.config.js +++ b/svelte.config.js @@ -36,6 +36,9 @@ const config = { } })(), pollInterval: 60000 + }, + paths: { + base: '/kael' } }, vitePlugin: { diff --git a/uv.lock b/uv.lock index 7bde0eeb0179..70cd4f23cf77 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.11, <3.13.0" resolution-markers = [ "python_full_version < '3.12' and sys_platform == 'darwin'", @@ -52,16 +52,16 @@ wheels = [ [[package]] name = "aiohappyeyeballs" -version = "2.4.4" +version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/55/e4373e888fdacb15563ef6fa9fa8c8252476ea071e96fb46defac9f18bf2/aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", size = 21977, upload-time = "2024-11-30T18:44:00.701Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8", size = 14756, upload-time = "2024-11-30T18:43:39.849Z" }, + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, ] [[package]] name = "aiohttp" -version = "3.11.11" +version = "3.12.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -72,50 +72,55 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/ed/f26db39d29cd3cb2f5a3374304c713fe5ab5a0e4c8ee25a0c45cc6adf844/aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e", size = 7669618, upload-time = "2024-12-18T21:20:50.191Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ae/e8806a9f054e15f1d18b04db75c23ec38ec954a10c0a68d3bd275d7e8be3/aiohttp-3.11.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ba74ec819177af1ef7f59063c6d35a214a8fde6f987f7661f4f0eecc468a8f76", size = 708624, upload-time = "2024-12-18T21:18:10.575Z" }, - { url = "https://files.pythonhosted.org/packages/c7/e0/313ef1a333fb4d58d0c55a6acb3cd772f5d7756604b455181049e222c020/aiohttp-3.11.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4af57160800b7a815f3fe0eba9b46bf28aafc195555f1824555fa2cfab6c1538", size = 468507, upload-time = "2024-12-18T21:18:12.224Z" }, - { url = "https://files.pythonhosted.org/packages/a9/60/03455476bf1f467e5b4a32a465c450548b2ce724eec39d69f737191f936a/aiohttp-3.11.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffa336210cf9cd8ed117011085817d00abe4c08f99968deef0013ea283547204", size = 455571, upload-time = "2024-12-18T21:18:15.506Z" }, - { url = "https://files.pythonhosted.org/packages/be/f9/469588603bd75bf02c8ffb8c8a0d4b217eed446b49d4a767684685aa33fd/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81b8fe282183e4a3c7a1b72f5ade1094ed1c6345a8f153506d114af5bf8accd9", size = 1685694, upload-time = "2024-12-18T21:18:17.512Z" }, - { url = "https://files.pythonhosted.org/packages/88/b9/1b7fa43faf6c8616fa94c568dc1309ffee2b6b68b04ac268e5d64b738688/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3af41686ccec6a0f2bdc66686dc0f403c41ac2089f80e2214a0f82d001052c03", size = 1743660, upload-time = "2024-12-18T21:18:20.878Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8b/0248d19dbb16b67222e75f6aecedd014656225733157e5afaf6a6a07e2e8/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:70d1f9dde0e5dd9e292a6d4d00058737052b01f3532f69c0c65818dac26dc287", size = 1785421, upload-time = "2024-12-18T21:18:22.948Z" }, - { url = "https://files.pythonhosted.org/packages/c4/11/f478e071815a46ca0a5ae974651ff0c7a35898c55063305a896e58aa1247/aiohttp-3.11.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:249cc6912405917344192b9f9ea5cd5b139d49e0d2f5c7f70bdfaf6b4dbf3a2e", size = 1675145, upload-time = "2024-12-18T21:18:24.788Z" }, - { url = "https://files.pythonhosted.org/packages/26/5d/284d182fecbb5075ae10153ff7374f57314c93a8681666600e3a9e09c505/aiohttp-3.11.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eb98d90b6690827dcc84c246811feeb4e1eea683c0eac6caed7549be9c84665", size = 1619804, upload-time = "2024-12-18T21:18:26.602Z" }, - { url = "https://files.pythonhosted.org/packages/1b/78/980064c2ad685c64ce0e8aeeb7ef1e53f43c5b005edcd7d32e60809c4992/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec82bf1fda6cecce7f7b915f9196601a1bd1a3079796b76d16ae4cce6d0ef89b", size = 1654007, upload-time = "2024-12-18T21:18:29.669Z" }, - { url = "https://files.pythonhosted.org/packages/21/8d/9e658d63b1438ad42b96f94da227f2e2c1d5c6001c9e8ffcc0bfb22e9105/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9fd46ce0845cfe28f108888b3ab17abff84ff695e01e73657eec3f96d72eef34", size = 1650022, upload-time = "2024-12-18T21:18:33.249Z" }, - { url = "https://files.pythonhosted.org/packages/85/fd/a032bf7f2755c2df4f87f9effa34ccc1ef5cea465377dbaeef93bb56bbd6/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:bd176afcf8f5d2aed50c3647d4925d0db0579d96f75a31e77cbaf67d8a87742d", size = 1732899, upload-time = "2024-12-18T21:18:35.225Z" }, - { url = "https://files.pythonhosted.org/packages/c5/0c/c2b85fde167dd440c7ba50af2aac20b5a5666392b174df54c00f888c5a75/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ec2aa89305006fba9ffb98970db6c8221541be7bee4c1d027421d6f6df7d1ce2", size = 1755142, upload-time = "2024-12-18T21:18:37.48Z" }, - { url = "https://files.pythonhosted.org/packages/bc/78/91ae1a3b3b3bed8b893c5d69c07023e151b1c95d79544ad04cf68f596c2f/aiohttp-3.11.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:92cde43018a2e17d48bb09c79e4d4cb0e236de5063ce897a5e40ac7cb4878773", size = 1692736, upload-time = "2024-12-18T21:18:40.967Z" }, - { url = "https://files.pythonhosted.org/packages/77/89/a7ef9c4b4cdb546fcc650ca7f7395aaffbd267f0e1f648a436bec33c9b95/aiohttp-3.11.11-cp311-cp311-win32.whl", hash = "sha256:aba807f9569455cba566882c8938f1a549f205ee43c27b126e5450dc9f83cc62", size = 416418, upload-time = "2024-12-18T21:18:44.281Z" }, - { url = "https://files.pythonhosted.org/packages/fc/db/2192489a8a51b52e06627506f8ac8df69ee221de88ab9bdea77aa793aa6a/aiohttp-3.11.11-cp311-cp311-win_amd64.whl", hash = "sha256:ae545f31489548c87b0cced5755cfe5a5308d00407000e72c4fa30b19c3220ac", size = 442509, upload-time = "2024-12-18T21:18:47.323Z" }, - { url = "https://files.pythonhosted.org/packages/69/cf/4bda538c502f9738d6b95ada11603c05ec260807246e15e869fc3ec5de97/aiohttp-3.11.11-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e595c591a48bbc295ebf47cb91aebf9bd32f3ff76749ecf282ea7f9f6bb73886", size = 704666, upload-time = "2024-12-18T21:18:49.254Z" }, - { url = "https://files.pythonhosted.org/packages/46/7b/87fcef2cad2fad420ca77bef981e815df6904047d0a1bd6aeded1b0d1d66/aiohttp-3.11.11-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3ea1b59dc06396b0b424740a10a0a63974c725b1c64736ff788a3689d36c02d2", size = 464057, upload-time = "2024-12-18T21:18:51.375Z" }, - { url = "https://files.pythonhosted.org/packages/5a/a6/789e1f17a1b6f4a38939fbc39d29e1d960d5f89f73d0629a939410171bc0/aiohttp-3.11.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8811f3f098a78ffa16e0ea36dffd577eb031aea797cbdba81be039a4169e242c", size = 455996, upload-time = "2024-12-18T21:18:53.11Z" }, - { url = "https://files.pythonhosted.org/packages/b7/dd/485061fbfef33165ce7320db36e530cd7116ee1098e9c3774d15a732b3fd/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7227b87a355ce1f4bf83bfae4399b1f5bb42e0259cb9405824bd03d2f4336a", size = 1682367, upload-time = "2024-12-18T21:18:55.053Z" }, - { url = "https://files.pythonhosted.org/packages/e9/d7/9ec5b3ea9ae215c311d88b2093e8da17e67b8856673e4166c994e117ee3e/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d40f9da8cabbf295d3a9dae1295c69975b86d941bc20f0a087f0477fa0a66231", size = 1736989, upload-time = "2024-12-18T21:18:56.933Z" }, - { url = "https://files.pythonhosted.org/packages/d6/fb/ea94927f7bfe1d86178c9d3e0a8c54f651a0a655214cce930b3c679b8f64/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffb3dc385f6bb1568aa974fe65da84723210e5d9707e360e9ecb51f59406cd2e", size = 1793265, upload-time = "2024-12-18T21:19:00.174Z" }, - { url = "https://files.pythonhosted.org/packages/40/7f/6de218084f9b653026bd7063cd8045123a7ba90c25176465f266976d8c82/aiohttp-3.11.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8f5f7515f3552d899c61202d99dcb17d6e3b0de777900405611cd747cecd1b8", size = 1691841, upload-time = "2024-12-18T21:19:02.3Z" }, - { url = "https://files.pythonhosted.org/packages/77/e2/992f43d87831cbddb6b09c57ab55499332f60ad6fdbf438ff4419c2925fc/aiohttp-3.11.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3499c7ffbfd9c6a3d8d6a2b01c26639da7e43d47c7b4f788016226b1e711caa8", size = 1619317, upload-time = "2024-12-18T21:19:04.33Z" }, - { url = "https://files.pythonhosted.org/packages/96/74/879b23cdd816db4133325a201287c95bef4ce669acde37f8f1b8669e1755/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8e2bf8029dbf0810c7bfbc3e594b51c4cc9101fbffb583a3923aea184724203c", size = 1641416, upload-time = "2024-12-18T21:19:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/30/98/b123f6b15d87c54e58fd7ae3558ff594f898d7f30a90899718f3215ad328/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b6212a60e5c482ef90f2d788835387070a88d52cf6241d3916733c9176d39eab", size = 1646514, upload-time = "2024-12-18T21:19:12.154Z" }, - { url = "https://files.pythonhosted.org/packages/d7/38/257fda3dc99d6978ab943141d5165ec74fd4b4164baa15e9c66fa21da86b/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d119fafe7b634dbfa25a8c597718e69a930e4847f0b88e172744be24515140da", size = 1702095, upload-time = "2024-12-18T21:19:15.51Z" }, - { url = "https://files.pythonhosted.org/packages/0c/f4/ddab089053f9fb96654df5505c0a69bde093214b3c3454f6bfdb1845f558/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:6fba278063559acc730abf49845d0e9a9e1ba74f85f0ee6efd5803f08b285853", size = 1734611, upload-time = "2024-12-18T21:19:18.849Z" }, - { url = "https://files.pythonhosted.org/packages/c3/d6/f30b2bc520c38c8aa4657ed953186e535ae84abe55c08d0f70acd72ff577/aiohttp-3.11.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:92fc484e34b733704ad77210c7957679c5c3877bd1e6b6d74b185e9320cc716e", size = 1694576, upload-time = "2024-12-18T21:19:21.257Z" }, - { url = "https://files.pythonhosted.org/packages/bc/97/b0a88c3f4c6d0020b34045ee6d954058abc870814f6e310c4c9b74254116/aiohttp-3.11.11-cp312-cp312-win32.whl", hash = "sha256:9f5b3c1ed63c8fa937a920b6c1bec78b74ee09593b3f5b979ab2ae5ef60d7600", size = 411363, upload-time = "2024-12-18T21:19:23.122Z" }, - { url = "https://files.pythonhosted.org/packages/7f/23/cc36d9c398980acaeeb443100f0216f50a7cfe20c67a9fd0a2f1a5a846de/aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d", size = 437666, upload-time = "2024-12-18T21:19:26.425Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/19/9e86722ec8e835959bd97ce8c1efa78cf361fa4531fca372551abcc9cdd6/aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117", size = 711246, upload-time = "2025-07-29T05:50:15.937Z" }, + { url = "https://files.pythonhosted.org/packages/71/f9/0a31fcb1a7d4629ac9d8f01f1cb9242e2f9943f47f5d03215af91c3c1a26/aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe", size = 483515, upload-time = "2025-07-29T05:50:17.442Z" }, + { url = "https://files.pythonhosted.org/packages/62/6c/94846f576f1d11df0c2e41d3001000527c0fdf63fce7e69b3927a731325d/aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9", size = 471776, upload-time = "2025-07-29T05:50:19.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/6c/f766d0aaafcee0447fad0328da780d344489c042e25cd58fde566bf40aed/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5", size = 1741977, upload-time = "2025-07-29T05:50:21.665Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/fb779a05ba6ff44d7bc1e9d24c644e876bfff5abe5454f7b854cace1b9cc/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728", size = 1690645, upload-time = "2025-07-29T05:50:23.333Z" }, + { url = "https://files.pythonhosted.org/packages/37/4e/a22e799c2035f5d6a4ad2cf8e7c1d1bd0923192871dd6e367dafb158b14c/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16", size = 1789437, upload-time = "2025-07-29T05:50:25.007Z" }, + { url = "https://files.pythonhosted.org/packages/28/e5/55a33b991f6433569babb56018b2fb8fb9146424f8b3a0c8ecca80556762/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0", size = 1828482, upload-time = "2025-07-29T05:50:26.693Z" }, + { url = "https://files.pythonhosted.org/packages/c6/82/1ddf0ea4f2f3afe79dffed5e8a246737cff6cbe781887a6a170299e33204/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b", size = 1730944, upload-time = "2025-07-29T05:50:28.382Z" }, + { url = "https://files.pythonhosted.org/packages/1b/96/784c785674117b4cb3877522a177ba1b5e4db9ce0fd519430b5de76eec90/aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd", size = 1668020, upload-time = "2025-07-29T05:50:30.032Z" }, + { url = "https://files.pythonhosted.org/packages/12/8a/8b75f203ea7e5c21c0920d84dd24a5c0e971fe1e9b9ebbf29ae7e8e39790/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8", size = 1716292, upload-time = "2025-07-29T05:50:31.983Z" }, + { url = "https://files.pythonhosted.org/packages/47/0b/a1451543475bb6b86a5cfc27861e52b14085ae232896a2654ff1231c0992/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50", size = 1711451, upload-time = "2025-07-29T05:50:33.989Z" }, + { url = "https://files.pythonhosted.org/packages/55/fd/793a23a197cc2f0d29188805cfc93aa613407f07e5f9da5cd1366afd9d7c/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676", size = 1691634, upload-time = "2025-07-29T05:50:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/ca/bf/23a335a6670b5f5dfc6d268328e55a22651b440fca341a64fccf1eada0c6/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7", size = 1785238, upload-time = "2025-07-29T05:50:37.597Z" }, + { url = "https://files.pythonhosted.org/packages/57/4f/ed60a591839a9d85d40694aba5cef86dde9ee51ce6cca0bb30d6eb1581e7/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7", size = 1805701, upload-time = "2025-07-29T05:50:39.591Z" }, + { url = "https://files.pythonhosted.org/packages/85/e0/444747a9455c5de188c0f4a0173ee701e2e325d4b2550e9af84abb20cdba/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685", size = 1718758, upload-time = "2025-07-29T05:50:41.292Z" }, + { url = "https://files.pythonhosted.org/packages/36/ab/1006278d1ffd13a698e5dd4bfa01e5878f6bddefc296c8b62649753ff249/aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b", size = 428868, upload-time = "2025-07-29T05:50:43.063Z" }, + { url = "https://files.pythonhosted.org/packages/10/97/ad2b18700708452400278039272032170246a1bf8ec5d832772372c71f1a/aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d", size = 453273, upload-time = "2025-07-29T05:50:44.613Z" }, + { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" }, + { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" }, + { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" }, + { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" }, + { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" }, + { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" }, + { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" }, + { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" }, + { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" }, + { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" }, ] [[package]] name = "aiosignal" -version = "1.3.2" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, ] [[package]] @@ -173,15 +178,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041, upload-time = "2025-01-05T13:13:07.985Z" }, ] -[[package]] -name = "appdirs" -version = "1.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41", size = 13470, upload-time = "2020-05-11T07:59:51.037Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128", size = 9566, upload-time = "2020-05-11T07:59:49.499Z" }, -] - [[package]] name = "apscheduler" version = "3.10.4" @@ -198,14 +194,14 @@ wheels = [ [[package]] name = "argon2-cffi" -version = "23.1.0" +version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/31/fa/57ec2c6d16ecd2ba0cf15f3c7d1c3c2e7b5fcb83555ff56d7ab10888ec8f/argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", size = 42798, upload-time = "2023-08-15T14:13:12.711Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea", size = 15124, upload-time = "2023-08-15T14:13:10.752Z" }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, ] [[package]] @@ -258,14 +254,14 @@ wheels = [ [[package]] name = "authlib" -version = "1.4.1" +version = "1.6.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cryptography" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/73/0aa3d68b1c3caeac01ae0bad7a3d2a23029c4a3b42c7ccb89d752ed67eb2/authlib-1.4.1.tar.gz", hash = "sha256:30ead9ea4993cdbab821dc6e01e818362f92da290c04c7f6a1940f86507a790d", size = 147376, upload-time = "2025-01-28T13:05:27.309Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/3f/1d3bbd0bf23bdd99276d4def22f29c27a914067b4cf66f753ff9b8bbd0f3/authlib-1.6.5.tar.gz", hash = "sha256:6aaf9c79b7cc96c900f0b284061691c5d4e61221640a948fe690b556a6d6d10b", size = 164553, upload-time = "2025-10-02T13:36:09.489Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/6a/e83a6c04f8c6014c33d97c135782a55370cf60513f8d9f99f1279c7f9c13/Authlib-1.4.1-py2.py3-none-any.whl", hash = "sha256:edc29c3f6a3e72cd9e9f45fff67fc663a2c364022eb0371c003f22d5405915c1", size = 225610, upload-time = "2025-01-28T13:05:24.761Z" }, + { url = "https://files.pythonhosted.org/packages/f8/aa/5082412d1ee302e9e7d80b6949bc4d2a8fa1149aaab610c5fc24709605d6/authlib-1.6.5-py2.py3-none-any.whl", hash = "sha256:3e0e0507807f842b02175507bdee8957a1d5707fd4afb17c32fb43fee90b6e3a", size = 243608, upload-time = "2025-10-02T13:36:07.637Z" }, ] [[package]] @@ -318,7 +314,7 @@ wheels = [ [[package]] name = "azure-identity" -version = "1.20.0" +version = "1.25.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -327,9 +323,9 @@ dependencies = [ { name = "msal-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ee/89/7d170fab0b85d9650cdb7abda087e849644beb52bd28f6804620dd0cecd9/azure_identity-1.20.0.tar.gz", hash = "sha256:40597210d56c83e15031b0fe2ea3b26420189e1e7f3e20bdbb292315da1ba014", size = 264447, upload-time = "2025-02-12T00:40:41.225Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/9e/4c9682a286c3c89e437579bd9f64f311020e5125c1321fd3a653166b5716/azure_identity-1.25.0.tar.gz", hash = "sha256:4177df34d684cddc026e6cf684e1abb57767aa9d84e7f2129b080ec45eee7733", size = 278507, upload-time = "2025-09-12T01:30:04.418Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/aa/819513c1dbef990af690bb5eefb5e337f8698d75dfdb7302528f50ce1994/azure_identity-1.20.0-py3-none-any.whl", hash = "sha256:5f23fc4889a66330e840bd78830287e14f3761820fe3c5f77ac875edcb9ec998", size = 188243, upload-time = "2025-02-12T00:40:44.99Z" }, + { url = "https://files.pythonhosted.org/packages/75/54/81683b6756676a22e037b209695b08008258e603f7e47c56834029c5922a/azure_identity-1.25.0-py3-none-any.whl", hash = "sha256:becaec086bbdf8d1a6aa4fb080c2772a0f824a97d50c29637ec8cc4933f1e82d", size = 190861, upload-time = "2025-09-12T01:30:06.474Z" }, ] [[package]] @@ -358,42 +354,44 @@ wheels = [ [[package]] name = "bcrypt" -version = "4.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/5d/6d7433e0f3cd46ce0b43cd65e1db465ea024dbb8216fb2404e919c2ad77b/bcrypt-4.3.0.tar.gz", hash = "sha256:3a3fd2204178b6d2adcf09cb4f6426ffef54762577a7c9b54c159008cb288c18", size = 25697, upload-time = "2025-02-28T01:24:09.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/22/5ada0b9af72b60cbc4c9a399fdde4af0feaa609d27eb0adc61607997a3fa/bcrypt-4.3.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:f81b0ed2639568bf14749112298f9e4e2b28853dab50a8b357e31798686a036d", size = 498019, upload-time = "2025-02-28T01:23:05.838Z" }, - { url = "https://files.pythonhosted.org/packages/b8/8c/252a1edc598dc1ce57905be173328eda073083826955ee3c97c7ff5ba584/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:864f8f19adbe13b7de11ba15d85d4a428c7e2f344bac110f667676a0ff84924b", size = 279174, upload-time = "2025-02-28T01:23:07.274Z" }, - { url = "https://files.pythonhosted.org/packages/29/5b/4547d5c49b85f0337c13929f2ccbe08b7283069eea3550a457914fc078aa/bcrypt-4.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e36506d001e93bffe59754397572f21bb5dc7c83f54454c990c74a468cd589e", size = 283870, upload-time = "2025-02-28T01:23:09.151Z" }, - { url = "https://files.pythonhosted.org/packages/be/21/7dbaf3fa1745cb63f776bb046e481fbababd7d344c5324eab47f5ca92dd2/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:842d08d75d9fe9fb94b18b071090220697f9f184d4547179b60734846461ed59", size = 279601, upload-time = "2025-02-28T01:23:11.461Z" }, - { url = "https://files.pythonhosted.org/packages/6d/64/e042fc8262e971347d9230d9abbe70d68b0a549acd8611c83cebd3eaec67/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7c03296b85cb87db865d91da79bf63d5609284fc0cab9472fdd8367bbd830753", size = 297660, upload-time = "2025-02-28T01:23:12.989Z" }, - { url = "https://files.pythonhosted.org/packages/50/b8/6294eb84a3fef3b67c69b4470fcdd5326676806bf2519cda79331ab3c3a9/bcrypt-4.3.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:62f26585e8b219cdc909b6a0069efc5e4267e25d4a3770a364ac58024f62a761", size = 284083, upload-time = "2025-02-28T01:23:14.5Z" }, - { url = "https://files.pythonhosted.org/packages/62/e6/baff635a4f2c42e8788fe1b1633911c38551ecca9a749d1052d296329da6/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:beeefe437218a65322fbd0069eb437e7c98137e08f22c4660ac2dc795c31f8bb", size = 279237, upload-time = "2025-02-28T01:23:16.686Z" }, - { url = "https://files.pythonhosted.org/packages/39/48/46f623f1b0c7dc2e5de0b8af5e6f5ac4cc26408ac33f3d424e5ad8da4a90/bcrypt-4.3.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:97eea7408db3a5bcce4a55d13245ab3fa566e23b4c67cd227062bb49e26c585d", size = 283737, upload-time = "2025-02-28T01:23:18.897Z" }, - { url = "https://files.pythonhosted.org/packages/49/8b/70671c3ce9c0fca4a6cc3cc6ccbaa7e948875a2e62cbd146e04a4011899c/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:191354ebfe305e84f344c5964c7cd5f924a3bfc5d405c75ad07f232b6dffb49f", size = 312741, upload-time = "2025-02-28T01:23:21.041Z" }, - { url = "https://files.pythonhosted.org/packages/27/fb/910d3a1caa2d249b6040a5caf9f9866c52114d51523ac2fb47578a27faee/bcrypt-4.3.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:41261d64150858eeb5ff43c753c4b216991e0ae16614a308a15d909503617732", size = 316472, upload-time = "2025-02-28T01:23:23.183Z" }, - { url = "https://files.pythonhosted.org/packages/dc/cf/7cf3a05b66ce466cfb575dbbda39718d45a609daa78500f57fa9f36fa3c0/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:33752b1ba962ee793fa2b6321404bf20011fe45b9afd2a842139de3011898fef", size = 343606, upload-time = "2025-02-28T01:23:25.361Z" }, - { url = "https://files.pythonhosted.org/packages/e3/b8/e970ecc6d7e355c0d892b7f733480f4aa8509f99b33e71550242cf0b7e63/bcrypt-4.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:50e6e80a4bfd23a25f5c05b90167c19030cf9f87930f7cb2eacb99f45d1c3304", size = 362867, upload-time = "2025-02-28T01:23:26.875Z" }, - { url = "https://files.pythonhosted.org/packages/a9/97/8d3118efd8354c555a3422d544163f40d9f236be5b96c714086463f11699/bcrypt-4.3.0-cp38-abi3-win32.whl", hash = "sha256:67a561c4d9fb9465ec866177e7aebcad08fe23aaf6fbd692a6fab69088abfc51", size = 160589, upload-time = "2025-02-28T01:23:28.381Z" }, - { url = "https://files.pythonhosted.org/packages/29/07/416f0b99f7f3997c69815365babbc2e8754181a4b1899d921b3c7d5b6f12/bcrypt-4.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:584027857bc2843772114717a7490a37f68da563b3620f78a849bcb54dc11e62", size = 152794, upload-time = "2025-02-28T01:23:30.187Z" }, - { url = "https://files.pythonhosted.org/packages/6e/c1/3fa0e9e4e0bfd3fd77eb8b52ec198fd6e1fd7e9402052e43f23483f956dd/bcrypt-4.3.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0d3efb1157edebfd9128e4e46e2ac1a64e0c1fe46fb023158a407c7892b0f8c3", size = 498969, upload-time = "2025-02-28T01:23:31.945Z" }, - { url = "https://files.pythonhosted.org/packages/ce/d4/755ce19b6743394787fbd7dff6bf271b27ee9b5912a97242e3caf125885b/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08bacc884fd302b611226c01014eca277d48f0a05187666bca23aac0dad6fe24", size = 279158, upload-time = "2025-02-28T01:23:34.161Z" }, - { url = "https://files.pythonhosted.org/packages/9b/5d/805ef1a749c965c46b28285dfb5cd272a7ed9fa971f970435a5133250182/bcrypt-4.3.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6746e6fec103fcd509b96bacdfdaa2fbde9a553245dbada284435173a6f1aef", size = 284285, upload-time = "2025-02-28T01:23:35.765Z" }, - { url = "https://files.pythonhosted.org/packages/ab/2b/698580547a4a4988e415721b71eb45e80c879f0fb04a62da131f45987b96/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:afe327968aaf13fc143a56a3360cb27d4ad0345e34da12c7290f1b00b8fe9a8b", size = 279583, upload-time = "2025-02-28T01:23:38.021Z" }, - { url = "https://files.pythonhosted.org/packages/f2/87/62e1e426418204db520f955ffd06f1efd389feca893dad7095bf35612eec/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d9af79d322e735b1fc33404b5765108ae0ff232d4b54666d46730f8ac1a43676", size = 297896, upload-time = "2025-02-28T01:23:39.575Z" }, - { url = "https://files.pythonhosted.org/packages/cb/c6/8fedca4c2ada1b6e889c52d2943b2f968d3427e5d65f595620ec4c06fa2f/bcrypt-4.3.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f1e3ffa1365e8702dc48c8b360fef8d7afeca482809c5e45e653af82ccd088c1", size = 284492, upload-time = "2025-02-28T01:23:40.901Z" }, - { url = "https://files.pythonhosted.org/packages/4d/4d/c43332dcaaddb7710a8ff5269fcccba97ed3c85987ddaa808db084267b9a/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:3004df1b323d10021fda07a813fd33e0fd57bef0e9a480bb143877f6cba996fe", size = 279213, upload-time = "2025-02-28T01:23:42.653Z" }, - { url = "https://files.pythonhosted.org/packages/dc/7f/1e36379e169a7df3a14a1c160a49b7b918600a6008de43ff20d479e6f4b5/bcrypt-4.3.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:531457e5c839d8caea9b589a1bcfe3756b0547d7814e9ce3d437f17da75c32b0", size = 284162, upload-time = "2025-02-28T01:23:43.964Z" }, - { url = "https://files.pythonhosted.org/packages/1c/0a/644b2731194b0d7646f3210dc4d80c7fee3ecb3a1f791a6e0ae6bb8684e3/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:17a854d9a7a476a89dcef6c8bd119ad23e0f82557afbd2c442777a16408e614f", size = 312856, upload-time = "2025-02-28T01:23:46.011Z" }, - { url = "https://files.pythonhosted.org/packages/dc/62/2a871837c0bb6ab0c9a88bf54de0fc021a6a08832d4ea313ed92a669d437/bcrypt-4.3.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6fb1fd3ab08c0cbc6826a2e0447610c6f09e983a281b919ed721ad32236b8b23", size = 316726, upload-time = "2025-02-28T01:23:47.575Z" }, - { url = "https://files.pythonhosted.org/packages/0c/a1/9898ea3faac0b156d457fd73a3cb9c2855c6fd063e44b8522925cdd8ce46/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e965a9c1e9a393b8005031ff52583cedc15b7884fce7deb8b0346388837d6cfe", size = 343664, upload-time = "2025-02-28T01:23:49.059Z" }, - { url = "https://files.pythonhosted.org/packages/40/f2/71b4ed65ce38982ecdda0ff20c3ad1b15e71949c78b2c053df53629ce940/bcrypt-4.3.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:79e70b8342a33b52b55d93b3a59223a844962bef479f6a0ea318ebbcadf71505", size = 363128, upload-time = "2025-02-28T01:23:50.399Z" }, - { url = "https://files.pythonhosted.org/packages/11/99/12f6a58eca6dea4be992d6c681b7ec9410a1d9f5cf368c61437e31daa879/bcrypt-4.3.0-cp39-abi3-win32.whl", hash = "sha256:b4d4e57f0a63fd0b358eb765063ff661328f69a04494427265950c71b992a39a", size = 160598, upload-time = "2025-02-28T01:23:51.775Z" }, - { url = "https://files.pythonhosted.org/packages/a9/cf/45fb5261ece3e6b9817d3d82b2f343a505fd58674a92577923bc500bd1aa/bcrypt-4.3.0-cp39-abi3-win_amd64.whl", hash = "sha256:e53e074b120f2877a35cc6c736b8eb161377caae8925c17688bd46ba56daaa5b", size = 152799, upload-time = "2025-02-28T01:23:53.139Z" }, - { url = "https://files.pythonhosted.org/packages/4c/b1/1289e21d710496b88340369137cc4c5f6ee036401190ea116a7b4ae6d32a/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a839320bf27d474e52ef8cb16449bb2ce0ba03ca9f44daba6d93fa1d8828e48a", size = 275103, upload-time = "2025-02-28T01:24:00.764Z" }, - { url = "https://files.pythonhosted.org/packages/94/41/19be9fe17e4ffc5d10b7b67f10e459fc4eee6ffe9056a88de511920cfd8d/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:bdc6a24e754a555d7316fa4774e64c6c3997d27ed2d1964d55920c7c227bc4ce", size = 280513, upload-time = "2025-02-28T01:24:02.243Z" }, - { url = "https://files.pythonhosted.org/packages/aa/73/05687a9ef89edebdd8ad7474c16d8af685eb4591c3c38300bb6aad4f0076/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:55a935b8e9a1d2def0626c4269db3fcd26728cbff1e84f0341465c31c4ee56d8", size = 274685, upload-time = "2025-02-28T01:24:04.512Z" }, - { url = "https://files.pythonhosted.org/packages/63/13/47bba97924ebe86a62ef83dc75b7c8a881d53c535f83e2c54c4bd701e05c/bcrypt-4.3.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:57967b7a28d855313a963aaea51bf6df89f833db4320da458e5b3c5ab6d4c938", size = 280110, upload-time = "2025-02-28T01:24:05.896Z" }, +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/36/3329e2518d70ad8e2e5817d5a4cac6bba05a47767ec416c7d020a965f408/bcrypt-5.0.0.tar.gz", hash = "sha256:f748f7c2d6fd375cc93d3fba7ef4a9e3a092421b8dbf34d8d4dc06be9492dfdd", size = 25386, upload-time = "2025-09-25T19:50:47.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/29/6237f151fbfe295fe3e074ecc6d44228faa1e842a81f6d34a02937ee1736/bcrypt-5.0.0-cp38-abi3-macosx_10_12_universal2.whl", hash = "sha256:fc746432b951e92b58317af8e0ca746efe93e66555f1b40888865ef5bf56446b", size = 494553, upload-time = "2025-09-25T19:49:49.006Z" }, + { url = "https://files.pythonhosted.org/packages/45/b6/4c1205dde5e464ea3bd88e8742e19f899c16fa8916fb8510a851fae985b5/bcrypt-5.0.0-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c2388ca94ffee269b6038d48747f4ce8df0ffbea43f31abfa18ac72f0218effb", size = 275009, upload-time = "2025-09-25T19:49:50.581Z" }, + { url = "https://files.pythonhosted.org/packages/3b/71/427945e6ead72ccffe77894b2655b695ccf14ae1866cd977e185d606dd2f/bcrypt-5.0.0-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:560ddb6ec730386e7b3b26b8b4c88197aaed924430e7b74666a586ac997249ef", size = 278029, upload-time = "2025-09-25T19:49:52.533Z" }, + { url = "https://files.pythonhosted.org/packages/17/72/c344825e3b83c5389a369c8a8e58ffe1480b8a699f46c127c34580c4666b/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d79e5c65dcc9af213594d6f7f1fa2c98ad3fc10431e7aa53c176b441943efbdd", size = 275907, upload-time = "2025-09-25T19:49:54.709Z" }, + { url = "https://files.pythonhosted.org/packages/0b/7e/d4e47d2df1641a36d1212e5c0514f5291e1a956a7749f1e595c07a972038/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2b732e7d388fa22d48920baa267ba5d97cca38070b69c0e2d37087b381c681fd", size = 296500, upload-time = "2025-09-25T19:49:56.013Z" }, + { url = "https://files.pythonhosted.org/packages/0f/c3/0ae57a68be2039287ec28bc463b82e4b8dc23f9d12c0be331f4782e19108/bcrypt-5.0.0-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:0c8e093ea2532601a6f686edbc2c6b2ec24131ff5c52f7610dd64fa4553b5464", size = 278412, upload-time = "2025-09-25T19:49:57.356Z" }, + { url = "https://files.pythonhosted.org/packages/45/2b/77424511adb11e6a99e3a00dcc7745034bee89036ad7d7e255a7e47be7d8/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5b1589f4839a0899c146e8892efe320c0fa096568abd9b95593efac50a87cb75", size = 275486, upload-time = "2025-09-25T19:49:59.116Z" }, + { url = "https://files.pythonhosted.org/packages/43/0a/405c753f6158e0f3f14b00b462d8bca31296f7ecfc8fc8bc7919c0c7d73a/bcrypt-5.0.0-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:89042e61b5e808b67daf24a434d89bab164d4de1746b37a8d173b6b14f3db9ff", size = 277940, upload-time = "2025-09-25T19:50:00.869Z" }, + { url = "https://files.pythonhosted.org/packages/62/83/b3efc285d4aadc1fa83db385ec64dcfa1707e890eb42f03b127d66ac1b7b/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e3cf5b2560c7b5a142286f69bde914494b6d8f901aaa71e453078388a50881c4", size = 310776, upload-time = "2025-09-25T19:50:02.393Z" }, + { url = "https://files.pythonhosted.org/packages/95/7d/47ee337dacecde6d234890fe929936cb03ebc4c3a7460854bbd9c97780b8/bcrypt-5.0.0-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f632fd56fc4e61564f78b46a2269153122db34988e78b6be8b32d28507b7eaeb", size = 312922, upload-time = "2025-09-25T19:50:04.232Z" }, + { url = "https://files.pythonhosted.org/packages/d6/3a/43d494dfb728f55f4e1cf8fd435d50c16a2d75493225b54c8d06122523c6/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:801cad5ccb6b87d1b430f183269b94c24f248dddbbc5c1f78b6ed231743e001c", size = 341367, upload-time = "2025-09-25T19:50:05.559Z" }, + { url = "https://files.pythonhosted.org/packages/55/ab/a0727a4547e383e2e22a630e0f908113db37904f58719dc48d4622139b5c/bcrypt-5.0.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3cf67a804fc66fc217e6914a5635000259fbbbb12e78a99488e4d5ba445a71eb", size = 359187, upload-time = "2025-09-25T19:50:06.916Z" }, + { url = "https://files.pythonhosted.org/packages/1b/bb/461f352fdca663524b4643d8b09e8435b4990f17fbf4fea6bc2a90aa0cc7/bcrypt-5.0.0-cp38-abi3-win32.whl", hash = "sha256:3abeb543874b2c0524ff40c57a4e14e5d3a66ff33fb423529c88f180fd756538", size = 153752, upload-time = "2025-09-25T19:50:08.515Z" }, + { url = "https://files.pythonhosted.org/packages/41/aa/4190e60921927b7056820291f56fc57d00d04757c8b316b2d3c0d1d6da2c/bcrypt-5.0.0-cp38-abi3-win_amd64.whl", hash = "sha256:35a77ec55b541e5e583eb3436ffbbf53b0ffa1fa16ca6782279daf95d146dcd9", size = 150881, upload-time = "2025-09-25T19:50:09.742Z" }, + { url = "https://files.pythonhosted.org/packages/54/12/cd77221719d0b39ac0b55dbd39358db1cd1246e0282e104366ebbfb8266a/bcrypt-5.0.0-cp38-abi3-win_arm64.whl", hash = "sha256:cde08734f12c6a4e28dc6755cd11d3bdfea608d93d958fffbe95a7026ebe4980", size = 144931, upload-time = "2025-09-25T19:50:11.016Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ba/2af136406e1c3839aea9ecadc2f6be2bcd1eff255bd451dd39bcf302c47a/bcrypt-5.0.0-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:0c418ca99fd47e9c59a301744d63328f17798b5947b0f791e9af3c1c499c2d0a", size = 495313, upload-time = "2025-09-25T19:50:12.309Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ee/2f4985dbad090ace5ad1f7dd8ff94477fe089b5fab2040bd784a3d5f187b/bcrypt-5.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ddb4e1500f6efdd402218ffe34d040a1196c072e07929b9820f363a1fd1f4191", size = 275290, upload-time = "2025-09-25T19:50:13.673Z" }, + { url = "https://files.pythonhosted.org/packages/e4/6e/b77ade812672d15cf50842e167eead80ac3514f3beacac8902915417f8b7/bcrypt-5.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7aeef54b60ceddb6f30ee3db090351ecf0d40ec6e2abf41430997407a46d2254", size = 278253, upload-time = "2025-09-25T19:50:15.089Z" }, + { url = "https://files.pythonhosted.org/packages/36/c4/ed00ed32f1040f7990dac7115f82273e3c03da1e1a1587a778d8cea496d8/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f0ce778135f60799d89c9693b9b398819d15f1921ba15fe719acb3178215a7db", size = 276084, upload-time = "2025-09-25T19:50:16.699Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c4/fa6e16145e145e87f1fa351bbd54b429354fd72145cd3d4e0c5157cf4c70/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a71f70ee269671460b37a449f5ff26982a6f2ba493b3eabdd687b4bf35f875ac", size = 297185, upload-time = "2025-09-25T19:50:18.525Z" }, + { url = "https://files.pythonhosted.org/packages/24/b4/11f8a31d8b67cca3371e046db49baa7c0594d71eb40ac8121e2fc0888db0/bcrypt-5.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f8429e1c410b4073944f03bd778a9e066e7fad723564a52ff91841d278dfc822", size = 278656, upload-time = "2025-09-25T19:50:19.809Z" }, + { url = "https://files.pythonhosted.org/packages/ac/31/79f11865f8078e192847d2cb526e3fa27c200933c982c5b2869720fa5fce/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:edfcdcedd0d0f05850c52ba3127b1fce70b9f89e0fe5ff16517df7e81fa3cbb8", size = 275662, upload-time = "2025-09-25T19:50:21.567Z" }, + { url = "https://files.pythonhosted.org/packages/d4/8d/5e43d9584b3b3591a6f9b68f755a4da879a59712981ef5ad2a0ac1379f7a/bcrypt-5.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:611f0a17aa4a25a69362dcc299fda5c8a3d4f160e2abb3831041feb77393a14a", size = 278240, upload-time = "2025-09-25T19:50:23.305Z" }, + { url = "https://files.pythonhosted.org/packages/89/48/44590e3fc158620f680a978aafe8f87a4c4320da81ed11552f0323aa9a57/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:db99dca3b1fdc3db87d7c57eac0c82281242d1eabf19dcb8a6b10eb29a2e72d1", size = 311152, upload-time = "2025-09-25T19:50:24.597Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/e4fbfc46f14f47b0d20493669a625da5827d07e8a88ee460af6cd9768b44/bcrypt-5.0.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:5feebf85a9cefda32966d8171f5db7e3ba964b77fdfe31919622256f80f9cf42", size = 313284, upload-time = "2025-09-25T19:50:26.268Z" }, + { url = "https://files.pythonhosted.org/packages/25/ae/479f81d3f4594456a01ea2f05b132a519eff9ab5768a70430fa1132384b1/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3ca8a166b1140436e058298a34d88032ab62f15aae1c598580333dc21d27ef10", size = 341643, upload-time = "2025-09-25T19:50:28.02Z" }, + { url = "https://files.pythonhosted.org/packages/df/d2/36a086dee1473b14276cd6ea7f61aef3b2648710b5d7f1c9e032c29b859f/bcrypt-5.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:61afc381250c3182d9078551e3ac3a41da14154fbff647ddf52a769f588c4172", size = 359698, upload-time = "2025-09-25T19:50:31.347Z" }, + { url = "https://files.pythonhosted.org/packages/c0/f6/688d2cd64bfd0b14d805ddb8a565e11ca1fb0fd6817175d58b10052b6d88/bcrypt-5.0.0-cp39-abi3-win32.whl", hash = "sha256:64d7ce196203e468c457c37ec22390f1a61c85c6f0b8160fd752940ccfb3a683", size = 153725, upload-time = "2025-09-25T19:50:34.384Z" }, + { url = "https://files.pythonhosted.org/packages/9f/b9/9d9a641194a730bda138b3dfe53f584d61c58cd5230e37566e83ec2ffa0d/bcrypt-5.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:64ee8434b0da054d830fa8e89e1c8bf30061d539044a39524ff7dec90481e5c2", size = 150912, upload-time = "2025-09-25T19:50:35.69Z" }, + { url = "https://files.pythonhosted.org/packages/27/44/d2ef5e87509158ad2187f4dd0852df80695bb1ee0cfe0a684727b01a69e0/bcrypt-5.0.0-cp39-abi3-win_arm64.whl", hash = "sha256:f2347d3534e76bf50bca5500989d6c1d05ed64b440408057a37673282c654927", size = 144953, upload-time = "2025-09-25T19:50:37.32Z" }, + { url = "https://files.pythonhosted.org/packages/8a/75/4aa9f5a4d40d762892066ba1046000b329c7cd58e888a6db878019b282dc/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7edda91d5ab52b15636d9c30da87d2cc84f426c72b9dba7a9b4fe142ba11f534", size = 271180, upload-time = "2025-09-25T19:50:38.575Z" }, + { url = "https://files.pythonhosted.org/packages/54/79/875f9558179573d40a9cc743038ac2bf67dfb79cecb1e8b5d70e88c94c3d/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:046ad6db88edb3c5ece4369af997938fb1c19d6a699b9c1b27b0db432faae4c4", size = 273791, upload-time = "2025-09-25T19:50:39.913Z" }, + { url = "https://files.pythonhosted.org/packages/bc/fe/975adb8c216174bf70fc17535f75e85ac06ed5252ea077be10d9cff5ce24/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:dcd58e2b3a908b5ecc9b9df2f0085592506ac2d5110786018ee5e160f28e0911", size = 270746, upload-time = "2025-09-25T19:50:43.306Z" }, + { url = "https://files.pythonhosted.org/packages/e4/f8/972c96f5a2b6c4b3deca57009d93e946bbdbe2241dca9806d502f29dd3ee/bcrypt-5.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:6b8f520b61e8781efee73cba14e3e8c9556ccfb375623f4f97429544734545b4", size = 273375, upload-time = "2025-09-25T19:50:45.43Z" }, ] [[package]] @@ -417,47 +415,9 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764, upload-time = "2024-02-18T19:09:04.156Z" }, ] -[[package]] -name = "bitarray" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/62/dcfac53d22ef7e904ed10a8e710a36391d2d6753c34c869b51bfc5e4ad54/bitarray-3.0.0.tar.gz", hash = "sha256:a2083dc20f0d828a7cdf7a16b20dae56aab0f43dc4f347a3b3039f6577992b03", size = 126627, upload-time = "2024-10-15T21:53:33.592Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/41/321edc0fbf7e8c88552d5ff9ee07777d58e2078f2706c6478bc6651b1945/bitarray-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:44c3e78b60070389b824d5a654afa1c893df723153c81904088d4922c3cfb6ac", size = 172452, upload-time = "2024-10-15T21:49:45.77Z" }, - { url = "https://files.pythonhosted.org/packages/48/92/4c312d6d55ac30dae96749830c9f5007a914efcb591ee0828914078eec9f/bitarray-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:545d36332de81e4742a845a80df89530ff193213a50b4cbef937ed5a44c0e5e5", size = 123502, upload-time = "2024-10-15T21:49:46.923Z" }, - { url = "https://files.pythonhosted.org/packages/75/2c/9f3ed70ffac8e6d2b0880e132d9e5024e4ef9404a24220deca8dbd702f15/bitarray-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8a9eb510cde3fa78c2e302bece510bf5ed494ec40e6b082dec753d6e22d5d1b1", size = 121363, upload-time = "2024-10-15T21:49:48.107Z" }, - { url = "https://files.pythonhosted.org/packages/48/e0/8ec59416aaa7ca1461a0268c0fe2fbdc8d574ac41e307980f555b773d5f6/bitarray-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e3727ab63dfb6bde00b281934e2212bb7529ea3006c0031a556a84d2268bea5", size = 285792, upload-time = "2024-10-15T21:49:49.582Z" }, - { url = "https://files.pythonhosted.org/packages/b9/8a/fb9d76ecb44a79f02188240278574376e851d0ca81437f433c9e6481d2e5/bitarray-3.0.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2055206ed653bee0b56628f6a4d248d53e5660228d355bbec0014bdfa27050ae", size = 300848, upload-time = "2024-10-15T21:49:51.614Z" }, - { url = "https://files.pythonhosted.org/packages/63/c5/067b688553b23e99d61ecf930abf1ad5cb5f80c2ebe6f0e2fe8ecab00b3f/bitarray-3.0.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:147542299f458bdb177f798726e5f7d39ab8491de4182c3c6d9885ed275a3c2b", size = 303027, upload-time = "2024-10-15T21:49:53.419Z" }, - { url = "https://files.pythonhosted.org/packages/dc/46/25ebc667907736b2c5c84f4bd8260d9bece8b69719a33db5c3f3dcb281a5/bitarray-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3f761184b93092077c7f6b7dad7bd4e671c1620404a76620da7872ceb576a94", size = 286125, upload-time = "2024-10-15T21:49:54.754Z" }, - { url = "https://files.pythonhosted.org/packages/16/dd/f9a1d84965a992ff42cae5b61536e68fc944f3e31a349b690347d98fc5e0/bitarray-3.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e008b7b4ce6c7f7a54b250c45c28d4243cc2a3bbfd5298fa7dac92afda229842", size = 277111, upload-time = "2024-10-15T21:49:55.969Z" }, - { url = "https://files.pythonhosted.org/packages/16/5b/44f298586a09beb62ec553f9efa06c8a5356d2e230e4080c72cb2800a48f/bitarray-3.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dfea514e665af278b2e1d4deb542de1cd4f77413bee83dd15ae16175976ea8d5", size = 280941, upload-time = "2024-10-15T21:49:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/28/7c/c6e157332227862727959057ba2987e6710985992b196a81f61995f21e19/bitarray-3.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:66d6134b7bb737b88f1d16478ad0927c571387f6054f4afa5557825a4c1b78e2", size = 272817, upload-time = "2024-10-15T21:49:58.443Z" }, - { url = "https://files.pythonhosted.org/packages/b7/5d/9f7aaaaf85b5247b4a69b93af60ac7dcfff5545bf544a35517618c4244a0/bitarray-3.0.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3cd565253889940b4ec4768d24f101d9fe111cad4606fdb203ea16f9797cf9ed", size = 295830, upload-time = "2024-10-15T21:50:00.332Z" }, - { url = "https://files.pythonhosted.org/packages/14/1b/86dd50edd2e0612b092fe4caec3001a24298c9acab5e89a503f002ed3bef/bitarray-3.0.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4800c91a14656789d2e67d9513359e23e8a534c8ee1482bb9b517a4cfc845200", size = 307592, upload-time = "2024-10-15T21:50:02.144Z" }, - { url = "https://files.pythonhosted.org/packages/d6/8f/45a1f1bcce5fd88d2f0bb2e1ebe8bbb55247edcb8e7a8ef06e4437e2b5e3/bitarray-3.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c2945e0390d1329c585c584c6b6d78be017d9c6a1288f9c92006fe907f69cc28", size = 278971, upload-time = "2024-10-15T21:50:03.591Z" }, - { url = "https://files.pythonhosted.org/packages/43/2d/948c5718fe901aa58c98cef52b8898a6bea865bea7528cff6c2bc703f9f3/bitarray-3.0.0-cp311-cp311-win32.whl", hash = "sha256:c23286abba0cb509733c6ce8f4013cd951672c332b2e184dbefbd7331cd234c8", size = 114242, upload-time = "2024-10-15T21:50:05.514Z" }, - { url = "https://files.pythonhosted.org/packages/8c/75/e921ada57bb0bcece5eb515927c031f0bc828f702b8f213639358d9df396/bitarray-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ca79f02a98cbda1472449d440592a2fe2ad96fe55515a0447fa8864a38017cf8", size = 121524, upload-time = "2024-10-15T21:50:07.401Z" }, - { url = "https://files.pythonhosted.org/packages/4e/2e/2e4beb2b714dc83a9e90ac0e4bacb1a191c71125734f72962ee2a20b9cfb/bitarray-3.0.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:184972c96e1c7e691be60c3792ca1a51dd22b7f25d96ebea502fe3c9b554f25d", size = 172152, upload-time = "2024-10-15T21:50:08.598Z" }, - { url = "https://files.pythonhosted.org/packages/e0/1f/9ec96408c060ffc3df5ba64d2b520fd0484cb3393a96691df8f660a43b17/bitarray-3.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:787db8da5e9e29be712f7a6bce153c7bc8697ccc2c38633e347bb9c82475d5c9", size = 123319, upload-time = "2024-10-15T21:50:09.799Z" }, - { url = "https://files.pythonhosted.org/packages/80/9f/4dd05086308bfcc84ad88c663460a8ad9f5f638f9f96eb5fa08381054db6/bitarray-3.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2da91ab3633c66999c2a352f0ca9ae064f553e5fc0eca231d28e7e305b83e942", size = 121242, upload-time = "2024-10-15T21:50:11.695Z" }, - { url = "https://files.pythonhosted.org/packages/55/bb/8865b7380e9d20445bc775079f24f2279a8c0d9ee11d57c49b118d39beaf/bitarray-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7edb83089acbf2c86c8002b96599071931dc4ea5e1513e08306f6f7df879a48b", size = 287463, upload-time = "2024-10-15T21:50:12.957Z" }, - { url = "https://files.pythonhosted.org/packages/db/8b/779119ee438090a80cbfaa49f96e783651183ab4c25b9760fe360aa7cb31/bitarray-3.0.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996d1b83eb904589f40974538223eaed1ab0f62be8a5105c280b9bd849e685c4", size = 301599, upload-time = "2024-10-15T21:50:14.224Z" }, - { url = "https://files.pythonhosted.org/packages/41/25/78f7ba7fa8ab428767dfb722fc1ea9aac4a9813e348023d8047d8fd32253/bitarray-3.0.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4817d73d995bd2b977d9cde6050be8d407791cf1f84c8047fa0bea88c1b815bc", size = 304837, upload-time = "2024-10-15T21:50:15.462Z" }, - { url = "https://files.pythonhosted.org/packages/f7/8d/30a448d3157b4239e635c92fc3b3789a5b87784875ca2776f65bd543d136/bitarray-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d47bc4ff9b0e1624d613563c6fa7b80aebe7863c56c3df5ab238bb7134e8755", size = 288588, upload-time = "2024-10-15T21:50:16.728Z" }, - { url = "https://files.pythonhosted.org/packages/86/e0/c1f1b595682244f55119d55f280b5a996bcd462b702ec220d976a7566d27/bitarray-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aca0a9cd376beaccd9f504961de83e776dd209c2de5a4c78dc87a78edf61839b", size = 279002, upload-time = "2024-10-15T21:50:17.993Z" }, - { url = "https://files.pythonhosted.org/packages/5c/4d/a17626923ad2c9d20ed1625fc5b27a8dfe2d1a3e877083e9422455ec302d/bitarray-3.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:572a61fba7e3a710a8324771322fba8488d134034d349dcd036a7aef74723a80", size = 281898, upload-time = "2024-10-15T21:50:19.599Z" }, - { url = "https://files.pythonhosted.org/packages/50/d8/5c410580a510e669d9a28bf17675e58843236c55c60fc6dc8f8747808757/bitarray-3.0.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a817ad70c1aff217530576b4f037dd9b539eb2926603354fcac605d824082ad1", size = 274622, upload-time = "2024-10-15T21:50:21.644Z" }, - { url = "https://files.pythonhosted.org/packages/e7/21/de2e8eda85c5f6a05bda75a00c22c94aee71ef09db0d5cbf22446de74312/bitarray-3.0.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2ac67b658fa5426503e9581a3fb44a26a3b346c1abd17105735f07db572195b3", size = 296930, upload-time = "2024-10-15T21:50:24.601Z" }, - { url = "https://files.pythonhosted.org/packages/13/7b/7cfad12d77db2932fb745fa281693b0031c3dfd7f2ecf5803be688cc3798/bitarray-3.0.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:12f19ede03e685c5c588ab5ed63167999295ffab5e1126c5fe97d12c0718c18f", size = 309836, upload-time = "2024-10-15T21:50:25.953Z" }, - { url = "https://files.pythonhosted.org/packages/53/e1/5120fbb8438a0d718e063f70168a2975e03f00ce6b86e74b8eec079cb492/bitarray-3.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcef31b062f756ba7eebcd7890c5d5de84b9d64ee877325257bcc9782288564a", size = 281535, upload-time = "2024-10-15T21:50:28.07Z" }, - { url = "https://files.pythonhosted.org/packages/73/75/8acebbbb4f85dcca73b8e91dde5d3e1e3e2317b36fae4f5b133c60720834/bitarray-3.0.0-cp312-cp312-win32.whl", hash = "sha256:656db7bdf1d81ec3b57b3cad7ec7276765964bcfd0eb81c5d1331f385298169c", size = 114423, upload-time = "2024-10-15T21:50:29.308Z" }, - { url = "https://files.pythonhosted.org/packages/ca/56/dadae4d4351b337de6e0269001fb40f3ebe9f72222190456713d2c1be53d/bitarray-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:f785af6b7cb07a9b1e5db0dea9ef9e3e8bb3d74874a0a61303eab9c16acc1999", size = 121680, upload-time = "2024-10-15T21:50:30.526Z" }, -] - [[package]] name = "black" -version = "25.1.0" +version = "25.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -465,55 +425,47 @@ dependencies = [ { name = "packaging" }, { name = "pathspec" }, { name = "platformdirs" }, + { name = "pytokens" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449, upload-time = "2025-01-29T04:15:40.373Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/4f/87f596aca05c3ce5b94b8663dbfe242a12843caaa82dd3f85f1ffdc3f177/black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0", size = 1614372, upload-time = "2025-01-29T05:37:11.71Z" }, - { url = "https://files.pythonhosted.org/packages/e7/d0/2c34c36190b741c59c901e56ab7f6e54dad8df05a6272a9747ecef7c6036/black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299", size = 1442865, upload-time = "2025-01-29T05:37:14.309Z" }, - { url = "https://files.pythonhosted.org/packages/21/d4/7518c72262468430ead45cf22bd86c883a6448b9eb43672765d69a8f1248/black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096", size = 1749699, upload-time = "2025-01-29T04:18:17.688Z" }, - { url = "https://files.pythonhosted.org/packages/58/db/4f5beb989b547f79096e035c4981ceb36ac2b552d0ac5f2620e941501c99/black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2", size = 1428028, upload-time = "2025-01-29T04:18:51.711Z" }, - { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988, upload-time = "2025-01-29T05:37:16.707Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985, upload-time = "2025-01-29T05:37:18.273Z" }, - { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816, upload-time = "2025-01-29T04:18:33.823Z" }, - { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860, upload-time = "2025-01-29T04:19:12.944Z" }, - { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/43/20b5c90612d7bdb2bdbcceeb53d588acca3bb8f0e4c5d5c751a2c8fdd55a/black-25.9.0.tar.gz", hash = "sha256:0474bca9a0dd1b51791fcc507a4e02078a1c63f6d4e4ae5544b9848c7adfb619", size = 648393, upload-time = "2025-09-19T00:27:37.758Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, + { url = "https://files.pythonhosted.org/packages/b7/f4/7531d4a336d2d4ac6cc101662184c8e7d068b548d35d874415ed9f4116ef/black-25.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:456386fe87bad41b806d53c062e2974615825c7a52159cde7ccaeb0695fa28fa", size = 1698727, upload-time = "2025-09-19T00:31:14.264Z" }, + { url = "https://files.pythonhosted.org/packages/28/f9/66f26bfbbf84b949cc77a41a43e138d83b109502cd9c52dfc94070ca51f2/black-25.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a16b14a44c1af60a210d8da28e108e13e75a284bf21a9afa6b4571f96ab8bb9d", size = 1555679, upload-time = "2025-09-19T00:31:29.265Z" }, + { url = "https://files.pythonhosted.org/packages/bf/59/61475115906052f415f518a648a9ac679d7afbc8da1c16f8fdf68a8cebed/black-25.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aaf319612536d502fdd0e88ce52d8f1352b2c0a955cc2798f79eeca9d3af0608", size = 1617453, upload-time = "2025-09-19T00:30:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5b/20fd5c884d14550c911e4fb1b0dae00d4abb60a4f3876b449c4d3a9141d5/black-25.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:c0372a93e16b3954208417bfe448e09b0de5cc721d521866cd9e0acac3c04a1f", size = 1333655, upload-time = "2025-09-19T00:30:56.715Z" }, + { url = "https://files.pythonhosted.org/packages/fb/8e/319cfe6c82f7e2d5bfb4d3353c6cc85b523d677ff59edc61fdb9ee275234/black-25.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1b9dc70c21ef8b43248f1d86aedd2aaf75ae110b958a7909ad8463c4aa0880b0", size = 1742012, upload-time = "2025-09-19T00:33:08.678Z" }, + { url = "https://files.pythonhosted.org/packages/94/cc/f562fe5d0a40cd2a4e6ae3f685e4c36e365b1f7e494af99c26ff7f28117f/black-25.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8e46eecf65a095fa62e53245ae2795c90bdecabd53b50c448d0a8bcd0d2e74c4", size = 1581421, upload-time = "2025-09-19T00:35:25.937Z" }, + { url = "https://files.pythonhosted.org/packages/84/67/6db6dff1ebc8965fd7661498aea0da5d7301074b85bba8606a28f47ede4d/black-25.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9101ee58ddc2442199a25cb648d46ba22cd580b00ca4b44234a324e3ec7a0f7e", size = 1655619, upload-time = "2025-09-19T00:30:49.241Z" }, + { url = "https://files.pythonhosted.org/packages/10/10/3faef9aa2a730306cf469d76f7f155a8cc1f66e74781298df0ba31f8b4c8/black-25.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:77e7060a00c5ec4b3367c55f39cf9b06e68965a4f2e61cecacd6d0d9b7ec945a", size = 1342481, upload-time = "2025-09-19T00:31:29.625Z" }, + { url = "https://files.pythonhosted.org/packages/1b/46/863c90dcd3f9d41b109b7f19032ae0db021f0b2a81482ba0a1e28c84de86/black-25.9.0-py3-none-any.whl", hash = "sha256:474b34c1342cdc157d307b56c4c65bce916480c4a8f6551fdc6bf9b486a7c4ae", size = 203363, upload-time = "2025-09-19T00:27:35.724Z" }, ] [[package]] name = "boto3" -version = "1.35.53" +version = "1.40.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/12/c1/1dc34b322d2f022d190c34dd4aa7f1a242d73633c25061bf56bd1319fe05/boto3-1.35.53.tar.gz", hash = "sha256:f4124548bb831e13504e805f2fbbfcee06df42fffea0655862c6eb9b95d6d1be", size = 111004, upload-time = "2024-10-31T19:41:56.442Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/75/45438d368f799a73d3ff4172606847d1c94c008286a5537e92711e0e00a7/boto3-1.40.5.tar.gz", hash = "sha256:7340706beffe93e3638adcd77cb266f46ba424f77623a5a6be591baa3cdbd3f3", size = 111989, upload-time = "2025-08-07T19:31:42.865Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/03/e76ff94253472c6aa7942b3efc726ca8e9c62fdebf884e017633258b7ba4/boto3-1.35.53-py3-none-any.whl", hash = "sha256:a9c0955df0b52b43749d81bde159343a40ea2a3537a46049336fe8193871b18e", size = 139159, upload-time = "2024-10-31T19:41:54.213Z" }, + { url = "https://files.pythonhosted.org/packages/9f/a1/d6ab54adbe92e4ef4f38875776ff2fbd041a22a53d6a3235c5c6ccfc176f/boto3-1.40.5-py3-none-any.whl", hash = "sha256:8072f11a973709b582ef9834794721d543869cc506d029477172054dcc19c2da", size = 140061, upload-time = "2025-08-07T19:31:40.716Z" }, ] [[package]] name = "botocore" -version = "1.35.99" +version = "1.40.70" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/9c/1df6deceee17c88f7170bad8325aa91452529d683486273928eecfd946d8/botocore-1.35.99.tar.gz", hash = "sha256:1eab44e969c39c5f3d9a3104a0836c24715579a455f12b3979a31d7cde51b3c3", size = 13490969, upload-time = "2025-01-14T20:20:11.419Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/c1/8c4c199ae1663feee579a15861e34f10b29da11ae6ea0ad7b6a847ef3823/botocore-1.40.70.tar.gz", hash = "sha256:61b1f2cecd54d1b28a081116fa113b97bf4e17da57c62ae2c2751fe4c528af1f", size = 14444592, upload-time = "2025-11-10T20:29:04.046Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/dd/d87e2a145fad9e08d0ec6edcf9d71f838ccc7acdd919acc4c0d4a93515f8/botocore-1.35.99-py3-none-any.whl", hash = "sha256:b22d27b6b617fc2d7342090d6129000af2efd20174215948c0d7ae2da0fab445", size = 13293216, upload-time = "2025-01-14T20:20:06.427Z" }, + { url = "https://files.pythonhosted.org/packages/55/d2/507fd0ee4dd574d2bdbdeac5df83f39d2cae1ffe97d4622cca6f6bab39f1/botocore-1.40.70-py3-none-any.whl", hash = "sha256:4a394ad25f5d9f1ef0bed610365744523eeb5c22de6862ab25d8c93f9f6d295c", size = 14106829, upload-time = "2025-11-10T20:29:01.101Z" }, ] [[package]] @@ -641,15 +593,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, ] -[[package]] -name = "chardet" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/f7b6ab21ec75897ed80c17d79b15951a719226b9fababf1e40ea74d69079/chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7", size = 2069618, upload-time = "2023-08-01T19:23:02.662Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/38/6f/f5fbc992a329ee4e0f288c1fe0e2ad9485ed064cac731ed2fe47dcc38cbf/chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970", size = 199385, upload-time = "2023-08-01T19:23:00.661Z" }, -] - [[package]] name = "charset-normalizer" version = "3.4.1" @@ -685,49 +628,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767, upload-time = "2024-12-24T18:12:32.852Z" }, ] -[[package]] -name = "chroma-hnswlib" -version = "0.7.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/73/09/10d57569e399ce9cbc5eee2134996581c957f63a9addfa6ca657daf006b8/chroma_hnswlib-0.7.6.tar.gz", hash = "sha256:4dce282543039681160259d29fcde6151cc9106c6461e0485f57cdccd83059b7", size = 32256, upload-time = "2024-07-22T20:19:29.259Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/af/d15fdfed2a204c0f9467ad35084fbac894c755820b203e62f5dcba2d41f1/chroma_hnswlib-0.7.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:81181d54a2b1e4727369486a631f977ffc53c5533d26e3d366dda243fb0998ca", size = 196911, upload-time = "2024-07-22T20:18:33.46Z" }, - { url = "https://files.pythonhosted.org/packages/0d/19/aa6f2139f1ff7ad23a690ebf2a511b2594ab359915d7979f76f3213e46c4/chroma_hnswlib-0.7.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4b4ab4e11f1083dd0a11ee4f0e0b183ca9f0f2ed63ededba1935b13ce2b3606f", size = 185000, upload-time = "2024-07-22T20:18:36.16Z" }, - { url = "https://files.pythonhosted.org/packages/79/b1/1b269c750e985ec7d40b9bbe7d66d0a890e420525187786718e7f6b07913/chroma_hnswlib-0.7.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53db45cd9173d95b4b0bdccb4dbff4c54a42b51420599c32267f3abbeb795170", size = 2377289, upload-time = "2024-07-22T20:18:37.761Z" }, - { url = "https://files.pythonhosted.org/packages/c7/2d/d5663e134436e5933bc63516a20b5edc08b4c1b1588b9680908a5f1afd04/chroma_hnswlib-0.7.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5c093f07a010b499c00a15bc9376036ee4800d335360570b14f7fe92badcdcf9", size = 2411755, upload-time = "2024-07-22T20:18:39.949Z" }, - { url = "https://files.pythonhosted.org/packages/3e/79/1bce519cf186112d6d5ce2985392a89528c6e1e9332d680bf752694a4cdf/chroma_hnswlib-0.7.6-cp311-cp311-win_amd64.whl", hash = "sha256:0540b0ac96e47d0aa39e88ea4714358ae05d64bbe6bf33c52f316c664190a6a3", size = 151888, upload-time = "2024-07-22T20:18:45.003Z" }, - { url = "https://files.pythonhosted.org/packages/93/ac/782b8d72de1c57b64fdf5cb94711540db99a92768d93d973174c62d45eb8/chroma_hnswlib-0.7.6-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e87e9b616c281bfbe748d01705817c71211613c3b063021f7ed5e47173556cb7", size = 197804, upload-time = "2024-07-22T20:18:46.442Z" }, - { url = "https://files.pythonhosted.org/packages/32/4e/fd9ce0764228e9a98f6ff46af05e92804090b5557035968c5b4198bc7af9/chroma_hnswlib-0.7.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ec5ca25bc7b66d2ecbf14502b5729cde25f70945d22f2aaf523c2d747ea68912", size = 185421, upload-time = "2024-07-22T20:18:47.72Z" }, - { url = "https://files.pythonhosted.org/packages/d9/3d/b59a8dedebd82545d873235ef2d06f95be244dfece7ee4a1a6044f080b18/chroma_hnswlib-0.7.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:305ae491de9d5f3c51e8bd52d84fdf2545a4a2bc7af49765cda286b7bb30b1d4", size = 2389672, upload-time = "2024-07-22T20:18:49.583Z" }, - { url = "https://files.pythonhosted.org/packages/74/1e/80a033ea4466338824974a34f418e7b034a7748bf906f56466f5caa434b0/chroma_hnswlib-0.7.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:822ede968d25a2c88823ca078a58f92c9b5c4142e38c7c8b4c48178894a0a3c5", size = 2436986, upload-time = "2024-07-22T20:18:51.872Z" }, -] - [[package]] name = "chromadb" -version = "0.6.3" +version = "1.0.20" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "bcrypt" }, { name = "build" }, - { name = "chroma-hnswlib" }, - { name = "fastapi" }, { name = "grpcio" }, { name = "httpx" }, { name = "importlib-resources" }, + { name = "jsonschema" }, { name = "kubernetes" }, { name = "mmh3" }, { name = "numpy" }, { name = "onnxruntime" }, { name = "opentelemetry-api" }, { name = "opentelemetry-exporter-otlp-proto-grpc" }, - { name = "opentelemetry-instrumentation-fastapi" }, { name = "opentelemetry-sdk" }, { name = "orjson" }, { name = "overrides" }, { name = "posthog" }, + { name = "pybase64" }, { name = "pydantic" }, { name = "pypika" }, { name = "pyyaml" }, @@ -739,9 +661,13 @@ dependencies = [ { name = "typing-extensions" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/39/cd/f0f2de3f466ff514fb6b58271c14f6d22198402bb5b71b8d890231265946/chromadb-0.6.3.tar.gz", hash = "sha256:c8f34c0b704b9108b04491480a36d42e894a960429f87c6516027b5481d59ed3", size = 29297929, upload-time = "2025-01-14T22:20:40.184Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/5d/430c4780738ed8385afb2031c619c71e4d354b435f1523fd628562d42377/chromadb-1.0.20.tar.gz", hash = "sha256:9ca88516f1eefa26e4c308ec9bdae9d209c0ba5fe1fae3f16b250e52246944db", size = 1244999, upload-time = "2025-08-18T17:03:31.195Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/8e/5c186c77bf749b6fe0528385e507e463f1667543328d76fd00a49e1a4e6a/chromadb-0.6.3-py3-none-any.whl", hash = "sha256:4851258489a3612b558488d98d09ae0fe0a28d5cad6bd1ba64b96fdc419dc0e5", size = 611129, upload-time = "2025-01-14T22:20:33.784Z" }, + { url = "https://files.pythonhosted.org/packages/59/2f/d40a4aedd9298a012fb9f455a1e334fc875e12c9c667aab8a956a9dff559/chromadb-1.0.20-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:0955b9cbd0dfe23ecfd8d911254ff9e57750acbe9c5ff723e2975290092d9d29", size = 19069234, upload-time = "2025-08-18T17:03:28.714Z" }, + { url = "https://files.pythonhosted.org/packages/6a/2e/fcc80bb635719d3cf0705be89e2510bd191d5f544d1c5e9e4392ba95cff4/chromadb-1.0.20-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:52819408a48f0209a0ce4e6655eaaa683cce03f8081f297f88699f00bc8281aa", size = 18264273, upload-time = "2025-08-18T17:03:25.614Z" }, + { url = "https://files.pythonhosted.org/packages/4f/de/e93edfcebf863d652bb0c03c23ae5a4e9e448b6e01fdac8a8624aa7dd2a4/chromadb-1.0.20-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68dbe15270e743077d47360695e0af918d17b225011e00d491afefbee017097f", size = 18835560, upload-time = "2025-08-18T17:03:18.783Z" }, + { url = "https://files.pythonhosted.org/packages/61/4f/c88ead80ae78c839152cca5dc6edae65b8a1da090b7220739b54c75549eb/chromadb-1.0.20-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2044e1400f67588271ebd2fa654dd5333e9ad108f800aa57a6fa09237afb6142", size = 19755334, upload-time = "2025-08-18T17:03:22.386Z" }, + { url = "https://files.pythonhosted.org/packages/6f/81/6decbd21c67572d67707f7e168851f10404e2857897456c6ba220e9b09be/chromadb-1.0.20-cp39-abi3-win_amd64.whl", hash = "sha256:b81be370b7c34138c01a41d11304498a13598cf9b21ecde31bba932492071301", size = 19778671, upload-time = "2025-08-18T17:03:33.206Z" }, ] [[package]] @@ -756,27 +682,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload-time = "2024-12-21T18:38:41.666Z" }, ] -[[package]] -name = "colbert-ai" -version = "0.2.21" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "datasets" }, - { name = "flask" }, - { name = "git-python" }, - { name = "ninja" }, - { name = "python-dotenv" }, - { name = "scipy" }, - { name = "tqdm" }, - { name = "transformers" }, - { name = "ujson" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/dc/7edb06e3bb01326610ecfdfc8e396c6867ba7de6e58cda2356a604419899/colbert_ai-0.2.21.tar.gz", hash = "sha256:a8d6fdb4e2272f2b08ed37f8e5096072160d8415d1e40585751898b77e625bab", size = 87978, upload-time = "2024-08-20T20:14:25.262Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/9c/5d847be0f05e5266880fb1c183e642a6c34cd6a101c1d6219dfa74887543/colbert_ai-0.2.21-py3-none-any.whl", hash = "sha256:8c17e7be44e7f3989f2067f1176af4f65f4612d62850586657e8afb8314cb2a6", size = 116142, upload-time = "2024-08-20T20:14:23.32Z" }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -862,31 +767,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686, upload-time = "2024-06-09T16:20:16.715Z" }, ] -[[package]] -name = "datasets" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "dill" }, - { name = "filelock" }, - { name = "fsspec", extra = ["http"] }, - { name = "huggingface-hub" }, - { name = "multiprocess" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "pyarrow" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "tqdm" }, - { name = "xxhash" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/48/744286c044e2b942d4fa67f92816126522ad1f0675def0ea3264e6242005/datasets-3.2.0.tar.gz", hash = "sha256:9a6e1a356052866b5dbdd9c9eedb000bf3fc43d986e3584d9b028f4976937229", size = 558366, upload-time = "2024-12-10T16:56:38.162Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/84/0df6c5981f5fc722381662ff8cfbdf8aad64bec875f75d80b55bfef394ce/datasets-3.2.0-py3-none-any.whl", hash = "sha256:f3d2ba2698b7284a4518019658596a6a8bc79f31e51516524249d6c59cf0fe2a", size = 480647, upload-time = "2024-12-10T16:56:34.742Z" }, -] - [[package]] name = "ddgs" version = "9.0.0" @@ -922,15 +802,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1d/8f/c7f227eb42cfeaddce3eb0c96c60cbca37797fa7b34f8e1aeadf6c5c0983/Deprecated-1.2.15-py2.py3-none-any.whl", hash = "sha256:353bc4a8ac4bfc96800ddab349d89c25dec1079f65fd53acdcc1e0b975b21320", size = 9941, upload-time = "2024-11-15T14:42:03.315Z" }, ] -[[package]] -name = "dill" -version = "0.3.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/17/4d/ac7ffa80c69ea1df30a8aa11b3578692a5118e7cd1aa157e3ef73b092d15/dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", size = 184847, upload-time = "2024-01-27T23:42:16.145Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/7a/cef76fd8438a42f96db64ddaa85280485a9c395e7df3db8158cfec1eee34/dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7", size = 116252, upload-time = "2024-01-27T23:42:14.239Z" }, -] - [[package]] name = "distro" version = "1.9.0" @@ -940,49 +811,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "docker" -version = "7.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834, upload-time = "2024-05-23T11:13:57.216Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774, upload-time = "2024-05-23T11:13:55.01Z" }, -] - [[package]] name = "docx2txt" version = "0.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7d/7d/60ee3f2b16d9bfdfa72e8599470a2c1a5b759cb113c6fe1006be28359327/docx2txt-0.8.tar.gz", hash = "sha256:2c06d98d7cfe2d3947e5760a57d924e3ff07745b379c8737723922e7009236e5", size = 2814, upload-time = "2019-06-23T19:58:36.94Z" } -[[package]] -name = "duckduckgo-search" -version = "8.0.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "lxml" }, - { name = "primp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/c0/e18c2148d33a9d87f6a0cc00acba30b4e547be0f8cb85ccb313a6e8fbac7/duckduckgo_search-8.0.2.tar.gz", hash = "sha256:3109a99967b29cab8862823bbe320d140d5c792415de851b9d6288de2311b3ec", size = 21807, upload-time = "2025-05-15T08:43:25.311Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/6c/e36d22e76f4aa4e1ea7ea9b443bd49b5ffd2f13d430840f47e35284f797a/duckduckgo_search-8.0.2-py3-none-any.whl", hash = "sha256:b5ff8b6b8f169b8e1b15a788a5749aa900ebcefd6e1ab485787582f8d5b4f1ef", size = 18184, upload-time = "2025-05-15T08:43:23.713Z" }, -] - [[package]] name = "durationpy" version = "0.9" @@ -1013,33 +847,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359, upload-time = "2025-02-09T03:17:01.998Z" }, ] -[[package]] -name = "elastic-transport" -version = "8.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6a/54/d498a766ac8fa475f931da85a154666cc81a70f8eb4a780bc8e4e934e9ac/elastic_transport-8.17.1.tar.gz", hash = "sha256:5edef32ac864dca8e2f0a613ef63491ee8d6b8cfb52881fa7313ba9290cac6d2", size = 73425, upload-time = "2025-03-13T07:28:30.776Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/cd/b71d5bc74cde7fc6fd9b2ff9389890f45d9762cbbbf81dc5e51fd7588c4a/elastic_transport-8.17.1-py3-none-any.whl", hash = "sha256:192718f498f1d10c5e9aa8b9cf32aed405e469a7f0e9d6a8923431dbb2c59fb8", size = 64969, upload-time = "2025-03-13T07:28:29.031Z" }, -] - -[[package]] -name = "elasticsearch" -version = "9.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "elastic-transport" }, - { name = "python-dateutil" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/39/58/0081e189ef83dd1f11cb600df842bffb8eaa05c097cb1672c5bd335b46c2/elasticsearch-9.0.1.tar.gz", hash = "sha256:76f9b519cfd15a860f615a94ba90dcb9543b721306bc5144ecc15f0b4d5d2781", size = 819519, upload-time = "2025-04-28T13:47:17.974Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/eb/03140387b1a378878a4228d0d796e80298ac54fc4fe6fe9e39087d142efe/elasticsearch-9.0.1-py3-none-any.whl", hash = "sha256:9fd110f9bb77310343709d9cccbd523a431a6e528d8441b01a26b97eef3238a3", size = 905510, upload-time = "2025-04-28T13:47:13.531Z" }, -] - [[package]] name = "emoji" version = "2.14.1" @@ -1058,15 +865,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/8b/5fe2cc11fee489817272089c4203e679c63b570a5aaeb18d852ae3cbba6a/et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa", size = 18059, upload-time = "2024-10-25T17:25:39.051Z" }, ] -[[package]] -name = "eval-type-backport" -version = "0.2.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/ea/8b0ac4469d4c347c6a385ff09dc3c048c2d021696664e26c7ee6791631b5/eval_type_backport-0.2.2.tar.gz", hash = "sha256:f0576b4cf01ebb5bd358d02314d31846af5e07678387486e2c798af0e7d849c1", size = 9079, upload-time = "2024-12-21T20:09:46.005Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/31/55cd413eaccd39125368be33c46de24a1f639f2e12349b0361b4678f3915/eval_type_backport-0.2.2-py3-none-any.whl", hash = "sha256:cb6ad7c393517f476f96d456d0412ea80f0a8cf96f6892834cd9340149111b0a", size = 5830, upload-time = "2024-12-21T20:09:44.175Z" }, -] - [[package]] name = "events" version = "0.5" @@ -1077,25 +875,25 @@ wheels = [ [[package]] name = "fake-useragent" -version = "2.1.0" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/99/32/5b400819e6c4a71491f6a48723db8412bb057bf800d63d653b1641bd2bde/fake_useragent-2.1.0.tar.gz", hash = "sha256:cbb2cde0512ecefec1e6175e59d8bcc5cd94af25161432860769a4f3767ad62c", size = 124873, upload-time = "2025-03-12T17:25:36.882Z" } +sdist = { url = "https://files.pythonhosted.org/packages/41/43/948d10bf42735709edb5ae51e23297d034086f17fc7279fef385a7acb473/fake_useragent-2.2.0.tar.gz", hash = "sha256:4e6ab6571e40cc086d788523cf9e018f618d07f9050f822ff409a4dfe17c16b2", size = 158898, upload-time = "2025-04-14T15:32:19.238Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/9e/1ed0964081abafb530173f68f9182a98aa2d82550cc843e1f7c844bc06e7/fake_useragent-2.1.0-py3-none-any.whl", hash = "sha256:1363d8be4934627f80a84c21cce72d33c5da650a9f1fd7398520b1edb6ecd873", size = 125764, upload-time = "2025-03-12T17:25:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/51/37/b3ea9cd5558ff4cb51957caca2193981c6b0ff30bd0d2630ac62505d99d0/fake_useragent-2.2.0-py3-none-any.whl", hash = "sha256:67f35ca4d847b0d298187443aaf020413746e56acd985a611908c73dba2daa24", size = 161695, upload-time = "2025-04-14T15:32:17.732Z" }, ] [[package]] name = "fastapi" -version = "0.115.7" +version = "0.118.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/f5/3f921e59f189e513adb9aef826e2841672d50a399fead4e69afdeb808ff4/fastapi-0.115.7.tar.gz", hash = "sha256:0f106da6c01d88a6786b3248fb4d7a940d071f6f488488898ad5d354b25ed015", size = 293177, upload-time = "2025-01-22T22:54:27.791Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/3c/2b9345a6504e4055eaa490e0b41c10e338ad61d9aeaae41d97807873cdf2/fastapi-0.118.0.tar.gz", hash = "sha256:5e81654d98c4d2f53790a7d32d25a7353b30c81441be7d0958a26b5d761fa1c8", size = 310536, upload-time = "2025-09-29T03:37:23.126Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/7f/bbd4dcf0faf61bc68a01939256e2ed02d681e9334c1a3cef24d5f77aba9f/fastapi-0.115.7-py3-none-any.whl", hash = "sha256:eb6a8c8bf7f26009e8147111ff15b5177a0e19bb4a45bc3486ab14804539d21e", size = 94777, upload-time = "2025-01-22T22:54:25.878Z" }, + { url = "https://files.pythonhosted.org/packages/54/20/54e2bdaad22ca91a59455251998d43094d5c3d3567c52c7c04774b3f43f2/fastapi-0.118.0-py3-none-any.whl", hash = "sha256:705137a61e2ef71019d2445b123aa8845bd97273c395b744d5a7dfe559056855", size = 97694, upload-time = "2025-09-29T03:37:21.338Z" }, ] [[package]] @@ -1133,38 +931,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, ] -[[package]] -name = "firecrawl-py" -version = "1.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nest-asyncio" }, - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/18/db/e4f8ef9f0475b91b7c16a15e02fe19069d443cc5516cdefa2f9a0924a9a3/firecrawl_py-1.12.0.tar.gz", hash = "sha256:bbf883f6c774f05a5426121b85978a5f7b5ab11e614aff609f0673b097c3e553", size = 19655, upload-time = "2025-02-13T15:40:15.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/d8/301d829099082c606ed16ed2a9acd263c47a365d471b9636435bf5d858b3/firecrawl_py-1.12.0-py3-none-any.whl", hash = "sha256:2b9c549315027da32421aca2a7ca597cb05cdbb968cfe0a89f389c7bb20afa4a", size = 31854, upload-time = "2025-02-13T15:40:14.492Z" }, -] - -[[package]] -name = "flask" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/89/50/dff6380f1c7f84135484e176e0cac8690af72fa90e932ad2a0a60e28c69b/flask-3.1.0.tar.gz", hash = "sha256:5f873c5184c897c8d9d1b05df1e3d01b14910ce69607a117bd3277098a5836ac", size = 680824, upload-time = "2024-11-13T18:24:38.127Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/47/93213ee66ef8fae3b93b3e29206f6b251e65c97bd91d8e1c5596ef15af0a/flask-3.1.0-py3-none-any.whl", hash = "sha256:d667207822eb83f1c4b50949b1623c8fc8d51f2341d65f72e1a1815397551136", size = 102979, upload-time = "2024-11-13T18:24:36.135Z" }, -] - [[package]] name = "flatbuffers" version = "24.12.23" @@ -1252,20 +1018,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901, upload-time = "2024-10-23T09:48:28.851Z" }, ] -[[package]] -name = "fs" -version = "2.4.16" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "appdirs" }, - { name = "setuptools" }, - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5d/a9/af5bfd5a92592c16cdae5c04f68187a309be8a146b528eac3c6e30edbad2/fs-2.4.16.tar.gz", hash = "sha256:ae97c7d51213f4b70b6a958292530289090de3a7e15841e108fbe144f069d313", size = 187441, upload-time = "2022-05-02T09:25:54.22Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/5c/a3d95dc1ec6cdeb032d789b552ecc76effa3557ea9186e1566df6aac18df/fs-2.4.16-py2.py3-none-any.whl", hash = "sha256:660064febbccda264ae0b6bace80a8d1be9e089e0a5eb2427b7d517f9a91545c", size = 135261, upload-time = "2022-05-02T09:25:52.363Z" }, -] - [[package]] name = "fsspec" version = "2024.9.0" @@ -1275,11 +1027,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1d/a0/6aaea0c2fbea2f89bfd5db25fb1e3481896a423002ebe4e55288907a97a3/fsspec-2024.9.0-py3-none-any.whl", hash = "sha256:a0947d552d8a6efa72cc2c730b12c41d043509156966cca4fb157b0f2a0c574b", size = 179253, upload-time = "2024-09-04T15:06:55.908Z" }, ] -[package.optional-dependencies] -http = [ - { name = "aiohttp" }, -] - [[package]] name = "ftfy" version = "6.2.3" @@ -1292,55 +1039,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ed/46/14d230ad057048aea7ccd2f96a80905830866d281ea90a6662a825490659/ftfy-6.2.3-py3-none-any.whl", hash = "sha256:f15761b023f3061a66207d33f0c0149ad40a8319fd16da91796363e2c049fdf8", size = 43011, upload-time = "2024-08-06T01:30:44.955Z" }, ] -[[package]] -name = "gcp-storage-emulator" -version = "2024.8.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fs" }, - { name = "google-crc32c" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/17/c2/a0b0e1e54fdd9453603d90939faf652e2488b617c8752edc4ebcd89f1686/gcp_storage_emulator-2024.8.3.tar.gz", hash = "sha256:e5d45e5c23a0344c1c4c44b8f8c36f7e8975ca1fcc5134cab608b96ddccd9225", size = 24928, upload-time = "2024-08-03T19:13:58.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/53/bf/b6c717bd7a5b59244388057d36789e72c28bfaa5e51f3a494563a4e3028e/gcp_storage_emulator-2024.8.3-py3-none-any.whl", hash = "sha256:1dc4ea56a0caf50fc6092898b9461d08b494824bfbbcca168e2af5da89c053ce", size = 19385, upload-time = "2024-08-03T19:13:56.296Z" }, -] - -[[package]] -name = "git-python" -version = "1.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "gitpython" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/3c/f0726fd577517ff8f09e6fe49f153ec9c595f1964c02c209c757d473780a/git-python-1.0.3.zip", hash = "sha256:a7f51d07c7a0b0a15cb4dfa78601196dd20624211153d07c092b811edb6e86fb", size = 4286, upload-time = "2019-10-13T10:30:24.257Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/de/0cc6353a45cdb1e137cffac5383097b300cc578e2e1133eeb847e23a1394/git_python-1.0.3-py2.py3-none-any.whl", hash = "sha256:8820ce93786cd11a76d44c7153708588e8056213e4c512406ea3732871aa9ad6", size = 1888, upload-time = "2019-10-13T10:30:22.489Z" }, -] - -[[package]] -name = "gitdb" -version = "4.0.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "smmap" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, -] - -[[package]] -name = "gitpython" -version = "3.1.44" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "gitdb" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/89/37df0b71473153574a5cdef8f242de422a0f5d26d7a9e231e6f169b4ad14/gitpython-3.1.44.tar.gz", hash = "sha256:c87e30b26253bf5418b01b0660f818967f3c503193838337fe5e573331249269", size = 214196, upload-time = "2025-01-02T07:32:43.59Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl", hash = "sha256:9e0e10cda9bed1ee64bc9a6de50e7e38a9c9943241cd7f585f6df3ed28011110", size = 207599, upload-time = "2025-01-02T07:32:40.731Z" }, -] - [[package]] name = "google-ai-generativelanguage" version = "0.6.15" @@ -1484,7 +1182,7 @@ wheels = [ [[package]] name = "google-genai" -version = "1.15.0" +version = "1.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1492,12 +1190,13 @@ dependencies = [ { name = "httpx" }, { name = "pydantic" }, { name = "requests" }, + { name = "tenacity" }, { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/19/da5a085ce419c33b9e6ae308005efad9bfa1b10f59f449d075bba1f16a64/google_genai-1.15.0.tar.gz", hash = "sha256:118bb26960d6343cd64f1aeb5c2b02144a36ad06716d0d1eb1fa3e0904db51f1", size = 173452, upload-time = "2025-05-13T13:55:17.73Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b4/11/108ddd3aca8af6a9e2369e59b9646a3a4c64aefb39d154f6467ab8d79f34/google_genai-1.38.0.tar.gz", hash = "sha256:363272fc4f677d0be6a1aed7ebabe8adf45e1626a7011a7886a587e9464ca9ec", size = 244903, upload-time = "2025-09-16T23:25:42.577Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/e2/acc99d36fd439fb2e558c7aebd049329dbfc08a094faf17d847d393e2810/google_genai-1.15.0-py3-none-any.whl", hash = "sha256:6d7f149cc735038b680722bed495004720514c234e2a445ab2f27967955071dd", size = 171278, upload-time = "2025-05-13T13:55:16.314Z" }, + { url = "https://files.pythonhosted.org/packages/53/6c/1de711bab3c118284904c3bedf870519e8c63a7a8e0905ac3833f1db9cbc/google_genai-1.38.0-py3-none-any.whl", hash = "sha256:95407425132d42b3fa11bc92b3f5cf61a0fbd8d9add1f0e89aac52c46fbba090", size = 245558, upload-time = "2025-09-16T23:25:41.141Z" }, ] [[package]] @@ -1532,14 +1231,14 @@ wheels = [ [[package]] name = "googleapis-common-protos" -version = "1.63.2" +version = "1.70.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0b/1a/41723ae380fa9c561cbe7b61c4eef9091d5fe95486465ccfc84845877331/googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87", size = 112890, upload-time = "2024-06-24T16:51:33.669Z" } +sdist = { url = "https://files.pythonhosted.org/packages/39/24/33db22342cf4a2ea27c9955e6713140fedd51e8b141b5ce5260897020f1a/googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257", size = 145903, upload-time = "2025-04-14T10:17:02.924Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/48/87422ff1bddcae677fb6f58c97f5cfc613304a5e8ce2c3662760199c0a84/googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945", size = 220001, upload-time = "2024-06-24T16:51:31.399Z" }, + { url = "https://files.pythonhosted.org/packages/86/f1/62a193f0227cf15a920390abe675f386dec35f7ae3ffe6da582d3ade42c7/googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8", size = 294530, upload-time = "2025-04-14T10:17:01.271Z" }, ] [[package]] @@ -1570,28 +1269,30 @@ wheels = [ [[package]] name = "grpcio" -version = "1.67.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/53/d9282a66a5db45981499190b77790570617a604a38f3d103d0400974aeb5/grpcio-1.67.1.tar.gz", hash = "sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732", size = 12580022, upload-time = "2024-10-29T06:30:07.787Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/59/2c/b60d6ea1f63a20a8d09c6db95c4f9a16497913fb3048ce0990ed81aeeca0/grpcio-1.67.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:7818c0454027ae3384235a65210bbf5464bd715450e30a3d40385453a85a70cb", size = 5119075, upload-time = "2024-10-29T06:24:04.696Z" }, - { url = "https://files.pythonhosted.org/packages/b3/9a/e1956f7ca582a22dd1f17b9e26fcb8229051b0ce6d33b47227824772feec/grpcio-1.67.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ea33986b70f83844cd00814cee4451055cd8cab36f00ac64a31f5bb09b31919e", size = 11009159, upload-time = "2024-10-29T06:24:07.781Z" }, - { url = "https://files.pythonhosted.org/packages/43/a8/35fbbba580c4adb1d40d12e244cf9f7c74a379073c0a0ca9d1b5338675a1/grpcio-1.67.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:c7a01337407dd89005527623a4a72c5c8e2894d22bead0895306b23c6695698f", size = 5629476, upload-time = "2024-10-29T06:24:11.444Z" }, - { url = "https://files.pythonhosted.org/packages/77/c9/864d336e167263d14dfccb4dbfa7fce634d45775609895287189a03f1fc3/grpcio-1.67.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80b866f73224b0634f4312a4674c1be21b2b4afa73cb20953cbbb73a6b36c3cc", size = 6239901, upload-time = "2024-10-29T06:24:14.2Z" }, - { url = "https://files.pythonhosted.org/packages/f7/1e/0011408ebabf9bd69f4f87cc1515cbfe2094e5a32316f8714a75fd8ddfcb/grpcio-1.67.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9fff78ba10d4250bfc07a01bd6254a6d87dc67f9627adece85c0b2ed754fa96", size = 5881010, upload-time = "2024-10-29T06:24:17.451Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7d/fbca85ee9123fb296d4eff8df566f458d738186d0067dec6f0aa2fd79d71/grpcio-1.67.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:8a23cbcc5bb11ea7dc6163078be36c065db68d915c24f5faa4f872c573bb400f", size = 6580706, upload-time = "2024-10-29T06:24:20.038Z" }, - { url = "https://files.pythonhosted.org/packages/75/7a/766149dcfa2dfa81835bf7df623944c1f636a15fcb9b6138ebe29baf0bc6/grpcio-1.67.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1a65b503d008f066e994f34f456e0647e5ceb34cfcec5ad180b1b44020ad4970", size = 6161799, upload-time = "2024-10-29T06:24:22.604Z" }, - { url = "https://files.pythonhosted.org/packages/09/13/5b75ae88810aaea19e846f5380611837de411181df51fd7a7d10cb178dcb/grpcio-1.67.1-cp311-cp311-win32.whl", hash = "sha256:e29ca27bec8e163dca0c98084040edec3bc49afd10f18b412f483cc68c712744", size = 3616330, upload-time = "2024-10-29T06:24:25.775Z" }, - { url = "https://files.pythonhosted.org/packages/aa/39/38117259613f68f072778c9638a61579c0cfa5678c2558706b10dd1d11d3/grpcio-1.67.1-cp311-cp311-win_amd64.whl", hash = "sha256:786a5b18544622bfb1e25cc08402bd44ea83edfb04b93798d85dca4d1a0b5be5", size = 4354535, upload-time = "2024-10-29T06:24:28.614Z" }, - { url = "https://files.pythonhosted.org/packages/6e/25/6f95bd18d5f506364379eabc0d5874873cc7dbdaf0757df8d1e82bc07a88/grpcio-1.67.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:267d1745894200e4c604958da5f856da6293f063327cb049a51fe67348e4f953", size = 5089809, upload-time = "2024-10-29T06:24:31.24Z" }, - { url = "https://files.pythonhosted.org/packages/10/3f/d79e32e5d0354be33a12db2267c66d3cfeff700dd5ccdd09fd44a3ff4fb6/grpcio-1.67.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:85f69fdc1d28ce7cff8de3f9c67db2b0ca9ba4449644488c1e0303c146135ddb", size = 10981985, upload-time = "2024-10-29T06:24:34.942Z" }, - { url = "https://files.pythonhosted.org/packages/21/f2/36fbc14b3542e3a1c20fb98bd60c4732c55a44e374a4eb68f91f28f14aab/grpcio-1.67.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:f26b0b547eb8d00e195274cdfc63ce64c8fc2d3e2d00b12bf468ece41a0423a0", size = 5588770, upload-time = "2024-10-29T06:24:38.145Z" }, - { url = "https://files.pythonhosted.org/packages/0d/af/bbc1305df60c4e65de8c12820a942b5e37f9cf684ef5e49a63fbb1476a73/grpcio-1.67.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4422581cdc628f77302270ff839a44f4c24fdc57887dc2a45b7e53d8fc2376af", size = 6214476, upload-time = "2024-10-29T06:24:41.006Z" }, - { url = "https://files.pythonhosted.org/packages/92/cf/1d4c3e93efa93223e06a5c83ac27e32935f998bc368e276ef858b8883154/grpcio-1.67.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d7616d2ded471231c701489190379e0c311ee0a6c756f3c03e6a62b95a7146e", size = 5850129, upload-time = "2024-10-29T06:24:43.553Z" }, - { url = "https://files.pythonhosted.org/packages/ae/ca/26195b66cb253ac4d5ef59846e354d335c9581dba891624011da0e95d67b/grpcio-1.67.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8a00efecde9d6fcc3ab00c13f816313c040a28450e5e25739c24f432fc6d3c75", size = 6568489, upload-time = "2024-10-29T06:24:46.453Z" }, - { url = "https://files.pythonhosted.org/packages/d1/94/16550ad6b3f13b96f0856ee5dfc2554efac28539ee84a51d7b14526da985/grpcio-1.67.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:699e964923b70f3101393710793289e42845791ea07565654ada0969522d0a38", size = 6149369, upload-time = "2024-10-29T06:24:49.112Z" }, - { url = "https://files.pythonhosted.org/packages/33/0d/4c3b2587e8ad7f121b597329e6c2620374fccbc2e4e1aa3c73ccc670fde4/grpcio-1.67.1-cp312-cp312-win32.whl", hash = "sha256:4e7b904484a634a0fff132958dabdb10d63e0927398273917da3ee103e8d1f78", size = 3599176, upload-time = "2024-10-29T06:24:51.443Z" }, - { url = "https://files.pythonhosted.org/packages/7d/36/0c03e2d80db69e2472cf81c6123aa7d14741de7cf790117291a703ae6ae1/grpcio-1.67.1-cp312-cp312-win_amd64.whl", hash = "sha256:5721e66a594a6c4204458004852719b38f3d5522082be9061d6510b455c90afc", size = 4346574, upload-time = "2024-10-29T06:24:54.587Z" }, +version = "1.74.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/b4/35feb8f7cab7239c5b94bd2db71abb3d6adb5f335ad8f131abb6060840b6/grpcio-1.74.0.tar.gz", hash = "sha256:80d1f4fbb35b0742d3e3d3bb654b7381cd5f015f8497279a1e9c21ba623e01b1", size = 12756048, upload-time = "2025-07-24T18:54:23.039Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/77/b2f06db9f240a5abeddd23a0e49eae2b6ac54d85f0e5267784ce02269c3b/grpcio-1.74.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:69e1a8180868a2576f02356565f16635b99088da7df3d45aaa7e24e73a054e31", size = 5487368, upload-time = "2025-07-24T18:53:03.548Z" }, + { url = "https://files.pythonhosted.org/packages/48/99/0ac8678a819c28d9a370a663007581744a9f2a844e32f0fa95e1ddda5b9e/grpcio-1.74.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8efe72fde5500f47aca1ef59495cb59c885afe04ac89dd11d810f2de87d935d4", size = 10999804, upload-time = "2025-07-24T18:53:05.095Z" }, + { url = "https://files.pythonhosted.org/packages/45/c6/a2d586300d9e14ad72e8dc211c7aecb45fe9846a51e558c5bca0c9102c7f/grpcio-1.74.0-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:a8f0302f9ac4e9923f98d8e243939a6fb627cd048f5cd38595c97e38020dffce", size = 5987667, upload-time = "2025-07-24T18:53:07.157Z" }, + { url = "https://files.pythonhosted.org/packages/c9/57/5f338bf56a7f22584e68d669632e521f0de460bb3749d54533fc3d0fca4f/grpcio-1.74.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f609a39f62a6f6f05c7512746798282546358a37ea93c1fcbadf8b2fed162e3", size = 6655612, upload-time = "2025-07-24T18:53:09.244Z" }, + { url = "https://files.pythonhosted.org/packages/82/ea/a4820c4c44c8b35b1903a6c72a5bdccec92d0840cf5c858c498c66786ba5/grpcio-1.74.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c98e0b7434a7fa4e3e63f250456eaef52499fba5ae661c58cc5b5477d11e7182", size = 6219544, upload-time = "2025-07-24T18:53:11.221Z" }, + { url = "https://files.pythonhosted.org/packages/a4/17/0537630a921365928f5abb6d14c79ba4dcb3e662e0dbeede8af4138d9dcf/grpcio-1.74.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:662456c4513e298db6d7bd9c3b8df6f75f8752f0ba01fb653e252ed4a59b5a5d", size = 6334863, upload-time = "2025-07-24T18:53:12.925Z" }, + { url = "https://files.pythonhosted.org/packages/e2/a6/85ca6cb9af3f13e1320d0a806658dca432ff88149d5972df1f7b51e87127/grpcio-1.74.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3d14e3c4d65e19d8430a4e28ceb71ace4728776fd6c3ce34016947474479683f", size = 7019320, upload-time = "2025-07-24T18:53:15.002Z" }, + { url = "https://files.pythonhosted.org/packages/4f/a7/fe2beab970a1e25d2eff108b3cf4f7d9a53c185106377a3d1989216eba45/grpcio-1.74.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bf949792cee20d2078323a9b02bacbbae002b9e3b9e2433f2741c15bdeba1c4", size = 6514228, upload-time = "2025-07-24T18:53:16.999Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c2/2f9c945c8a248cebc3ccda1b7a1bf1775b9d7d59e444dbb18c0014e23da6/grpcio-1.74.0-cp311-cp311-win32.whl", hash = "sha256:55b453812fa7c7ce2f5c88be3018fb4a490519b6ce80788d5913f3f9d7da8c7b", size = 3817216, upload-time = "2025-07-24T18:53:20.564Z" }, + { url = "https://files.pythonhosted.org/packages/ff/d1/a9cf9c94b55becda2199299a12b9feef0c79946b0d9d34c989de6d12d05d/grpcio-1.74.0-cp311-cp311-win_amd64.whl", hash = "sha256:86ad489db097141a907c559988c29718719aa3e13370d40e20506f11b4de0d11", size = 4495380, upload-time = "2025-07-24T18:53:22.058Z" }, + { url = "https://files.pythonhosted.org/packages/4c/5d/e504d5d5c4469823504f65687d6c8fb97b7f7bf0b34873b7598f1df24630/grpcio-1.74.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:8533e6e9c5bd630ca98062e3a1326249e6ada07d05acf191a77bc33f8948f3d8", size = 5445551, upload-time = "2025-07-24T18:53:23.641Z" }, + { url = "https://files.pythonhosted.org/packages/43/01/730e37056f96f2f6ce9f17999af1556df62ee8dab7fa48bceeaab5fd3008/grpcio-1.74.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:2918948864fec2a11721d91568effffbe0a02b23ecd57f281391d986847982f6", size = 10979810, upload-time = "2025-07-24T18:53:25.349Z" }, + { url = "https://files.pythonhosted.org/packages/79/3d/09fd100473ea5c47083889ca47ffd356576173ec134312f6aa0e13111dee/grpcio-1.74.0-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:60d2d48b0580e70d2e1954d0d19fa3c2e60dd7cbed826aca104fff518310d1c5", size = 5941946, upload-time = "2025-07-24T18:53:27.387Z" }, + { url = "https://files.pythonhosted.org/packages/8a/99/12d2cca0a63c874c6d3d195629dcd85cdf5d6f98a30d8db44271f8a97b93/grpcio-1.74.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3601274bc0523f6dc07666c0e01682c94472402ac2fd1226fd96e079863bfa49", size = 6621763, upload-time = "2025-07-24T18:53:29.193Z" }, + { url = "https://files.pythonhosted.org/packages/9d/2c/930b0e7a2f1029bbc193443c7bc4dc2a46fedb0203c8793dcd97081f1520/grpcio-1.74.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:176d60a5168d7948539def20b2a3adcce67d72454d9ae05969a2e73f3a0feee7", size = 6180664, upload-time = "2025-07-24T18:53:30.823Z" }, + { url = "https://files.pythonhosted.org/packages/db/d5/ff8a2442180ad0867717e670f5ec42bfd8d38b92158ad6bcd864e6d4b1ed/grpcio-1.74.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e759f9e8bc908aaae0412642afe5416c9f983a80499448fcc7fab8692ae044c3", size = 6301083, upload-time = "2025-07-24T18:53:32.454Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ba/b361d390451a37ca118e4ec7dccec690422e05bc85fba2ec72b06cefec9f/grpcio-1.74.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:9e7c4389771855a92934b2846bd807fc25a3dfa820fd912fe6bd8136026b2707", size = 6994132, upload-time = "2025-07-24T18:53:34.506Z" }, + { url = "https://files.pythonhosted.org/packages/3b/0c/3a5fa47d2437a44ced74141795ac0251bbddeae74bf81df3447edd767d27/grpcio-1.74.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:cce634b10aeab37010449124814b05a62fb5f18928ca878f1bf4750d1f0c815b", size = 6489616, upload-time = "2025-07-24T18:53:36.217Z" }, + { url = "https://files.pythonhosted.org/packages/ae/95/ab64703b436d99dc5217228babc76047d60e9ad14df129e307b5fec81fd0/grpcio-1.74.0-cp312-cp312-win32.whl", hash = "sha256:885912559974df35d92219e2dc98f51a16a48395f37b92865ad45186f294096c", size = 3807083, upload-time = "2025-07-24T18:53:37.911Z" }, + { url = "https://files.pythonhosted.org/packages/84/59/900aa2445891fc47a33f7d2f76e00ca5d6ae6584b20d19af9c06fa09bf9a/grpcio-1.74.0-cp312-cp312-win_amd64.whl", hash = "sha256:42f8fee287427b94be63d916c90399ed310ed10aadbf9e2e5538b3e497d269bc", size = 4490123, upload-time = "2025-07-24T18:53:39.528Z" }, ] [[package]] @@ -1608,35 +1309,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/90/40/972271de05f9315c0d69f9f7ebbcadd83bc85322f538637d11bb8c67803d/grpcio_status-1.62.3-py3-none-any.whl", hash = "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8", size = 14448, upload-time = "2024-08-06T00:30:15.702Z" }, ] -[[package]] -name = "grpcio-tools" -version = "1.62.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "grpcio" }, - { name = "protobuf" }, - { name = "setuptools" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/fa/b69bd8040eafc09b88bb0ec0fea59e8aacd1a801e688af087cead213b0d0/grpcio-tools-1.62.3.tar.gz", hash = "sha256:7c7136015c3d62c3eef493efabaf9e3380e3e66d24ee8e94c01cb71377f57833", size = 4538520, upload-time = "2024-08-06T00:37:11.035Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/52/2dfe0a46b63f5ebcd976570aa5fc62f793d5a8b169e211c6a5aede72b7ae/grpcio_tools-1.62.3-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:703f46e0012af83a36082b5f30341113474ed0d91e36640da713355cd0ea5d23", size = 5147623, upload-time = "2024-08-06T00:30:54.894Z" }, - { url = "https://files.pythonhosted.org/packages/f0/2e/29fdc6c034e058482e054b4a3c2432f84ff2e2765c1342d4f0aa8a5c5b9a/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7cc83023acd8bc72cf74c2edbe85b52098501d5b74d8377bfa06f3e929803492", size = 2719538, upload-time = "2024-08-06T00:30:57.928Z" }, - { url = "https://files.pythonhosted.org/packages/f9/60/abe5deba32d9ec2c76cdf1a2f34e404c50787074a2fee6169568986273f1/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ff7d58a45b75df67d25f8f144936a3e44aabd91afec833ee06826bd02b7fbe7", size = 3070964, upload-time = "2024-08-06T00:31:00.267Z" }, - { url = "https://files.pythonhosted.org/packages/bc/ad/e2b066684c75f8d9a48508cde080a3a36618064b9cadac16d019ca511444/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f2483ea232bd72d98a6dc6d7aefd97e5bc80b15cd909b9e356d6f3e326b6e43", size = 2805003, upload-time = "2024-08-06T00:31:02.565Z" }, - { url = "https://files.pythonhosted.org/packages/9c/3f/59bf7af786eae3f9d24ee05ce75318b87f541d0950190ecb5ffb776a1a58/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:962c84b4da0f3b14b3cdb10bc3837ebc5f136b67d919aea8d7bb3fd3df39528a", size = 3685154, upload-time = "2024-08-06T00:31:05.339Z" }, - { url = "https://files.pythonhosted.org/packages/f1/79/4dd62478b91e27084c67b35a2316ce8a967bd8b6cb8d6ed6c86c3a0df7cb/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ad0473af5544f89fc5a1ece8676dd03bdf160fb3230f967e05d0f4bf89620e3", size = 3297942, upload-time = "2024-08-06T00:31:08.456Z" }, - { url = "https://files.pythonhosted.org/packages/b8/cb/86449ecc58bea056b52c0b891f26977afc8c4464d88c738f9648da941a75/grpcio_tools-1.62.3-cp311-cp311-win32.whl", hash = "sha256:db3bc9fa39afc5e4e2767da4459df82b095ef0cab2f257707be06c44a1c2c3e5", size = 910231, upload-time = "2024-08-06T00:31:11.464Z" }, - { url = "https://files.pythonhosted.org/packages/45/a4/9736215e3945c30ab6843280b0c6e1bff502910156ea2414cd77fbf1738c/grpcio_tools-1.62.3-cp311-cp311-win_amd64.whl", hash = "sha256:e0898d412a434e768a0c7e365acabe13ff1558b767e400936e26b5b6ed1ee51f", size = 1052496, upload-time = "2024-08-06T00:31:13.665Z" }, - { url = "https://files.pythonhosted.org/packages/2a/a5/d6887eba415ce318ae5005e8dfac3fa74892400b54b6d37b79e8b4f14f5e/grpcio_tools-1.62.3-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d102b9b21c4e1e40af9a2ab3c6d41afba6bd29c0aa50ca013bf85c99cdc44ac5", size = 5147690, upload-time = "2024-08-06T00:31:16.436Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7c/3cde447a045e83ceb4b570af8afe67ffc86896a2fe7f59594dc8e5d0a645/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0a52cc9444df978438b8d2332c0ca99000521895229934a59f94f37ed896b133", size = 2720538, upload-time = "2024-08-06T00:31:18.905Z" }, - { url = "https://files.pythonhosted.org/packages/88/07/f83f2750d44ac4f06c07c37395b9c1383ef5c994745f73c6bfaf767f0944/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141d028bf5762d4a97f981c501da873589df3f7e02f4c1260e1921e565b376fa", size = 3071571, upload-time = "2024-08-06T00:31:21.684Z" }, - { url = "https://files.pythonhosted.org/packages/37/74/40175897deb61e54aca716bc2e8919155b48f33aafec8043dda9592d8768/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47a5c093ab256dec5714a7a345f8cc89315cb57c298b276fa244f37a0ba507f0", size = 2806207, upload-time = "2024-08-06T00:31:24.208Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/d8de915105a217cbcb9084d684abdc032030dcd887277f2ef167372287fe/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f6831fdec2b853c9daa3358535c55eed3694325889aa714070528cf8f92d7d6d", size = 3685815, upload-time = "2024-08-06T00:31:26.917Z" }, - { url = "https://files.pythonhosted.org/packages/fd/d9/4360a6c12be3d7521b0b8c39e5d3801d622fbb81cc2721dbd3eee31e28c8/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e02d7c1a02e3814c94ba0cfe43d93e872c758bd8fd5c2797f894d0c49b4a1dfc", size = 3298378, upload-time = "2024-08-06T00:31:30.401Z" }, - { url = "https://files.pythonhosted.org/packages/29/3b/7cdf4a9e5a3e0a35a528b48b111355cd14da601413a4f887aa99b6da468f/grpcio_tools-1.62.3-cp312-cp312-win32.whl", hash = "sha256:b881fd9505a84457e9f7e99362eeedd86497b659030cf57c6f0070df6d9c2b9b", size = 910416, upload-time = "2024-08-06T00:31:33.118Z" }, - { url = "https://files.pythonhosted.org/packages/6c/66/dd3ec249e44c1cc15e902e783747819ed41ead1336fcba72bf841f72c6e9/grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl", hash = "sha256:11c625eebefd1fd40a228fc8bae385e448c7e32a6ae134e43cf13bbc23f902b7", size = 1052856, upload-time = "2024-08-06T00:31:36.519Z" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -1951,6 +1623,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, ] +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + [[package]] name = "kubernetes" version = "31.0.0" @@ -1975,7 +1674,7 @@ wheels = [ [[package]] name = "langchain" -version = "0.3.26" +version = "0.3.27" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, @@ -1986,14 +1685,14 @@ dependencies = [ { name = "requests" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7f/13/a9931800ee42bbe0f8850dd540de14e80dda4945e7ee36e20b5d5964286e/langchain-0.3.26.tar.gz", hash = "sha256:8ff034ee0556d3e45eff1f1e96d0d745ced57858414dba7171c8ebdbeb5580c9", size = 10226808, upload-time = "2025-06-20T22:23:01.174Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f6/f4f7f3a56626fe07e2bb330feb61254dbdf06c506e6b59a536a337da51cf/langchain-0.3.27.tar.gz", hash = "sha256:aa6f1e6274ff055d0fd36254176770f356ed0a8994297d1df47df341953cec62", size = 10233809, upload-time = "2025-07-24T14:42:32.959Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/f2/c09a2e383283e3af1db669ab037ac05a45814f4b9c472c48dc24c0cef039/langchain-0.3.26-py3-none-any.whl", hash = "sha256:361bb2e61371024a8c473da9f9c55f4ee50f269c5ab43afdb2b1309cb7ac36cf", size = 1012336, upload-time = "2025-06-20T22:22:58.874Z" }, + { url = "https://files.pythonhosted.org/packages/f6/d5/4861816a95b2f6993f1360cfb605aacb015506ee2090433a71de9cca8477/langchain-0.3.27-py3-none-any.whl", hash = "sha256:7b20c4f338826acb148d885b20a73a16e410ede9ee4f19bb02011852d5f98798", size = 1018194, upload-time = "2025-07-24T14:42:30.23Z" }, ] [[package]] name = "langchain-community" -version = "0.3.26" +version = "0.3.29" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, @@ -2009,14 +1708,14 @@ dependencies = [ { name = "sqlalchemy" }, { name = "tenacity" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/15/69940212569e7d7ac7b486fba244701448e8685f79069b73206c44e96fde/langchain_community-0.3.26.tar.gz", hash = "sha256:49f9d71dc20bc42ccecd6875d02fafef1be0e211a0b22cecbd678f5fd3719487", size = 33235791, upload-time = "2025-06-20T22:32:41.727Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/71/72ddc8802d5edcd3b31bc4f0eb62cdf85c30c9b845e34cc879dab0b45679/langchain_community-0.3.29.tar.gz", hash = "sha256:1f3d37973b10458052bb3cc02dce9773a8ffbd02961698c6d395b8c8d7f9e004", size = 33238072, upload-time = "2025-08-27T15:29:14.249Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/8e/d3d201f648e8d09dc1072a734c4dc1f59455b91d7d162427256533bf5a87/langchain_community-0.3.26-py3-none-any.whl", hash = "sha256:b25a553ee9d44a6c02092a440da6c561a9312c7013ffc25365ac3f8694edb53a", size = 2529186, upload-time = "2025-06-20T22:32:39.738Z" }, + { url = "https://files.pythonhosted.org/packages/2b/3c/107819dbed0be3f7a041245bce861c8dd4883ed08040ed482d278a274f22/langchain_community-0.3.29-py3-none-any.whl", hash = "sha256:c876ec7ef40b46353af164197f4e08e157650e8a02c9fb9d49351cdc16c839fe", size = 2530803, upload-time = "2025-08-27T15:29:12.52Z" }, ] [[package]] name = "langchain-core" -version = "0.3.68" +version = "0.3.79" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, @@ -2027,21 +1726,21 @@ dependencies = [ { name = "tenacity" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/23/20/f5b18a17bfbe3416177e702ab2fd230b7d168abb17be31fb48f43f0bb772/langchain_core-0.3.68.tar.gz", hash = "sha256:312e1932ac9aa2eaf111b70fdc171776fa571d1a86c1f873dcac88a094b19c6f", size = 563041, upload-time = "2025-07-03T17:02:28.704Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c8/99/f926495f467e0f43289f12e951655d267d1eddc1136c3cf4dd907794a9a7/langchain_core-0.3.79.tar.gz", hash = "sha256:024ba54a346dd9b13fb8b2342e0c83d0111e7f26fa01f545ada23ad772b55a60", size = 580895, upload-time = "2025-10-09T21:59:08.359Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/da/c89be0a272993bfcb762b2a356b9f55de507784c2755ad63caec25d183bf/langchain_core-0.3.68-py3-none-any.whl", hash = "sha256:5e5c1fbef419590537c91b8c2d86af896fbcbaf0d5ed7fdcdd77f7d8f3467ba0", size = 441405, upload-time = "2025-07-03T17:02:27.115Z" }, + { url = "https://files.pythonhosted.org/packages/fc/71/46b0efaf3fc6ad2c2bd600aef500f1cb2b7038a4042f58905805630dd29d/langchain_core-0.3.79-py3-none-any.whl", hash = "sha256:92045bfda3e741f8018e1356f83be203ec601561c6a7becfefe85be5ddc58fdb", size = 449779, upload-time = "2025-10-09T21:59:06.493Z" }, ] [[package]] name = "langchain-text-splitters" -version = "0.3.8" +version = "0.3.11" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e7/ac/b4a25c5716bb0103b1515f1f52cc69ffb1035a5a225ee5afe3aed28bf57b/langchain_text_splitters-0.3.8.tar.gz", hash = "sha256:116d4b9f2a22dda357d0b79e30acf005c5518177971c66a9f1ab0edfdb0f912e", size = 42128, upload-time = "2025-04-04T14:03:51.521Z" } +sdist = { url = "https://files.pythonhosted.org/packages/11/43/dcda8fd25f0b19cb2835f2f6bb67f26ad58634f04ac2d8eae00526b0fa55/langchain_text_splitters-0.3.11.tar.gz", hash = "sha256:7a50a04ada9a133bbabb80731df7f6ddac51bc9f1b9cab7fa09304d71d38a6cc", size = 46458, upload-time = "2025-08-31T23:02:58.316Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/a3/3696ff2444658053c01b6b7443e761f28bb71217d82bb89137a978c5f66f/langchain_text_splitters-0.3.8-py3-none-any.whl", hash = "sha256:e75cc0f4ae58dcf07d9f18776400cf8ade27fadd4ff6d264df6278bb302f6f02", size = 32440, upload-time = "2025-04-04T14:03:50.6Z" }, + { url = "https://files.pythonhosted.org/packages/58/0d/41a51b40d24ff0384ec4f7ab8dd3dcea8353c05c973836b5e289f1465d4f/langchain_text_splitters-0.3.11-py3-none-any.whl", hash = "sha256:cf079131166a487f1372c8ab5d0bfaa6c0a4291733d9c43a34a16ac9bcd6a393", size = 33845, upload-time = "2025-08-31T23:02:57.195Z" }, ] [[package]] @@ -2053,24 +1752,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } -[[package]] -name = "langfuse" -version = "2.44.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "backoff" }, - { name = "httpx" }, - { name = "idna" }, - { name = "packaging" }, - { name = "pydantic" }, - { name = "wrapt" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a4/85/5a21a1d3be81e71f11f6d50affbb929eea3d5bbfab649bf8811bba83776f/langfuse-2.44.0.tar.gz", hash = "sha256:dfa5378ff7022ae9fe5b8b842c0365347c98f9ef2b772dcee6a93a45442de28c", size = 106834, upload-time = "2024-08-20T11:47:50.695Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/54/03550a879a90ae4242542335b0883bb2d297c75f32cb58604064879a8f3b/langfuse-2.44.0-py3-none-any.whl", hash = "sha256:adb73400a6ad6d597cc95c31381c82f81face3d5fb69391181f224a26f7e8562", size = 195931, upload-time = "2024-08-20T11:47:48.623Z" }, -] - [[package]] name = "langsmith" version = "0.4.5" @@ -2170,11 +1851,11 @@ wheels = [ [[package]] name = "markdown" -version = "3.7" +version = "3.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086, upload-time = "2024-08-16T15:55:17.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8d/37/02347f6d6d8279247a5837082ebc26fc0d5aaeaf75aa013fcbb433c777ab/markdown-3.9.tar.gz", hash = "sha256:d2900fe1782bd33bdbbd56859defef70c2e78fc46668f8eb9df3128138f2cb6a", size = 364585, upload-time = "2025-09-04T20:25:22.885Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349, upload-time = "2024-08-16T15:55:16.176Z" }, + { url = "https://files.pythonhosted.org/packages/70/ae/44c4a6a4cbb496d93c6257954260fe3a6e91b7bed2240e5dad2a717f5111/markdown-3.9-py3-none-any.whl", hash = "sha256:9f4d91ed810864ea88a6f32c07ba8bee1346c0cc1f6b1f9f6c822f2a9667d280", size = 107441, upload-time = "2025-09-04T20:25:21.784Z" }, ] [[package]] @@ -2230,26 +1911,34 @@ wheels = [ ] [[package]] -name = "mdurl" -version = "0.1.2" +name = "mcp" +version = "1.14.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/e9/242096400d702924b49f8d202c6ded7efb8841cacba826b5d2e6183aef7b/mcp-1.14.1.tar.gz", hash = "sha256:31c4406182ba15e8f30a513042719c3f0a38c615e76188ee5a736aaa89e20134", size = 454944, upload-time = "2025-09-18T13:37:19.971Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, + { url = "https://files.pythonhosted.org/packages/8e/11/d334fbb7c2aeddd2e762b86d7a619acffae012643a5738e698f975a2a9e2/mcp-1.14.1-py3-none-any.whl", hash = "sha256:3b7a479e8e5cbf5361bdc1da8bc6d500d795dc3aff44b44077a363a7f7e945a4", size = 163809, upload-time = "2025-09-18T13:37:18.165Z" }, ] [[package]] -name = "milvus-lite" -version = "2.4.11" +name = "mdurl" +version = "0.1.2" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tqdm" }, -] +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/42/6f4706066ec3251d5a3d42f7fc2bbb02deffa518e40ec63d9abdee58964b/milvus_lite-2.4.11-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:9e563ae0dca1b41bfd76b90f06b2bcc474460fe4eba142c9bab18d2747ff843b", size = 19841144, upload-time = "2024-12-31T02:16:35.679Z" }, - { url = "https://files.pythonhosted.org/packages/c9/69/eabed32162362ba460d81b5c26c6554c2ffef9427fc5d440aa74fbe675dc/milvus_lite-2.4.11-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d21472bd24eb327542817829ce7cb51878318e6173c4d62353c77421aecf98d6", size = 16872814, upload-time = "2024-12-31T08:44:42.047Z" }, - { url = "https://files.pythonhosted.org/packages/ed/85/feb5ef0d92ab4b62c20a5a91fdfc8515f1038d9947a41f5e8ba357724c28/milvus_lite-2.4.11-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8e6ef27f7f84976f9fd0047b675ede746db2e0cc581c44a916ac9e71e0cef05d", size = 36006762, upload-time = "2025-01-02T11:29:11.907Z" }, - { url = "https://files.pythonhosted.org/packages/8d/c2/b294a7699ef097d7b0ab89f95f34fb0710726f12d7da912734e18c2558eb/milvus_lite-2.4.11-py3-none-manylinux2014_x86_64.whl", hash = "sha256:551f56b49fcfbb330b658b4a3c56ed29ba9b692ec201edd1f2dade7f5e39957d", size = 45177882, upload-time = "2024-12-31T02:16:47.42Z" }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] [[package]] @@ -2301,32 +1990,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/67/7e8406a29b6c45be7af7740456f7f37025f0506ae2e05fb9009a53946860/monotonic-1.6-py2.py3-none-any.whl", hash = "sha256:68687e19a14f11f26d140dd5c86f3dba4bf5df58003000ed467e0e2a69bca96c", size = 8154, upload-time = "2021-04-09T21:58:05.122Z" }, ] -[[package]] -name = "moto" -version = "5.0.26" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "boto3" }, - { name = "botocore" }, - { name = "cryptography" }, - { name = "jinja2" }, - { name = "python-dateutil" }, - { name = "requests" }, - { name = "responses" }, - { name = "werkzeug" }, - { name = "xmltodict" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8b/a9/996e9d0c8c5d6f8b044d4facfe6eb6c42feb4ab5c2a24d78f780bd942f61/moto-5.0.26.tar.gz", hash = "sha256:6829f58a670a087e7c5b63f8183c6b72d64a1444e420c212250b7326b69a9183", size = 6442983, upload-time = "2025-01-05T21:06:36.53Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/dd/40c20b3bcdf335f56776e1adea5edd1b1026f3f98816944a123393f64df3/moto-5.0.26-py3-none-any.whl", hash = "sha256:803831f427ca6c0452ae4fb898d731cfc19906466a33a88cbc1076abcbfcbba7", size = 4614956, upload-time = "2025-01-05T21:06:32.282Z" }, -] - -[package.optional-dependencies] -s3 = [ - { name = "py-partiql-parser" }, - { name = "pyyaml" }, -] - [[package]] name = "mpmath" version = "1.3.0" @@ -2401,22 +2064,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051, upload-time = "2024-09-09T23:49:36.506Z" }, ] -[[package]] -name = "multiprocess" -version = "0.70.16" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dill" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/ae/04f39c5d0d0def03247c2893d6f2b83c136bf3320a2154d7b8858f2ba72d/multiprocess-0.70.16.tar.gz", hash = "sha256:161af703d4652a0e1410be6abccecde4a7ddffd19341be0a7011b94aeb171ac1", size = 1772603, upload-time = "2024-01-28T18:52:34.85Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/f7/7ec7fddc92e50714ea3745631f79bd9c96424cb2702632521028e57d3a36/multiprocess-0.70.16-py310-none-any.whl", hash = "sha256:c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02", size = 134824, upload-time = "2024-01-28T18:52:26.062Z" }, - { url = "https://files.pythonhosted.org/packages/50/15/b56e50e8debaf439f44befec5b2af11db85f6e0f344c3113ae0be0593a91/multiprocess-0.70.16-py311-none-any.whl", hash = "sha256:af4cabb0dac72abfb1e794fa7855c325fd2b55a10a44628a3c1ad3311c04127a", size = 143519, upload-time = "2024-01-28T18:52:28.115Z" }, - { url = "https://files.pythonhosted.org/packages/0a/7d/a988f258104dcd2ccf1ed40fdc97e26c4ac351eeaf81d76e266c52d84e2f/multiprocess-0.70.16-py312-none-any.whl", hash = "sha256:fc0544c531920dde3b00c29863377f87e1632601092ea2daca74e4beb40faa2e", size = 146741, upload-time = "2024-01-28T18:52:29.395Z" }, - { url = "https://files.pythonhosted.org/packages/ea/89/38df130f2c799090c978b366cfdf5b96d08de5b29a4a293df7f7429fa50b/multiprocess-0.70.16-py38-none-any.whl", hash = "sha256:a71d82033454891091a226dfc319d0cfa8019a4e888ef9ca910372a446de4435", size = 132628, upload-time = "2024-01-28T18:52:30.853Z" }, - { url = "https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", size = 133351, upload-time = "2024-01-28T18:52:31.981Z" }, -] - [[package]] name = "mypy-extensions" version = "1.0.0" @@ -2444,30 +2091,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, ] -[[package]] -name = "ninja" -version = "1.11.1.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/8f/21a2701f95b7d0d5137736561b3427ece0c4a1e085d4a223b92d16ab7d8b/ninja-1.11.1.3.tar.gz", hash = "sha256:edfa0d2e9d7ead1635b03e40a32ad56cc8f56798b6e2e9848d8300b174897076", size = 129532, upload-time = "2024-12-15T09:13:01.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/ba/0069cd4a83d68f7b0308be70e219b15d675e50c8ea28763a3f0373c45bfc/ninja-1.11.1.3-py3-none-macosx_10_9_universal2.whl", hash = "sha256:2b4879ea3f1169f3d855182c57dcc84d1b5048628c8b7be0d702b81882a37237", size = 279132, upload-time = "2024-12-15T09:12:23.11Z" }, - { url = "https://files.pythonhosted.org/packages/72/6b/3805be87df8417a0c7b21078c8045f2a1e59b34f371bfe4cb4fb0d6df7f2/ninja-1.11.1.3-py3-none-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bc3ebc8b2e47716149f3541742b5cd8e0b08f51013b825c05baca3e34854370d", size = 472101, upload-time = "2024-12-15T09:12:26.077Z" }, - { url = "https://files.pythonhosted.org/packages/6b/35/a8e38d54768e67324e365e2a41162be298f51ec93e6bd4b18d237d7250d8/ninja-1.11.1.3-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a27e78ca71316c8654965ee94b286a98c83877bfebe2607db96897bbfe458af0", size = 422884, upload-time = "2024-12-15T09:12:28.643Z" }, - { url = "https://files.pythonhosted.org/packages/2f/99/7996457319e139c02697fb2aa28e42fe32bb0752cef492edc69d56a3552e/ninja-1.11.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2883ea46b3c5079074f56820f9989c6261fcc6fd873d914ee49010ecf283c3b2", size = 157046, upload-time = "2024-12-15T09:12:31.489Z" }, - { url = "https://files.pythonhosted.org/packages/6d/8b/93f38e5cddf76ccfdab70946515b554f25d2b4c95ef9b2f9cfbc43fa7cc1/ninja-1.11.1.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c4bdb9fd2d0c06501ae15abfd23407660e95659e384acd36e013b6dd7d8a8e4", size = 180014, upload-time = "2024-12-15T09:12:32.864Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/713884d0fa3c972164f69d552e0701d30e2bf25eba9ef160bfb3dc69926a/ninja-1.11.1.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:114ed5c61c8474df6a69ab89097a20749b769e2c219a452cb2fadc49b0d581b0", size = 157098, upload-time = "2024-12-15T09:12:35.738Z" }, - { url = "https://files.pythonhosted.org/packages/c7/22/ecb0f70e77c9e22ee250aa717a608a142756833a34d43943d7d658ee0e56/ninja-1.11.1.3-py3-none-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fa2247fce98f683bc712562d82b22b8a0a5c000738a13147ca2d1b68c122298", size = 130089, upload-time = "2024-12-15T09:12:38.497Z" }, - { url = "https://files.pythonhosted.org/packages/ec/a6/3ee846c20ab6ad95b90c5c8703c76cb1f39cc8ce2d1ae468956e3b1b2581/ninja-1.11.1.3-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:a38c6c6c8032bed68b70c3b065d944c35e9f903342875d3a3218c1607987077c", size = 372508, upload-time = "2024-12-15T09:12:41.055Z" }, - { url = "https://files.pythonhosted.org/packages/95/0d/aa44abe4141f29148ce671ac8c92045878906b18691c6f87a29711c2ff1c/ninja-1.11.1.3-py3-none-musllinux_1_1_i686.whl", hash = "sha256:56ada5d33b8741d298836644042faddebc83ee669782d661e21563034beb5aba", size = 419369, upload-time = "2024-12-15T09:12:42.461Z" }, - { url = "https://files.pythonhosted.org/packages/f7/ec/48bf5105568ac9bd2016b701777bdd5000cc09a14ac837fef9f15e8d634e/ninja-1.11.1.3-py3-none-musllinux_1_1_ppc64le.whl", hash = "sha256:53409151da081f3c198bb0bfc220a7f4e821e022c5b7d29719adda892ddb31bb", size = 420304, upload-time = "2024-12-15T09:12:45.326Z" }, - { url = "https://files.pythonhosted.org/packages/18/e5/69df63976cf971a03379899f8520a036c9dbab26330b37197512aed5b3df/ninja-1.11.1.3-py3-none-musllinux_1_1_s390x.whl", hash = "sha256:1ad2112c2b0159ed7c4ae3731595191b1546ba62316fc40808edecd0306fefa3", size = 416056, upload-time = "2024-12-15T09:12:48.125Z" }, - { url = "https://files.pythonhosted.org/packages/6f/4f/bdb401af7ed0e24a3fef058e13a149f2de1ce4b176699076993615d55610/ninja-1.11.1.3-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:28aea3c1c280cba95b8608d50797169f3a34280e3e9a6379b6e340f0c9eaeeb0", size = 379725, upload-time = "2024-12-15T09:12:50.873Z" }, - { url = "https://files.pythonhosted.org/packages/bd/68/05e7863bf13128c61652eeb3ec7096c3d3a602f32f31752dbfb034e3fa07/ninja-1.11.1.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b6966f83064a88a51693073eea3decd47e08c3965241e09578ef7aa3a7738329", size = 434881, upload-time = "2024-12-15T09:12:54.754Z" }, - { url = "https://files.pythonhosted.org/packages/bd/ad/edc0d1efe77f29f45bbca2e1dab07ef597f61a88de6e4bccffc0aec2256c/ninja-1.11.1.3-py3-none-win32.whl", hash = "sha256:a4a3b71490557e18c010cbb26bd1ea9a0c32ee67e8f105e9731515b6e0af792e", size = 255988, upload-time = "2024-12-15T09:12:56.417Z" }, - { url = "https://files.pythonhosted.org/packages/03/93/09a9f7672b4f97438aca6217ac54212a63273f1cd3b46b731d0bb22c53e7/ninja-1.11.1.3-py3-none-win_amd64.whl", hash = "sha256:04d48d14ea7ba11951c156599ab526bdda575450797ff57c6fdf99b2554d09c7", size = 296502, upload-time = "2024-12-15T09:12:57.801Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9d/0cc1e82849070ff3cbee69f326cb48a839407bcd15d8844443c30a5e7509/ninja-1.11.1.3-py3-none-win_arm64.whl", hash = "sha256:17978ad611d8ead578d83637f5ae80c2261b033db0b493a7ce94f88623f29e1b", size = 270571, upload-time = "2024-12-15T09:12:59.23Z" }, -] - [[package]] name = "nltk" version = "3.9.1" @@ -2682,20 +2305,15 @@ dependencies = [ { name = "black" }, { name = "boto3" }, { name = "chromadb" }, - { name = "colbert-ai" }, { name = "cryptography" }, { name = "ddgs" }, - { name = "docker" }, { name = "docx2txt" }, { name = "einops" }, - { name = "elasticsearch" }, { name = "fake-useragent" }, { name = "fastapi" }, { name = "faster-whisper" }, - { name = "firecrawl-py" }, { name = "fpdf2" }, { name = "ftfy" }, - { name = "gcp-storage-emulator" }, { name = "google-api-python-client" }, { name = "google-auth-httplib2" }, { name = "google-auth-oauthlib" }, @@ -2703,50 +2321,42 @@ dependencies = [ { name = "google-genai" }, { name = "google-generativeai" }, { name = "googleapis-common-protos" }, + { name = "grpcio" }, { name = "httpx", extra = ["brotli", "cli", "http2", "socks", "zstd"] }, + { name = "itsdangerous" }, { name = "langchain" }, { name = "langchain-community" }, - { name = "langfuse" }, { name = "ldap3" }, { name = "loguru" }, { name = "markdown" }, - { name = "moto", extra = ["s3"] }, + { name = "mcp" }, { name = "nltk" }, { name = "onnxruntime" }, { name = "openai" }, { name = "opencv-python-headless" }, { name = "openpyxl" }, { name = "opensearch-py" }, - { name = "oracledb" }, { name = "pandas" }, - { name = "passlib", extra = ["bcrypt"] }, { name = "peewee" }, { name = "peewee-migrate" }, - { name = "pgvector" }, { name = "pillow" }, - { name = "pinecone" }, - { name = "playwright" }, + { name = "protobuf" }, { name = "psutil" }, - { name = "psycopg2-binary" }, + { name = "pyarrow" }, { name = "pycrdt" }, { name = "pydantic" }, { name = "pydub" }, { name = "pyjwt", extra = ["crypto"] }, { name = "pymdown-extensions" }, - { name = "pymilvus" }, - { name = "pymongo" }, { name = "pymysql" }, { name = "pypandoc" }, { name = "pypdf" }, - { name = "pytest" }, - { name = "pytest-docker" }, { name = "python-jose" }, { name = "python-multipart" }, { name = "python-pptx" }, { name = "python-socketio" }, { name = "pytube" }, { name = "pyxlsb" }, - { name = "qdrant-client" }, { name = "rank-bm25" }, { name = "rapidocr-onnxruntime" }, { name = "redis" }, @@ -2757,7 +2367,7 @@ dependencies = [ { name = "soundfile" }, { name = "sqlalchemy" }, { name = "starlette-compress" }, - { name = "tencentcloud-sdk-python" }, + { name = "starsessions", extra = ["redis"] }, { name = "tiktoken" }, { name = "transformers" }, { name = "unstructured" }, @@ -2777,105 +2387,91 @@ requires-dist = [ { name = "accelerate" }, { name = "aiocache" }, { name = "aiofiles" }, - { name = "aiohttp", specifier = "==3.11.11" }, + { name = "aiohttp", specifier = "==3.12.15" }, { name = "alembic", specifier = "==1.14.0" }, { name = "anthropic" }, { name = "apscheduler", specifier = "==3.10.4" }, - { name = "argon2-cffi", specifier = "==23.1.0" }, + { name = "argon2-cffi", specifier = "==25.1.0" }, { name = "asgiref", specifier = "==3.8.1" }, { name = "async-timeout" }, - { name = "authlib", specifier = "==1.4.1" }, + { name = "authlib", specifier = "==1.6.5" }, { name = "azure-ai-documentintelligence", specifier = "==1.0.2" }, - { name = "azure-identity", specifier = "==1.20.0" }, + { name = "azure-identity", specifier = "==1.25.0" }, { name = "azure-storage-blob", specifier = "==12.24.1" }, - { name = "bcrypt", specifier = "==4.3.0" }, - { name = "black", specifier = "==25.1.0" }, - { name = "boto3", specifier = "==1.35.53" }, - { name = "chromadb", specifier = "==0.6.3" }, - { name = "colbert-ai", specifier = "==0.2.21" }, + { name = "bcrypt", specifier = "==5.0.0" }, + { name = "black", specifier = "==25.9.0" }, + { name = "boto3", specifier = "==1.40.5" }, + { name = "chromadb", specifier = "==1.0.20" }, { name = "cryptography" }, { name = "ddgs", specifier = "==9.0.0" }, - { name = "docker", specifier = "~=7.1.0" }, { name = "docx2txt", specifier = "==0.8" }, - { name = "duckduckgo-search", specifier = "==8.0.2" }, { name = "einops", specifier = "==0.8.1" }, - { name = "elasticsearch", specifier = "==9.0.1" }, - { name = "fake-useragent", specifier = "==2.1.0" }, - { name = "fastapi", specifier = "==0.115.7" }, + { name = "fake-useragent", specifier = "==2.2.0" }, + { name = "fastapi", specifier = "==0.118.0" }, { name = "faster-whisper", specifier = "==1.1.1" }, - { name = "firecrawl-py", specifier = "==1.12.0" }, { name = "fpdf2", specifier = "==2.8.2" }, { name = "ftfy", specifier = "==6.2.3" }, - { name = "gcp-storage-emulator", specifier = ">=2024.8.3" }, { name = "google-api-python-client" }, { name = "google-auth-httplib2" }, { name = "google-auth-oauthlib" }, { name = "google-cloud-storage", specifier = "==2.19.0" }, - { name = "google-genai", specifier = "==1.15.0" }, + { name = "google-genai", specifier = "==1.38.0" }, { name = "google-generativeai", specifier = "==0.8.5" }, - { name = "googleapis-common-protos", specifier = "==1.63.2" }, + { name = "googleapis-common-protos", specifier = "==1.70.0" }, + { name = "grpcio", specifier = "==1.74.0" }, { name = "httpx", extras = ["brotli", "cli", "http2", "socks", "zstd"], specifier = "==0.28.1" }, - { name = "langchain", specifier = "==0.3.26" }, - { name = "langchain-community", specifier = "==0.3.26" }, - { name = "langfuse", specifier = "==2.44.0" }, + { name = "itsdangerous", specifier = "==2.2.0" }, + { name = "langchain", specifier = "==0.3.27" }, + { name = "langchain-community", specifier = "==0.3.29" }, { name = "ldap3", specifier = "==2.9.1" }, { name = "loguru", specifier = "==0.7.3" }, - { name = "markdown", specifier = "==3.7" }, - { name = "moto", extras = ["s3"], specifier = ">=5.0.26" }, + { name = "markdown", specifier = "==3.9" }, + { name = "mcp", specifier = "==1.14.1" }, { name = "nltk", specifier = "==3.9.1" }, { name = "onnxruntime", specifier = "==1.20.1" }, { name = "openai" }, { name = "opencv-python-headless", specifier = "==4.11.0.86" }, { name = "openpyxl", specifier = "==3.1.5" }, { name = "opensearch-py", specifier = "==2.8.0" }, - { name = "oracledb", specifier = ">=3.2.0" }, { name = "pandas", specifier = "==2.2.3" }, - { name = "passlib", extras = ["bcrypt"], specifier = "==1.7.4" }, { name = "peewee", specifier = "==3.18.1" }, { name = "peewee-migrate", specifier = "==1.12.2" }, - { name = "pgvector", specifier = "==0.4.0" }, - { name = "pillow", specifier = "==11.2.1" }, - { name = "pinecone", specifier = "==6.0.2" }, - { name = "playwright", specifier = "==1.49.1" }, + { name = "pillow", specifier = "==11.3.0" }, + { name = "protobuf", specifier = "==5.29.5" }, { name = "psutil" }, - { name = "psycopg2-binary", specifier = "==2.9.9" }, + { name = "pyarrow", specifier = "==20.0.0" }, { name = "pycrdt", specifier = "==0.12.25" }, - { name = "pydantic", specifier = "==2.11.7" }, + { name = "pydantic", specifier = "==2.11.9" }, { name = "pydub" }, { name = "pyjwt", extras = ["crypto"], specifier = "==2.10.1" }, { name = "pymdown-extensions", specifier = "==10.14.2" }, - { name = "pymilvus", specifier = "==2.5.0" }, - { name = "pymongo" }, { name = "pymysql", specifier = "==1.1.1" }, { name = "pypandoc", specifier = "==1.15" }, - { name = "pypdf", specifier = "==4.3.1" }, - { name = "pytest", specifier = "~=8.3.2" }, - { name = "pytest-docker", specifier = "~=3.1.1" }, - { name = "python-jose", specifier = "==3.4.0" }, + { name = "pypdf", specifier = "==6.0.0" }, + { name = "python-jose", specifier = "==3.5.0" }, { name = "python-multipart", specifier = "==0.0.20" }, { name = "python-pptx", specifier = "==1.0.2" }, { name = "python-socketio", specifier = "==5.13.0" }, { name = "pytube", specifier = "==15.0.0" }, { name = "pyxlsb", specifier = "==1.0.10" }, - { name = "qdrant-client", specifier = "==1.14.3" }, { name = "rank-bm25", specifier = "==0.2.2" }, { name = "rapidocr-onnxruntime", specifier = "==1.4.4" }, { name = "redis" }, - { name = "requests", specifier = "==2.32.4" }, + { name = "requests", specifier = "==2.32.5" }, { name = "restrictedpython", specifier = "==8.0" }, - { name = "sentence-transformers", specifier = "==4.1.0" }, + { name = "sentence-transformers", specifier = "==5.1.1" }, { name = "sentencepiece" }, { name = "soundfile", specifier = "==0.13.1" }, { name = "sqlalchemy", specifier = "==2.0.38" }, { name = "starlette-compress", specifier = "==1.6.0" }, - { name = "tencentcloud-sdk-python", specifier = "==3.0.1336" }, + { name = "starsessions", extras = ["redis"], specifier = "==2.2.1" }, { name = "tiktoken" }, { name = "transformers" }, - { name = "unstructured", specifier = "==0.16.17" }, - { name = "uvicorn", extras = ["standard"], specifier = "==0.34.2" }, + { name = "unstructured", specifier = "==0.18.15" }, + { name = "uvicorn", extras = ["standard"], specifier = "==0.37.0" }, { name = "validators", specifier = "==0.35.0" }, { name = "xlrd", specifier = "==2.0.1" }, - { name = "youtube-transcript-api", specifier = "==1.1.0" }, + { name = "youtube-transcript-api", specifier = "==1.2.2" }, ] [package.metadata.requires-dev] @@ -2947,108 +2543,74 @@ wheels = [ ] [[package]] -name = "opensearch-py" -version = "2.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "events" }, - { name = "python-dateutil" }, - { name = "requests" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7c/e4/192c97ca676c81f69e138a22e10fb03f64e14a55633cb2acffb41bf6d061/opensearch_py-2.8.0.tar.gz", hash = "sha256:6598df0bc7a003294edd0ba88a331e0793acbb8c910c43edf398791e3b2eccda", size = 237923, upload-time = "2024-11-29T21:06:02.952Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/35/a957c6fb88ff6874996be688448b889475cf0ea978446cd5a30e764e0561/opensearch_py-2.8.0-py3-none-any.whl", hash = "sha256:52c60fdb5d4dcf6cce3ee746c13b194529b0161e0f41268b98ab8f1624abe2fa", size = 353492, upload-time = "2024-11-29T21:05:56.075Z" }, -] - -[[package]] -name = "opentelemetry-api" -version = "1.29.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "deprecated" }, - { name = "importlib-metadata" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bc/8e/b886a5e9861afa188d1fe671fb96ff9a1d90a23d57799331e137cc95d573/opentelemetry_api-1.29.0.tar.gz", hash = "sha256:d04a6cf78aad09614f52964ecb38021e248f5714dc32c2e0d8fd99517b4d69cf", size = 62900, upload-time = "2024-12-11T17:02:23.275Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/53/5249ea860d417a26a3a6f1bdedfc0748c4f081a3adaec3d398bc0f7c6a71/opentelemetry_api-1.29.0-py3-none-any.whl", hash = "sha256:5fcd94c4141cc49c736271f3e1efb777bebe9cc535759c54c936cca4f1b312b8", size = 64304, upload-time = "2024-12-11T17:01:48.691Z" }, -] - -[[package]] -name = "opentelemetry-exporter-otlp-proto-grpc" -version = "1.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "backoff" }, - { name = "googleapis-common-protos" }, - { name = "grpcio" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-proto" }, - { name = "opentelemetry-sdk" }, +name = "opensearch-py" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "events" }, + { name = "python-dateutil" }, + { name = "requests" }, + { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e4/ab/1be294b194af410f350f867a54621b4f33b7551adce2ae795e907148fc1e/opentelemetry_exporter_otlp_proto_grpc-1.15.0.tar.gz", hash = "sha256:844f2a4bb9bcda34e4eb6fe36765e5031aacb36dc60ed88c90fc246942ea26e7", size = 27262, upload-time = "2022-12-09T22:28:44.359Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/e4/192c97ca676c81f69e138a22e10fb03f64e14a55633cb2acffb41bf6d061/opensearch_py-2.8.0.tar.gz", hash = "sha256:6598df0bc7a003294edd0ba88a331e0793acbb8c910c43edf398791e3b2eccda", size = 237923, upload-time = "2024-11-29T21:06:02.952Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/8f/73ad108bcfd61b4169be5ad8b76acaf9158f224740da10ab9ea3469d551a/opentelemetry_exporter_otlp_proto_grpc-1.15.0-py3-none-any.whl", hash = "sha256:c2a5492ba7d140109968135d641d06ce3c5bd73c50665f787526065d57d7fd1d", size = 20378, upload-time = "2022-12-09T22:28:14.623Z" }, + { url = "https://files.pythonhosted.org/packages/23/35/a957c6fb88ff6874996be688448b889475cf0ea978446cd5a30e764e0561/opensearch_py-2.8.0-py3-none-any.whl", hash = "sha256:52c60fdb5d4dcf6cce3ee746c13b194529b0161e0f41268b98ab8f1624abe2fa", size = 353492, upload-time = "2024-11-29T21:05:56.075Z" }, ] [[package]] -name = "opentelemetry-instrumentation" -version = "0.50b0" +name = "opentelemetry-api" +version = "1.29.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "packaging" }, - { name = "wrapt" }, + { name = "deprecated" }, + { name = "importlib-metadata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/79/2e/2e59a7cb636dc394bd7cf1758ada5e8ed87590458ca6bb2f9c26e0243847/opentelemetry_instrumentation-0.50b0.tar.gz", hash = "sha256:7d98af72de8dec5323e5202e46122e5f908592b22c6d24733aad619f07d82979", size = 26539, upload-time = "2024-12-11T17:05:18.336Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/8e/b886a5e9861afa188d1fe671fb96ff9a1d90a23d57799331e137cc95d573/opentelemetry_api-1.29.0.tar.gz", hash = "sha256:d04a6cf78aad09614f52964ecb38021e248f5714dc32c2e0d8fd99517b4d69cf", size = 62900, upload-time = "2024-12-11T17:02:23.275Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/b1/55a77152a83ec8998e520a3a575f44af1020cfe4bdc000b7538583293b85/opentelemetry_instrumentation-0.50b0-py3-none-any.whl", hash = "sha256:b8f9fc8812de36e1c6dffa5bfc6224df258841fb387b6dfe5df15099daa10630", size = 30728, upload-time = "2024-12-11T17:03:54.948Z" }, + { url = "https://files.pythonhosted.org/packages/43/53/5249ea860d417a26a3a6f1bdedfc0748c4f081a3adaec3d398bc0f7c6a71/opentelemetry_api-1.29.0-py3-none-any.whl", hash = "sha256:5fcd94c4141cc49c736271f3e1efb777bebe9cc535759c54c936cca4f1b312b8", size = 64304, upload-time = "2024-12-11T17:01:48.691Z" }, ] [[package]] -name = "opentelemetry-instrumentation-asgi" -version = "0.50b0" +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.29.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "asgiref" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-instrumentation" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "opentelemetry-util-http" }, + { name = "opentelemetry-proto" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/cc/a7b2fd243c6d2621803092eba62e450071b6752dfe4f64f530bbfd91a328/opentelemetry_instrumentation_asgi-0.50b0.tar.gz", hash = "sha256:3ca4cb5616ae6a3e8ce86e7d5c360a8d8cc8ed722cf3dc8a5e44300774e87d49", size = 24105, upload-time = "2024-12-11T17:05:23.773Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/58/f7fd7eaf592b2521999a4271ab3ce1c82fe37fe9b0dc25c348398d95d66a/opentelemetry_exporter_otlp_proto_common-1.29.0.tar.gz", hash = "sha256:e7c39b5dbd1b78fe199e40ddfe477e6983cb61aa74ba836df09c3869a3e3e163", size = 19133, upload-time = "2024-12-11T17:02:27.092Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/81/0899c6b56b1023835f266d909250d439174afa0c34ed5944c5021d3da263/opentelemetry_instrumentation_asgi-0.50b0-py3-none-any.whl", hash = "sha256:2ba1297f746e55dec5a17fe825689da0613662fb25c004c3965a6c54b1d5be22", size = 16304, upload-time = "2024-12-11T17:04:03.555Z" }, + { url = "https://files.pythonhosted.org/packages/9e/75/7609bda3d72bf307839570b226180513e854c01443ebe265ed732a4980fc/opentelemetry_exporter_otlp_proto_common-1.29.0-py3-none-any.whl", hash = "sha256:a9d7376c06b4da9cf350677bcddb9618ed4b8255c3f6476975f5e38274ecd3aa", size = 18459, upload-time = "2024-12-11T17:01:54.817Z" }, ] [[package]] -name = "opentelemetry-instrumentation-fastapi" -version = "0.50b0" +name = "opentelemetry-exporter-otlp-proto-grpc" +version = "1.29.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "deprecated" }, + { name = "googleapis-common-protos" }, + { name = "grpcio" }, { name = "opentelemetry-api" }, - { name = "opentelemetry-instrumentation" }, - { name = "opentelemetry-instrumentation-asgi" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "opentelemetry-util-http" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8d/f8/1917b0b3e414e23c7d71c9a33f0ce020f94bc47d22a30f54ace704e07588/opentelemetry_instrumentation_fastapi-0.50b0.tar.gz", hash = "sha256:16b9181682136da210295def2bb304a32fb9bdee9a935cdc9da43567f7c1149e", size = 19214, upload-time = "2024-12-11T17:05:42.062Z" } +sdist = { url = "https://files.pythonhosted.org/packages/41/aa/b3f2190613141f35fe15145bf438334fdd1eac8aeeee4f7ecbc887999443/opentelemetry_exporter_otlp_proto_grpc-1.29.0.tar.gz", hash = "sha256:3d324d07d64574d72ed178698de3d717f62a059a93b6b7685ee3e303384e73ea", size = 26224, upload-time = "2024-12-11T17:02:28.911Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/d6/37784bb30b213e2dd6838b9f96c2940907022c1b75ef1ff18a99afe42433/opentelemetry_instrumentation_fastapi-0.50b0-py3-none-any.whl", hash = "sha256:8f03b738495e4705fbae51a2826389c7369629dace89d0f291c06ffefdff5e52", size = 12079, upload-time = "2024-12-11T17:04:26.15Z" }, + { url = "https://files.pythonhosted.org/packages/f2/de/4b4127a25d1594851d99032f3a9acb09cb512d11edec713410fb906607f4/opentelemetry_exporter_otlp_proto_grpc-1.29.0-py3-none-any.whl", hash = "sha256:5a2a3a741a2543ed162676cf3eefc2b4150e6f4f0a193187afb0d0e65039c69c", size = 18520, upload-time = "2024-12-11T17:01:57.001Z" }, ] [[package]] name = "opentelemetry-proto" -version = "1.15.0" +version = "1.29.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/80/b3b2a98039574e57b6b15982219ae025d55f8c46d50dde258865ce5601b4/opentelemetry_proto-1.15.0.tar.gz", hash = "sha256:9c4008e40ac8cab359daac283fbe7002c5c29c77ea2674ad5626a249e64e0101", size = 35713, upload-time = "2022-12-09T22:28:55.409Z" } +sdist = { url = "https://files.pythonhosted.org/packages/80/52/fd3b3d79e1b00ad2dcac92db6885e49bedbf7a6828647954e4952d653132/opentelemetry_proto-1.29.0.tar.gz", hash = "sha256:3c136aa293782e9b44978c738fff72877a4b78b5d21a64e879898db7b2d93e5d", size = 34320, upload-time = "2024-12-11T17:02:44.709Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/56/8343d94af8f32594f6b0bd273f72a40e430fb5970a353237af53af5d3031/opentelemetry_proto-1.15.0-py3-none-any.whl", hash = "sha256:044b6d044b4d10530f250856f933442b8753a17f94ae37c207607f733fb9a844", size = 52616, upload-time = "2022-12-09T22:28:30.03Z" }, + { url = "https://files.pythonhosted.org/packages/bd/66/a500e38ee322d89fce61c74bd7769c8ef3bebc6c2f43fda5f3fc3441286d/opentelemetry_proto-1.29.0-py3-none-any.whl", hash = "sha256:495069c6f5495cbf732501cdcd3b7f60fda2b9d3d4255706ca99b7ca8dec53ff", size = 55818, upload-time = "2024-12-11T17:02:14.03Z" }, ] [[package]] @@ -3078,36 +2640,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/da/fb/dc15fad105450a015e913cfa4f5c27b6a5f1bea8fb649f8cae11e699c8af/opentelemetry_semantic_conventions-0.50b0-py3-none-any.whl", hash = "sha256:e87efba8fdb67fb38113efea6a349531e75ed7ffc01562f65b802fcecb5e115e", size = 166602, upload-time = "2024-12-11T17:02:19.504Z" }, ] -[[package]] -name = "opentelemetry-util-http" -version = "0.50b0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/10/ce3f0d1157cedbd819194f0b27a6bbb7c19a8bceb3941e4a4775014076cf/opentelemetry_util_http-0.50b0.tar.gz", hash = "sha256:dc4606027e1bc02aabb9533cc330dd43f874fca492e4175c31d7154f341754af", size = 7859, upload-time = "2024-12-11T17:06:14.206Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8a/9e1b54f50d1fddebbeac9a9b0632f8db6ece7add904fb593ee2e268ee4de/opentelemetry_util_http-0.50b0-py3-none-any.whl", hash = "sha256:21f8aedac861ffa3b850f8c0a6c373026189eb8630ac6e14a2bf8c55695cc090", size = 6942, upload-time = "2024-12-11T17:05:13.342Z" }, -] - -[[package]] -name = "oracledb" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/2d/8336527f248dbeb7183b7b4bfafe3499119c467236f8916ce0ec3b8ef2b6/oracledb-3.2.0.tar.gz", hash = "sha256:9bf9f1c93e53142b33d1c5ebf5ababeebd2062a01d5ead68bbb640439ecf2223", size = 872574, upload-time = "2025-06-26T21:57:13.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/02/8279be85defe274a5dbc565c27f927d7d772117c070008853d75d4d780a8/oracledb-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:42e936190c5c76b115e2803e9c51a416a895c31ca551bc154b8c52121a84ee78", size = 3985060, upload-time = "2025-06-26T21:57:30.753Z" }, - { url = "https://files.pythonhosted.org/packages/38/a2/ce33fca6a15b3357d00c92bffcfa614b2d9f008d8e997f57e0302c760fb6/oracledb-3.2.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a87a331df19a84cad3d50a99cd505f8d0ec500e5e22438a025bd66e037b20715", size = 2507408, upload-time = "2025-06-26T21:57:33.34Z" }, - { url = "https://files.pythonhosted.org/packages/17/1b/dcaeb174ca777f28e05ac3d862cb468ce4b0a9c36900aa5f12ecbf29029f/oracledb-3.2.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b62f0c018e437b91254f019715a5fd5daafcf3182afee86ccd9d0f3dac75c0a7", size = 2687910, upload-time = "2025-06-26T21:57:36.173Z" }, - { url = "https://files.pythonhosted.org/packages/c2/f6/a575191c027b89486947597a7b6ae9c2abbc05eae2b79de037a6039ae455/oracledb-3.2.0-cp311-cp311-win32.whl", hash = "sha256:01477e65f129f8927ef64cd4b48d68646fc0115e1e95484dac5b82dd9da7b98b", size = 1548061, upload-time = "2025-06-26T21:57:38.273Z" }, - { url = "https://files.pythonhosted.org/packages/4e/ec/a9b5488858d3b45213ce03f442c5cdf5aef356269071b84caecadb326e29/oracledb-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:a1dc529f06a95ca3560d233609c266c17e828a08a70b8a434e2c3fe7000825eb", size = 1891446, upload-time = "2025-06-26T21:57:40.737Z" }, - { url = "https://files.pythonhosted.org/packages/56/d1/04632c2fab7c9ab91c68630eb221e17019e74d5b023badc0c191e83119cf/oracledb-3.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:1c2658983520b460776e74c75bb50e51a78e8ab743b64adc844a26a3a8a0bc7c", size = 3959613, upload-time = "2025-06-26T21:57:43.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/de/ebb82b6193583d0c7f13f908756d44bd2c03207b501457773b0793018231/oracledb-3.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c7a599ffe3238824951948992ab6b4532a0c1d4b33900d412f738a7da476d47", size = 2336800, upload-time = "2025-06-26T21:57:45.997Z" }, - { url = "https://files.pythonhosted.org/packages/1e/f5/f81f72fac3cfb52fc18965d4d07d76e26103c2cc60641a796b9618904b54/oracledb-3.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9388ad0e09dc4030cd62779acc0ae4e9dfd338da7d30c72768fb0589461485ff", size = 2509427, upload-time = "2025-06-26T21:57:48.686Z" }, - { url = "https://files.pythonhosted.org/packages/02/ad/ded50edb5010b27173f203421f69f90e5f00acaf5686ccd4f7963e1c695b/oracledb-3.2.0-cp312-cp312-win32.whl", hash = "sha256:94ac95e52e6f4a9394408aba6cc5f90581219ecb872d450b2a80df9aa3cc4216", size = 1511775, upload-time = "2025-06-26T21:57:50.474Z" }, - { url = "https://files.pythonhosted.org/packages/5f/75/684d2e18d57d72abf85366e8e1f61aaa2e6b15c71bf95f5bb6e9d7e0c9a5/oracledb-3.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:a367604d091ee82c9e3f6d97e34b8ec919646209bda78337f6156b76252dd024", size = 1850296, upload-time = "2025-06-26T21:57:52.649Z" }, -] - [[package]] name = "orjson" version = "3.10.14" @@ -3188,20 +2720,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248, upload-time = "2024-09-20T13:09:23.137Z" }, ] -[[package]] -name = "passlib" -version = "1.7.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b6/06/9da9ee59a67fae7761aab3ccc84fa4f3f33f125b370f1ccdb915bf967c11/passlib-1.7.4.tar.gz", hash = "sha256:defd50f72b65c5402ab2c573830a6978e5f202ad0d984793c8dde2c4152ebe04", size = 689844, upload-time = "2020-10-08T19:00:52.121Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/a4/ab6b7589382ca3df236e03faa71deac88cae040af60c071a78d254a62172/passlib-1.7.4-py2.py3-none-any.whl", hash = "sha256:aa6bca462b8d8bda89c70b382f0c298a20b5560af6cbfa2dce410c0a2fb669f1", size = 525554, upload-time = "2020-10-08T19:00:49.856Z" }, -] - -[package.optional-dependencies] -bcrypt = [ - { name = "bcrypt" }, -] - [[package]] name = "pathspec" version = "0.12.1" @@ -3230,78 +2748,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8c/32/de329eb77c16ebe2d52971d55954e4c34c7302ab285df8897b8d8dfd705e/peewee_migrate-1.12.2-py3-none-any.whl", hash = "sha256:2930bf83ef802cdb5fb123116c5eb87cbf3756cb27674f674923be6bb27dabee", size = 18580, upload-time = "2023-08-07T11:40:02.468Z" }, ] -[[package]] -name = "pgvector" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e2/40/296ffb7f97fc7ec7b7c34f46861a519c576d561fd31455fc75c5ce2fa8db/pgvector-0.4.0.tar.gz", hash = "sha256:f909f8e8081b57fb8a2442c36c3a1e521228d0d4ad66100c28c674806ff62688", size = 30688, upload-time = "2025-03-16T00:56:01.321Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/fb/77d29e98b36f1a0c6f770157001d3747557cae46f0e6f6d282461e554b80/pgvector-0.4.0-py3-none-any.whl", hash = "sha256:9d3e0c27f676c61d2fd4270ac1bc520d39b947b199200babe4a56d6d00c74a07", size = 27027, upload-time = "2025-03-16T00:55:59.948Z" }, -] - [[package]] name = "pillow" -version = "11.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707, upload-time = "2025-04-12T17:50:03.289Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/08/3fbf4b98924c73037a8e8b4c2c774784805e0fb4ebca6c5bb60795c40125/pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70", size = 3198450, upload-time = "2025-04-12T17:47:37.135Z" }, - { url = "https://files.pythonhosted.org/packages/84/92/6505b1af3d2849d5e714fc75ba9e69b7255c05ee42383a35a4d58f576b16/pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf", size = 3030550, upload-time = "2025-04-12T17:47:39.345Z" }, - { url = "https://files.pythonhosted.org/packages/3c/8c/ac2f99d2a70ff966bc7eb13dacacfaab57c0549b2ffb351b6537c7840b12/pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7", size = 4415018, upload-time = "2025-04-12T17:47:41.128Z" }, - { url = "https://files.pythonhosted.org/packages/1f/e3/0a58b5d838687f40891fff9cbaf8669f90c96b64dc8f91f87894413856c6/pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8", size = 4498006, upload-time = "2025-04-12T17:47:42.912Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/6ba14718135f08fbfa33308efe027dd02b781d3f1d5c471444a395933aac/pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600", size = 4517773, upload-time = "2025-04-12T17:47:44.611Z" }, - { url = "https://files.pythonhosted.org/packages/20/f2/805ad600fc59ebe4f1ba6129cd3a75fb0da126975c8579b8f57abeb61e80/pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788", size = 4607069, upload-time = "2025-04-12T17:47:46.46Z" }, - { url = "https://files.pythonhosted.org/packages/71/6b/4ef8a288b4bb2e0180cba13ca0a519fa27aa982875882392b65131401099/pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e", size = 4583460, upload-time = "2025-04-12T17:47:49.255Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/f29c705a09cbc9e2a456590816e5c234382ae5d32584f451c3eb41a62062/pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e", size = 4661304, upload-time = "2025-04-12T17:47:51.067Z" }, - { url = "https://files.pythonhosted.org/packages/6e/1a/c8217b6f2f73794a5e219fbad087701f412337ae6dbb956db37d69a9bc43/pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6", size = 2331809, upload-time = "2025-04-12T17:47:54.425Z" }, - { url = "https://files.pythonhosted.org/packages/e2/72/25a8f40170dc262e86e90f37cb72cb3de5e307f75bf4b02535a61afcd519/pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193", size = 2676338, upload-time = "2025-04-12T17:47:56.535Z" }, - { url = "https://files.pythonhosted.org/packages/06/9e/76825e39efee61efea258b479391ca77d64dbd9e5804e4ad0fa453b4ba55/pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7", size = 2414918, upload-time = "2025-04-12T17:47:58.217Z" }, - { url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185, upload-time = "2025-04-12T17:48:00.417Z" }, - { url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306, upload-time = "2025-04-12T17:48:02.391Z" }, - { url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121, upload-time = "2025-04-12T17:48:04.554Z" }, - { url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707, upload-time = "2025-04-12T17:48:06.831Z" }, - { url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921, upload-time = "2025-04-12T17:48:09.229Z" }, - { url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523, upload-time = "2025-04-12T17:48:11.631Z" }, - { url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836, upload-time = "2025-04-12T17:48:13.592Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390, upload-time = "2025-04-12T17:48:15.938Z" }, - { url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309, upload-time = "2025-04-12T17:48:17.885Z" }, - { url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768, upload-time = "2025-04-12T17:48:19.655Z" }, - { url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087, upload-time = "2025-04-12T17:48:21.991Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ad/2613c04633c7257d9481ab21d6b5364b59fc5d75faafd7cb8693523945a3/pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed", size = 3181734, upload-time = "2025-04-12T17:49:46.789Z" }, - { url = "https://files.pythonhosted.org/packages/a4/fd/dcdda4471ed667de57bb5405bb42d751e6cfdd4011a12c248b455c778e03/pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c", size = 2999841, upload-time = "2025-04-12T17:49:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/ac/89/8a2536e95e77432833f0db6fd72a8d310c8e4272a04461fb833eb021bf94/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd", size = 3437470, upload-time = "2025-04-12T17:49:50.831Z" }, - { url = "https://files.pythonhosted.org/packages/9d/8f/abd47b73c60712f88e9eda32baced7bfc3e9bd6a7619bb64b93acff28c3e/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076", size = 3460013, upload-time = "2025-04-12T17:49:53.278Z" }, - { url = "https://files.pythonhosted.org/packages/f6/20/5c0a0aa83b213b7a07ec01e71a3d6ea2cf4ad1d2c686cc0168173b6089e7/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b", size = 3527165, upload-time = "2025-04-12T17:49:55.164Z" }, - { url = "https://files.pythonhosted.org/packages/58/0e/2abab98a72202d91146abc839e10c14f7cf36166f12838ea0c4db3ca6ecb/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f", size = 3571586, upload-time = "2025-04-12T17:49:57.171Z" }, - { url = "https://files.pythonhosted.org/packages/21/2c/5e05f58658cf49b6667762cca03d6e7d85cededde2caf2ab37b81f80e574/pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044", size = 2674751, upload-time = "2025-04-12T17:49:59.628Z" }, -] - -[[package]] -name = "pinecone" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "pinecone-plugin-interface" }, - { name = "python-dateutil" }, - { name = "typing-extensions" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/40/e0/3584dcde7f2cb299b4deb5cc0491f2c9c130c7a72c1d4691fe2c9c3a3613/pinecone-6.0.2.tar.gz", hash = "sha256:9c2e74be8b3abe76909da9b4dae61bced49aade51f6fc39b87edb97a1f8df0e4", size = 175104, upload-time = "2025-03-13T21:05:18.763Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/c7/2bc1210aa51528b9ba75aede1f169998f50942cc47cdd82dd2dbcba4faa5/pinecone-6.0.2-py3-none-any.whl", hash = "sha256:a85fa36d7d1451e7b7563ccfc7e3e2dadd39b33e5d53b2882468db8514ab8847", size = 421874, upload-time = "2025-03-13T21:05:17.11Z" }, -] - -[[package]] -name = "pinecone-plugin-interface" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/fb/e8a4063264953ead9e2b24d9b390152c60f042c951c47f4592e9996e57ff/pinecone_plugin_interface-0.0.7.tar.gz", hash = "sha256:b8e6675e41847333aa13923cc44daa3f85676d7157324682dc1640588a982846", size = 3370, upload-time = "2024-06-05T01:57:52.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/1d/a21fdfcd6d022cb64cef5c2a29ee6691c6c103c4566b41646b080b7536a5/pinecone_plugin_interface-0.0.7-py3-none-any.whl", hash = "sha256:875857ad9c9fc8bbc074dbe780d187a2afd21f5bfe0f3b08601924a61ef1bba8", size = 6249, upload-time = "2024-06-05T01:57:50.583Z" }, +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" }, + { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" }, + { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" }, + { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" }, + { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" }, + { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" }, + { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" }, + { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" }, + { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" }, + { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" }, + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" }, + { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" }, + { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" }, + { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" }, + { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" }, ] [[package]] @@ -3313,24 +2794,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439, upload-time = "2024-09-17T19:06:49.212Z" }, ] -[[package]] -name = "playwright" -version = "1.49.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet" }, - { name = "pyee" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/be/01025581052e43eb698092c4328d7497ca62bcb5c83f15a611d4a71b4b92/playwright-1.49.1-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:1041ffb45a0d0bc44d698d3a5aa3ac4b67c9bd03540da43a0b70616ad52592b8", size = 39559859, upload-time = "2024-12-10T17:32:14.907Z" }, - { url = "https://files.pythonhosted.org/packages/79/25/ef1010a42cc7d576282015d983c5451d73e369b198b6eb32a177fae281f8/playwright-1.49.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:9f38ed3d0c1f4e0a6d1c92e73dd9a61f8855133249d6f0cec28648d38a7137be", size = 38808973, upload-time = "2024-12-10T17:32:22.516Z" }, - { url = "https://files.pythonhosted.org/packages/70/4b/3930cf10f303a10d493a382e4448aaff898b4065698b3b8d92f902e53e08/playwright-1.49.1-py3-none-macosx_11_0_universal2.whl", hash = "sha256:3be48c6d26dc819ca0a26567c1ae36a980a0303dcd4249feb6f59e115aaddfb8", size = 39559863, upload-time = "2024-12-10T17:32:29.12Z" }, - { url = "https://files.pythonhosted.org/packages/9a/c1/ea765e72a746dc7ec2ce155ffea29d454e7171db78f3c09185e888387246/playwright-1.49.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:753ca90ee31b4b03d165cfd36e477309ebf2b4381953f2a982ff612d85b147d2", size = 44163300, upload-time = "2024-12-10T17:32:35.647Z" }, - { url = "https://files.pythonhosted.org/packages/5a/52/95efac704bf36b770a2522d88a6dee298042845d10bfb35f7ca0fcc36d91/playwright-1.49.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd9bc8dab37aa25198a01f555f0a2e2c3813fe200fef018ac34dfe86b34994b9", size = 43744353, upload-time = "2024-12-10T17:32:43.189Z" }, - { url = "https://files.pythonhosted.org/packages/f9/97/a3fccc9aaa6da83890772e9980703b0ea6b1e1ad42042fb50df3aef6c641/playwright-1.49.1-py3-none-win32.whl", hash = "sha256:43b304be67f096058e587dac453ece550eff87b8fbed28de30f4f022cc1745bb", size = 34060663, upload-time = "2024-12-10T17:32:49.904Z" }, - { url = "https://files.pythonhosted.org/packages/71/a9/bd88ac0bd498c91aab3aba2e393d1fa59f72a7243e9265ccbf4861ca4f64/playwright-1.49.1-py3-none-win_amd64.whl", hash = "sha256:47b23cb346283278f5b4d1e1990bcb6d6302f80c0aa0ca93dd0601a1400191df", size = 34060667, upload-time = "2024-12-10T17:32:56.459Z" }, -] - [[package]] name = "pluggy" version = "1.5.0" @@ -3340,18 +2803,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556, upload-time = "2024-04-20T21:34:40.434Z" }, ] -[[package]] -name = "portalocker" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891, upload-time = "2024-07-13T23:15:34.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/fb/a70a4214956182e0d7a9099ab17d50bfcba1056188e9b14f35b9e2b62a0d/portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf", size = 18423, upload-time = "2024-07-13T23:15:32.602Z" }, -] - [[package]] name = "posthog" version = "3.8.3" @@ -3439,16 +2890,16 @@ wheels = [ [[package]] name = "protobuf" -version = "4.25.5" +version = "5.29.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/67/dd/48d5fdb68ec74d70fabcc252e434492e56f70944d9f17b6a15e3746d2295/protobuf-4.25.5.tar.gz", hash = "sha256:7f8249476b4a9473645db7f8ab42b02fe1488cbe5fb72fddd445e0665afd8584", size = 380315, upload-time = "2024-09-18T22:25:43.093Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/35/1b3c5a5e6107859c4ca902f4fbb762e48599b78129a05d20684fef4a4d04/protobuf-4.25.5-cp310-abi3-win32.whl", hash = "sha256:5e61fd921603f58d2f5acb2806a929b4675f8874ff5f330b7d6f7e2e784bbcd8", size = 392457, upload-time = "2024-09-18T22:25:26.449Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ad/bf3f358e90b7e70bf7fb520702cb15307ef268262292d3bdb16ad8ebc815/protobuf-4.25.5-cp310-abi3-win_amd64.whl", hash = "sha256:4be0571adcbe712b282a330c6e89eae24281344429ae95c6d85e79e84780f5ea", size = 413449, upload-time = "2024-09-18T22:25:29.409Z" }, - { url = "https://files.pythonhosted.org/packages/51/49/d110f0a43beb365758a252203c43eaaad169fe7749da918869a8c991f726/protobuf-4.25.5-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:b2fde3d805354df675ea4c7c6338c1aecd254dfc9925e88c6d31a2bcb97eb173", size = 394248, upload-time = "2024-09-18T22:25:30.727Z" }, - { url = "https://files.pythonhosted.org/packages/c6/ab/0f384ca0bc6054b1a7b6009000ab75d28a5506e4459378b81280ae7fd358/protobuf-4.25.5-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:919ad92d9b0310070f8356c24b855c98df2b8bd207ebc1c0c6fcc9ab1e007f3d", size = 293717, upload-time = "2024-09-18T22:25:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/05/a6/094a2640be576d760baa34c902dcb8199d89bce9ed7dd7a6af74dcbbd62d/protobuf-4.25.5-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:fe14e16c22be926d3abfcb500e60cab068baf10b542b8c858fa27e098123e331", size = 294635, upload-time = "2024-09-18T22:25:33.49Z" }, - { url = "https://files.pythonhosted.org/packages/33/90/f198a61df8381fb43ae0fe81b3d2718e8dcc51ae8502c7657ab9381fbc4f/protobuf-4.25.5-py3-none-any.whl", hash = "sha256:0aebecb809cae990f8129ada5ca273d9d670b76d9bfc9b1809f0a9c02b7dbf41", size = 156467, upload-time = "2024-09-18T22:25:41.606Z" }, + { url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" }, + { url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" }, + { url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" }, + { url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" }, + { url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" }, + { url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" }, ] [[package]] @@ -3466,76 +2917,39 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/d7/7831438e6c3ebbfa6e01a927127a6cb42ad3ab844247f3c5b96bea25d73d/psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649", size = 254444, upload-time = "2024-12-19T18:22:11.335Z" }, ] -[[package]] -name = "psycopg2-binary" -version = "2.9.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/07/e720e53bfab016ebcc34241695ccc06a9e3d91ba19b40ca81317afbdc440/psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c", size = 384973, upload-time = "2023-10-03T12:48:55.128Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/ac/702d300f3df169b9d0cbef0340d9f34a78bc18dc2dbafbcb39ff0f165cf8/psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26", size = 2822581, upload-time = "2023-10-03T12:46:30.64Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1f/a6cf0cdf944253f7c45d90fbc876cc8bed5cc9942349306245715c0d88d6/psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f", size = 2552633, upload-time = "2023-10-03T12:46:32.808Z" }, - { url = "https://files.pythonhosted.org/packages/81/0b/3adf561107c865928455891156d1dde5325253f7f4316fe56cd2c3f73570/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2", size = 2851075, upload-time = "2023-10-03T12:46:35.138Z" }, - { url = "https://files.pythonhosted.org/packages/f7/98/c2fedcbf0a9607519a010dcf88571138b2251062dbde3610cdba5ba1eee1/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0", size = 3080509, upload-time = "2023-10-03T12:46:37.44Z" }, - { url = "https://files.pythonhosted.org/packages/c2/05/81e8bc7fca95574c9323e487d9ce1b58a4cfcc17f89b8fe843af46361211/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53", size = 3264303, upload-time = "2023-10-03T12:46:40.73Z" }, - { url = "https://files.pythonhosted.org/packages/ce/85/62825cabc6aad53104b7b6d12eb2ad74737d268630032d07b74d4444cb72/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be", size = 3019515, upload-time = "2023-10-03T12:46:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/9ca2b8e01a0912c9a14234fd5df7a241a1e44778c5797bf4b8eaa8dc3d3a/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27", size = 2355892, upload-time = "2023-10-03T12:46:45.632Z" }, - { url = "https://files.pythonhosted.org/packages/73/17/ba28bb0022db5e2015a82d2df1c4b0d419c37fa07a588b3aff3adc4939f6/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359", size = 2534903, upload-time = "2023-10-03T12:46:47.934Z" }, - { url = "https://files.pythonhosted.org/packages/3b/92/b463556409cdc12791cd8b1dae0072bf8efe817ef68b7ea3d9cf7d0e5656/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2", size = 2486597, upload-time = "2023-10-03T12:46:50.598Z" }, - { url = "https://files.pythonhosted.org/packages/92/57/96576e07132d7f7a1ac1df939575e6fdd8951aea337ee152b586bb51a971/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc", size = 2454908, upload-time = "2023-10-03T12:46:52.903Z" }, - { url = "https://files.pythonhosted.org/packages/7c/ae/cedd56e1f4a2b0e37213283caf3733a875c4c76f3372241e19c0d2a87355/psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d", size = 1024240, upload-time = "2023-10-03T12:46:55.009Z" }, - { url = "https://files.pythonhosted.org/packages/25/1f/7ae31759142999a8d06b3e250c1346c4abcdcada8fa884376775dc1de686/psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417", size = 1163655, upload-time = "2023-10-03T12:46:57.038Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d0/5f2db14e7b53552276ab613399a83f83f85b173a862d3f20580bc7231139/psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf", size = 2823784, upload-time = "2023-10-03T12:47:00.404Z" }, - { url = "https://files.pythonhosted.org/packages/18/ca/da384fd47233e300e3e485c90e7aab5d7def896d1281239f75901faf87d4/psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d", size = 2553308, upload-time = "2023-11-01T10:40:33.984Z" }, - { url = "https://files.pythonhosted.org/packages/50/66/fa53d2d3d92f6e1ef469d92afc6a4fe3f6e8a9a04b687aa28fb1f1d954ee/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212", size = 2851283, upload-time = "2023-10-03T12:47:02.736Z" }, - { url = "https://files.pythonhosted.org/packages/04/37/2429360ac5547378202db14eec0dde76edbe1f6627df5a43c7e164922859/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493", size = 3081839, upload-time = "2023-10-03T12:47:05.027Z" }, - { url = "https://files.pythonhosted.org/packages/62/2a/c0530b59d7e0d09824bc2102ecdcec0456b8ca4d47c0caa82e86fce3ed4c/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996", size = 3264488, upload-time = "2023-10-03T12:47:08.962Z" }, - { url = "https://files.pythonhosted.org/packages/19/57/9f172b900795ea37246c78b5f52e00f4779984370855b3e161600156906d/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119", size = 3020700, upload-time = "2023-10-03T12:47:12.23Z" }, - { url = "https://files.pythonhosted.org/packages/94/68/1176fc14ea76861b7b8360be5176e87fb20d5091b137c76570eb4e237324/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba", size = 2355968, upload-time = "2023-10-03T12:47:14.817Z" }, - { url = "https://files.pythonhosted.org/packages/70/bb/aec2646a705a09079d008ce88073401cd61fc9b04f92af3eb282caa3a2ec/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07", size = 2536101, upload-time = "2023-10-03T12:47:17.454Z" }, - { url = "https://files.pythonhosted.org/packages/14/33/12818c157e333cb9d9e6753d1b2463b6f60dbc1fade115f8e4dc5c52cac4/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb", size = 2487064, upload-time = "2023-10-03T12:47:20.717Z" }, - { url = "https://files.pythonhosted.org/packages/56/a2/7851c68fe8768f3c9c246198b6356ee3e4a8a7f6820cc798443faada3400/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe", size = 2456257, upload-time = "2023-10-03T12:47:23.004Z" }, - { url = "https://files.pythonhosted.org/packages/6f/ee/3ba07c6dc7c3294e717e94720da1597aedc82a10b1b180203ce183d4631a/psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93", size = 1024709, upload-time = "2023-10-28T09:37:24.991Z" }, - { url = "https://files.pythonhosted.org/packages/7b/08/9c66c269b0d417a0af9fb969535f0371b8c538633535a7a6a5ca3f9231e2/psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab", size = 1163864, upload-time = "2023-10-28T09:37:28.155Z" }, -] - -[[package]] -name = "py-partiql-parser" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/a1/0a2867e48b232b4f82c4929ef7135f2a5d72c3886b957dccf63c70aa2fcb/py_partiql_parser-0.6.1.tar.gz", hash = "sha256:8583ff2a0e15560ef3bc3df109a7714d17f87d81d33e8c38b7fed4e58a63215d", size = 17120, upload-time = "2024-12-25T22:06:41.327Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/97/84/0e410c20bbe9a504fc56e97908f13261c2b313d16cbb3b738556166f044a/py_partiql_parser-0.6.1-py2.py3-none-any.whl", hash = "sha256:ff6a48067bff23c37e9044021bf1d949c83e195490c17e020715e927fe5b2456", size = 23520, upload-time = "2024-12-25T22:06:39.106Z" }, -] - [[package]] name = "pyarrow" -version = "19.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/01/fe1fd04744c2aa038e5a11c7a4adb3d62bce09798695e54f7274b5977134/pyarrow-19.0.0.tar.gz", hash = "sha256:8d47c691765cf497aaeed4954d226568563f1b3b74ff61139f2d77876717084b", size = 1129096, upload-time = "2025-01-16T04:24:25.844Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/42/fba3a35bef5833bf88ed35e6a810dc1781236e1d4f808d2df824a7d21819/pyarrow-19.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8e3a839bf36ec03b4315dc924d36dcde5444a50066f1c10f8290293c0427b46a", size = 30711936, upload-time = "2025-01-16T04:20:24.904Z" }, - { url = "https://files.pythonhosted.org/packages/88/7a/0da93a3eaaf251a30e32f3221e874263cdcd366c2cd6b7c05293aad91152/pyarrow-19.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:ce42275097512d9e4e4a39aade58ef2b3798a93aa3026566b7892177c266f735", size = 32133182, upload-time = "2025-01-16T04:20:30.315Z" }, - { url = "https://files.pythonhosted.org/packages/2f/df/fe43b1c50d3100d0de53f988344118bc20362d0de005f8a407454fa565f8/pyarrow-19.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9348a0137568c45601b031a8d118275069435f151cbb77e6a08a27e8125f59d4", size = 41145489, upload-time = "2025-01-16T04:20:37.336Z" }, - { url = "https://files.pythonhosted.org/packages/45/bb/6f73b41b342a0342f2516a02db4aa97a4f9569cc35482a5c288090140cd4/pyarrow-19.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a0144a712d990d60f7f42b7a31f0acaccf4c1e43e957f7b1ad58150d6f639c1", size = 42177823, upload-time = "2025-01-16T04:20:44.23Z" }, - { url = "https://files.pythonhosted.org/packages/23/7b/f038a96f421e453a71bd7a0f78d62b1b2ae9bcac06ed51179ca532e6a0a2/pyarrow-19.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:2a1a109dfda558eb011e5f6385837daffd920d54ca00669f7a11132d0b1e6042", size = 40530609, upload-time = "2025-01-16T04:20:52.991Z" }, - { url = "https://files.pythonhosted.org/packages/b8/39/a2a6714b471c000e6dd6af4495dce00d7d1332351b8e3170dfb9f91dad1f/pyarrow-19.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:be686bf625aa7b9bada18defb3a3ea3981c1099697239788ff111d87f04cd263", size = 42081534, upload-time = "2025-01-16T04:21:02.925Z" }, - { url = "https://files.pythonhosted.org/packages/6c/a3/8396fb06ca05d807e89980c177be26617aad15211ece3184e0caa730b8a6/pyarrow-19.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:239ca66d9a05844bdf5af128861af525e14df3c9591bcc05bac25918e650d3a2", size = 25281090, upload-time = "2025-01-16T04:21:09.976Z" }, - { url = "https://files.pythonhosted.org/packages/bc/2e/152885f5ef421e80dae68b9c133ab261934f93a6d5e16b61d79c0ed597fb/pyarrow-19.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:a7bbe7109ab6198688b7079cbad5a8c22de4d47c4880d8e4847520a83b0d1b68", size = 30667964, upload-time = "2025-01-16T04:21:15.594Z" }, - { url = "https://files.pythonhosted.org/packages/80/c2/08bbee9a8610a47c9a1466845f405baf53a639ddd947c5133d8ba13544b6/pyarrow-19.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:4624c89d6f777c580e8732c27bb8e77fd1433b89707f17c04af7635dd9638351", size = 32125039, upload-time = "2025-01-16T04:21:22.681Z" }, - { url = "https://files.pythonhosted.org/packages/d2/56/06994df823212f5688d3c8bf4294928b12c9be36681872853655724d28c6/pyarrow-19.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b6d3ce4288793350dc2d08d1e184fd70631ea22a4ff9ea5c4ff182130249d9b", size = 41140729, upload-time = "2025-01-16T04:21:31.655Z" }, - { url = "https://files.pythonhosted.org/packages/94/65/38ad577c98140a9db71e9e1e594b6adb58a7478a5afec6456a8ca2df7f70/pyarrow-19.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:450a7d27e840e4d9a384b5c77199d489b401529e75a3b7a3799d4cd7957f2f9c", size = 42202267, upload-time = "2025-01-16T04:21:37.523Z" }, - { url = "https://files.pythonhosted.org/packages/b6/1f/966b722251a7354114ccbb71cf1a83922023e69efd8945ebf628a851ec4c/pyarrow-19.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a08e2a8a039a3f72afb67a6668180f09fddaa38fe0d21f13212b4aba4b5d2451", size = 40505858, upload-time = "2025-01-16T04:21:43.639Z" }, - { url = "https://files.pythonhosted.org/packages/3b/5e/6bc81aa7fc9affc7d1c03b912fbcc984ca56c2a18513684da267715dab7b/pyarrow-19.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:f43f5aef2a13d4d56adadae5720d1fed4c1356c993eda8b59dace4b5983843c1", size = 42084973, upload-time = "2025-01-16T04:21:52.705Z" }, - { url = "https://files.pythonhosted.org/packages/53/c3/2f56da818b6a4758cbd514957c67bd0f078ebffa5390ee2e2bf0f9e8defc/pyarrow-19.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f672f5364b2d7829ef7c94be199bb88bf5661dd485e21d2d37de12ccb78a136", size = 25241976, upload-time = "2025-01-16T04:21:59.088Z" }, +version = "20.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/a2/b7930824181ceadd0c63c1042d01fa4ef63eee233934826a7a2a9af6e463/pyarrow-20.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:24ca380585444cb2a31324c546a9a56abbe87e26069189e14bdba19c86c049f0", size = 30856035, upload-time = "2025-04-27T12:28:40.78Z" }, + { url = "https://files.pythonhosted.org/packages/9b/18/c765770227d7f5bdfa8a69f64b49194352325c66a5c3bb5e332dfd5867d9/pyarrow-20.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:95b330059ddfdc591a3225f2d272123be26c8fa76e8c9ee1a77aad507361cfdb", size = 32309552, upload-time = "2025-04-27T12:28:47.051Z" }, + { url = "https://files.pythonhosted.org/packages/44/fb/dfb2dfdd3e488bb14f822d7335653092dde150cffc2da97de6e7500681f9/pyarrow-20.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f0fb1041267e9968c6d0d2ce3ff92e3928b243e2b6d11eeb84d9ac547308232", size = 41334704, upload-time = "2025-04-27T12:28:55.064Z" }, + { url = "https://files.pythonhosted.org/packages/58/0d/08a95878d38808051a953e887332d4a76bc06c6ee04351918ee1155407eb/pyarrow-20.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8ff87cc837601532cc8242d2f7e09b4e02404de1b797aee747dd4ba4bd6313f", size = 42399836, upload-time = "2025-04-27T12:29:02.13Z" }, + { url = "https://files.pythonhosted.org/packages/f3/cd/efa271234dfe38f0271561086eedcad7bc0f2ddd1efba423916ff0883684/pyarrow-20.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:7a3a5dcf54286e6141d5114522cf31dd67a9e7c9133d150799f30ee302a7a1ab", size = 40711789, upload-time = "2025-04-27T12:29:09.951Z" }, + { url = "https://files.pythonhosted.org/packages/46/1f/7f02009bc7fc8955c391defee5348f510e589a020e4b40ca05edcb847854/pyarrow-20.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a6ad3e7758ecf559900261a4df985662df54fb7fdb55e8e3b3aa99b23d526b62", size = 42301124, upload-time = "2025-04-27T12:29:17.187Z" }, + { url = "https://files.pythonhosted.org/packages/4f/92/692c562be4504c262089e86757a9048739fe1acb4024f92d39615e7bab3f/pyarrow-20.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6bb830757103a6cb300a04610e08d9636f0cd223d32f388418ea893a3e655f1c", size = 42916060, upload-time = "2025-04-27T12:29:24.253Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ec/9f5c7e7c828d8e0a3c7ef50ee62eca38a7de2fa6eb1b8fa43685c9414fef/pyarrow-20.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96e37f0766ecb4514a899d9a3554fadda770fb57ddf42b63d80f14bc20aa7db3", size = 44547640, upload-time = "2025-04-27T12:29:32.782Z" }, + { url = "https://files.pythonhosted.org/packages/54/96/46613131b4727f10fd2ffa6d0d6f02efcc09a0e7374eff3b5771548aa95b/pyarrow-20.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3346babb516f4b6fd790da99b98bed9708e3f02e734c84971faccb20736848dc", size = 25781491, upload-time = "2025-04-27T12:29:38.464Z" }, + { url = "https://files.pythonhosted.org/packages/a1/d6/0c10e0d54f6c13eb464ee9b67a68b8c71bcf2f67760ef5b6fbcddd2ab05f/pyarrow-20.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:75a51a5b0eef32727a247707d4755322cb970be7e935172b6a3a9f9ae98404ba", size = 30815067, upload-time = "2025-04-27T12:29:44.384Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e2/04e9874abe4094a06fd8b0cbb0f1312d8dd7d707f144c2ec1e5e8f452ffa/pyarrow-20.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:211d5e84cecc640c7a3ab900f930aaff5cd2702177e0d562d426fb7c4f737781", size = 32297128, upload-time = "2025-04-27T12:29:52.038Z" }, + { url = "https://files.pythonhosted.org/packages/31/fd/c565e5dcc906a3b471a83273039cb75cb79aad4a2d4a12f76cc5ae90a4b8/pyarrow-20.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ba3cf4182828be7a896cbd232aa8dd6a31bd1f9e32776cc3796c012855e1199", size = 41334890, upload-time = "2025-04-27T12:29:59.452Z" }, + { url = "https://files.pythonhosted.org/packages/af/a9/3bdd799e2c9b20c1ea6dc6fa8e83f29480a97711cf806e823f808c2316ac/pyarrow-20.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c3a01f313ffe27ac4126f4c2e5ea0f36a5fc6ab51f8726cf41fee4b256680bd", size = 42421775, upload-time = "2025-04-27T12:30:06.875Z" }, + { url = "https://files.pythonhosted.org/packages/10/f7/da98ccd86354c332f593218101ae56568d5dcedb460e342000bd89c49cc1/pyarrow-20.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a2791f69ad72addd33510fec7bb14ee06c2a448e06b649e264c094c5b5f7ce28", size = 40687231, upload-time = "2025-04-27T12:30:13.954Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1b/2168d6050e52ff1e6cefc61d600723870bf569cbf41d13db939c8cf97a16/pyarrow-20.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4250e28a22302ce8692d3a0e8ec9d9dde54ec00d237cff4dfa9c1fbf79e472a8", size = 42295639, upload-time = "2025-04-27T12:30:21.949Z" }, + { url = "https://files.pythonhosted.org/packages/b2/66/2d976c0c7158fd25591c8ca55aee026e6d5745a021915a1835578707feb3/pyarrow-20.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:89e030dc58fc760e4010148e6ff164d2f44441490280ef1e97a542375e41058e", size = 42908549, upload-time = "2025-04-27T12:30:29.551Z" }, + { url = "https://files.pythonhosted.org/packages/31/a9/dfb999c2fc6911201dcbf348247f9cc382a8990f9ab45c12eabfd7243a38/pyarrow-20.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6102b4864d77102dbbb72965618e204e550135a940c2534711d5ffa787df2a5a", size = 44557216, upload-time = "2025-04-27T12:30:36.977Z" }, + { url = "https://files.pythonhosted.org/packages/a0/8e/9adee63dfa3911be2382fb4d92e4b2e7d82610f9d9f668493bebaa2af50f/pyarrow-20.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:96d6a0a37d9c98be08f5ed6a10831d88d52cac7b13f5287f1e0f625a0de8062b", size = 25660496, upload-time = "2025-04-27T12:30:42.809Z" }, ] [[package]] name = "pyasn1" -version = "0.4.8" +version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a4/db/fffec68299e6d7bad3d504147f9094830b704527a7fc098b721d38cc7fa7/pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", size = 146820, upload-time = "2019-11-16T17:27:38.772Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/1e/a94a8d635fa3ce4cfc7f506003548d0a2447ae76fd5ca53932970fe3053f/pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", size = 77145, upload-time = "2019-11-16T17:27:11.07Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, ] [[package]] @@ -3550,6 +2964,63 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/89/bc88a6711935ba795a679ea6ebee07e128050d6382eaa35a0a47c8032bdc/pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd", size = 181537, upload-time = "2024-09-11T16:02:10.336Z" }, ] +[[package]] +name = "pybase64" +version = "1.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/14/43297a7b7f0c1bf0c00b596f754ee3ac946128c64d21047ccf9c9bbc5165/pybase64-1.4.2.tar.gz", hash = "sha256:46cdefd283ed9643315d952fe44de80dc9b9a811ce6e3ec97fd1827af97692d0", size = 137246, upload-time = "2025-07-27T13:08:57.808Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/fb/edaa56bbf04715efc3c36966cc0150e01d7a8336c3da182f850b7fd43d32/pybase64-1.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26284ef64f142067293347bcc9d501d2b5d44b92eab9d941cb10a085fb01c666", size = 38238, upload-time = "2025-07-27T13:02:44.224Z" }, + { url = "https://files.pythonhosted.org/packages/28/a4/ca1538e9adf08f5016b3543b0060c18aea9a6e805dd20712a197c509d90d/pybase64-1.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:52dd32fe5cbfd8af8f3f034a4a65ee61948c72e5c358bf69d59543fc0dbcf950", size = 31659, upload-time = "2025-07-27T13:02:45.445Z" }, + { url = "https://files.pythonhosted.org/packages/0b/8f/f9b49926a60848ba98350dd648227ec524fb78340b47a450c4dbaf24b1bb/pybase64-1.4.2-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:37f133e8c96427995480bb6d396d9d49e949a3e829591845bb6a5a7f215ca177", size = 68318, upload-time = "2025-07-27T13:02:46.644Z" }, + { url = "https://files.pythonhosted.org/packages/29/9b/6ed2dd2bc8007f33b8316d6366b0901acbdd5665b419c2893b3dd48708de/pybase64-1.4.2-cp311-cp311-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a6ee3874b0abbdd4c903d3989682a3f016fd84188622879f6f95a5dc5718d7e5", size = 71357, upload-time = "2025-07-27T13:02:47.937Z" }, + { url = "https://files.pythonhosted.org/packages/fb/69/be9ac8127da8d8339db7129683bd2975cecb0bf40a82731e1a492577a177/pybase64-1.4.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5c69f177b1e404b22b05802127d6979acf4cb57f953c7de9472410f9c3fdece7", size = 59817, upload-time = "2025-07-27T13:02:49.163Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a2/e3e09e000b509609276ee28b71beb0b61462d4a43b3e0db0a44c8652880c/pybase64-1.4.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:80c817e88ef2ca3cc9a285fde267690a1cb821ce0da4848c921c16f0fec56fda", size = 56639, upload-time = "2025-07-27T13:02:50.384Z" }, + { url = "https://files.pythonhosted.org/packages/01/70/ad7eff88aa4f1be06db705812e1f01749606933bf8fe9df553bb04b703e6/pybase64-1.4.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7a4bb6e7e45bfdaea0f2aaf022fc9a013abe6e46ccea31914a77e10f44098688", size = 59368, upload-time = "2025-07-27T13:02:51.883Z" }, + { url = "https://files.pythonhosted.org/packages/9d/82/0cd1b4bcd2a4da7805cfa04587be783bf9583b34ac16cadc29cf119a4fa2/pybase64-1.4.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2710a80d41a2b41293cb0e5b84b5464f54aa3f28f7c43de88784d2d9702b8a1c", size = 59981, upload-time = "2025-07-27T13:02:53.16Z" }, + { url = "https://files.pythonhosted.org/packages/3c/4c/8029a03468307dfaf0f9694d31830487ee43af5f8a73407004907724e8ac/pybase64-1.4.2-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:aa6122c8a81f6597e1c1116511f03ed42cf377c2100fe7debaae7ca62521095a", size = 54908, upload-time = "2025-07-27T13:02:54.363Z" }, + { url = "https://files.pythonhosted.org/packages/a1/8b/70bd0fe659e242efd0f60895a8ce1fe88e3a4084fd1be368974c561138c9/pybase64-1.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7e22b02505d64db308e9feeb6cb52f1d554ede5983de0befa59ac2d2ffb6a5f", size = 58650, upload-time = "2025-07-27T13:02:55.905Z" }, + { url = "https://files.pythonhosted.org/packages/64/ca/9c1d23cbc4b9beac43386a32ad53903c816063cef3f14c10d7c3d6d49a23/pybase64-1.4.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:edfe4a3c8c4007f09591f49b46a89d287ef5e8cd6630339536fe98ff077263c2", size = 52323, upload-time = "2025-07-27T13:02:57.192Z" }, + { url = "https://files.pythonhosted.org/packages/aa/29/a6292e9047248c8616dc53131a49da6c97a61616f80e1e36c73d7ef895fe/pybase64-1.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b79b4a53dd117ffbd03e96953f2e6bd2827bfe11afeb717ea16d9b0893603077", size = 68979, upload-time = "2025-07-27T13:02:58.594Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e0/cfec7b948e170395d8e88066e01f50e71195db9837151db10c14965d6222/pybase64-1.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fd9afa7a61d89d170607faf22287290045757e782089f0357b8f801d228d52c3", size = 58037, upload-time = "2025-07-27T13:02:59.753Z" }, + { url = "https://files.pythonhosted.org/packages/74/7e/0ac1850198c9c35ef631174009cee576f4d8afff3bf493ce310582976ab4/pybase64-1.4.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5c17b092e4da677a595178d2db17a5d2fafe5c8e418d46c0c4e4cde5adb8cff3", size = 54416, upload-time = "2025-07-27T13:03:00.978Z" }, + { url = "https://files.pythonhosted.org/packages/1b/45/b0b037f27e86c50e62d927f0bc1bde8b798dd55ab39197b116702e508d05/pybase64-1.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:120799274cf55f3f5bb8489eaa85142f26170564baafa7cf3e85541c46b6ab13", size = 56257, upload-time = "2025-07-27T13:03:02.201Z" }, + { url = "https://files.pythonhosted.org/packages/d2/0d/5034598aac56336d88fd5aaf6f34630330643b51d399336b8c788d798fc5/pybase64-1.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:522e4e712686acec2d25de9759dda0b0618cb9f6588523528bc74715c0245c7b", size = 70889, upload-time = "2025-07-27T13:03:03.437Z" }, + { url = "https://files.pythonhosted.org/packages/8a/3b/0645f21bb08ecf45635b624958b5f9e569069d31ecbf125dc7e0e5b83f60/pybase64-1.4.2-cp311-cp311-win32.whl", hash = "sha256:bfd828792982db8d787515535948c1e340f1819407c8832f94384c0ebeaf9d74", size = 33631, upload-time = "2025-07-27T13:03:05.194Z" }, + { url = "https://files.pythonhosted.org/packages/8f/08/24f8103c1f19e78761026cdd9f3b3be73239bc19cf5ab6fef0e8042d0bc6/pybase64-1.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7a9e89d40dbf833af481d1d5f1a44d173c9c4b56a7c8dba98e39a78ee87cfc52", size = 35781, upload-time = "2025-07-27T13:03:06.779Z" }, + { url = "https://files.pythonhosted.org/packages/66/cd/832fb035a0ea7eb53d776a5cfa961849e22828f6dfdfcdb9eb43ba3c0166/pybase64-1.4.2-cp311-cp311-win_arm64.whl", hash = "sha256:ce5809fa90619b03eab1cd63fec142e6cf1d361731a9b9feacf27df76c833343", size = 30903, upload-time = "2025-07-27T13:03:07.903Z" }, + { url = "https://files.pythonhosted.org/packages/28/6d/11ede991e800797b9f5ebd528013b34eee5652df93de61ffb24503393fa5/pybase64-1.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2c75d1388855b5a1015b65096d7dbcc708e7de3245dcbedeb872ec05a09326", size = 38326, upload-time = "2025-07-27T13:03:09.065Z" }, + { url = "https://files.pythonhosted.org/packages/fe/84/87f1f565f42e2397e2aaa2477c86419f5173c3699881c42325c090982f0a/pybase64-1.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6b621a972a01841368fdb9dedc55fd3c6e0c7217d0505ba3b1ebe95e7ef1b493", size = 31661, upload-time = "2025-07-27T13:03:10.295Z" }, + { url = "https://files.pythonhosted.org/packages/cb/2a/a24c810e7a61d2cc6f73fe9ee4872a03030887fa8654150901b15f376f65/pybase64-1.4.2-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f48c32ac6a16cbf57a5a96a073fef6ff7e3526f623cd49faa112b7f9980bafba", size = 68192, upload-time = "2025-07-27T13:03:11.467Z" }, + { url = "https://files.pythonhosted.org/packages/ee/87/d9baf98cbfc37b8657290ad4421f3a3c36aa0eafe4872c5859cfb52f3448/pybase64-1.4.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ace8b23093a6bb862477080d9059b784096ab2f97541e8bfc40d42f062875149", size = 71587, upload-time = "2025-07-27T13:03:12.719Z" }, + { url = "https://files.pythonhosted.org/packages/0b/89/3df043cc56ef3b91b7aa0c26ae822a2d7ec8da0b0fd7c309c879b0eb5988/pybase64-1.4.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1772c7532a7fb6301baea3dd3e010148dbf70cd1136a83c2f5f91bdc94822145", size = 59910, upload-time = "2025-07-27T13:03:14.266Z" }, + { url = "https://files.pythonhosted.org/packages/75/4f/6641e9edf37aeb4d4524dc7ba2168eff8d96c90e77f6283c2be3400ab380/pybase64-1.4.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:f86f7faddcba5cbfea475f8ab96567834c28bf09ca6c7c3d66ee445adac80d8f", size = 56701, upload-time = "2025-07-27T13:03:15.6Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7f/20d8ac1046f12420a0954a45a13033e75f98aade36eecd00c64e3549b071/pybase64-1.4.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:0b8c8e275b5294089f314814b4a50174ab90af79d6a4850f6ae11261ff6a7372", size = 59288, upload-time = "2025-07-27T13:03:16.823Z" }, + { url = "https://files.pythonhosted.org/packages/17/ea/9c0ca570e3e50b3c6c3442e280c83b321a0464c86a9db1f982a4ff531550/pybase64-1.4.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:864d85a0470c615807ae8b97d724d068b940a2d10ac13a5f1b9e75a3ce441758", size = 60267, upload-time = "2025-07-27T13:03:18.132Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46894929d71ccedebbfb0284173b0fea96bc029cd262654ba8451a7035d6/pybase64-1.4.2-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:47254d97ed2d8351e30ecfdb9e2414547f66ba73f8a09f932c9378ff75cd10c5", size = 54801, upload-time = "2025-07-27T13:03:19.669Z" }, + { url = "https://files.pythonhosted.org/packages/6a/1e/02c95218ea964f0b2469717c2c69b48e63f4ca9f18af01a5b2a29e4c1216/pybase64-1.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:264b65ecc4f0ee73f3298ab83bbd8008f7f9578361b8df5b448f985d8c63e02a", size = 58599, upload-time = "2025-07-27T13:03:20.951Z" }, + { url = "https://files.pythonhosted.org/packages/15/45/ccc21004930789b8fb439d43e3212a6c260ccddb2bf450c39a20db093f33/pybase64-1.4.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:fbcc2b30cd740c16c9699f596f22c7a9e643591311ae72b1e776f2d539e9dd9d", size = 52388, upload-time = "2025-07-27T13:03:23.064Z" }, + { url = "https://files.pythonhosted.org/packages/c4/45/22e46e549710c4c237d77785b6fb1bc4c44c288a5c44237ba9daf5c34b82/pybase64-1.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cda9f79c22d51ee4508f5a43b673565f1d26af4330c99f114e37e3186fdd3607", size = 68802, upload-time = "2025-07-27T13:03:24.673Z" }, + { url = "https://files.pythonhosted.org/packages/55/0c/232c6261b81296e5593549b36e6e7884a5da008776d12665923446322c36/pybase64-1.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0c91c6d2a7232e2a1cd10b3b75a8bb657defacd4295a1e5e80455df2dfc84d4f", size = 57841, upload-time = "2025-07-27T13:03:25.948Z" }, + { url = "https://files.pythonhosted.org/packages/20/8a/b35a615ae6f04550d696bb179c414538b3b477999435fdd4ad75b76139e4/pybase64-1.4.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:a370dea7b1cee2a36a4d5445d4e09cc243816c5bc8def61f602db5a6f5438e52", size = 54320, upload-time = "2025-07-27T13:03:27.495Z" }, + { url = "https://files.pythonhosted.org/packages/d3/a9/8bd4f9bcc53689f1b457ecefed1eaa080e4949d65a62c31a38b7253d5226/pybase64-1.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9aa4de83f02e462a6f4e066811c71d6af31b52d7484de635582d0e3ec3d6cc3e", size = 56482, upload-time = "2025-07-27T13:03:28.942Z" }, + { url = "https://files.pythonhosted.org/packages/75/e5/4a7735b54a1191f61c3f5c2952212c85c2d6b06eb5fb3671c7603395f70c/pybase64-1.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83a1c2f9ed00fee8f064d548c8654a480741131f280e5750bb32475b7ec8ee38", size = 70959, upload-time = "2025-07-27T13:03:30.171Z" }, + { url = "https://files.pythonhosted.org/packages/d3/67/e2b6cb32c782e12304d467418e70da0212567f42bd4d3b5eb1fdf64920ad/pybase64-1.4.2-cp312-cp312-win32.whl", hash = "sha256:a6e5688b18d558e8c6b8701cc8560836c4bbeba61d33c836b4dba56b19423716", size = 33683, upload-time = "2025-07-27T13:03:31.775Z" }, + { url = "https://files.pythonhosted.org/packages/4f/bc/d5c277496063a09707486180f17abbdbdebbf2f5c4441b20b11d3cb7dc7c/pybase64-1.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:c995d21b8bd08aa179cd7dd4db0695c185486ecc72da1e8f6c37ec86cadb8182", size = 35817, upload-time = "2025-07-27T13:03:32.99Z" }, + { url = "https://files.pythonhosted.org/packages/e6/69/e4be18ae685acff0ae77f75d4586590f29d2cd187bf603290cf1d635cad4/pybase64-1.4.2-cp312-cp312-win_arm64.whl", hash = "sha256:e254b9258c40509c2ea063a7784f6994988f3f26099d6e08704e3c15dfed9a55", size = 30900, upload-time = "2025-07-27T13:03:34.499Z" }, + { url = "https://files.pythonhosted.org/packages/32/34/b67371f4fcedd5e2def29b1cf92a4311a72f590c04850f370c75297b48ce/pybase64-1.4.2-graalpy311-graalpy242_311_native-macosx_10_9_x86_64.whl", hash = "sha256:b4eed40a5f1627ee65613a6ac834a33f8ba24066656f569c852f98eb16f6ab5d", size = 38667, upload-time = "2025-07-27T13:07:25.315Z" }, + { url = "https://files.pythonhosted.org/packages/aa/3e/e57fe09ed1c7e740d21c37023c5f7c8963b4c36380f41d10261cc76f93b4/pybase64-1.4.2-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:57885fa521e9add235af4db13e9e048d3a2934cd27d7c5efac1925e1b4d6538d", size = 32094, upload-time = "2025-07-27T13:07:28.235Z" }, + { url = "https://files.pythonhosted.org/packages/51/34/f40d3262c3953814b9bcdcf858436bd5bc1133a698be4bcc7ed2a8c0730d/pybase64-1.4.2-graalpy311-graalpy242_311_native-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eef9255d926c64e2fca021d3aee98023bacb98e1518e5986d6aab04102411b04", size = 43212, upload-time = "2025-07-27T13:07:31.327Z" }, + { url = "https://files.pythonhosted.org/packages/8c/2a/5e05d25718cb8ffd68bd46553ddfd2b660893d937feda1716b8a3b21fb38/pybase64-1.4.2-graalpy311-graalpy242_311_native-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:89614ea2d2329b6708746c540e0f14d692125df99fb1203ff0de948d9e68dfc9", size = 35789, upload-time = "2025-07-27T13:07:34.026Z" }, + { url = "https://files.pythonhosted.org/packages/d5/9d/f56c3ee6e94faaae2896ecaf666428330cb24096abf7d2427371bb2b403a/pybase64-1.4.2-graalpy311-graalpy242_311_native-win_amd64.whl", hash = "sha256:e401cecd2d7ddcd558768b2140fd4430746be4d17fb14c99eec9e40789df136d", size = 35861, upload-time = "2025-07-27T13:07:37.099Z" }, + { url = "https://files.pythonhosted.org/packages/0e/bf/5ebaa2d9ddb5fc506633bc8b820fc27e64da964937fb30929c0367c47d00/pybase64-1.4.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0a5393be20b0705870f5a8969749af84d734c077de80dd7e9f5424a247afa85e", size = 38162, upload-time = "2025-07-27T13:07:58.364Z" }, + { url = "https://files.pythonhosted.org/packages/25/41/795c5fd6e5571bb675bf9add8a048166dddf8951c2a903fea8557743886b/pybase64-1.4.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:448f0259a2f1a17eb086f70fe2ad9b556edba1fc5bc4e62ce6966179368ee9f8", size = 31452, upload-time = "2025-07-27T13:08:01.259Z" }, + { url = "https://files.pythonhosted.org/packages/aa/dd/c819003b59b2832256b72ad23cbeadbd95d083ef0318d07149a58b7a88af/pybase64-1.4.2-pp311-pypy311_pp73-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:1159e70cba8e76c3d8f334bd1f8fd52a1bb7384f4c3533831b23ab2df84a6ef3", size = 40668, upload-time = "2025-07-27T13:08:04.176Z" }, + { url = "https://files.pythonhosted.org/packages/0e/c5/38c6aba28678c4a4db49312a6b8171b93a0ffe9f21362cf4c0f325caa850/pybase64-1.4.2-pp311-pypy311_pp73-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d943bc5dad8388971494554b97f22ae06a46cc7779ad0de3d4bfdf7d0bbea30", size = 41281, upload-time = "2025-07-27T13:08:07.395Z" }, + { url = "https://files.pythonhosted.org/packages/e5/23/5927bd9e59714e4e8cefd1d21ccd7216048bb1c6c3e7104b1b200afdc63d/pybase64-1.4.2-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:10b99182c561d86422c5de4265fd1f8f172fb38efaed9d72c71fb31e279a7f94", size = 35433, upload-time = "2025-07-27T13:08:10.551Z" }, + { url = "https://files.pythonhosted.org/packages/01/0f/fab7ed5bf4926523c3b39f7621cea3e0da43f539fbc2270e042f1afccb79/pybase64-1.4.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bb082c1114f046e59fcbc4f2be13edc93b36d7b54b58605820605be948f8fdf6", size = 36131, upload-time = "2025-07-27T13:08:13.777Z" }, +] + [[package]] name = "pyclipper" version = "1.3.0.post6" @@ -3610,7 +3081,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.11.7" +version = "2.11.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -3618,9 +3089,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" }, ] [[package]] @@ -3673,15 +3144,16 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.7.1" +version = "2.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, + { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/73/7b/c58a586cd7d9ac66d2ee4ba60ca2d241fa837c02bca9bea80a9a8c3d22a9/pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93", size = 79920, upload-time = "2024-12-31T11:27:44.632Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/46/93416fdae86d40879714f72956ac14df9c7b76f7d41a4d68aa9f71a0028b/pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd", size = 29718, upload-time = "2024-12-31T11:27:43.201Z" }, + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] [[package]] @@ -3693,18 +3165,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327, upload-time = "2021-03-10T02:09:53.503Z" }, ] -[[package]] -name = "pyee" -version = "12.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d2/a7/8faaa62a488a2a1e0d56969757f087cbd2729e9bcfa508c230299f366b4c/pyee-12.0.0.tar.gz", hash = "sha256:c480603f4aa2927d4766eb41fa82793fe60a82cbfdb8d688e0d08c55a534e145", size = 29675, upload-time = "2024-08-30T19:40:43.555Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/0d/95993c08c721ec68892547f2117e8f9dfbcef2ca71e098533541b4a54d5f/pyee-12.0.0-py3-none-any.whl", hash = "sha256:7b14b74320600049ccc7d0e0b1becd3b4bd0a03c745758225e31a59f4095c990", size = 14831, upload-time = "2024-08-30T19:40:42.132Z" }, -] - [[package]] name = "pygments" version = "2.19.1" @@ -3741,53 +3201,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/a3/61527d80d84e9fd4d97649322e83bd7efde8200fc07fe34469c8c2bd0d91/pymdown_extensions-10.14.2-py3-none-any.whl", hash = "sha256:f45bc5892410e54fd738ab8ccd736098b7ff0cb27fdb4bf24d0a0c6584bc90e1", size = 264459, upload-time = "2025-01-29T02:56:34.421Z" }, ] -[[package]] -name = "pymilvus" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "grpcio" }, - { name = "milvus-lite", marker = "sys_platform != 'win32'" }, - { name = "pandas" }, - { name = "protobuf" }, - { name = "python-dotenv" }, - { name = "setuptools" }, - { name = "ujson" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f7/3d/e6b593cf456e4300e3aa58b76e55f392166c5df2ea3605666ad6200503fb/pymilvus-2.5.0.tar.gz", hash = "sha256:4da14a3bd957a4921166f9355fd1f1ac5c5e4e80b46f12f64d9c9a6dcb8cb395", size = 1238729, upload-time = "2024-11-26T08:10:27.752Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/f1/76af6c8e1481879f5e0c0d885ab899ab8869fd939b27ac7a0b6c3b3b4ebe/pymilvus-2.5.0-py3-none-any.whl", hash = "sha256:a0e8653d8fe78019abfda79b3404ef7423f312501e8cbd7dc728051ce8732652", size = 212848, upload-time = "2024-11-26T08:10:25.953Z" }, -] - -[[package]] -name = "pymongo" -version = "4.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1a/35/b62a3139f908c68b69aac6a6a3f8cc146869de0a7929b994600e2c587c77/pymongo-4.10.1.tar.gz", hash = "sha256:a9de02be53b6bb98efe0b9eda84ffa1ec027fcb23a2de62c4f941d9a2f2f3330", size = 1903902, upload-time = "2024-10-01T23:07:58.525Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/a3/d6403ec53fa2fe922b4a5c86388ea5fada01dd51d803e17bb2a7c9cda839/pymongo-4.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:57ee6becae534e6d47848c97f6a6dff69e3cce7c70648d6049bd586764febe59", size = 889238, upload-time = "2024-10-01T23:06:36.03Z" }, - { url = "https://files.pythonhosted.org/packages/29/a2/9643450424bcf241e80bb713497ec2e3273c183d548b4eca357f75d71885/pymongo-4.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6f437a612f4d4f7aca1812311b1e84477145e950fdafe3285b687ab8c52541f3", size = 889504, upload-time = "2024-10-01T23:06:37.328Z" }, - { url = "https://files.pythonhosted.org/packages/ec/40/4759984f34415509e9111be8ee863034611affdc1e0b41016c9d53b2f1b3/pymongo-4.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a970fd3117ab40a4001c3dad333bbf3c43687d90f35287a6237149b5ccae61d", size = 1649069, upload-time = "2024-10-01T23:06:38.553Z" }, - { url = "https://files.pythonhosted.org/packages/56/0f/b6e917478a3ada81e768475516cd544982cc42cbb7d3be325182768139e1/pymongo-4.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7c4d0e7cd08ef9f8fbf2d15ba281ed55604368a32752e476250724c3ce36c72e", size = 1714927, upload-time = "2024-10-01T23:06:40.292Z" }, - { url = "https://files.pythonhosted.org/packages/56/c5/4237d94dfa19ebdf9a92b1071e2139c91f48908c5782e592c571c33b67ab/pymongo-4.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca6f700cff6833de4872a4e738f43123db34400173558b558ae079b5535857a4", size = 1683454, upload-time = "2024-10-01T23:06:42.257Z" }, - { url = "https://files.pythonhosted.org/packages/9a/16/dbffca9d4ad66f2a325c280f1177912fa23235987f7b9033e283da889b7a/pymongo-4.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cec237c305fcbeef75c0bcbe9d223d1e22a6e3ba1b53b2f0b79d3d29c742b45b", size = 1653840, upload-time = "2024-10-01T23:06:43.991Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4d/21df934ef5cf8f0e587bac922a129e13d4c0346c54e9bf2371b90dd31112/pymongo-4.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3337804ea0394a06e916add4e5fac1c89902f1b6f33936074a12505cab4ff05", size = 1613233, upload-time = "2024-10-01T23:06:46.113Z" }, - { url = "https://files.pythonhosted.org/packages/24/07/dd9c3db30e754680606295d5574521956898005db0629411a89163cc6eee/pymongo-4.10.1-cp311-cp311-win32.whl", hash = "sha256:778ac646ce6ac1e469664062dfe9ae1f5c9961f7790682809f5ec3b8fda29d65", size = 857331, upload-time = "2024-10-01T23:06:47.812Z" }, - { url = "https://files.pythonhosted.org/packages/02/68/b71c4106d03eef2482eade440c6f5737c2a4a42f6155726009f80ea38d06/pymongo-4.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:9df4ab5594fdd208dcba81be815fa8a8a5d8dedaf3b346cbf8b61c7296246a7a", size = 876473, upload-time = "2024-10-01T23:06:49.201Z" }, - { url = "https://files.pythonhosted.org/packages/10/d1/60ad99fe3f64d45e6c71ac0e3078e88d9b64112b1bae571fc3707344d6d1/pymongo-4.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fbedc4617faa0edf423621bb0b3b8707836687161210d470e69a4184be9ca011", size = 943356, upload-time = "2024-10-01T23:06:50.9Z" }, - { url = "https://files.pythonhosted.org/packages/ca/9b/21d4c6b4ee9c1fa9691c68dc2a52565e0acb644b9e95148569b4736a4ebd/pymongo-4.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7bd26b2aec8ceeb95a5d948d5cc0f62b0eb6d66f3f4230705c1e3d3d2c04ec76", size = 943142, upload-time = "2024-10-01T23:06:52.146Z" }, - { url = "https://files.pythonhosted.org/packages/07/af/691b7454e219a8eb2d1641aecedd607e3a94b93650c2011ad8a8fd74ef9f/pymongo-4.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb104c3c2a78d9d85571c8ac90ec4f95bca9b297c6eee5ada71fabf1129e1674", size = 1909129, upload-time = "2024-10-01T23:06:53.551Z" }, - { url = "https://files.pythonhosted.org/packages/0c/74/fd75d5ad4181d6e71ce0fca32404fb71b5046ac84d9a1a2f0862262dd032/pymongo-4.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4924355245a9c79f77b5cda2db36e0f75ece5faf9f84d16014c0a297f6d66786", size = 1987763, upload-time = "2024-10-01T23:06:55.304Z" }, - { url = "https://files.pythonhosted.org/packages/8a/56/6d3d0ef63c6d8cb98c7c653a3a2e617675f77a95f3853851d17a7664876a/pymongo-4.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11280809e5dacaef4971113f0b4ff4696ee94cfdb720019ff4fa4f9635138252", size = 1950821, upload-time = "2024-10-01T23:06:57.541Z" }, - { url = "https://files.pythonhosted.org/packages/70/ed/1603fa0c0e51444752c3fa91f16c3a97e6d92eb9fe5e553dae4f18df16f6/pymongo-4.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5d55f2a82e5eb23795f724991cac2bffbb1c0f219c0ba3bf73a835f97f1bb2e", size = 1912247, upload-time = "2024-10-01T23:06:59.023Z" }, - { url = "https://files.pythonhosted.org/packages/c1/66/e98b2308971d45667cb8179d4d66deca47336c90663a7e0527589f1038b7/pymongo-4.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e974ab16a60be71a8dfad4e5afccf8dd05d41c758060f5d5bda9a758605d9a5d", size = 1862230, upload-time = "2024-10-01T23:07:01.407Z" }, - { url = "https://files.pythonhosted.org/packages/6c/80/ba9b7ed212a5f8cf8ad7037ed5bbebc1c587fc09242108f153776e4a338b/pymongo-4.10.1-cp312-cp312-win32.whl", hash = "sha256:544890085d9641f271d4f7a47684450ed4a7344d6b72d5968bfae32203b1bb7c", size = 903045, upload-time = "2024-10-01T23:07:02.973Z" }, - { url = "https://files.pythonhosted.org/packages/76/8b/5afce891d78159912c43726fab32641e3f9718f14be40f978c148ea8db48/pymongo-4.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:dcc07b1277e8b4bf4d7382ca133850e323b7ab048b8353af496d050671c7ac52", size = 926686, upload-time = "2024-10-01T23:07:04.403Z" }, -] - [[package]] name = "pymysql" version = "1.1.1" @@ -3817,11 +3230,11 @@ wheels = [ [[package]] name = "pypdf" -version = "4.3.1" +version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/65/2ed7c9e1d31d860f096061b3dd2d665f501e09faaa0409a3f0d719d2a16d/pypdf-4.3.1.tar.gz", hash = "sha256:b2f37fe9a3030aa97ca86067a56ba3f9d3565f9a791b305c7355d8392c30d91b", size = 293266, upload-time = "2024-07-21T19:35:20.207Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/ac/a300a03c3b34967c050677ccb16e7a4b65607ee5df9d51e8b6d713de4098/pypdf-6.0.0.tar.gz", hash = "sha256:282a99d2cc94a84a3a3159f0d9358c0af53f85b4d28d76ea38b96e9e5ac2a08d", size = 5033827, upload-time = "2025-08-11T14:22:02.352Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/60/eccdd92dd4af3e4bea6d6a342f7588c618a15b9bec4b968af581e498bcc4/pypdf-4.3.1-py3-none-any.whl", hash = "sha256:64b31da97eda0771ef22edb1bfecd5deee4b72c3d1736b7df2689805076d6418", size = 295825, upload-time = "2024-07-21T19:35:18.126Z" }, + { url = "https://files.pythonhosted.org/packages/2c/83/2cacc506eb322bb31b747bc06ccb82cc9aa03e19ee9c1245e538e49d52be/pypdf-6.0.0-py3-none-any.whl", hash = "sha256:56ea60100ce9f11fc3eec4f359da15e9aec3821b036c1f06d2b660d35683abb8", size = 310465, upload-time = "2025-08-11T14:22:00.481Z" }, ] [[package]] @@ -3875,19 +3288,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/30/05/ce271016e351fddc8399e546f6e23761967ee09c8c568bbfbecb0c150171/pytest_asyncio-1.0.0-py3-none-any.whl", hash = "sha256:4f024da9f1ef945e680dc68610b52550e36590a67fd31bb3b4943979a1f90ef3", size = 15976, upload-time = "2025-05-26T04:54:39.035Z" }, ] -[[package]] -name = "pytest-docker" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e7/a6/543f2fb157ad228fcc04a8974aa16c989058834d8e539608814cf722f1b3/pytest-docker-3.1.1.tar.gz", hash = "sha256:2371524804a752aaa766c79b9eee8e634534afddb82597f3b573da7c5d6ffb5f", size = 12918, upload-time = "2024-02-02T09:18:11.74Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/a4/69defc13bf77ee5aeb3e7b7c45393d6c7312e9c4d8b55d280a094ff76ff3/pytest_docker-3.1.1-py3-none-any.whl", hash = "sha256:fd0d48d6feac41f62acbc758319215ec9bb805c2309622afb07c27fa5c5ae362", size = 8243, upload-time = "2024-02-02T09:18:10.61Z" }, -] - [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -3932,16 +3332,16 @@ wheels = [ [[package]] name = "python-jose" -version = "3.4.0" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ecdsa" }, { name = "pyasn1" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8e/a0/c49687cf40cb6128ea4e0559855aff92cd5ebd1a60a31c08526818c0e51e/python-jose-3.4.0.tar.gz", hash = "sha256:9a9a40f418ced8ecaf7e3b28d69887ceaa76adad3bcaa6dae0d9e596fec1d680", size = 92145, upload-time = "2025-02-18T17:26:41.985Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/77/3a1c9039db7124eb039772b935f2244fbb73fc8ee65b9acf2375da1c07bf/python_jose-3.5.0.tar.gz", hash = "sha256:fb4eaa44dbeb1c26dcc69e4bd7ec54a1cb8dd64d3b4d81ef08d90ff453f2b01b", size = 92726, upload-time = "2025-05-28T17:31:54.288Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/63/b0/2586ea6b6fd57a994ece0b56418cbe93fff0efb85e2c9eb6b0caf24a4e37/python_jose-3.4.0-py2.py3-none-any.whl", hash = "sha256:9c9f616819652d109bd889ecd1e15e9a162b9b94d682534c9c2146092945b78f", size = 34616, upload-time = "2025-02-18T17:26:40.826Z" }, + { url = "https://files.pythonhosted.org/packages/d9/c3/0bd11992072e6a1c513b16500a5d07f91a24017c5909b02c72c62d7ad024/python_jose-3.5.0-py2.py3-none-any.whl", hash = "sha256:abd1202f23d34dfad2c3d28cb8617b90acf34132c7afd60abd0b0b7d3cb55771", size = 34624, upload-time = "2025-05-28T17:31:52.802Z" }, ] [[package]] @@ -4004,6 +3404,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/32/b4fb8585d1be0f68bde7e110dffbcf354915f77ad8c778563f0ad9655c02/python_socketio-5.13.0-py3-none-any.whl", hash = "sha256:51f68d6499f2df8524668c24bcec13ba1414117cfb3a90115c559b601ab10caf", size = 77800, upload-time = "2025-04-12T15:46:58.412Z" }, ] +[[package]] +name = "pytokens" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/8d/a762be14dae1c3bf280202ba3172020b2b0b4c537f94427435f19c413b72/pytokens-0.3.0.tar.gz", hash = "sha256:2f932b14ed08de5fcf0b391ace2642f858f1394c0857202959000b68ed7a458a", size = 17644, upload-time = "2025-11-05T13:36:35.34Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, +] + [[package]] name = "pytube" version = "15.0.0" @@ -4024,15 +3433,15 @@ wheels = [ [[package]] name = "pywin32" -version = "308" +version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156, upload-time = "2024-10-12T20:42:05.78Z" }, - { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559, upload-time = "2024-10-12T20:42:07.644Z" }, - { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495, upload-time = "2024-10-12T20:42:09.803Z" }, - { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729, upload-time = "2024-10-12T20:42:12.001Z" }, - { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015, upload-time = "2024-10-12T20:42:14.044Z" }, - { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033, upload-time = "2024-10-12T20:42:16.215Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, + { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, + { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, ] [[package]] @@ -4070,24 +3479,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, ] -[[package]] -name = "qdrant-client" -version = "1.14.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "grpcio" }, - { name = "httpx", extra = ["http2"] }, - { name = "numpy" }, - { name = "portalocker" }, - { name = "protobuf" }, - { name = "pydantic" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1d/56/3f355f931c239c260b4fe3bd6433ec6c9e6185cd5ae0970fe89d0ca6daee/qdrant_client-1.14.3.tar.gz", hash = "sha256:bb899e3e065b79c04f5e47053d59176150c0a5dabc09d7f476c8ce8e52f4d281", size = 286766, upload-time = "2025-06-16T11:13:47.838Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/5e/8174c845707e60b60b65c58f01e40bbc1d8181b5ff6463f25df470509917/qdrant_client-1.14.3-py3-none-any.whl", hash = "sha256:66faaeae00f9b5326946851fe4ca4ddb1ad226490712e2f05142266f68dfc04d", size = 328969, upload-time = "2025-06-16T11:13:46.636Z" }, -] - [[package]] name = "rank-bm25" version = "0.2.2" @@ -4169,6 +3560,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3c/5f/fa26b9b2672cbe30e07d9a5bdf39cf16e3b80b42916757c5f92bca88e4ba/redis-5.2.1-py3-none-any.whl", hash = "sha256:ee7e1056b9aea0f04c6c2ed59452947f34c4940ee025f5dd83e6a6418b6989e4", size = 261502, upload-time = "2024-12-06T09:50:39.656Z" }, ] +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + [[package]] name = "regex" version = "2024.11.6" @@ -4209,7 +3614,7 @@ wheels = [ [[package]] name = "requests" -version = "2.32.4" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -4217,9 +3622,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [[package]] @@ -4247,20 +3652,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, ] -[[package]] -name = "responses" -version = "0.25.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyyaml" }, - { name = "requests" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/97/63/759996eea0f17e8dc4c9ea9c60765292d28a7750bdbee073ad55d83caa57/responses-0.25.6.tar.gz", hash = "sha256:eae7ce61a9603004e76c05691e7c389e59652d91e94b419623c12bbfb8e331d8", size = 79145, upload-time = "2025-01-13T21:04:27.895Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/c4/8d23584b3a3471ea6f5a18cfb035e11eeb9fa9b3112d901477c6ad10cc4e/responses-0.25.6-py3-none-any.whl", hash = "sha256:9cac8f21e1193bb150ec557875377e41ed56248aed94e4567ed644db564bacf1", size = 34730, upload-time = "2025-01-13T21:04:24.895Z" }, -] - [[package]] name = "restrictedpython" version = "8.0" @@ -4283,6 +3674,56 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424, upload-time = "2024-11-01T16:43:55.817Z" }, ] +[[package]] +name = "rpds-py" +version = "0.28.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/48/dc/95f074d43452b3ef5d06276696ece4b3b5d696e7c9ad7173c54b1390cd70/rpds_py-0.28.0.tar.gz", hash = "sha256:abd4df20485a0983e2ca334a216249b6186d6e3c1627e106651943dbdb791aea", size = 27419, upload-time = "2025-10-22T22:24:29.327Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/34/058d0db5471c6be7bef82487ad5021ff8d1d1d27794be8730aad938649cf/rpds_py-0.28.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:03065002fd2e287725d95fbc69688e0c6daf6c6314ba38bdbaa3895418e09296", size = 362344, upload-time = "2025-10-22T22:21:39.713Z" }, + { url = "https://files.pythonhosted.org/packages/5d/67/9503f0ec8c055a0782880f300c50a2b8e5e72eb1f94dfc2053da527444dd/rpds_py-0.28.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:28ea02215f262b6d078daec0b45344c89e161eab9526b0d898221d96fdda5f27", size = 348440, upload-time = "2025-10-22T22:21:41.056Z" }, + { url = "https://files.pythonhosted.org/packages/68/2e/94223ee9b32332a41d75b6f94b37b4ce3e93878a556fc5f152cbd856a81f/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25dbade8fbf30bcc551cb352376c0ad64b067e4fc56f90e22ba70c3ce205988c", size = 379068, upload-time = "2025-10-22T22:21:42.593Z" }, + { url = "https://files.pythonhosted.org/packages/b4/25/54fd48f9f680cfc44e6a7f39a5fadf1d4a4a1fd0848076af4a43e79f998c/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3c03002f54cc855860bfdc3442928ffdca9081e73b5b382ed0b9e8efe6e5e205", size = 390518, upload-time = "2025-10-22T22:21:43.998Z" }, + { url = "https://files.pythonhosted.org/packages/1b/85/ac258c9c27f2ccb1bd5d0697e53a82ebcf8088e3186d5d2bf8498ee7ed44/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9699fa7990368b22032baf2b2dce1f634388e4ffc03dfefaaac79f4695edc95", size = 525319, upload-time = "2025-10-22T22:21:45.645Z" }, + { url = "https://files.pythonhosted.org/packages/40/cb/c6734774789566d46775f193964b76627cd5f42ecf246d257ce84d1912ed/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9b06fe1a75e05e0713f06ea0c89ecb6452210fd60e2f1b6ddc1067b990e08d9", size = 404896, upload-time = "2025-10-22T22:21:47.544Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/14e37ce83202c632c89b0691185dca9532288ff9d390eacae3d2ff771bae/rpds_py-0.28.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac9f83e7b326a3f9ec3ef84cda98fb0a74c7159f33e692032233046e7fd15da2", size = 382862, upload-time = "2025-10-22T22:21:49.176Z" }, + { url = "https://files.pythonhosted.org/packages/6a/83/f3642483ca971a54d60caa4449f9d6d4dbb56a53e0072d0deff51b38af74/rpds_py-0.28.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:0d3259ea9ad8743a75a43eb7819324cdab393263c91be86e2d1901ee65c314e0", size = 398848, upload-time = "2025-10-22T22:21:51.024Z" }, + { url = "https://files.pythonhosted.org/packages/44/09/2d9c8b2f88e399b4cfe86efdf2935feaf0394e4f14ab30c6c5945d60af7d/rpds_py-0.28.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a7548b345f66f6695943b4ef6afe33ccd3f1b638bd9afd0f730dd255c249c9e", size = 412030, upload-time = "2025-10-22T22:21:52.665Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f5/e1cec473d4bde6df1fd3738be8e82d64dd0600868e76e92dfeaebbc2d18f/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c9a40040aa388b037eb39416710fbcce9443498d2eaab0b9b45ae988b53f5c67", size = 559700, upload-time = "2025-10-22T22:21:54.123Z" }, + { url = "https://files.pythonhosted.org/packages/8d/be/73bb241c1649edbf14e98e9e78899c2c5e52bbe47cb64811f44d2cc11808/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8f60c7ea34e78c199acd0d3cda37a99be2c861dd2b8cf67399784f70c9f8e57d", size = 584581, upload-time = "2025-10-22T22:21:56.102Z" }, + { url = "https://files.pythonhosted.org/packages/9c/9c/ffc6e9218cd1eb5c2c7dbd276c87cd10e8c2232c456b554169eb363381df/rpds_py-0.28.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1571ae4292649100d743b26d5f9c63503bb1fedf538a8f29a98dce2d5ba6b4e6", size = 549981, upload-time = "2025-10-22T22:21:58.253Z" }, + { url = "https://files.pythonhosted.org/packages/5f/50/da8b6d33803a94df0149345ee33e5d91ed4d25fc6517de6a25587eae4133/rpds_py-0.28.0-cp311-cp311-win32.whl", hash = "sha256:5cfa9af45e7c1140af7321fa0bef25b386ee9faa8928c80dc3a5360971a29e8c", size = 214729, upload-time = "2025-10-22T22:21:59.625Z" }, + { url = "https://files.pythonhosted.org/packages/12/fd/b0f48c4c320ee24c8c20df8b44acffb7353991ddf688af01eef5f93d7018/rpds_py-0.28.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd8d86b5d29d1b74100982424ba53e56033dc47720a6de9ba0259cf81d7cecaa", size = 223977, upload-time = "2025-10-22T22:22:01.092Z" }, + { url = "https://files.pythonhosted.org/packages/b4/21/c8e77a2ac66e2ec4e21f18a04b4e9a0417ecf8e61b5eaeaa9360a91713b4/rpds_py-0.28.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e27d3a5709cc2b3e013bf93679a849213c79ae0573f9b894b284b55e729e120", size = 217326, upload-time = "2025-10-22T22:22:02.944Z" }, + { url = "https://files.pythonhosted.org/packages/b8/5c/6c3936495003875fe7b14f90ea812841a08fca50ab26bd840e924097d9c8/rpds_py-0.28.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6b4f28583a4f247ff60cd7bdda83db8c3f5b05a7a82ff20dd4b078571747708f", size = 366439, upload-time = "2025-10-22T22:22:04.525Z" }, + { url = "https://files.pythonhosted.org/packages/56/f9/a0f1ca194c50aa29895b442771f036a25b6c41a35e4f35b1a0ea713bedae/rpds_py-0.28.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d678e91b610c29c4b3d52a2c148b641df2b4676ffe47c59f6388d58b99cdc424", size = 348170, upload-time = "2025-10-22T22:22:06.397Z" }, + { url = "https://files.pythonhosted.org/packages/18/ea/42d243d3a586beb72c77fa5def0487daf827210069a95f36328e869599ea/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e819e0e37a44a78e1383bf1970076e2ccc4dc8c2bbaa2f9bd1dc987e9afff628", size = 378838, upload-time = "2025-10-22T22:22:07.932Z" }, + { url = "https://files.pythonhosted.org/packages/e7/78/3de32e18a94791af8f33601402d9d4f39613136398658412a4e0b3047327/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5ee514e0f0523db5d3fb171f397c54875dbbd69760a414dccf9d4d7ad628b5bd", size = 393299, upload-time = "2025-10-22T22:22:09.435Z" }, + { url = "https://files.pythonhosted.org/packages/13/7e/4bdb435afb18acea2eb8a25ad56b956f28de7c59f8a1d32827effa0d4514/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5f3fa06d27fdcee47f07a39e02862da0100cb4982508f5ead53ec533cd5fe55e", size = 518000, upload-time = "2025-10-22T22:22:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/31/d0/5f52a656875cdc60498ab035a7a0ac8f399890cc1ee73ebd567bac4e39ae/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46959ef2e64f9e4a41fc89aa20dbca2b85531f9a72c21099a3360f35d10b0d5a", size = 408746, upload-time = "2025-10-22T22:22:13.143Z" }, + { url = "https://files.pythonhosted.org/packages/3e/cd/49ce51767b879cde77e7ad9fae164ea15dce3616fe591d9ea1df51152706/rpds_py-0.28.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8455933b4bcd6e83fde3fefc987a023389c4b13f9a58c8d23e4b3f6d13f78c84", size = 386379, upload-time = "2025-10-22T22:22:14.602Z" }, + { url = "https://files.pythonhosted.org/packages/6a/99/e4e1e1ee93a98f72fc450e36c0e4d99c35370220e815288e3ecd2ec36a2a/rpds_py-0.28.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:ad50614a02c8c2962feebe6012b52f9802deec4263946cddea37aaf28dd25a66", size = 401280, upload-time = "2025-10-22T22:22:16.063Z" }, + { url = "https://files.pythonhosted.org/packages/61/35/e0c6a57488392a8b319d2200d03dad2b29c0db9996f5662c3b02d0b86c02/rpds_py-0.28.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e5deca01b271492553fdb6c7fd974659dce736a15bae5dad7ab8b93555bceb28", size = 412365, upload-time = "2025-10-22T22:22:17.504Z" }, + { url = "https://files.pythonhosted.org/packages/ff/6a/841337980ea253ec797eb084665436007a1aad0faac1ba097fb906c5f69c/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:735f8495a13159ce6a0d533f01e8674cec0c57038c920495f87dcb20b3ddb48a", size = 559573, upload-time = "2025-10-22T22:22:19.108Z" }, + { url = "https://files.pythonhosted.org/packages/e7/5e/64826ec58afd4c489731f8b00729c5f6afdb86f1df1df60bfede55d650bb/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:961ca621ff10d198bbe6ba4957decca61aa2a0c56695384c1d6b79bf61436df5", size = 583973, upload-time = "2025-10-22T22:22:20.768Z" }, + { url = "https://files.pythonhosted.org/packages/b6/ee/44d024b4843f8386a4eeaa4c171b3d31d55f7177c415545fd1a24c249b5d/rpds_py-0.28.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2374e16cc9131022e7d9a8f8d65d261d9ba55048c78f3b6e017971a4f5e6353c", size = 553800, upload-time = "2025-10-22T22:22:22.25Z" }, + { url = "https://files.pythonhosted.org/packages/7d/89/33e675dccff11a06d4d85dbb4d1865f878d5020cbb69b2c1e7b2d3f82562/rpds_py-0.28.0-cp312-cp312-win32.whl", hash = "sha256:d15431e334fba488b081d47f30f091e5d03c18527c325386091f31718952fe08", size = 216954, upload-time = "2025-10-22T22:22:24.105Z" }, + { url = "https://files.pythonhosted.org/packages/af/36/45f6ebb3210887e8ee6dbf1bc710ae8400bb417ce165aaf3024b8360d999/rpds_py-0.28.0-cp312-cp312-win_amd64.whl", hash = "sha256:a410542d61fc54710f750d3764380b53bf09e8c4edbf2f9141a82aa774a04f7c", size = 227844, upload-time = "2025-10-22T22:22:25.551Z" }, + { url = "https://files.pythonhosted.org/packages/57/91/f3fb250d7e73de71080f9a221d19bd6a1c1eb0d12a1ea26513f6c1052ad6/rpds_py-0.28.0-cp312-cp312-win_arm64.whl", hash = "sha256:1f0cfd1c69e2d14f8c892b893997fa9a60d890a0c8a603e88dca4955f26d1edd", size = 217624, upload-time = "2025-10-22T22:22:26.914Z" }, + { url = "https://files.pythonhosted.org/packages/ae/bc/b43f2ea505f28119bd551ae75f70be0c803d2dbcd37c1b3734909e40620b/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f5e7101145427087e493b9c9b959da68d357c28c562792300dd21a095118ed16", size = 363913, upload-time = "2025-10-22T22:24:07.129Z" }, + { url = "https://files.pythonhosted.org/packages/28/f2/db318195d324c89a2c57dc5195058cbadd71b20d220685c5bd1da79ee7fe/rpds_py-0.28.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:31eb671150b9c62409a888850aaa8e6533635704fe2b78335f9aaf7ff81eec4d", size = 350452, upload-time = "2025-10-22T22:24:08.754Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f2/1391c819b8573a4898cedd6b6c5ec5bc370ce59e5d6bdcebe3c9c1db4588/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48b55c1f64482f7d8bd39942f376bfdf2f6aec637ee8c805b5041e14eeb771db", size = 380957, upload-time = "2025-10-22T22:24:10.826Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5c/e5de68ee7eb7248fce93269833d1b329a196d736aefb1a7481d1e99d1222/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24743a7b372e9a76171f6b69c01aedf927e8ac3e16c474d9fe20d552a8cb45c7", size = 391919, upload-time = "2025-10-22T22:24:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/fb/4f/2376336112cbfeb122fd435d608ad8d5041b3aed176f85a3cb32c262eb80/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:389c29045ee8bbb1627ea190b4976a310a295559eaf9f1464a1a6f2bf84dde78", size = 528541, upload-time = "2025-10-22T22:24:14.197Z" }, + { url = "https://files.pythonhosted.org/packages/68/53/5ae232e795853dd20da7225c5dd13a09c0a905b1a655e92bdf8d78a99fd9/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23690b5827e643150cf7b49569679ec13fe9a610a15949ed48b85eb7f98f34ec", size = 405629, upload-time = "2025-10-22T22:24:16.001Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2d/351a3b852b683ca9b6b8b38ed9efb2347596973849ba6c3a0e99877c10aa/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f0c9266c26580e7243ad0d72fc3e01d6b33866cfab5084a6da7576bcf1c4f72", size = 384123, upload-time = "2025-10-22T22:24:17.585Z" }, + { url = "https://files.pythonhosted.org/packages/e0/15/870804daa00202728cc91cb8e2385fa9f1f4eb49857c49cfce89e304eae6/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:4c6c4db5d73d179746951486df97fd25e92396be07fc29ee8ff9a8f5afbdfb27", size = 400923, upload-time = "2025-10-22T22:24:19.512Z" }, + { url = "https://files.pythonhosted.org/packages/53/25/3706b83c125fa2a0bccceac951de3f76631f6bd0ee4d02a0ed780712ef1b/rpds_py-0.28.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3b695a8fa799dd2cfdb4804b37096c5f6dba1ac7f48a7fbf6d0485bcd060316", size = 413767, upload-time = "2025-10-22T22:24:21.316Z" }, + { url = "https://files.pythonhosted.org/packages/ef/f9/ce43dbe62767432273ed2584cef71fef8411bddfb64125d4c19128015018/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:6aa1bfce3f83baf00d9c5fcdbba93a3ab79958b4c7d7d1f55e7fe68c20e63912", size = 561530, upload-time = "2025-10-22T22:24:22.958Z" }, + { url = "https://files.pythonhosted.org/packages/46/c9/ffe77999ed8f81e30713dd38fd9ecaa161f28ec48bb80fa1cd9118399c27/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:7b0f9dceb221792b3ee6acb5438eb1f02b0cb2c247796a72b016dcc92c6de829", size = 585453, upload-time = "2025-10-22T22:24:24.779Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d2/4a73b18821fd4669762c855fd1f4e80ceb66fb72d71162d14da58444a763/rpds_py-0.28.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5d0145edba8abd3db0ab22b5300c99dc152f5c9021fab861be0f0544dc3cbc5f", size = 552199, upload-time = "2025-10-22T22:24:26.54Z" }, +] + [[package]] name = "rsa" version = "4.9" @@ -4297,14 +3738,14 @@ wheels = [ [[package]] name = "s3transfer" -version = "0.10.4" +version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/0a/1cdbabf9edd0ea7747efdf6c9ab4e7061b085aa7f9bfc36bb1601563b069/s3transfer-0.10.4.tar.gz", hash = "sha256:29edc09801743c21eb5ecbc617a152df41d3c287f67b615f73e5f750583666a7", size = 145287, upload-time = "2024-11-20T21:06:05.981Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/05/d52bf1e65044b4e5e27d4e63e8d1579dbdec54fce685908ae09bc3720030/s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf", size = 150589, upload-time = "2025-07-18T19:22:42.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/66/05/7957af15543b8c9799209506df4660cba7afc4cf94bfb60513827e96bed6/s3transfer-0.10.4-py3-none-any.whl", hash = "sha256:244a76a24355363a68164241438de1b72f8781664920260c48465896b712a41e", size = 83175, upload-time = "2024-11-20T21:06:03.961Z" }, + { url = "https://files.pythonhosted.org/packages/6d/4f/d073e09df851cfa251ef7840007d04db3293a0482ce607d2b993926089be/s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724", size = 85308, upload-time = "2025-07-18T19:22:40.947Z" }, ] [[package]] @@ -4382,7 +3823,7 @@ wheels = [ [[package]] name = "sentence-transformers" -version = "4.1.0" +version = "5.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, @@ -4394,9 +3835,9 @@ dependencies = [ { name = "transformers" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/73/84/b30d1b29ff58cfdff423e36a50efd622c8e31d7039b1a0d5e72066620da1/sentence_transformers-4.1.0.tar.gz", hash = "sha256:f125ffd1c727533e0eca5d4567de72f84728de8f7482834de442fd90c2c3d50b", size = 272420, upload-time = "2025-04-15T13:46:13.732Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/47/7d61a19ba7e6b5f36f0ffff5bbf032a1c1913612caac611e12383069eda0/sentence_transformers-5.1.1.tar.gz", hash = "sha256:8af3f844b2ecf9a6c2dfeafc2c02938a87f61202b54329d70dfd7dfd7d17a84e", size = 374434, upload-time = "2025-09-22T11:28:27.54Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/2d/1151b371f28caae565ad384fdc38198f1165571870217aedda230b9d7497/sentence_transformers-4.1.0-py3-none-any.whl", hash = "sha256:382a7f6be1244a100ce40495fb7523dbe8d71b3c10b299f81e6b735092b3b8ca", size = 345695, upload-time = "2025-04-15T13:46:12.44Z" }, + { url = "https://files.pythonhosted.org/packages/48/21/4670d03ab8587b0ab6f7d5fa02a95c3dd6b1f39d0e40e508870201f3d76c/sentence_transformers-5.1.1-py3-none-any.whl", hash = "sha256:5ed544629eafe89ca668a8910ebff96cf0a9c5254ec14b05c66c086226c892fd", size = 486574, upload-time = "2025-09-22T11:28:26.311Z" }, ] [[package]] @@ -4485,15 +3926,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] -[[package]] -name = "smmap" -version = "5.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, -] - [[package]] name = "sniffio" version = "1.3.1" @@ -4569,6 +4001,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/aa/e4/592120713a314621c692211eba034d09becaf6bc8848fabc1dc2a54d8c16/SQLAlchemy-2.0.38-py3-none-any.whl", hash = "sha256:63178c675d4c80def39f1febd625a6333f44c0ba269edd8a468b156394b27753", size = 1896347, upload-time = "2025-02-06T22:08:29.784Z" }, ] +[[package]] +name = "sse-starlette" +version = "3.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/db/3c/fa6517610dc641262b77cc7bf994ecd17465812c1b0585fe33e11be758ab/sse_starlette-3.0.3.tar.gz", hash = "sha256:88cfb08747e16200ea990c8ca876b03910a23b547ab3bd764c0d8eb81019b971", size = 21943, upload-time = "2025-10-30T18:44:20.117Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/23/a0/984525d19ca5c8a6c33911a0c164b11490dd0f90ff7fd689f704f84e9a11/sse_starlette-3.0.3-py3-none-any.whl", hash = "sha256:af5bf5a6f3933df1d9c7f8539633dc8444ca6a97ab2e2a7cd3b6e431ac03a431", size = 11765, upload-time = "2025-10-30T18:44:18.834Z" }, +] + [[package]] name = "starlette" version = "0.45.3" @@ -4596,6 +4040,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/df/4a/40ff289cdc106f6ec0c157c17f5cff13fac582ad0be54637b6081d64f547/starlette_compress-1.6.0-py3-none-any.whl", hash = "sha256:861bbf56df551bd33da95f0d7af102db0034f2786cd5ec3eae713d39a9c44ea6", size = 11390, upload-time = "2025-05-21T09:37:55.625Z" }, ] +[[package]] +name = "starsessions" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "itsdangerous" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/a1/dd738cd47b7a1c681cae49c4f7c88cc953b2aca4de455c2aacda6652e7ce/starsessions-2.2.1.tar.gz", hash = "sha256:ce5e4448d9bf2c76222e56cd099ad92d22313e8a4def612e22b71a122cc11da0", size = 15048, upload-time = "2024-10-23T09:01:12.343Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/ce/fc699345a3cdfb4425b5dc1e446f1b49702ac55907a6a4d5d806f2512dae/starsessions-2.2.1-py3-none-any.whl", hash = "sha256:8097b33d70017b2d2331307f0ea923620b5bfb847118d2e5872805d0c1c16f83", size = 14621, upload-time = "2024-10-23T09:01:10.88Z" }, +] + +[package.optional-dependencies] +redis = [ + { name = "redis" }, +] + [[package]] name = "sympy" version = "1.13.1" @@ -4617,18 +4079,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b6/cb/b86984bed139586d01532a587464b5805f12e397594f19f931c4c2fbfa61/tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539", size = 28169, upload-time = "2024-07-29T12:12:25.825Z" }, ] -[[package]] -name = "tencentcloud-sdk-python" -version = "3.0.1336" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/d6/4d57d25c0614cccb9d017962f3bfe20313b2c42bdfa3c4c33fa02c35906d/tencentcloud-sdk-python-3.0.1336.tar.gz", hash = "sha256:1c6a1413267030c142ba2a2e4f64ce12026157efd0f4c446efca1856dbae6f35", size = 11427085, upload-time = "2025-03-10T20:45:29.435Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/c7/e1877f3962966b3442218b0ccaadaa70eb1c89171f5f06eace029bd49c6d/tencentcloud_sdk_python-3.0.1336-py2.py3-none-any.whl", hash = "sha256:1c6280d427274b6f76e01220951ee49fd203c1c78d79e5ba62bfc3df6e566299", size = 12165181, upload-time = "2025-03-10T20:45:16.982Z" }, -] - [[package]] name = "threadpoolctl" version = "3.5.0" @@ -4839,42 +4289,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/97/3f/c4c51c55ff8487f2e6d0e618dba917e3c3ee2caae6cf0fbb59c9b1876f2e/tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8", size = 17859, upload-time = "2023-10-22T17:41:36.511Z" }, ] -[[package]] -name = "ujson" -version = "5.10.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/00/3110fd566786bfa542adb7932d62035e0c0ef662a8ff6544b6643b3d6fd7/ujson-5.10.0.tar.gz", hash = "sha256:b3cd8f3c5d8c7738257f1018880444f7b7d9b66232c64649f562d7ba86ad4bc1", size = 7154885, upload-time = "2024-05-14T02:02:34.233Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/ec/3c551ecfe048bcb3948725251fb0214b5844a12aa60bee08d78315bb1c39/ujson-5.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a5b366812c90e69d0f379a53648be10a5db38f9d4ad212b60af00bd4048d0f00", size = 55353, upload-time = "2024-05-14T02:00:48.04Z" }, - { url = "https://files.pythonhosted.org/packages/8d/9f/4731ef0671a0653e9f5ba18db7c4596d8ecbf80c7922dd5fe4150f1aea76/ujson-5.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:502bf475781e8167f0f9d0e41cd32879d120a524b22358e7f205294224c71126", size = 51813, upload-time = "2024-05-14T02:00:49.28Z" }, - { url = "https://files.pythonhosted.org/packages/1f/2b/44d6b9c1688330bf011f9abfdb08911a9dc74f76926dde74e718d87600da/ujson-5.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b91b5d0d9d283e085e821651184a647699430705b15bf274c7896f23fe9c9d8", size = 51988, upload-time = "2024-05-14T02:00:50.484Z" }, - { url = "https://files.pythonhosted.org/packages/29/45/f5f5667427c1ec3383478092a414063ddd0dfbebbcc533538fe37068a0a3/ujson-5.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:129e39af3a6d85b9c26d5577169c21d53821d8cf68e079060602e861c6e5da1b", size = 53561, upload-time = "2024-05-14T02:00:52.146Z" }, - { url = "https://files.pythonhosted.org/packages/26/21/a0c265cda4dd225ec1be595f844661732c13560ad06378760036fc622587/ujson-5.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f77b74475c462cb8b88680471193064d3e715c7c6074b1c8c412cb526466efe9", size = 58497, upload-time = "2024-05-14T02:00:53.366Z" }, - { url = "https://files.pythonhosted.org/packages/28/36/8fde862094fd2342ccc427a6a8584fed294055fdee341661c78660f7aef3/ujson-5.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ec0ca8c415e81aa4123501fee7f761abf4b7f386aad348501a26940beb1860f", size = 997877, upload-time = "2024-05-14T02:00:55.095Z" }, - { url = "https://files.pythonhosted.org/packages/90/37/9208e40d53baa6da9b6a1c719e0670c3f474c8fc7cc2f1e939ec21c1bc93/ujson-5.10.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab13a2a9e0b2865a6c6db9271f4b46af1c7476bfd51af1f64585e919b7c07fd4", size = 1140632, upload-time = "2024-05-14T02:00:57.099Z" }, - { url = "https://files.pythonhosted.org/packages/89/d5/2626c87c59802863d44d19e35ad16b7e658e4ac190b0dead17ff25460b4c/ujson-5.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57aaf98b92d72fc70886b5a0e1a1ca52c2320377360341715dd3933a18e827b1", size = 1043513, upload-time = "2024-05-14T02:00:58.488Z" }, - { url = "https://files.pythonhosted.org/packages/2f/ee/03662ce9b3f16855770f0d70f10f0978ba6210805aa310c4eebe66d36476/ujson-5.10.0-cp311-cp311-win32.whl", hash = "sha256:2987713a490ceb27edff77fb184ed09acdc565db700ee852823c3dc3cffe455f", size = 38616, upload-time = "2024-05-14T02:01:00.463Z" }, - { url = "https://files.pythonhosted.org/packages/3e/20/952dbed5895835ea0b82e81a7be4ebb83f93b079d4d1ead93fcddb3075af/ujson-5.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:f00ea7e00447918ee0eff2422c4add4c5752b1b60e88fcb3c067d4a21049a720", size = 42071, upload-time = "2024-05-14T02:01:02.211Z" }, - { url = "https://files.pythonhosted.org/packages/e8/a6/fd3f8bbd80842267e2d06c3583279555e8354c5986c952385199d57a5b6c/ujson-5.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:98ba15d8cbc481ce55695beee9f063189dce91a4b08bc1d03e7f0152cd4bbdd5", size = 55642, upload-time = "2024-05-14T02:01:04.055Z" }, - { url = "https://files.pythonhosted.org/packages/a8/47/dd03fd2b5ae727e16d5d18919b383959c6d269c7b948a380fdd879518640/ujson-5.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9d2edbf1556e4f56e50fab7d8ff993dbad7f54bac68eacdd27a8f55f433578e", size = 51807, upload-time = "2024-05-14T02:01:05.25Z" }, - { url = "https://files.pythonhosted.org/packages/25/23/079a4cc6fd7e2655a473ed9e776ddbb7144e27f04e8fc484a0fb45fe6f71/ujson-5.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6627029ae4f52d0e1a2451768c2c37c0c814ffc04f796eb36244cf16b8e57043", size = 51972, upload-time = "2024-05-14T02:01:06.458Z" }, - { url = "https://files.pythonhosted.org/packages/04/81/668707e5f2177791869b624be4c06fb2473bf97ee33296b18d1cf3092af7/ujson-5.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ccb77b3e40b151e20519c6ae6d89bfe3f4c14e8e210d910287f778368bb3d1", size = 53686, upload-time = "2024-05-14T02:01:07.618Z" }, - { url = "https://files.pythonhosted.org/packages/bd/50/056d518a386d80aaf4505ccf3cee1c40d312a46901ed494d5711dd939bc3/ujson-5.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3caf9cd64abfeb11a3b661329085c5e167abbe15256b3b68cb5d914ba7396f3", size = 58591, upload-time = "2024-05-14T02:01:08.901Z" }, - { url = "https://files.pythonhosted.org/packages/fc/d6/aeaf3e2d6fb1f4cfb6bf25f454d60490ed8146ddc0600fae44bfe7eb5a72/ujson-5.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6e32abdce572e3a8c3d02c886c704a38a1b015a1fb858004e03d20ca7cecbb21", size = 997853, upload-time = "2024-05-14T02:01:10.772Z" }, - { url = "https://files.pythonhosted.org/packages/f8/d5/1f2a5d2699f447f7d990334ca96e90065ea7f99b142ce96e85f26d7e78e2/ujson-5.10.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a65b6af4d903103ee7b6f4f5b85f1bfd0c90ba4eeac6421aae436c9988aa64a2", size = 1140689, upload-time = "2024-05-14T02:01:12.214Z" }, - { url = "https://files.pythonhosted.org/packages/f2/2c/6990f4ccb41ed93744aaaa3786394bca0875503f97690622f3cafc0adfde/ujson-5.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:604a046d966457b6cdcacc5aa2ec5314f0e8c42bae52842c1e6fa02ea4bda42e", size = 1043576, upload-time = "2024-05-14T02:01:14.39Z" }, - { url = "https://files.pythonhosted.org/packages/14/f5/a2368463dbb09fbdbf6a696062d0c0f62e4ae6fa65f38f829611da2e8fdd/ujson-5.10.0-cp312-cp312-win32.whl", hash = "sha256:6dea1c8b4fc921bf78a8ff00bbd2bfe166345f5536c510671bccececb187c80e", size = 38764, upload-time = "2024-05-14T02:01:15.83Z" }, - { url = "https://files.pythonhosted.org/packages/59/2d/691f741ffd72b6c84438a93749ac57bf1a3f217ac4b0ea4fd0e96119e118/ujson-5.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:38665e7d8290188b1e0d57d584eb8110951a9591363316dd41cf8686ab1d0abc", size = 42211, upload-time = "2024-05-14T02:01:17.567Z" }, -] - [[package]] name = "unstructured" -version = "0.16.17" +version = "0.18.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "backoff" }, { name = "beautifulsoup4" }, - { name = "chardet" }, + { name = "charset-normalizer" }, { name = "dataclasses-json" }, { name = "emoji" }, { name = "filetype" }, @@ -4894,9 +4316,9 @@ dependencies = [ { name = "unstructured-client" }, { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/85/90/cf5cbf152d0d1ab507c14e2535d4a9442ad59308ced8c26b71d8b93ace52/unstructured-0.16.17.tar.gz", hash = "sha256:590700ed344ed27a6dce8b3ffdeec2c427bd4f057d9bcb470f8ce828cc20b314", size = 1670303, upload-time = "2025-01-29T12:53:50.37Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/08/cf969b274f652e2fe48a6807b827498c7142dc749bdbd46ab24ea97a5fd5/unstructured-0.18.15.tar.gz", hash = "sha256:81d8481280a4ac5cefe74bdb6db3687e8f240d5643706f86728eac39549112b5", size = 1691102, upload-time = "2025-09-17T14:30:59.524Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/b7/b0f668213b8b3d17190da161faa7eae5681627835fab76094c4697b12729/unstructured-0.16.17-py3-none-any.whl", hash = "sha256:9b55bf47ac6532f16e6ef27f5b823e037ab860f07d377784b9dc43a99a981268", size = 1755843, upload-time = "2025-01-29T12:53:47.374Z" }, + { url = "https://files.pythonhosted.org/packages/62/24/7b8a8a9c23b209dc484b0d82905847c5f6b96a579bade367f3f3e40263f3/unstructured-0.18.15-py3-none-any.whl", hash = "sha256:f05b1defcbe8190319d30da8adddbb888f74bf8ec7f65886867d7dca41d67ad0", size = 1778900, upload-time = "2025-09-17T14:30:57.872Z" }, ] [[package]] @@ -4937,15 +4359,15 @@ wheels = [ [[package]] name = "uvicorn" -version = "0.34.2" +version = "0.37.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/ae/9bbb19b9e1c450cf9ecaef06463e40234d98d95bf572fab11b4f19ae5ded/uvicorn-0.34.2.tar.gz", hash = "sha256:0e929828f6186353a80b58ea719861d2629d766293b6d19baf086ba31d4f3328", size = 76815, upload-time = "2025-04-19T06:02:50.101Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/57/1616c8274c3442d802621abf5deb230771c7a0fec9414cb6763900eb3868/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13", size = 80367, upload-time = "2025-09-23T13:33:47.486Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/4b/4cef6ce21a2aaca9d852a6e84ef4f135d99fcd74fa75105e2fc0c8308acd/uvicorn-0.34.2-py3-none-any.whl", hash = "sha256:deb49af569084536d269fe0a6d67e3754f104cf03aba7c11c40f01aadf33c403", size = 62483, upload-time = "2025-04-19T06:02:48.42Z" }, + { url = "https://files.pythonhosted.org/packages/85/cd/584a2ceb5532af99dd09e50919e3615ba99aa127e9850eafe5f31ddfdb9a/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c", size = 67976, upload-time = "2025-09-23T13:33:45.842Z" }, ] [package.optional-dependencies] @@ -5083,18 +4505,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/0b/c7e5d11020242984d9d37990310520ed663b942333b83a033c2f20191113/websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e", size = 156277, upload-time = "2024-11-13T07:11:27.848Z" }, ] -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - [[package]] name = "win32-setctime" version = "1.2.0" @@ -5165,53 +4575,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/ea/53d1fe468e63e092cf16e2c18d16f50c29851242f9dd12d6a66e0d7f0d02/XlsxWriter-3.2.0-py3-none-any.whl", hash = "sha256:ecfd5405b3e0e228219bcaf24c2ca0915e012ca9464a14048021d21a995d490e", size = 159925, upload-time = "2024-02-18T23:11:21.559Z" }, ] -[[package]] -name = "xmltodict" -version = "0.14.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942, upload-time = "2024-10-16T06:10:29.683Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981, upload-time = "2024-10-16T06:10:27.649Z" }, -] - -[[package]] -name = "xxhash" -version = "3.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/5e/d6e5258d69df8b4ed8c83b6664f2b47d30d2dec551a29ad72a6c69eafd31/xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f", size = 84241, upload-time = "2024-08-17T09:20:38.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/c7/afed0f131fbda960ff15eee7f304fa0eeb2d58770fade99897984852ef23/xxhash-3.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02c2e816896dc6f85922ced60097bcf6f008dedfc5073dcba32f9c8dd786f3c1", size = 31969, upload-time = "2024-08-17T09:18:00.852Z" }, - { url = "https://files.pythonhosted.org/packages/8c/0c/7c3bc6d87e5235672fcc2fb42fd5ad79fe1033925f71bf549ee068c7d1ca/xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6027dcd885e21581e46d3c7f682cfb2b870942feeed58a21c29583512c3f09f8", size = 30800, upload-time = "2024-08-17T09:18:01.863Z" }, - { url = "https://files.pythonhosted.org/packages/04/9e/01067981d98069eec1c20201f8c145367698e9056f8bc295346e4ea32dd1/xxhash-3.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1308fa542bbdbf2fa85e9e66b1077eea3a88bef38ee8a06270b4298a7a62a166", size = 221566, upload-time = "2024-08-17T09:18:03.461Z" }, - { url = "https://files.pythonhosted.org/packages/d4/09/d4996de4059c3ce5342b6e1e6a77c9d6c91acce31f6ed979891872dd162b/xxhash-3.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c28b2fdcee797e1c1961cd3bcd3d545cab22ad202c846235197935e1df2f8ef7", size = 201214, upload-time = "2024-08-17T09:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/62/f5/6d2dc9f8d55a7ce0f5e7bfef916e67536f01b85d32a9fbf137d4cadbee38/xxhash-3.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:924361811732ddad75ff23e90efd9ccfda4f664132feecb90895bade6a1b4623", size = 429433, upload-time = "2024-08-17T09:18:06.957Z" }, - { url = "https://files.pythonhosted.org/packages/d9/72/9256303f10e41ab004799a4aa74b80b3c5977d6383ae4550548b24bd1971/xxhash-3.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89997aa1c4b6a5b1e5b588979d1da048a3c6f15e55c11d117a56b75c84531f5a", size = 194822, upload-time = "2024-08-17T09:18:08.331Z" }, - { url = "https://files.pythonhosted.org/packages/34/92/1a3a29acd08248a34b0e6a94f4e0ed9b8379a4ff471f1668e4dce7bdbaa8/xxhash-3.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:685c4f4e8c59837de103344eb1c8a3851f670309eb5c361f746805c5471b8c88", size = 208538, upload-time = "2024-08-17T09:18:10.332Z" }, - { url = "https://files.pythonhosted.org/packages/53/ad/7fa1a109663366de42f724a1cdb8e796a260dbac45047bce153bc1e18abf/xxhash-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbd2ecfbfee70bc1a4acb7461fa6af7748ec2ab08ac0fa298f281c51518f982c", size = 216953, upload-time = "2024-08-17T09:18:11.707Z" }, - { url = "https://files.pythonhosted.org/packages/35/02/137300e24203bf2b2a49b48ce898ecce6fd01789c0fcd9c686c0a002d129/xxhash-3.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:25b5a51dc3dfb20a10833c8eee25903fd2e14059e9afcd329c9da20609a307b2", size = 203594, upload-time = "2024-08-17T09:18:13.799Z" }, - { url = "https://files.pythonhosted.org/packages/23/03/aeceb273933d7eee248c4322b98b8e971f06cc3880e5f7602c94e5578af5/xxhash-3.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a8fb786fb754ef6ff8c120cb96629fb518f8eb5a61a16aac3a979a9dbd40a084", size = 210971, upload-time = "2024-08-17T09:18:15.824Z" }, - { url = "https://files.pythonhosted.org/packages/e3/64/ed82ec09489474cbb35c716b189ddc1521d8b3de12b1b5ab41ce7f70253c/xxhash-3.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a905ad00ad1e1c34fe4e9d7c1d949ab09c6fa90c919860c1534ff479f40fd12d", size = 415050, upload-time = "2024-08-17T09:18:17.142Z" }, - { url = "https://files.pythonhosted.org/packages/71/43/6db4c02dcb488ad4e03bc86d70506c3d40a384ee73c9b5c93338eb1f3c23/xxhash-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:963be41bcd49f53af6d795f65c0da9b4cc518c0dd9c47145c98f61cb464f4839", size = 192216, upload-time = "2024-08-17T09:18:18.779Z" }, - { url = "https://files.pythonhosted.org/packages/22/6d/db4abec29e7a567455344433d095fdb39c97db6955bb4a2c432e486b4d28/xxhash-3.5.0-cp311-cp311-win32.whl", hash = "sha256:109b436096d0a2dd039c355fa3414160ec4d843dfecc64a14077332a00aeb7da", size = 30120, upload-time = "2024-08-17T09:18:20.009Z" }, - { url = "https://files.pythonhosted.org/packages/52/1c/fa3b61c0cf03e1da4767213672efe186b1dfa4fc901a4a694fb184a513d1/xxhash-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:b702f806693201ad6c0a05ddbbe4c8f359626d0b3305f766077d51388a6bac58", size = 30003, upload-time = "2024-08-17T09:18:21.052Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8e/9e6fc572acf6e1cc7ccb01973c213f895cb8668a9d4c2b58a99350da14b7/xxhash-3.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:c4dcb4120d0cc3cc448624147dba64e9021b278c63e34a38789b688fd0da9bf3", size = 26777, upload-time = "2024-08-17T09:18:22.809Z" }, - { url = "https://files.pythonhosted.org/packages/07/0e/1bfce2502c57d7e2e787600b31c83535af83746885aa1a5f153d8c8059d6/xxhash-3.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00", size = 31969, upload-time = "2024-08-17T09:18:24.025Z" }, - { url = "https://files.pythonhosted.org/packages/3f/d6/8ca450d6fe5b71ce521b4e5db69622383d039e2b253e9b2f24f93265b52c/xxhash-3.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9", size = 30787, upload-time = "2024-08-17T09:18:25.318Z" }, - { url = "https://files.pythonhosted.org/packages/5b/84/de7c89bc6ef63d750159086a6ada6416cc4349eab23f76ab870407178b93/xxhash-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84", size = 220959, upload-time = "2024-08-17T09:18:26.518Z" }, - { url = "https://files.pythonhosted.org/packages/fe/86/51258d3e8a8545ff26468c977101964c14d56a8a37f5835bc0082426c672/xxhash-3.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793", size = 200006, upload-time = "2024-08-17T09:18:27.905Z" }, - { url = "https://files.pythonhosted.org/packages/02/0a/96973bd325412feccf23cf3680fd2246aebf4b789122f938d5557c54a6b2/xxhash-3.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be", size = 428326, upload-time = "2024-08-17T09:18:29.335Z" }, - { url = "https://files.pythonhosted.org/packages/11/a7/81dba5010f7e733de88af9555725146fc133be97ce36533867f4c7e75066/xxhash-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6", size = 194380, upload-time = "2024-08-17T09:18:30.706Z" }, - { url = "https://files.pythonhosted.org/packages/fb/7d/f29006ab398a173f4501c0e4977ba288f1c621d878ec217b4ff516810c04/xxhash-3.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90", size = 207934, upload-time = "2024-08-17T09:18:32.133Z" }, - { url = "https://files.pythonhosted.org/packages/8a/6e/6e88b8f24612510e73d4d70d9b0c7dff62a2e78451b9f0d042a5462c8d03/xxhash-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27", size = 216301, upload-time = "2024-08-17T09:18:33.474Z" }, - { url = "https://files.pythonhosted.org/packages/af/51/7862f4fa4b75a25c3b4163c8a873f070532fe5f2d3f9b3fc869c8337a398/xxhash-3.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2", size = 203351, upload-time = "2024-08-17T09:18:34.889Z" }, - { url = "https://files.pythonhosted.org/packages/22/61/8d6a40f288f791cf79ed5bb113159abf0c81d6efb86e734334f698eb4c59/xxhash-3.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d", size = 210294, upload-time = "2024-08-17T09:18:36.355Z" }, - { url = "https://files.pythonhosted.org/packages/17/02/215c4698955762d45a8158117190261b2dbefe9ae7e5b906768c09d8bc74/xxhash-3.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab", size = 414674, upload-time = "2024-08-17T09:18:38.536Z" }, - { url = "https://files.pythonhosted.org/packages/31/5c/b7a8db8a3237cff3d535261325d95de509f6a8ae439a5a7a4ffcff478189/xxhash-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e", size = 192022, upload-time = "2024-08-17T09:18:40.138Z" }, - { url = "https://files.pythonhosted.org/packages/78/e3/dd76659b2811b3fd06892a8beb850e1996b63e9235af5a86ea348f053e9e/xxhash-3.5.0-cp312-cp312-win32.whl", hash = "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8", size = 30170, upload-time = "2024-08-17T09:18:42.163Z" }, - { url = "https://files.pythonhosted.org/packages/d9/6b/1c443fe6cfeb4ad1dcf231cdec96eb94fb43d6498b4469ed8b51f8b59a37/xxhash-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e", size = 30040, upload-time = "2024-08-17T09:18:43.699Z" }, - { url = "https://files.pythonhosted.org/packages/0f/eb/04405305f290173acc0350eba6d2f1a794b57925df0398861a20fbafa415/xxhash-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2", size = 26796, upload-time = "2024-08-17T09:18:45.29Z" }, -] - [[package]] name = "yarl" version = "1.18.3" @@ -5260,15 +4623,15 @@ wheels = [ [[package]] name = "youtube-transcript-api" -version = "1.1.0" +version = "1.2.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "defusedxml" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/dd/10d413b20a2d14fa483853d0f6d920a0a0a6887d7c60167e4641733f99fb/youtube_transcript_api-1.1.0.tar.gz", hash = "sha256:786d9e64bd7fffee0dbc1471a61a798cebdc379b9cf8f7661d3664e831fcc1a5", size = 470144, upload-time = "2025-06-11T22:30:44.048Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/f8/5e12d3d0c7001c3b3078697b9918241022bdb1ae12715e9debb00a83e16e/youtube_transcript_api-1.2.2.tar.gz", hash = "sha256:5f67cfaff3621d969778817a3d7b2172c16784855f45fcaed4f0529632e2fef4", size = 469634, upload-time = "2025-08-04T12:22:52.158Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/69/63f1b9f96a9d3b6bd35288fe27f987c41bd157e47b3d07ca025549e3f8e6/youtube_transcript_api-1.1.0-py3-none-any.whl", hash = "sha256:876ac42b1e3f8cc99b81d8fd810bd74ed07511e51dff5db50e714e3156ad3595", size = 485739, upload-time = "2025-06-11T22:30:40.515Z" }, + { url = "https://files.pythonhosted.org/packages/41/92/3d1a580f0efcad926f45876cf6cb92b2c260e84ae75dae5463bbf38f92e7/youtube_transcript_api-1.2.2-py3-none-any.whl", hash = "sha256:feca8c7f7c9d65188ef6377fc0e01cf466e6b68f1b3e648019646ab342f994d2", size = 485047, upload-time = "2025-08-04T12:22:50.836Z" }, ] [[package]] @@ -5321,4 +4684,4 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f2/61/ac78a1263bc83a5cf29e7458b77a568eda5a8f81980691bbc6eb6a0d45cc/zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35", size = 5191313, upload-time = "2024-07-15T00:16:09.758Z" }, { url = "https://files.pythonhosted.org/packages/e7/54/967c478314e16af5baf849b6ee9d6ea724ae5b100eb506011f045d3d4e16/zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d", size = 430877, upload-time = "2024-07-15T00:16:11.758Z" }, { url = "https://files.pythonhosted.org/packages/75/37/872d74bd7739639c4553bf94c84af7d54d8211b626b352bc57f0fd8d1e3f/zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b", size = 495595, upload-time = "2024-07-15T00:16:13.731Z" }, -] \ No newline at end of file +] diff --git a/vite.config.ts b/vite.config.ts index df802c081cb4..22eaec706f50 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,6 +3,7 @@ import { defineConfig } from 'vite'; import { viteStaticCopy } from 'vite-plugin-static-copy'; +// @ts-ignore export default defineConfig({ plugins: [ sveltekit(), @@ -26,6 +27,30 @@ export default defineConfig({ worker: { format: 'es' }, + server: { + port: 5173, + proxy: { + '^/kael/api/': { + target: 'http://localhost:8083', + changeOrigin: true + // 如果后端实际上是 /api 而不是 /kael/api,添加: + // rewrite: p => p.replace(/^\/kael\/api\//, '/api/') + }, + '/kael/openai': { + target: 'http://localhost:8083', + changeOrigin: true + }, + '/kael/ollama': { + target: 'http://localhost:8083', + changeOrigin: true + }, + '/kael/ws': { + target: 'http://localhost:8083', + ws: true, + changeOrigin: true + } + } + }, esbuild: { pure: process.env.ENV === 'dev' ? [] : ['console.log', 'console.debug', 'console.error'] }