modify: jwt 完善

This commit is contained in:
2026-07-23 17:29:26 +08:00
parent a25ec7630f
commit b5aa970213
15 changed files with 327 additions and 124 deletions
+6
View File
@@ -26,3 +26,9 @@ config
# chongming-utils
utils
# vscode
.vscode
# .agents
.agents
+1 -1
View File
@@ -54,4 +54,4 @@ uv run serve
## 更多文档
- Worker 开发指南(待补充)
- [配置说明](http://124.71.68.6:3000/chongming/chongming-config.git/README.md)
- [配置说明](http://124.71.68.6:3000/chongming/chongming-config/src/branch/master/README.md)
+5 -3
View File
@@ -26,10 +26,7 @@ job_store_path = "scheduler_jobs.db"
cache_store_path = "./cache_data"
[security]
access_token_expire_minutes = 1440
algorithm = "HS256"
max_sessions_per_user = 5
refresh_token_expire_days = 7
secret_key = "your-secret-key-change-in-production"
[development]
@@ -79,6 +76,11 @@ base = [
"nanio",
"boto3",
"modelvault",
"volcenginesdkarkruntime",
"chongming_jwt",
"chongming-database",
"aiosqlite",
"sqlmodel",
]
linux = [
"gunicorn.glogging",
+10 -12
View File
@@ -8,12 +8,11 @@ dependencies = [
"boto3",
"chongming-jwt",
"chongming-request",
"chongming-worker",
"chongming-database",
"diskcache",
"eclipse-zenoh",
"fastapi[uvicorn]",
"gunicorn",
"modelvault",
"module-bank",
"nanio",
"openai",
@@ -24,6 +23,9 @@ dependencies = [
"typing-extensions",
"uvicorn",
"volcengine-python-sdk[ark]>=5.0.41",
"chongming-config",
"chongming-password",
"chongming-worker",
]
description = "基于 modules-bank 的 fastapi 打包脚手架"
name = "chongming-zenoh"
@@ -45,17 +47,13 @@ packages = ["src/chongming"]
[[tool.uv.index]]
url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple"
[tool.uv.workspace]
members = [
"utils/worker",
"utils/request",
"utils/jwt",
]
[tool.uv.sources]
chongming-request = { workspace = true }
chongming-worker = { workspace = true }
chongming-jwt = { workspace = true }
chongming-request = { git = "http://124.71.68.6:3000/chongming/chongming-utils-request.git" }
chongming-jwt = { git = "http://124.71.68.6:3000/chongming/chongming-utils-jwt.git" }
chongming-database = { git = "http://124.71.68.6:3000/chongming/chongming-utils-database.git" }
chongming-config = { git = "http://124.71.68.6:3000/chongming/chongming-utils-config.git" }
chongming-password = { git = "http://124.71.68.6:3000/chongming/chongming-utils-password.git" }
chongming-worker = { git = "http://124.71.68.6:3000/chongming/chongming-utils-worker.git" }
[project.scripts]
build = "chongming.scripts.build:build"
+1 -2
View File
@@ -1,5 +1,5 @@
import uvicorn
from .app.core.config import load_config
from chongming_config import load_config
from .app.core.logger import get_logger
@@ -22,7 +22,6 @@ def serve():
logger.info(f"启动日志: {log_config}")
uvicorn.run("chongming.app:app", **server_config)
def gunicorn_serve():
"""
使用 gunicorn 启动服务
+1 -1
View File
@@ -15,7 +15,7 @@ from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from .core.config import get_config
from chongming_config import get_config
from .core.logger import get_logger
from .core.static_files import SVFSStaticFiles
from .core import lifespan_setup
+42
View File
@@ -0,0 +1,42 @@
from fastapi import Depends, HTTPException, status, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from chongming_jwt import JWT
from chongming_config import get_config
security_scheme = HTTPBearer(auto_error=False)
def jwt_auth_dependency(
credentials: HTTPAuthorizationCredentials = Depends(security_scheme)
) -> dict:
"""JWT 校验依赖,返回解码后的 payload,校验失败抛出 401"""
config =get_config()
secret = config["security"]["secret_key"]
algorithm = config["security"]["algorithm"]
jwt = JWT(secret, algorithm)
if not credentials:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Missing authorization header",
headers={"WWW-Authenticate": "Bearer"},
)
token = credentials.credentials
try:
payload_str = jwt.decode(token)
import json
payload = json.loads(payload_str)
return payload
except Exception as e:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=f"Invalid token: {str(e)}",
headers={"WWW-Authenticate": "Bearer"},
)
async def store_user_to_request(
request: Request,
user: dict = Depends(jwt_auth_dependency)
) -> None:
request.state.user = user
+73 -26
View File
@@ -1,8 +1,10 @@
import os
import inspect
import subprocess
import time
import multiprocessing
import asyncio
import socket
import sys
import boto3
from botocore.exceptions import ClientError
@@ -11,7 +13,7 @@ from diskcache import Cache
from fastapi import FastAPI
import zenoh
from ..core.config import get_config, get_workers_config
from chongming_config import get_config, get_workers_config
from ..core.logger import get_logger
from ..core.route_generator import register_dynamic_routes
from ..core.worker_manager import WorkerManager
@@ -24,26 +26,61 @@ try:
except KeyError: # pragma: no cover
raise ValueError("配置不存在")
def setup_nanio(app: FastAPI):
"""启动 nanio 子进程作为 S3 兼容存储服务。"""
nanio_config = config.get("nanio", {})
env = os.environ.copy()
env["NANIO_ACCESS_KEY"] = nanio_config.get("nanio_access_key", "minioadmin")
env["NANIO_SECRET_KEY"] = nanio_config.get("nanio_secret_key", "minioadmin")
def is_port_in_use(port: int, host: str = "127.0.0.1") -> bool:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.settimeout(0.5)
return s.connect_ex((host, port)) == 0
proc = subprocess.Popen(
[
"nanio",
"serve",
"--data-dir",
nanio_config.get("storage_path", "./data/storage")
],
env=env,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
def _run_nanio():
"""子进程入口:直接调用 nanio.cli.main()"""
# 设置环境变量(从主进程继承,但重新设置确保有效)
os.environ.setdefault("NANIO_ACCESS_KEY", "minioadmin")
os.environ.setdefault("NANIO_SECRET_KEY", "minioadmin")
os.environ.setdefault("NANIO_DATA_DIR", "./data/storage")
os.environ.setdefault("NANIO_HOST", "127.0.0.1")
os.environ.setdefault("NANIO_PORT", "9000")
# 伪造 sys.argv 使 nanio 认为是以 `nanio serve` 启动
sys.argv = ["nanio", "serve"]
try:
from nanio.cli import main
main()
except Exception as e:
with open("nanio_error.log", "w") as f:
f.write(f"Nanio server failed: {e}\n")
import traceback
traceback.print_exc(file=f)
raise
def setup_nanio(app: FastAPI):
if is_port_in_use(9000, "127.0.0.1"):
logger.info("Nanio 已在 127.0.0.1:9000 运行,跳过")
return
# 启动子进程
proc = multiprocessing.Process(target=_run_nanio, daemon=False)
proc.start()
app.state.nanio_process = proc
logger.info("Nanio 进程已启动")
logger.info("Nanio 子进程已启动 (PID: %s)", proc.pid)
# 等待端口可用
for _ in range(50): # 最多等待 5 秒
if is_port_in_use(9000, "127.0.0.1"):
logger.info("Nanio 已监听 9000 端口")
return
time.sleep(0.1)
# 超时或进程退出
if not proc.is_alive():
try:
with open("nanio_error.log", "r") as f:
err = f.read()
except FileNotFoundError:
err = "无错误日志"
logger.error("Nanio 进程已退出,错误: %s", err)
raise RuntimeError("Nanio 进程启动失败")
else:
logger.error("Nanio 进程启动超时(仍在运行但未监听端口)")
raise RuntimeError("Nanio 端口未就绪")
def setup_s3(app: FastAPI):
"""初始化 S3 客户端,并确保 bucket 存在。"""
@@ -56,12 +93,19 @@ def setup_s3(app: FastAPI):
config=Config(signature_version=nanio_config.get("signature_version", "s3v4")),
region_name=nanio_config.get("region_name", "us-east-1")
)
bucket = nanio_config.get("bucket", "chongming")
try:
s3_client.head_bucket(Bucket=nanio_config.get("bucket", "chongming"))
s3_client.head_bucket(Bucket=bucket)
except ClientError as e:
if e.response["Error"]["Code"] == "404":
s3_client.create_bucket(Bucket="chongming")
logger.info("Bucket 'chongming' 已创建")
try:
s3_client.create_bucket(Bucket=bucket)
logger.info(f"Bucket '{bucket}' 已创建")
except ClientError as create_err:
if create_err.response["Error"]["Code"] in ("BucketAlreadyOwnedByYou", "BucketAlreadyExists"):
logger.info(f"Bucket '{bucket}' 已存在(由其他进程创建),忽略")
else:
raise
else:
raise
@@ -141,9 +185,11 @@ async def register_routes(app: FastAPI, manager: WorkerManager):
async def shutdown_nanio(app: FastAPI):
"""终止 nanio 进程。"""
proc = getattr(app.state, "nanio_process", None)
if proc:
if proc and proc.is_alive():
proc.terminate()
proc.wait()
proc.join(timeout=5)
if proc.is_alive():
proc.kill()
logger.info("Nanio 进程已终止")
async def cleanup_workers(app: FastAPI):
@@ -171,3 +217,4 @@ async def cleanup_workers(app: FastAPI):
cleanup(worker_id)
except Exception as e:
logger.error(f"cleanup 调用失败 {module_name}: {e}")
+1 -1
View File
@@ -4,7 +4,7 @@ import datetime
from pathlib import Path
from logging.handlers import RotatingFileHandler
from ..core.config import get_config
from chongming_config import get_config
config = get_config()
+27 -8
View File
@@ -5,16 +5,15 @@
为每个端点生成带有正确 Pydantic 类型注解的处理函数,确保 OpenAPI 文档
正确反映参数类型、响应结构,并注册到 components/schemas。
"""
import asyncio
import json
from typing import Any, Dict, List, Optional, get_type_hints
from typing import Any, Dict, List, Optional
from inspect import Parameter, Signature
from fastapi import FastAPI, HTTPException, APIRouter, Query, Path as FastAPIPath, Depends
from fastapi import FastAPI, HTTPException, APIRouter, Query, Path as FastAPIPath, Request, Depends
from pydantic import create_model, Field, BaseModel
from .worker_manager import WorkerManager
from .logger import get_logger
from .auth import store_user_to_request
logger = get_logger("route_generator")
@@ -89,6 +88,7 @@ class RouteConfig:
self.docstring: str = data.get("docstring", "")
self.timeout: float = data.get("timeout", 3.0)
self.cacheable: bool = data.get("cacheable", False)
self.auth_required: bool = data.get("auth_required", True)
def parse_params(self) -> Dict[str, str]:
"""解析 params 列表为 {name: type} 字典"""
@@ -261,11 +261,15 @@ def _make_body_endpoint(worker_manager: WorkerManager, rc: RouteConfig, worker_t
cacheable = rc.cacheable
async def endpoint(
request: Request,
body: RequestModel, # type: ignore
) -> Any:
try:
payload = body.model_dump()
payload.setdefault("_method", http_method)
user_info = getattr(request.state, "user", None)
if user_info:
payload["user_info"] = user_info
result = await worker_manager.call(
worker_type=worker_type,
subject=subject,
@@ -304,12 +308,17 @@ def _make_query_endpoint(worker_manager: WorkerManager, rc: RouteConfig, worker_
# 无参数情况
if not param_spec_combined:
async def _simple_endpoint() -> Any:
async def _simple_endpoint(request: Request) -> Any:
payload = {}
payload.setdefault("_method", http_method)
user_info = getattr(request.state, "user", None)
if user_info:
payload["user_info"] = user_info
try:
result = await worker_manager.call(
worker_type=worker_type,
subject=subject,
payload={"_method": http_method},
payload=payload,
timeout=timeout,
cacheable=cacheable,
)
@@ -324,9 +333,12 @@ def _make_query_endpoint(worker_manager: WorkerManager, rc: RouteConfig, worker_
# 构造参数名列表(用于从 kwargs 中提取)
param_names = list(param_spec_combined.keys())
async def endpoint(**kwargs: Any) -> Any:
async def endpoint(request: Request, **kwargs: Any) -> Any:
payload = {k: kwargs[k] for k in param_names}
payload.setdefault("_method", http_method)
user_info = getattr(request.state, "user", None)
if user_info:
payload["user_info"] = user_info
try:
result = await worker_manager.call(
worker_type=worker_type,
@@ -343,7 +355,9 @@ def _make_query_endpoint(worker_manager: WorkerManager, rc: RouteConfig, worker_
raise HTTPException(status_code=500, detail="内部服务器错误")
# 构建带类型注解的 Parameter 列表
params: List[Parameter] = []
params: List[Parameter] = [
Parameter("request", Parameter.POSITIONAL_OR_KEYWORD, annotation=Request)
]
annotations: Dict[str, Any] = {}
for name, type_str in param_spec_combined.items():
py_type = _parse_python_type(type_str)
@@ -403,6 +417,10 @@ def _register_single_route(
extra_schemas[request_model_name] = RequestModel
endpoint = _make_query_endpoint(worker_manager, rc, worker_type, path_params, query_params)
dependencies = []
if rc.auth_required:
dependencies.append(Depends(store_user_to_request))
# 注册路由 - 使用 worker_type 作为 OpenAPI 分组标签
# 每个 worker 类型自动成为一个独立的分组,显示在 Swagger UI 中
router.add_api_route(
@@ -414,5 +432,6 @@ def _register_single_route(
response_model=ResponseModel,
tags=[worker_type],
include_in_schema=True,
dependencies=dependencies,
)
logger.info(f"已注册动态路由: {rc.method} {rc.path} -> worker {worker_type}.{rc.subject} | tags=[{worker_type}]")
+4 -1
View File
@@ -25,7 +25,7 @@ from module_bank import PythonToSQLite
from module_bank.encryption import Encryption
from sqlite_vfs.core import SQLiteVFS
from sqlite_vfs.folder_packer import FolderPacker
from ..app.core.config import get_config, Config
from chongming_config import get_config, Config
# ── 常量 ────────────────────────────────────────────────────────────────────
@@ -263,6 +263,9 @@ def _stage_pyinstaller(config: Config) -> tuple[str, str]:
for imp in build_imports:
cmd.extend(["--hidden-import", imp])
cmd.append("--collect-all")
cmd.append("nanio")
cmd.append("main.py")
result = _run_cmd(cmd, cwd="build", capture=True)
BIN
View File
Binary file not shown.
-27
View File
@@ -1,27 +0,0 @@
#!/usr/bin/env python
import json
from chongming_jwt import JWT
# 使用与 config.toml 相同的密钥(可从配置读取)
SECRET = "your-secret-key-change-in-production"
jwt = JWT(SECRET, "HS256")
# 1. 生成 token
payload = json.dumps({"sub": "test_user", "role": "admin"})
token = jwt.encode(payload, expires_in_seconds=3600)
print(f"✅ Token: {token}")
# 2. 解码验证
decoded = jwt.decode(token)
print(f"✅ Decoded: {decoded}")
# 3. 仅验证(不返回内容)
is_valid = jwt.validate(token)
print(f"✅ Valid: {is_valid}")
# 4. 测试无效 token
try:
jwt.decode(token + "invalid")
except Exception as e:
print(f"❌ Invalid token caught: {e}")
Generated
+155 -41
View File
@@ -2,14 +2,6 @@ version = 1
revision = 3
requires-python = ">=3.12"
[manifest]
members = [
"chongming-jwt",
"chongming-request",
"chongming-worker",
"chongming-zenoh",
]
[[package]]
name = "aiofiles"
version = "25.1.0"
@@ -19,6 +11,15 @@ wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" },
]
[[package]]
name = "aiosqlite"
version = "0.22.1"
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" }
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload-time = "2025-12-23T19:25:43.997Z" }
wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" },
]
[[package]]
name = "altgraph"
version = "0.17.5"
@@ -193,36 +194,51 @@ wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a0/17/1073b53b68c9b5ca6914adf5f8bf55aacc2d3be102418c90700160ea8605/cffi-2.1.0-cp315-cp315t-win_arm64.whl", hash = "sha256:cbb7640ce37159548d2147b5b8c241f962143d4c71231431820783f4dc78f210", size = 186405, upload-time = "2026-07-06T21:34:24.857Z" },
]
[[package]]
name = "chongming-config"
version = "0.1.0"
source = { git = "http://124.71.68.6:3000/chongming/chongming-utils-config.git#33470637c7346e8ef049bef2b0b202d7ed272c3d" }
dependencies = [
{ name = "tomli" },
{ name = "typing-extensions" },
]
[[package]]
name = "chongming-database"
version = "0.1.0"
source = { git = "http://124.71.68.6:3000/chongming/chongming-utils-database.git#b318f0f3cbdd85c98b86eec38a1fc51e8603d8da" }
dependencies = [
{ name = "aiosqlite" },
{ name = "sqlmodel" },
]
[[package]]
name = "chongming-jwt"
source = { editable = "utils/jwt" }
version = "0.1.0"
source = { git = "http://124.71.68.6:3000/chongming/chongming-utils-jwt.git#09489e74e6140859e7bbe5bd09343fbe5faf8a9a" }
[[package]]
name = "chongming-password"
version = "0.1.0"
source = { git = "http://124.71.68.6:3000/chongming/chongming-utils-password.git#589a56765f2e60cbb76e050047e5195023b6857d" }
[[package]]
name = "chongming-request"
version = "0.1.0"
source = { editable = "utils/request" }
source = { git = "http://124.71.68.6:3000/chongming/chongming-utils-request.git#a3b8dd032331660af7256eef360f075b45d6222d" }
dependencies = [
{ name = "eclipse-zenoh" },
]
[package.metadata]
requires-dist = [{ name = "eclipse-zenoh", specifier = ">=1.9.0" }]
[[package]]
name = "chongming-worker"
version = "0.1.0"
source = { editable = "utils/worker" }
source = { git = "http://124.71.68.6:3000/chongming/chongming-utils-worker.git#4b8985d5bd4fc45894bc3e27ecbd541277b83e2f" }
dependencies = [
{ name = "eclipse-zenoh" },
{ name = "tomli" },
]
[package.metadata]
requires-dist = [
{ name = "eclipse-zenoh", specifier = ">=1.9.0" },
{ name = "tomli", specifier = ">=2.4.1" },
]
[[package]]
name = "chongming-zenoh"
version = "0.1.0"
@@ -230,14 +246,16 @@ source = { editable = "." }
dependencies = [
{ name = "apscheduler" },
{ name = "boto3" },
{ name = "chongming-config" },
{ name = "chongming-database" },
{ name = "chongming-jwt" },
{ name = "chongming-password" },
{ name = "chongming-request" },
{ name = "chongming-worker" },
{ name = "diskcache" },
{ name = "eclipse-zenoh" },
{ name = "fastapi" },
{ name = "gunicorn" },
{ name = "modelvault" },
{ name = "module-bank" },
{ name = "nanio" },
{ name = "openai" },
@@ -262,14 +280,16 @@ dev = [
requires-dist = [
{ name = "apscheduler" },
{ name = "boto3" },
{ name = "chongming-jwt", editable = "utils/jwt" },
{ name = "chongming-request", editable = "utils/request" },
{ name = "chongming-worker", editable = "utils/worker" },
{ name = "chongming-config", git = "http://124.71.68.6:3000/chongming/chongming-utils-config.git" },
{ name = "chongming-database", git = "http://124.71.68.6:3000/chongming/chongming-utils-database.git" },
{ name = "chongming-jwt", git = "http://124.71.68.6:3000/chongming/chongming-utils-jwt.git" },
{ name = "chongming-password", git = "http://124.71.68.6:3000/chongming/chongming-utils-password.git" },
{ name = "chongming-request", git = "http://124.71.68.6:3000/chongming/chongming-utils-request.git" },
{ name = "chongming-worker", git = "http://124.71.68.6:3000/chongming/chongming-utils-worker.git" },
{ name = "diskcache" },
{ name = "eclipse-zenoh" },
{ name = "fastapi", extras = ["uvicorn"] },
{ name = "gunicorn" },
{ name = "modelvault" },
{ name = "module-bank" },
{ name = "nanio" },
{ name = "openai" },
@@ -420,6 +440,61 @@ wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9e/7c/8e3c6ad324ea5cb36604fc3f968554887891c316d9dfde57761611d907ad/fastapi-0.139.0-py3-none-any.whl", hash = "sha256:cf15e1e9e667ddb0ad63811e60bd11390d1aac838ca4a7a23f421807b2308189", size = 130339, upload-time = "2026-07-01T16:35:32.19Z" },
]
[[package]]
name = "greenlet"
version = "3.5.3"
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" }
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e2/f1/fbbfef6af0bad0548f09bc28948ea3c275b4edb19e17fc5ca9900a6a634d/greenlet-3.5.3.tar.gz", hash = "sha256:a61efc018fd3eb317eeca31aba90ee9e7f26f22884a79b6c6ec715bf71bb62f1", size = 200270, upload-time = "2026-06-26T19:28:24.832Z" }
wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/5d/6e/4c37d51a2b7f82d2ff11bb6b5f7d766d9a011726624af255e843727627a3/greenlet-3.5.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:719757059f5a53fd0dde23f78cffeafcdd97b21c850ddb7ca684a3c1a1f122e2", size = 288685, upload-time = "2026-06-26T18:22:08.977Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7a/73/815dd90131c1b71ebdf53dbc7c276cafec2a1173b97559f97aba72724a87/greenlet-3.5.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efa9f765dd09f9d0cdac651ffdf631ee59ec5dc6ee7a73e0c012ba9c52fbdf5b", size = 604761, upload-time = "2026-06-26T19:07:10.114Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9f/57/079cfe76bcef36b153b25607ee91c6fcb58f17f8b23c86bbbeabe0c88d72/greenlet-3.5.3-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7faba15ac005376e02a0384504e0243be3370ce010296a44a820feb342b505ab", size = 617044, upload-time = "2026-06-26T19:10:07.25Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/37/87/b4d095775a3fb1bcafbb483fc206b27ebb785724c83051447737085dc54e/greenlet-3.5.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:87142215824be6ac05e2e8e2786eec307ccbc27c36723c3881959df654af6861", size = 614244, upload-time = "2026-06-26T18:32:17.594Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8a/70/7559b609683650fa2b95b8ab84b4ab0b26556a635d19675e12aa832d826d/greenlet-3.5.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215275b1b49320987352e6c1b054acca0064f965a2c66992bed9a6f7d913f149", size = 1574210, upload-time = "2026-06-26T19:09:03.077Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ae/73/be55392074c60fc37655ca40fa6022457bfbf6718e9e342a7b0b41f96dd2/greenlet-3.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6b1b0eed82364b0e32c4ea0f221452d33e6bb17ae094d9f72aed9851812747ea", size = 1638627, upload-time = "2026-06-26T18:31:44.748Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/14/40/c57489acf8e37d74e2913d4eff63aa0dba17acccc4bdeef874dde2dbbec9/greenlet-3.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:cde8adafa2365676f74a979744629589999093bc86e2484214f58e61df08902c", size = 239882, upload-time = "2026-06-26T18:23:27.518Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/71/fd/6fea0e3d6600f785069481ee637e09378dd4118acdfd38ad88ae2db31c98/greenlet-3.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:c4e7b79d83805475f0102008843f6eb45fd3bb0b2e88c774adab5fbaab27117d", size = 238211, upload-time = "2026-06-26T18:22:37.671Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9b/ff/a620267401db30a50cc8450ee90730e2d4a85658c055c0e760d4ed47fb13/greenlet-3.5.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c8d87c2134d871df96ecdea9cec7cbaab286dadab0f56476e57aaf9e8ac11550", size = 287609, upload-time = "2026-06-26T18:21:14.724Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d6/fa/5401ac78021c826a25b6dde0c705e0a8f29b617509f9185a31dac15fbe1b/greenlet-3.5.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d185dd1621757e70c3861cceffd5317ab4e7ed7eb09c82994828468527ade5", size = 607435, upload-time = "2026-06-26T19:07:11.412Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e9/76/1dc144a2e56e65d36405078ed774224375ea520a1870a6e46e08bb4ac7bf/greenlet-3.5.3-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1c514a468149bf8fbbab874188a3535cd8a48a3e353eb53a3d424296f8dbacd3", size = 619787, upload-time = "2026-06-26T19:10:08.396Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bf/87/c298cee62df1de4ad7fec32abda73526cff347fd143a6ed4ac369246668a/greenlet-3.5.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:915f887cf2682b66419b879423a2e072634aa7b7dce6f3ada4957cfced3f1e9a", size = 616786, upload-time = "2026-06-26T18:32:19.128Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/9e/2e/e6f009885ed0705ccf33fe0583c117cfd03cde77e31a596dd5785a30762b/greenlet-3.5.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:766cfd421c13e450feb340cd472a3ed9957d438727b7b4593ad7c76c5d2b0deb", size = 1574316, upload-time = "2026-06-26T19:09:04.273Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ef/fe/43fd110b01e40da0adb7c90ac7ea744bef2d43dca00de5095fd2351c2a68/greenlet-3.5.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2ecda9ec22edf38fa389369eaed8c3d37c05f3c54e69f69438dbb2cc1de1458b", size = 1638614, upload-time = "2026-06-26T18:31:46.297Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0f/7c/062447147a61f8b4337b156fe70d32a165fcf2f89d7ca6255e572806705c/greenlet-3.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:c82304750f057167ff60d188df1d0cc1764ce9567eadf03e6a7443bcedd0b30b", size = 239850, upload-time = "2026-06-26T18:21:54.613Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c7/7e/220a7f5824a64a60443fc03b39dfac4ea63a7fb6d481efa27eafa928e7f4/greenlet-3.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:dc133a1569ee667b2a6ef56ce551084aeefd87a5acbc4736d336d1e2edc6cfc4", size = 238141, upload-time = "2026-06-26T18:22:48.507Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c3/93/43e116ee114b28737ba7e12952a0d4e2f55944d0f84e42bc91ba7192a3c9/greenlet-3.5.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:fd2e02fa07485778536a036222d616ab957b1d533f36b3ed98ce725d9c9d3117", size = 288202, upload-time = "2026-06-26T18:23:49.604Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/82/2f/146d218299046a43d1f029fd544b3d110d0f175a09c715c7e8da4a4a345d/greenlet-3.5.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0a0628d1597eb0897b62f55d1343f772405fd25f3b2a796c76874b0c2e22e8", size = 654096, upload-time = "2026-06-26T19:07:12.71Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a0/cc/04738cafb3f45fa991ea44f9de94c47dcec964f5a972300988a6751f49d9/greenlet-3.5.3-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ebd933a6adabc298bab47731a130fe6bfb888bd934eee37810f151159544540d", size = 666304, upload-time = "2026-06-26T19:10:09.503Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ce/aa/4e0dad5e605c270c784ab911c43da6adb136ccd4d81180f763ca429a723d/greenlet-3.5.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b9d501b40e80b70e32323c799dd9b420a5577a9601469d362ae1ffb690f3a7c", size = 663635, upload-time = "2026-06-26T18:32:20.802Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d1/50/13efdbea246fe3d3b735e191fec08fb50809f53cd2383ebe123d0809e44b/greenlet-3.5.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a1fad1d11e7d6aab184107baa8e4ece11ccba3ec9599cd7efa5ff4d70d43256a", size = 1621252, upload-time = "2026-06-26T19:09:05.647Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f7/22/c0a336ae4a1410fd5f5121098e5bfbf1865f64c5ef80b4b5412886c4a332/greenlet-3.5.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fad5aec764399f1b5cc347ad250a59660f20c8f8888ea6bae1f93b769cce1154", size = 1684824, upload-time = "2026-06-26T18:31:47.738Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7a/94/91aec0030bea75c4b3244251d0de60a1f3432d1ecb53ab6c437fb5c3ba61/greenlet-3.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:7669aa24cf2a1041d6f7899575b494a3ab4cf68bfcc8609b1dc0be7272db835e", size = 240754, upload-time = "2026-06-26T18:22:15.669Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e5/06/68d0983e79e02138f64b4d303c500c27ddb48e5e77f3debb80888a921eae/greenlet-3.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:5b4807c4082c9d1b6d9eed56fcd041863e37f2228106eef24c30ca096e238605", size = 239549, upload-time = "2026-06-26T18:22:42.996Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/91/95/3e161213d7f1d378d15aa9e792093e9bfe01844680d04b7fd6e0107c9098/greenlet-3.5.3-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:271a8ea7c1024e8a0d7dd2be66dd66dda8a07193f41a17b9e924f7600f5b62be", size = 296389, upload-time = "2026-06-26T18:22:20.657Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/00/92/715c44721abe2b4d1ae9abde4179411868a5bff312479f54e105d372f131/greenlet-3.5.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19131729ae0ddc3c2e1ef85e650169b5e37ee32e400f215f78b94d7b0d567310", size = 653382, upload-time = "2026-06-26T19:07:14.209Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a0/83/37a10372a1090a6624cca8e74c12df1a36c2dc36429ed0255b7fb1aeee23/greenlet-3.5.3-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1540dd8e5fc2a5aec40fbb98ef8e149fa47c89a4b4a1cf2575a14d3d1869d7a8", size = 659401, upload-time = "2026-06-26T19:10:10.876Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/db/e2/d1509cad4207da559cc42986ecdd8fc67ad0d1bba2bf03023c467fd5e0f3/greenlet-3.5.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e81fa194a1d20967877bdf9c7794db2bc99063e5be36aee710c08f04c5bb087f", size = 656969, upload-time = "2026-06-26T18:32:22.272Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/86/7d/eaf70de20aadca3a5884aec58362861c64ce45e7b277f47ed026926a3b89/greenlet-3.5.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55cf4d777485d43110e47133cbba6d74a8885a87ec1227ef0267f9ee80c5aa21", size = 1617822, upload-time = "2026-06-26T19:09:06.893Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8a/f9/414d38fc400ae4350d4185eaad1827676f7cf5287b9136e0ed1cbbe20a7f/greenlet-3.5.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:12a248ba75f6a9a236375f52296c498c89ff1d8badf32deb9eca7abd5853f7da", size = 1677983, upload-time = "2026-06-26T18:31:49.396Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e4/15/7edb977e08f9bff702fe42d6c902702786ff6b9694058b4e6a2a6ac90e57/greenlet-3.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:efc6bd60ea02e085862c74a3ef64b147ffc6f1a5ea7d9f26e7a939943f68c1e3", size = 243626, upload-time = "2026-06-26T18:24:41.485Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2c/8a/93928dce91e6b3598b5e779e8d1fd6576a504640c58e78627077f6a7a91a/greenlet-3.5.3-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:ea03f2f04367845d6b58eeed276e1e56e51f0b97d8ad5a88a7d20a91dc9056cc", size = 288860, upload-time = "2026-06-26T18:22:48.07Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/4f/ca/69db42d447a1378043e2c8f19c09cbbd1263371505053c496b49066d3d16/greenlet-3.5.3-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78dbef602fda6d97d957eb7937f70c9ce9e9527330347f8f6b6f9e554a9e7a47", size = 659747, upload-time = "2026-06-26T19:07:15.565Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a8/0b/af7ac2ef8dd41e3da1a40dda6305c23b9a03e13ba975ec916357b50f8575/greenlet-3.5.3-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f73857adb8fee13fa56c172bd11262f888c0c648f9fea113e777bb2c7904a81", size = 670419, upload-time = "2026-06-26T19:10:12.293Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/51/1e/1d51640cacbfc455dbe9f9a9f594c49e4e244f63b9971a2f4764e46cc53d/greenlet-3.5.3-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:232fec92e823addaf02d9472cf7381e24a1d046a6ced1103c5caa4c21b9dfc1d", size = 668787, upload-time = "2026-06-26T18:32:24.298Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/21/66/4030d5b0b5894500023f003bb054d9bb354dfbd1e186c3a296759172f5f5/greenlet-3.5.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2421c3564da9429d5586d46ca31ebb26516b5498a802cf65c041a8e8a8980d34", size = 1626305, upload-time = "2026-06-26T19:09:08.281Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0e/50/5221371c7550108dfa3c378debc41d032aa9c78e89abb01d8011cfc93289/greenlet-3.5.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e0f0d160f0b2e558e6c75f7930967183255dc9735e5f5b8cae58ee09c9576d8b", size = 1688631, upload-time = "2026-06-26T18:31:51.278Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/68/5d/00d469daae3c65d2bf620b10eee82eb022127d483c6bc8c69fae6f3fbf17/greenlet-3.5.3-cp315-cp315-win_amd64.whl", hash = "sha256:dd99329bbc15ca78dcc583dba05d0b1b0bae01ab6c2174989f5aaee3e41ac930", size = 241027, upload-time = "2026-06-26T18:22:38.203Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e7/e8/883785b44c5780ed71e83d3e4437e710470be17a2e181e8b601e2da0dc4a/greenlet-3.5.3-cp315-cp315-win_arm64.whl", hash = "sha256:499fef2acede88c1864a57bb586b4bf533c81e1b82df7ab93451cdb47dfec227", size = 240085, upload-time = "2026-06-26T18:23:54.217Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/1c/da/4f4a8450962fad137c1c8981a3f1b8919d06c829993d4d476f9c525d5173/greenlet-3.5.3-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:176bc16a721fa5fc294d70b87b4dfa5fbdd251b3da5d5372735ecef9bd7d6d0c", size = 297221, upload-time = "2026-06-26T18:23:27.176Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/57/66/b3bfae3e220a9b63ea539a0eea681800c69ab1aada757eae8789f183e7ce/greenlet-3.5.3-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:629b614d2b786e89c50440e246f33eea78f58a962d0bdbbcc809e6d13605903f", size = 657221, upload-time = "2026-06-26T19:07:16.973Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7b/81/b6d4d73a709684fc77e7fa034d7c2fe82cffa9fc920fadcaa659c2626213/greenlet-3.5.3-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b2e857ae16f5f72142edf75f9f176fe7526ba19a2841df1420516f83831c9f2", size = 663226, upload-time = "2026-06-26T19:10:13.723Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f5/07/e210b02b589f16e74ff48b730690e4a34ffe984219fce4f3c1a0e7ec8545/greenlet-3.5.3-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e515757e2e36bcbf1fad09a46e1557e8b1ae1797d4b44d09da7deed88ad28608", size = 660802, upload-time = "2026-06-26T18:32:26.081Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/eb/2e/5303eb3fa06bca089060f479707182a93e360683bc252acf846c3090d34e/greenlet-3.5.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b363d46ed1ea431825fdb01471bb024fc08399bad1572a616e853c7684415adb", size = 1622157, upload-time = "2026-06-26T19:09:09.527Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/54/70/50de47a488f14df260b50ae34fb5d56016e308b098eab02c878b5223c26a/greenlet-3.5.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e44da2f5bbdaabaf7d80b73dbb430c7035771e9f244e3c8b769715c9d8fa0a16", size = 1681159, upload-time = "2026-06-26T18:31:52.986Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a7/13/1055e1dda7882073eda533e2b96c62e55bbd2db7fda6d5ece992febc7071/greenlet-3.5.3-cp315-cp315t-win_amd64.whl", hash = "sha256:8ff8bed3e3baa20a3ea261ce00526f1898ad4801d4886fd2220580ee0ad8fadf", size = 244007, upload-time = "2026-06-26T18:22:04.353Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b4/0d/ca7d15afbdc397e3401134c9e1800d51d12b829661786187a4ad08fe484f/greenlet-3.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:b7068bd09f761f3f5b4d214c2bed063186b2a86148c740b3873e3f56d79bac31", size = 242586, upload-time = "2026-06-26T18:23:37.93Z" },
]
[[package]]
name = "gunicorn"
version = "26.0.0"
@@ -603,22 +678,6 @@ wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl", hash = "sha256:da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea", size = 38117, upload-time = "2025-11-22T08:28:36.939Z" },
]
[[package]]
name = "modelvault"
version = "0.16.0"
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" }
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/8a/c8/e2d64e9d80040efd1e01fe25ef121f5faa473ce40631c34dbe4e66c1f271/modelvault-0.16.0.tar.gz", hash = "sha256:aa8378dbb9f6beffa76ae8cbbfacf549486d0e195a72e28ca299b737cc839eef", size = 236231, upload-time = "2026-06-08T01:04:07.736Z" }
wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a9/21/2ce73f22e30413f9167324e5e61bcad4dd7a50b038c2b08c3aa0150774e8/modelvault-0.16.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:a0a33a00387d2bf41c8aa69532a4669275614ba758decd502f5d6ec0f417442d", size = 2314107, upload-time = "2026-06-08T01:03:57.258Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/75/ec/2a83eca634b8576494a9aa795d8da6b204003ebf17e63d44f33ef368c4e0/modelvault-0.16.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ec12950aa612690991692d7973e74f4e15bbb3f8d67e92d11532eb436d42f39d", size = 2207973, upload-time = "2026-06-08T01:03:33.756Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d0/44/27fcfc8ac0536e0a20cc8bb9ee01a87063b2ff2cef43d916f48bfa171f4f/modelvault-0.16.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1245e57151e7508606fd34e4d8510a460c1f3810157c09a4449936cf3a798bde", size = 2442060, upload-time = "2026-06-08T01:04:06.264Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/35/a3/0042eb943d36b449d45b2d617ec02db11459328f4111a48683c2965331dd/modelvault-0.16.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:55f1e962e785da4c896b15476897f81b300d7147f6d5b51f6666497c5d8d3674", size = 2481291, upload-time = "2026-06-08T01:04:08.08Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/c9/e9/96e0a637d080419b221e63a4ee393d18aaef3b9132bcecfaa528b5c6f55f/modelvault-0.16.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5cafa8505f9c0e4d15eaa43e320430c688551968bbe8cfe7510d2c9f63afab68", size = 1957214, upload-time = "2026-06-08T01:03:52.779Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/49/ed/a8c0b32454e5a315e55ad3f3b70671b9f66495915d658419aa8484c46cd7/modelvault-0.16.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1b2b65d4017f83675f9c1a8c0c9b9e8e1ea541526776e57c6e698e81f677b4a2", size = 2075934, upload-time = "2026-06-08T01:04:01.389Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0a/29/e250a6edd613451c680dbf20ddcbe528c68762d369f0f5bf3ac31090796a/modelvault-0.16.0-cp39-abi3-win_amd64.whl", hash = "sha256:95e42e53aba0de5c8f798863ab25a3271ef8405c51728a15399977e39a187a66", size = 2091287, upload-time = "2026-06-08T01:05:47.349Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/a9/44/352248e4a1723994dd3b6ccd1306b74b3c6c2bd5b8e02c66572626e5ae66/modelvault-0.16.0-cp39-abi3-win_arm64.whl", hash = "sha256:7b3defb3ce620039e63eef90bb7973d727b42ab8e3bc8303490429f9bc32c96b", size = 1894605, upload-time = "2026-06-08T01:05:34.93Z" },
]
[[package]]
name = "module-bank"
version = "0.3.2"
@@ -1113,6 +1172,47 @@ wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
]
[[package]]
name = "sqlalchemy"
version = "2.0.51"
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" }
dependencies = [
{ name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" },
{ name = "typing-extensions" },
]
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/02/f1/a7a892f18d4d224e6b26f706531eafccc41e37594d37d304786969ee13cb/sqlalchemy-2.0.51.tar.gz", hash = "sha256:804dccd8a4a6242c4e30ad961e540e18a588f6527202f2d6791b01845d59fdc9", size = 9912201, upload-time = "2026-06-15T15:41:20.012Z" }
wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d5/70/e868bc5412acd101a8280f25c95f10eeae0771c4eb806b02491142810ee8/sqlalchemy-2.0.51-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d78702b26ba1c18b2d0fb2ea940ba7f17a9581b42e8361ff93920ebbee1235a", size = 2160291, upload-time = "2026-06-15T16:08:48.918Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e5/1c/71ee0f8a6b9d7316a1ccd30430b4c62b6c2e36adc96017a4e3a72dce49d6/sqlalchemy-2.0.51-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581921d849d6e6f994d560389192955e80e2950e18fcdfe2ccea863e01158e6e", size = 3343835, upload-time = "2026-06-15T16:19:42.613Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/2b/7c/7ab9f9aadc5944fdd06612484ed7918fe376ad871a5f50404dc1536e0194/sqlalchemy-2.0.51-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d21ce524ab86c23046e992a5b81cb54c21079c6df6e78b8fc77d77cac70a6b9", size = 3358470, upload-time = "2026-06-15T16:26:38.011Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d0/7d/ff77169fee6186de145a7f2b87006c39638391130abbab2b1f63ac6ea583/sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c5d98a2709840027f5a347c3af0a7c3d5f6c1ff93af2ca1c54494e23cba8f389", size = 3289874, upload-time = "2026-06-15T16:19:45.212Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/6f/3b/6c505903710d781b55bc3141ee34a062bf9745a6b5bc7333305b9ed63b33/sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1181256e0f16479691b5616d36375dc2620ad8332b25978763c3d206ad3f3f1d", size = 3321692, upload-time = "2026-06-15T16:26:39.747Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/3c/b7/c5ffe50aa2f4d947c9250e1519d939260329a07fe6272edfccd784b3d007/sqlalchemy-2.0.51-cp312-cp312-win32.whl", hash = "sha256:9f380393be5abeb6815f68fd39271b95127173511b6706b0a630a9995d53f8f5", size = 2119674, upload-time = "2026-06-15T16:23:09.543Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/25/dc/46a65916af68a06ef6b972c6050ba4c8f97070fe3fb33097d34229d9bef6/sqlalchemy-2.0.51-cp312-cp312-win_amd64.whl", hash = "sha256:2cf39aabdf48e87c1c2c2ed6d20d33ffa0733b3071ce9c5f66357947dd009080", size = 2146670, upload-time = "2026-06-15T16:23:11.048Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/54/fe/a210d52fd1a90ecfae8a78e9d8b27e18d733d60818a8bf250ff690b75120/sqlalchemy-2.0.51-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c2056838b6685b72fdb36c99996cf862753461a62f2e84f4196371d3b2d6a07", size = 2157184, upload-time = "2026-06-15T16:08:50.374Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/17/6b/2dce8369b199cb855110e056032f94a9f66dacc2237d3d39c115a86eac56/sqlalchemy-2.0.51-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483b11bd46bf35fc14c52faf338b04300c9e6ce554bce9b11be85bfec3bc3195", size = 3284735, upload-time = "2026-06-15T16:19:46.934Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/53/ff/dbc495b8a14da840faffb353857a72d4190113cac33727906fb997047f0f/sqlalchemy-2.0.51-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bed1ee8b01da6088210aa9412023326fb98a599ba502e6118308601dcbef77f", size = 3302756, upload-time = "2026-06-15T16:26:41.336Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cf/d5/fde8f4dddcf518ee15ab35a7c6a28acc32c8ba548d1d2aa451f96e6dbb0b/sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72ca54c952107ba5cd58854b67a5a6268631289d21651a1235396f3b98b47400", size = 3232055, upload-time = "2026-06-15T16:19:49.286Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/67/d1/43d3a0ac955a58601c24fa23038b1c55ee3a1ec02c0f96ebb1eae2bcf614/sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b3e693d15533a45cd5906f0589f9c35090bef6ef45bf1e8195c424aa0ae06a8d", size = 3269850, upload-time = "2026-06-15T16:26:43.017Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/94/df/de669c7054cd47c4439ac34b1b2ee8b804a794791fbb10720e997a2c87c7/sqlalchemy-2.0.51-cp313-cp313-win32.whl", hash = "sha256:b93ab07b5292dbe7e6b8da89475275e7042744283921344b56105f3eeb0f828b", size = 2117721, upload-time = "2026-06-15T16:23:12.36Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/d0/8a/403c51d064196bae20a0bc2476577f83a3f8dd299719a97417086b7f2ec5/sqlalchemy-2.0.51-cp313-cp313-win_amd64.whl", hash = "sha256:0f053118c30e53161857a953e4de667d90e274980dccbe5dd3829bbbeece72a5", size = 2143615, upload-time = "2026-06-15T16:23:13.906Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/b1/49/a739be2e1d02a96a658eb71ab45d921c874249252358ad24a5bffdd02525/sqlalchemy-2.0.51-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6ea306caaae6bd5afd0a46050003c88f6bf33227377a49298c498c3cb88ff491", size = 2158999, upload-time = "2026-06-15T16:08:51.759Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/23/6b/2e0e38cf75c8780eca78d9b2e78164f8bcfd70125e5caa588ff5cbb9c9f4/sqlalchemy-2.0.51-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c45a496d6bc05dec41dcd4c3a2b183723f47473255c159cd80b503c8f246424d", size = 3282539, upload-time = "2026-06-15T16:19:51.065Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/dd/a1/e77854cb5336fd37dc3c6ae3b71de242c98caac5725120be0b526b31cbd0/sqlalchemy-2.0.51-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4004ada0aafe8ae1991b2cd1d99c6d9146126e123bd6f883c260d974aa012e54", size = 3287545, upload-time = "2026-06-15T16:26:44.735Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/f6/ab/9e17272fd4dac8df3b83c4fbe52b998a1c9d89a843c8c35ff29b74ff7364/sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f6bcad487aee1c638d707235682fc96f741de00663619881ab235400d03289e", size = 3230929, upload-time = "2026-06-15T16:19:52.625Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/02/3c/52f408ea701781caee975606beccc48845f2aee8711ac29843d612c0306c/sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:39a76529db6305693d8d4affa58ad5b5e2e18edd62daea628b29b97930b3513d", size = 3252888, upload-time = "2026-06-15T16:26:46.454Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/24/16/3efd2ee6bc4ca4693a30a1dd17a91b606cae15d517d2a4746611d9b73ce8/sqlalchemy-2.0.51-cp314-cp314-win32.whl", hash = "sha256:08a204d8b5638717c26a24df18fcf40af45a6b22e35b70b1d62f0113c2e278e8", size = 2120551, upload-time = "2026-06-15T16:23:15.629Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/7b/78/55b12e70f45bccc40d9e483925c065027b3b98ea4cbbdf6f8c2546feaf6c/sqlalchemy-2.0.51-cp314-cp314-win_amd64.whl", hash = "sha256:96747bfbadb055466e5b46d572618170046b45ce5a4879167f50d70a5319a499", size = 2146318, upload-time = "2026-06-15T16:23:17.108Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/21/db/a9574ed40fed418924b1b1a3e54f47ee3963053b3d3d325a0d36b41f2c08/sqlalchemy-2.0.51-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1a213be1fcd5e49d9904c3b9939211ded90bc2a64e93f4c01963474285de", size = 2178920, upload-time = "2026-06-15T15:59:56.285Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/bf/90/a1bb5c7cbba76b7bc1fbd586d0a5479a7bc9c27b4a8298f22ec9423b2bb3/sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c6b36ed71f41942bdcd2ad2522be46bfce09d5705be5640ecf19bbc7660e4b7", size = 3566534, upload-time = "2026-06-15T15:58:35.024Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/15/4b/481f1fed30e0e9e8dd24aecbb49f29eb57fe7657ece5cf06ee9b84bb97d8/sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c2c62877097e1a0db401fba5cb4debee33265e5b2a55c4ccb489c02c53b4f72", size = 3535844, upload-time = "2026-06-15T16:02:43.973Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/02/71/0aa64aeda645510af0a43f7d9ee70932f0d1dc4263aed34c50ee891d9df3/sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0378d055e9e8cd6ce4d8dff683bdd3d7d413533c4ee51d67a2b1e0f9eacc0f23", size = 3475355, upload-time = "2026-06-15T15:58:36.592Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/05/db/6061db32316446135a3abae5f308d144ab988a34234726042da3e58b1c63/sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6e46fc36029eff666391e0531e5387b62ce6c4f1d8e50b3fb3099eaca1b42522", size = 3486591, upload-time = "2026-06-15T16:02:45.346Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/0d/c9/f14fdf71bb8957e0c7e39db69bbdf12b5c80f4ef775fdfa127bf4e0d6760/sqlalchemy-2.0.51-cp314-cp314t-win32.whl", hash = "sha256:9161cfc9efce70d1715f47d6ff40f79c6778c00d53be4fbc09d70301e4b83ba7", size = 2151313, upload-time = "2026-06-15T16:03:39.127Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/6a/c6/673e618e6f4f297e126d9b56ea2f6478708f6c1af4e3223835c22e2c3697/sqlalchemy-2.0.51-cp314-cp314t-win_amd64.whl", hash = "sha256:159bb6ba32059f57ad7375a8f50d844dd2f19d14954ecf820cd33e20debd46b2", size = 2186280, upload-time = "2026-06-15T16:03:40.569Z" },
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/e2/22/dbf013a12ec759e54a34a119e9e217435b3f71b2dd5c61a7ade0a25dae87/sqlalchemy-2.0.51-py3-none-any.whl", hash = "sha256:bb024d8b621d0be75f4f44ecc7c950450026e76d66dc8f791bb5331d7fed59d5", size = 1944334, upload-time = "2026-06-15T16:09:22.418Z" },
]
[[package]]
name = "sqlite-vfs"
version = "0.1.0"
@@ -1122,6 +1222,20 @@ wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/ef/26/a3f51ea9d10efe2c4f85cac78dcbd898b437d2331cf25d470f804e4498b7/sqlite_vfs-0.1.0-py3-none-any.whl", hash = "sha256:c6e27a35e504bb6360fb0d9083d79572367a903788b3b14aea5f1188130e9314", size = 10768, upload-time = "2025-11-08T08:15:18.588Z" },
]
[[package]]
name = "sqlmodel"
version = "0.0.39"
source = { registry = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple" }
dependencies = [
{ name = "pydantic" },
{ name = "sqlalchemy" },
{ name = "typing-extensions" },
]
sdist = { url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/68/ee/22a0559283c3cf6048678e787ed5d4959dcd00dedd8ba4567eeae684eeb1/sqlmodel-0.0.39.tar.gz", hash = "sha256:23d8e50a8d8ee936032ed79c55023a5d618dd6bc3c510bbf4909d1a7a605a570", size = 91057, upload-time = "2026-06-25T13:01:38.475Z" }
wheels = [
{ url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/packages/cf/7d/b9813a582d4eb310be35e1fc7dfaae71207d7b62e9e53be314ebd251b53b/sqlmodel-0.0.39-py3-none-any.whl", hash = "sha256:90ebe92ce5cc11d7fff8dc7cb594790a102333c8fe7c14865254f6fc5c939795", size = 29680, upload-time = "2026-06-25T13:01:37.494Z" },
]
[[package]]
name = "starlette"
version = "1.3.1"