Spaces:
Sleeping
Sleeping
Apply enhancements
Browse files- .python-version +1 -0
- Dockerfile +15 -5
- Makefile +29 -0
- README.md +165 -31
- main.py +0 -163
- pyproject.toml +30 -0
- {app β src/app}/__init__.py +0 -0
- src/app/__pycache__/__init__.cpython-312.pyc +0 -0
- src/app/__pycache__/banks.cpython-312.pyc +0 -0
- src/app/__pycache__/clip_service.cpython-312.pyc +0 -0
- src/app/__pycache__/clip_store.cpython-312.pyc +0 -0
- src/app/__pycache__/deps.cpython-312.pyc +0 -0
- src/app/__pycache__/image_io.cpython-312.pyc +0 -0
- src/app/__pycache__/label_hash.cpython-312.pyc +0 -0
- src/app/__pycache__/logging_utils.cpython-312.pyc +0 -0
- src/app/__pycache__/main.cpython-312.pyc +0 -0
- src/app/__pycache__/middleware.cpython-312.pyc +0 -0
- src/app/__pycache__/registry.cpython-312.pyc +0 -0
- src/app/__pycache__/results.cpython-312.pyc +0 -0
- src/app/__pycache__/schemas.cpython-312.pyc +0 -0
- src/app/__pycache__/settings.cpython-312.pyc +0 -0
- app_factory.py β src/app/app_factory.py +0 -0
- banks.py β src/app/banks.py +0 -0
- clip_service.py β src/app/clip_service.py +0 -0
- clip_store.py β src/app/clip_store.py +12 -1
- deps.py β src/app/deps.py +0 -0
- image_io.py β src/app/image_io.py +0 -0
- label_hash.py β src/app/label_hash.py +0 -0
- logging_utils.py β src/app/logging_utils.py +0 -0
- src/app/main.py +265 -0
- middleware.py β src/app/middleware.py +0 -0
- registry.py β src/app/registry.py +0 -0
- results.py β src/app/results.py +0 -0
- schemas.py β src/app/schemas.py +1 -1
- settings.py β src/app/settings.py +0 -0
- src/photo_classification.egg-info/PKG-INFO +192 -0
- src/photo_classification.egg-info/SOURCES.txt +24 -0
- src/photo_classification.egg-info/dependency_links.txt +1 -0
- src/photo_classification.egg-info/requires.txt +10 -0
- src/photo_classification.egg-info/top_level.txt +1 -0
- tests/__init__.py +1 -0
- tests/__pycache__/__init__.cpython-312.pyc +0 -0
- tests/__pycache__/conftest.cpython-312-pytest-8.3.2.pyc +0 -0
- tests/__pycache__/fakes.cpython-312.pyc +0 -0
- tests/__pycache__/test_api.cpython-312-pytest-8.3.2.pyc +0 -0
- tests/__pycache__/test_integration_real_clip.cpython-312-pytest-8.3.2.pyc +0 -0
- conftest.py β tests/conftest.py +0 -0
- fakes.py β tests/fakes.py +0 -0
- test_api.py β tests/test_api.py +0 -0
- uv.lock +850 -0
.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3.12
|
Dockerfile
CHANGED
|
@@ -3,15 +3,25 @@ FROM python:3.12-slim
|
|
| 3 |
ENV PYTHONDONTWRITEBYTECODE=1 \
|
| 4 |
PYTHONUNBUFFERED=1
|
| 5 |
|
| 6 |
-
WORKDIR /app
|
| 7 |
-
|
| 8 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 9 |
git \
|
| 10 |
&& rm -rf /var/lib/apt/lists/*
|
| 11 |
|
| 12 |
-
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
-
|
| 16 |
|
| 17 |
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
|
|
|
|
| 3 |
ENV PYTHONDONTWRITEBYTECODE=1 \
|
| 4 |
PYTHONUNBUFFERED=1
|
| 5 |
|
|
|
|
|
|
|
| 6 |
RUN apt-get update && apt-get install -y --no-install-recommends \
|
| 7 |
git \
|
| 8 |
&& rm -rf /var/lib/apt/lists/*
|
| 9 |
|
| 10 |
+
RUN useradd -m -u 1000 user
|
| 11 |
+
USER user
|
| 12 |
+
|
| 13 |
+
ENV HOME=/home/user \
|
| 14 |
+
PATH=/home/user/.local/bin:$PATH
|
| 15 |
+
|
| 16 |
+
WORKDIR $HOME/app
|
| 17 |
+
|
| 18 |
+
RUN pip install --no-cache-dir --upgrade pip
|
| 19 |
+
RUN pip install --no-cache-dir --user uv
|
| 20 |
+
|
| 21 |
+
COPY --chown=user pyproject.toml .
|
| 22 |
+
COPY --chown=user src ./src
|
| 23 |
+
RUN uv sync --no-dev
|
| 24 |
|
| 25 |
+
ENV PATH="$HOME/app/.venv/bin:$PATH"
|
| 26 |
|
| 27 |
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--workers", "1"]
|
Makefile
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.PHONY: help docker-build docker-run local-install local-run local-test local-test-integration
|
| 2 |
+
|
| 3 |
+
help:
|
| 4 |
+
@echo "---------------------------------------------------"
|
| 5 |
+
@echo "Targets:"
|
| 6 |
+
@echo " docker-build Build Docker image"
|
| 7 |
+
@echo " docker-run Run Docker image on :7860"
|
| 8 |
+
@echo " local-install Sync deps with uv"
|
| 9 |
+
@echo " local-run Run API locally on :7860"
|
| 10 |
+
@echo " local-test Run unit tests"
|
| 11 |
+
@echo " local-test-integration Run integration tests"
|
| 12 |
+
|
| 13 |
+
docker-build:
|
| 14 |
+
docker build -t photo-classification .
|
| 15 |
+
|
| 16 |
+
docker-run:
|
| 17 |
+
docker run --rm -p 7860:7860 photo-classification
|
| 18 |
+
|
| 19 |
+
local-install:
|
| 20 |
+
uv sync --extra dev --python 3.12
|
| 21 |
+
|
| 22 |
+
local-run:
|
| 23 |
+
uv run uvicorn app.main:app --host 0.0.0.0 --port 7860
|
| 24 |
+
|
| 25 |
+
local-test:
|
| 26 |
+
uv run pytest -q
|
| 27 |
+
|
| 28 |
+
local-test-integration:
|
| 29 |
+
uv run pytest -q -m integration
|
README.md
CHANGED
|
@@ -1,42 +1,176 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 24 |
{
|
| 25 |
"domain_top_n": 1,
|
| 26 |
"top_k": 3
|
| 27 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
-
|
| 32 |
|
| 33 |
-
|
|
|
|
|
|
|
| 34 |
|
| 35 |
-
|
| 36 |
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 38 |
|
| 39 |
-
|
| 40 |
|
| 41 |
-
|
| 42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Photo Classification API
|
| 3 |
+
emoji: π·
|
| 4 |
+
colorFrom: blue
|
| 5 |
+
colorTo: gray
|
| 6 |
+
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
+
---
|
| 9 |
+
|
| 10 |
+
# Photo Classification API
|
| 11 |
+
|
| 12 |
+
```
|
| 13 |
+
____ _ _ ____ _
|
| 14 |
+
| _ \| |__ ___ | |_ ___ / ___| | __ _ ___ ___
|
| 15 |
+
| |_) | '_ \ / _ \| __/ _ \ | | | |/ _` / __/ __|
|
| 16 |
+
| __/| | | | (_) | || (_) | | |___| | (_| \__ \__ \
|
| 17 |
+
|_| |_| |_|\___/ \__\___/ \____|_|\__,_|___/___/
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
A small, prompt-driven photo classification API built on CLIP. You upload a label set
|
| 21 |
+
(domains + labels with prompts), then classify images against that taxonomy without
|
| 22 |
+
any fine-tuning.
|
| 23 |
+
|
| 24 |
+
## Why this exists
|
| 25 |
+
|
| 26 |
+
- Fast taxonomy iteration: change labels or prompts without retraining.
|
| 27 |
+
- Simple deployment: CPU-only CLIP inference by default.
|
| 28 |
+
- Clear outputs: domain hits, chosen domains, and label hits with scores.
|
| 29 |
+
|
| 30 |
+
## Models
|
| 31 |
+
|
| 32 |
+
- Text and image embeddings are produced by CLIP (`openai/clip-vit-base-patch32`).
|
| 33 |
+
- All inference runs on CPU unless you adapt `ClipStore` to use GPU.
|
| 34 |
+
- Scoring uses cosine-like similarity with CLIP's logit scale and a softmax.
|
| 35 |
+
|
| 36 |
+
## Label datasets
|
| 37 |
+
|
| 38 |
+
Label sets are JSON files with `domains` and `labels_by_domain`, each item defining:
|
| 39 |
+
|
| 40 |
+
- `id`: stable identifier
|
| 41 |
+
- `display`: human-readable name
|
| 42 |
+
- `prompt`: the text prompt used for CLIP embedding
|
| 43 |
+
|
| 44 |
+
Examples:
|
| 45 |
+
|
| 46 |
+
- `label-dataset/personal-photos-lite-v1.json`
|
| 47 |
+
- `label-dataset/personal-photos-large-v1.json`
|
| 48 |
+
- `label-dataset/scene-dance-formation-group-v1.json`
|
| 49 |
+
|
| 50 |
+
Use these as starting points or create your own taxonomy.
|
| 51 |
+
|
| 52 |
+
## API quickstart
|
| 53 |
+
|
| 54 |
+
1) Start the service (Docker or `uvicorn app.main:app`).
|
| 55 |
+
2) Upload a label set.
|
| 56 |
+
3) Optionally activate a label set.
|
| 57 |
+
4) Classify images.
|
| 58 |
+
|
| 59 |
+
Endpoints:
|
| 60 |
+
|
| 61 |
+
- `POST /api/v1/label-sets` (upload)
|
| 62 |
+
- `GET /api/v1/label-sets` (list)
|
| 63 |
+
- `POST /api/v1/label-sets/{label_set_hash}/activate` (set default)
|
| 64 |
+
- `POST /api/v1/classify` (classify image)
|
| 65 |
+
|
| 66 |
+
`/api/v1/classify` body:
|
| 67 |
+
|
| 68 |
+
```json
|
| 69 |
+
{
|
| 70 |
+
"image_base64": "<base64>",
|
| 71 |
+
"domain_top_n": 2,
|
| 72 |
+
"top_k": 5
|
| 73 |
+
}
|
| 74 |
+
```
|
| 75 |
+
|
| 76 |
+
Response includes `domain_hits`, `chosen_domains`, `label_hits`, and timings.
|
| 77 |
+
|
| 78 |
+
## Recommended runtime config
|
| 79 |
+
|
| 80 |
+
Default params for stable results:
|
| 81 |
+
|
| 82 |
+
```json
|
| 83 |
{
|
| 84 |
"domain_top_n": 1,
|
| 85 |
"top_k": 3
|
| 86 |
}
|
| 87 |
+
```
|
| 88 |
+
|
| 89 |
+
Guard policy example:
|
| 90 |
+
|
| 91 |
+
- Use `domain_top_n = 3`, `top_k = 4`.
|
| 92 |
+
- If `non_dance` appears in `chosen_domains` and its top label score is high vs
|
| 93 |
+
`dance`, treat the photo as "not dancing" and skip dance-style conclusions.
|
| 94 |
+
|
| 95 |
+
## Architecture
|
| 96 |
+
|
| 97 |
+
- API layer: FastAPI endpoints and request/response schemas (`src/app/main.py`, `src/app/schemas.py`).
|
| 98 |
+
- Use-case layer: two-stage classification (domain -> labels) (`src/app/clip_service.py`).
|
| 99 |
+
- Model layer: CLIP model + processor + embedding banks (`src/app/clip_store.py`, `src/app/banks.py`).
|
| 100 |
+
- Runtime support: registry, settings, logging, middleware (`src/app/registry.py`, `src/app/settings.py`,
|
| 101 |
+
`src/app/logging_utils.py`, `src/app/middleware.py`).
|
| 102 |
+
|
| 103 |
+
## Coding rules (deeper)
|
| 104 |
+
|
| 105 |
+
Separation of concerns:
|
| 106 |
|
| 107 |
+
- API layer does IO only: parse input, validate, load image, call use-case, return typed DTOs.
|
| 108 |
+
- Use-case layer owns business logic: the two-stage classification and result shaping.
|
| 109 |
+
- Model layer owns ML specifics: CLIP loading, text/image encoding, and logit scaling.
|
| 110 |
+
- Data layer owns taxonomy inputs: JSON label sets, hashing, and embedding banks.
|
| 111 |
|
| 112 |
+
API vs use-case vs torch:
|
| 113 |
|
| 114 |
+
- API should not import torch or transformers; it deals in base64, Pydantic models, and HTTP.
|
| 115 |
+
- Use-case should not depend on HTTP; it accepts a bank + image and returns a typed result.
|
| 116 |
+
- Torch code lives in `ClipStore` only; the rest of the code treats embeddings as opaque tensors.
|
| 117 |
|
| 118 |
+
Typed outputs and clean steps:
|
| 119 |
|
| 120 |
+
- Each step returns a typed value (`LabelSetBank`, `ClassificationResult`, `Hit` lists).
|
| 121 |
+
- Keep operations in small pure functions or methods that express a single step:
|
| 122 |
+
- validate input
|
| 123 |
+
- load/normalize image
|
| 124 |
+
- encode image
|
| 125 |
+
- score domains
|
| 126 |
+
- merge label banks
|
| 127 |
+
- score labels
|
| 128 |
|
| 129 |
+
Dataset usage:
|
| 130 |
|
| 131 |
+
- Label sets are data, not code. Changes to taxonomy are done in JSON files or user payloads.
|
| 132 |
+
- Stable hashes (`label_set_hash`) are derived from canonical JSON for reproducibility.
|
| 133 |
+
|
| 134 |
+
Avoid old PyTorch habits:
|
| 135 |
+
|
| 136 |
+
- No training loops, optimizers, or manual grad handling; this is inference-only.
|
| 137 |
+
- Use `torch.no_grad()` and normalized embeddings for stable cosine-like comparisons.
|
| 138 |
+
- Keep tensors on the same device; `ClipStore` owns device placement.
|
| 139 |
+
- Prefer small, readable tensor ops over complex pipelines.
|
| 140 |
+
|
| 141 |
+
Error handling and HTTP boundaries:
|
| 142 |
+
|
| 143 |
+
- Decode/validate base64 and size limits in `image_io`, not inside ML code.
|
| 144 |
+
- Convert internal errors to HTTP responses at the boundary (e.g., 400/404/413).
|
| 145 |
+
- Log JSON events with request IDs for traceability.
|
| 146 |
+
|
| 147 |
+
## Tests
|
| 148 |
+
|
| 149 |
+
- Fast, deterministic tests use fakes for classifier and store (`tests/fakes.py`).
|
| 150 |
+
- Integration test optionally loads real CLIP (`tests/test_integration_real_clip.py`).
|
| 151 |
+
- Run:
|
| 152 |
+
- `pytest -q`
|
| 153 |
+
- `pytest -q -m integration`
|
| 154 |
+
|
| 155 |
+
## Project layout
|
| 156 |
+
|
| 157 |
+
```
|
| 158 |
+
.
|
| 159 |
+
βββ Dockerfile
|
| 160 |
+
βββ requirements.txt
|
| 161 |
+
βββ src
|
| 162 |
+
βββ app
|
| 163 |
+
βββ banks.py
|
| 164 |
+
βββ clip_service.py
|
| 165 |
+
βββ clip_store.py
|
| 166 |
+
βββ deps.py
|
| 167 |
+
βββ image_io.py
|
| 168 |
+
βββ label_hash.py
|
| 169 |
+
βββ logging_utils.py
|
| 170 |
+
βββ main.py
|
| 171 |
+
βββ middleware.py
|
| 172 |
+
βββ registry.py
|
| 173 |
+
βββ results.py
|
| 174 |
+
βββ schemas.py
|
| 175 |
+
βββ settings.py
|
| 176 |
+
```
|
main.py
DELETED
|
@@ -1,163 +0,0 @@
|
|
| 1 |
-
from __future__ import annotations
|
| 2 |
-
|
| 3 |
-
from fastapi import FastAPI, HTTPException, Request, Depends
|
| 4 |
-
from fastapi.responses import JSONResponse
|
| 5 |
-
|
| 6 |
-
from app.clip_store import ClipStore
|
| 7 |
-
from app.clip_service import TwoStageClassifier
|
| 8 |
-
from app.deps import get_bank, get_request_id, resolve_bank
|
| 9 |
-
from app.image_io import load_image_from_base64
|
| 10 |
-
from app.logging_utils import setup_logging, log_json
|
| 11 |
-
from app.middleware import RequestIdMiddleware
|
| 12 |
-
from app.registry import LabelSetRegistry
|
| 13 |
-
from app.schemas import (
|
| 14 |
-
ActivateResponse,
|
| 15 |
-
ClassifyRequest,
|
| 16 |
-
ClassifyResponse,
|
| 17 |
-
Hit,
|
| 18 |
-
LabelSet,
|
| 19 |
-
LabelSetCreateResponse,
|
| 20 |
-
LabelSetInfo,
|
| 21 |
-
)
|
| 22 |
-
from app.settings import settings
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
logger = setup_logging()
|
| 26 |
-
|
| 27 |
-
def build_app() -> FastAPI:
|
| 28 |
-
logger = setup_logging()
|
| 29 |
-
|
| 30 |
-
app = FastAPI(
|
| 31 |
-
title="Photo Classification API",
|
| 32 |
-
version="1.0.0",
|
| 33 |
-
docs_url="/docs",
|
| 34 |
-
redoc_url=None,
|
| 35 |
-
openapi_url="/openapi.json",
|
| 36 |
-
)
|
| 37 |
-
app.add_middleware(RequestIdMiddleware)
|
| 38 |
-
|
| 39 |
-
store = ClipStore()
|
| 40 |
-
classifier = TwoStageClassifier(store=store)
|
| 41 |
-
registry = LabelSetRegistry(banks={})
|
| 42 |
-
|
| 43 |
-
# register routes here (same code as before, using closure vars)
|
| 44 |
-
|
| 45 |
-
return app
|
| 46 |
-
|
| 47 |
-
app = build_app()
|
| 48 |
-
|
| 49 |
-
store = ClipStore()
|
| 50 |
-
classifier = TwoStageClassifier(store=store)
|
| 51 |
-
registry = LabelSetRegistry(banks={})
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
@app.exception_handler(Exception)
|
| 55 |
-
async def unhandled_exception_handler(request: Request, exc: Exception):
|
| 56 |
-
rid = getattr(request.state, "request_id", None)
|
| 57 |
-
log_json(logger, event="error.unhandled", request_id=rid, error=str(exc), path=str(request.url.path))
|
| 58 |
-
return JSONResponse(status_code=500, content={"detail": "internal server error"})
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
@app.post("/api/v1/label-sets", response_model=LabelSetCreateResponse)
|
| 62 |
-
def create_label_set(payload: LabelSet, request_id: str = Depends(get_request_id)) -> LabelSetCreateResponse:
|
| 63 |
-
bank = store.build_bank(payload)
|
| 64 |
-
registry.upsert(bank)
|
| 65 |
-
|
| 66 |
-
label_count = sum(len(b.ids) for b in bank.labels_by_domain.values())
|
| 67 |
-
is_default = (registry.default_hash == bank.label_set_hash)
|
| 68 |
-
|
| 69 |
-
log_json(
|
| 70 |
-
logger,
|
| 71 |
-
event="label_sets.upsert",
|
| 72 |
-
request_id=request_id,
|
| 73 |
-
label_set_hash=bank.label_set_hash,
|
| 74 |
-
name=bank.name,
|
| 75 |
-
domain_count=len(bank.domains.ids),
|
| 76 |
-
label_count=label_count,
|
| 77 |
-
is_default=is_default,
|
| 78 |
-
)
|
| 79 |
-
|
| 80 |
-
return LabelSetCreateResponse(
|
| 81 |
-
label_set_hash=bank.label_set_hash,
|
| 82 |
-
name=bank.name,
|
| 83 |
-
domain_count=len(bank.domains.ids),
|
| 84 |
-
label_count=label_count,
|
| 85 |
-
is_default=is_default,
|
| 86 |
-
)
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
@app.get("/api/v1/label-sets", response_model=list[LabelSetInfo])
|
| 90 |
-
def list_label_sets(request_id: str = Depends(get_request_id)) -> list[LabelSetInfo]:
|
| 91 |
-
out: list[LabelSetInfo] = []
|
| 92 |
-
for bank in registry.banks.values():
|
| 93 |
-
label_count = sum(len(b.ids) for b in bank.labels_by_domain.values())
|
| 94 |
-
out.append(
|
| 95 |
-
LabelSetInfo(
|
| 96 |
-
label_set_hash=bank.label_set_hash,
|
| 97 |
-
name=bank.name,
|
| 98 |
-
domain_count=len(bank.domains.ids),
|
| 99 |
-
label_count=label_count,
|
| 100 |
-
is_default=(registry.default_hash == bank.label_set_hash),
|
| 101 |
-
)
|
| 102 |
-
)
|
| 103 |
-
|
| 104 |
-
log_json(logger, event="label_sets.list", request_id=request_id, count=len(out))
|
| 105 |
-
return out
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
@app.post("/api/v1/label-sets/{label_set_hash}/activate", response_model=ActivateResponse)
|
| 109 |
-
def activate_label_set(label_set_hash: str, request_id: str = Depends(get_request_id)) -> ActivateResponse:
|
| 110 |
-
try:
|
| 111 |
-
registry.activate(label_set_hash)
|
| 112 |
-
except KeyError:
|
| 113 |
-
raise HTTPException(status_code=404, detail="Unknown label_set_hash")
|
| 114 |
-
|
| 115 |
-
log_json(logger, event="label_sets.activate", request_id=request_id, default_label_set_hash=label_set_hash)
|
| 116 |
-
return ActivateResponse(default_label_set_hash=label_set_hash)
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
@app.post("/api/v1/classify", response_model=ClassifyResponse)
|
| 120 |
-
def classify(
|
| 121 |
-
payload: ClassifyRequest,
|
| 122 |
-
request: Request,
|
| 123 |
-
request_id: str = Depends(get_request_id),
|
| 124 |
-
label_set_hash: Optional[str] = Query(default=None, description="If omitted, uses the default label set."),
|
| 125 |
-
) -> ClassifyResponse:
|
| 126 |
-
bank = resolve_bank(registry, label_set_hash)
|
| 127 |
-
|
| 128 |
-
image = load_image_from_base64(
|
| 129 |
-
payload.image_base64,
|
| 130 |
-
max_bytes=settings.max_image_mb * 1024 * 1024,
|
| 131 |
-
)
|
| 132 |
-
|
| 133 |
-
res = classifier.classify(
|
| 134 |
-
bank=bank,
|
| 135 |
-
image=image,
|
| 136 |
-
domain_top_n=payload.domain_top_n or settings.default_domain_top_n,
|
| 137 |
-
top_k=payload.top_k or settings.default_top_k,
|
| 138 |
-
)
|
| 139 |
-
|
| 140 |
-
log_json(
|
| 141 |
-
logger,
|
| 142 |
-
event="classify",
|
| 143 |
-
request_id=request_id,
|
| 144 |
-
label_set_hash=bank.label_set_hash,
|
| 145 |
-
model_id=settings.clip_model_id,
|
| 146 |
-
domain_top_n=payload.domain_top_n,
|
| 147 |
-
top_k=payload.top_k,
|
| 148 |
-
chosen_domains=res.chosen_domains,
|
| 149 |
-
elapsed_ms=res.timings.total_ms,
|
| 150 |
-
elapsed_domain_ms=res.timings.domain_ms,
|
| 151 |
-
elapsed_labels_ms=res.timings.labels_ms,
|
| 152 |
-
)
|
| 153 |
-
|
| 154 |
-
return ClassifyResponse(
|
| 155 |
-
label_set_hash=bank.label_set_hash,
|
| 156 |
-
model_id=settings.clip_model_id,
|
| 157 |
-
domain_hits=[Hit(id=i, score=s) for i, s in res.domain_hits],
|
| 158 |
-
chosen_domains=res.chosen_domains,
|
| 159 |
-
label_hits=[Hit(id=i, score=s) for i, s in res.label_hits],
|
| 160 |
-
elapsed_ms=res.timings.total_ms,
|
| 161 |
-
elapsed_domain_ms=res.timings.domain_ms,
|
| 162 |
-
elapsed_labels_ms=res.timings.labels_ms,
|
| 163 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pyproject.toml
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[build-system]
|
| 2 |
+
requires = ["setuptools>=68", "wheel"]
|
| 3 |
+
build-backend = "setuptools.build_meta"
|
| 4 |
+
|
| 5 |
+
[project]
|
| 6 |
+
name = "photo-classification"
|
| 7 |
+
version = "0.1.0"
|
| 8 |
+
description = "Prompt-driven photo classification API built on CLIP"
|
| 9 |
+
readme = "README.md"
|
| 10 |
+
requires-python = ">=3.12,<3.13"
|
| 11 |
+
dependencies = [
|
| 12 |
+
"fastapi==0.115.6",
|
| 13 |
+
"pillow==10.4.0",
|
| 14 |
+
"pydantic==2.8.2",
|
| 15 |
+
"torch==2.3.1",
|
| 16 |
+
"transformers==4.44.2",
|
| 17 |
+
"uvicorn[standard]==0.30.6",
|
| 18 |
+
]
|
| 19 |
+
|
| 20 |
+
[project.optional-dependencies]
|
| 21 |
+
dev = [
|
| 22 |
+
"httpx==0.27.2",
|
| 23 |
+
"pytest==8.3.2",
|
| 24 |
+
]
|
| 25 |
+
|
| 26 |
+
[tool.setuptools]
|
| 27 |
+
package-dir = {"" = "src"}
|
| 28 |
+
|
| 29 |
+
[tool.setuptools.packages.find]
|
| 30 |
+
where = ["src"]
|
{app β src/app}/__init__.py
RENAMED
|
File without changes
|
src/app/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (149 Bytes). View file
|
|
|
src/app/__pycache__/banks.cpython-312.pyc
ADDED
|
Binary file (964 Bytes). View file
|
|
|
src/app/__pycache__/clip_service.cpython-312.pyc
ADDED
|
Binary file (4.86 kB). View file
|
|
|
src/app/__pycache__/clip_store.cpython-312.pyc
ADDED
|
Binary file (5.74 kB). View file
|
|
|
src/app/__pycache__/deps.cpython-312.pyc
ADDED
|
Binary file (1.74 kB). View file
|
|
|
src/app/__pycache__/image_io.cpython-312.pyc
ADDED
|
Binary file (1.17 kB). View file
|
|
|
src/app/__pycache__/label_hash.cpython-312.pyc
ADDED
|
Binary file (737 Bytes). View file
|
|
|
src/app/__pycache__/logging_utils.cpython-312.pyc
ADDED
|
Binary file (1.57 kB). View file
|
|
|
src/app/__pycache__/main.cpython-312.pyc
ADDED
|
Binary file (14 kB). View file
|
|
|
src/app/__pycache__/middleware.cpython-312.pyc
ADDED
|
Binary file (1.09 kB). View file
|
|
|
src/app/__pycache__/registry.cpython-312.pyc
ADDED
|
Binary file (1.67 kB). View file
|
|
|
src/app/__pycache__/results.cpython-312.pyc
ADDED
|
Binary file (938 Bytes). View file
|
|
|
src/app/__pycache__/schemas.cpython-312.pyc
ADDED
|
Binary file (3.27 kB). View file
|
|
|
src/app/__pycache__/settings.cpython-312.pyc
ADDED
|
Binary file (705 Bytes). View file
|
|
|
app_factory.py β src/app/app_factory.py
RENAMED
|
File without changes
|
banks.py β src/app/banks.py
RENAMED
|
File without changes
|
clip_service.py β src/app/clip_service.py
RENAMED
|
File without changes
|
clip_store.py β src/app/clip_store.py
RENAMED
|
@@ -1,5 +1,7 @@
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
|
|
|
|
|
|
| 3 |
import torch
|
| 4 |
from transformers import CLIPModel, CLIPProcessor
|
| 5 |
|
|
@@ -18,7 +20,16 @@ class ClipStore:
|
|
| 18 |
def __init__(self) -> None:
|
| 19 |
self.device = torch.device("cpu")
|
| 20 |
self.model = CLIPModel.from_pretrained(settings.clip_model_id).to(self.device).eval()
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
def build_bank(self, label_set: LabelSet) -> LabelSetBank:
|
| 24 |
payload = label_set.model_dump()
|
|
|
|
| 1 |
from __future__ import annotations
|
| 2 |
|
| 3 |
+
import warnings
|
| 4 |
+
|
| 5 |
import torch
|
| 6 |
from transformers import CLIPModel, CLIPProcessor
|
| 7 |
|
|
|
|
| 20 |
def __init__(self) -> None:
|
| 21 |
self.device = torch.device("cpu")
|
| 22 |
self.model = CLIPModel.from_pretrained(settings.clip_model_id).to(self.device).eval()
|
| 23 |
+
with warnings.catch_warnings():
|
| 24 |
+
warnings.filterwarnings(
|
| 25 |
+
"ignore",
|
| 26 |
+
message="`clean_up_tokenization_spaces` was not set",
|
| 27 |
+
category=FutureWarning,
|
| 28 |
+
module="transformers.tokenization_utils_base",
|
| 29 |
+
)
|
| 30 |
+
self.processor = CLIPProcessor.from_pretrained(settings.clip_model_id)
|
| 31 |
+
if hasattr(self.processor, "tokenizer") and hasattr(self.processor.tokenizer, "clean_up_tokenization_spaces"):
|
| 32 |
+
self.processor.tokenizer.clean_up_tokenization_spaces = True
|
| 33 |
|
| 34 |
def build_bank(self, label_set: LabelSet) -> LabelSetBank:
|
| 35 |
payload = label_set.model_dump()
|
deps.py β src/app/deps.py
RENAMED
|
File without changes
|
image_io.py β src/app/image_io.py
RENAMED
|
File without changes
|
label_hash.py β src/app/label_hash.py
RENAMED
|
File without changes
|
logging_utils.py β src/app/logging_utils.py
RENAMED
|
File without changes
|
src/app/main.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from __future__ import annotations
|
| 2 |
+
|
| 3 |
+
from contextlib import asynccontextmanager
|
| 4 |
+
from dataclasses import dataclass
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
from fastapi import Depends, FastAPI, HTTPException, Query, Request, Response
|
| 8 |
+
from fastapi.responses import JSONResponse
|
| 9 |
+
|
| 10 |
+
from app.clip_store import ClipStore
|
| 11 |
+
from app.clip_service import TwoStageClassifier
|
| 12 |
+
from app.deps import get_request_id, resolve_bank
|
| 13 |
+
from app.image_io import load_image_from_base64
|
| 14 |
+
from app.logging_utils import setup_logging, log_json
|
| 15 |
+
from app.middleware import RequestIdMiddleware
|
| 16 |
+
from app.registry import LabelSetRegistry
|
| 17 |
+
from app.schemas import (
|
| 18 |
+
ActivateResponse,
|
| 19 |
+
ClassifyRequest,
|
| 20 |
+
ClassifyResponse,
|
| 21 |
+
Hit,
|
| 22 |
+
LabelSet,
|
| 23 |
+
LabelSetCreateResponse,
|
| 24 |
+
LabelSetInfo,
|
| 25 |
+
)
|
| 26 |
+
from app.settings import settings
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
logger = setup_logging()
|
| 30 |
+
|
| 31 |
+
BANNER = r"""
|
| 32 |
+
____ _ _ ____ _
|
| 33 |
+
| _ \| |__ ___ | |_ ___ / ___| | __ _ ___ ___
|
| 34 |
+
| |_) | '_ \ / _ \| __/ _ \ | | | |/ _` / __/ __|
|
| 35 |
+
| __/| | | | (_) | || (_) | | |___| | (_| \__ \__ \
|
| 36 |
+
|_| |_| |_|\___/ \__\___/ \____|_|\__,_|___/___/
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
@dataclass
|
| 41 |
+
class Resources:
|
| 42 |
+
store: ClipStore
|
| 43 |
+
classifier: TwoStageClassifier
|
| 44 |
+
registry: LabelSetRegistry
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
async def _maybe_aclose(obj) -> None:
|
| 48 |
+
aclose = getattr(obj, "aclose", None)
|
| 49 |
+
if callable(aclose):
|
| 50 |
+
await aclose()
|
| 51 |
+
return
|
| 52 |
+
close = getattr(obj, "close", None)
|
| 53 |
+
if callable(close):
|
| 54 |
+
close()
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
@asynccontextmanager
|
| 58 |
+
async def lifespan(app: FastAPI):
|
| 59 |
+
store = ClipStore()
|
| 60 |
+
classifier = TwoStageClassifier(store=store)
|
| 61 |
+
registry = LabelSetRegistry(banks={})
|
| 62 |
+
|
| 63 |
+
app.state.resources = Resources(store=store, classifier=classifier, registry=registry)
|
| 64 |
+
try:
|
| 65 |
+
yield
|
| 66 |
+
finally:
|
| 67 |
+
await _maybe_aclose(registry)
|
| 68 |
+
await _maybe_aclose(classifier)
|
| 69 |
+
await _maybe_aclose(store)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def get_resources(request: Request) -> Resources:
|
| 73 |
+
return request.app.state.resources
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def get_store(res: Resources = Depends(get_resources)) -> ClipStore:
|
| 77 |
+
return res.store
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def get_classifier(res: Resources = Depends(get_resources)) -> TwoStageClassifier:
|
| 81 |
+
return res.classifier
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def get_registry(res: Resources = Depends(get_resources)) -> LabelSetRegistry:
|
| 85 |
+
return res.registry
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
def create_app(*, resources: Resources | None = None) -> FastAPI:
|
| 89 |
+
app = FastAPI(
|
| 90 |
+
lifespan=lifespan,
|
| 91 |
+
title="Photo Classification API",
|
| 92 |
+
version="1.0.0",
|
| 93 |
+
description=f"```\n{BANNER.strip()}\n```",
|
| 94 |
+
docs_url="/docs",
|
| 95 |
+
redoc_url=None,
|
| 96 |
+
openapi_url="/openapi.json",
|
| 97 |
+
)
|
| 98 |
+
app.add_middleware(RequestIdMiddleware)
|
| 99 |
+
|
| 100 |
+
if resources is not None:
|
| 101 |
+
app.state.resources = resources
|
| 102 |
+
|
| 103 |
+
@asynccontextmanager
|
| 104 |
+
async def _lifespan_override(_app: FastAPI):
|
| 105 |
+
_app.state.resources = resources
|
| 106 |
+
try:
|
| 107 |
+
yield
|
| 108 |
+
finally:
|
| 109 |
+
await _maybe_aclose(resources.registry)
|
| 110 |
+
await _maybe_aclose(resources.classifier)
|
| 111 |
+
await _maybe_aclose(resources.store)
|
| 112 |
+
|
| 113 |
+
app.router.lifespan_context = _lifespan_override
|
| 114 |
+
|
| 115 |
+
@app.get("/favicon.ico", include_in_schema=False)
|
| 116 |
+
def favicon() -> Response:
|
| 117 |
+
svg = (
|
| 118 |
+
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'>"
|
| 119 |
+
"<rect width='64' height='64' rx='12' fill='#1f2937'/>"
|
| 120 |
+
"<circle cx='24' cy='28' r='10' fill='#f59e0b'/>"
|
| 121 |
+
"<circle cx='44' cy='28' r='10' fill='#60a5fa'/>"
|
| 122 |
+
"<rect x='18' y='38' width='28' height='10' rx='5' fill='#e5e7eb'/>"
|
| 123 |
+
"</svg>"
|
| 124 |
+
)
|
| 125 |
+
return Response(content=svg, media_type="image/svg+xml")
|
| 126 |
+
|
| 127 |
+
@app.exception_handler(Exception)
|
| 128 |
+
async def unhandled_exception_handler(request: Request, exc: Exception):
|
| 129 |
+
rid = getattr(request.state, "request_id", None)
|
| 130 |
+
log_json(logger, event="error.unhandled", request_id=rid, error=str(exc), path=str(request.url.path))
|
| 131 |
+
return JSONResponse(status_code=500, content={"detail": "internal server error"})
|
| 132 |
+
|
| 133 |
+
@app.post("/api/v1/label-sets", response_model=LabelSetCreateResponse)
|
| 134 |
+
def create_label_set(
|
| 135 |
+
payload: LabelSet,
|
| 136 |
+
request_id: str = Depends(get_request_id),
|
| 137 |
+
store: ClipStore = Depends(get_store),
|
| 138 |
+
registry: LabelSetRegistry = Depends(get_registry),
|
| 139 |
+
) -> LabelSetCreateResponse:
|
| 140 |
+
bank = store.build_bank(payload)
|
| 141 |
+
registry.upsert(bank)
|
| 142 |
+
|
| 143 |
+
label_count = sum(len(b.ids) for b in bank.labels_by_domain.values())
|
| 144 |
+
is_default = (registry.default_hash == bank.label_set_hash)
|
| 145 |
+
|
| 146 |
+
log_json(
|
| 147 |
+
logger,
|
| 148 |
+
event="label_sets.upsert",
|
| 149 |
+
request_id=request_id,
|
| 150 |
+
label_set_hash=bank.label_set_hash,
|
| 151 |
+
name=bank.name,
|
| 152 |
+
domain_count=len(bank.domains.ids),
|
| 153 |
+
label_count=label_count,
|
| 154 |
+
is_default=is_default,
|
| 155 |
+
)
|
| 156 |
+
|
| 157 |
+
return LabelSetCreateResponse(
|
| 158 |
+
label_set_hash=bank.label_set_hash,
|
| 159 |
+
name=bank.name,
|
| 160 |
+
domain_count=len(bank.domains.ids),
|
| 161 |
+
label_count=label_count,
|
| 162 |
+
is_default=is_default,
|
| 163 |
+
)
|
| 164 |
+
|
| 165 |
+
@app.get("/api/v1/label-sets", response_model=list[LabelSetInfo])
|
| 166 |
+
def list_label_sets(
|
| 167 |
+
request_id: str = Depends(get_request_id),
|
| 168 |
+
registry: LabelSetRegistry = Depends(get_registry),
|
| 169 |
+
) -> list[LabelSetInfo]:
|
| 170 |
+
out: list[LabelSetInfo] = []
|
| 171 |
+
for bank in registry.banks.values():
|
| 172 |
+
label_count = sum(len(b.ids) for b in bank.labels_by_domain.values())
|
| 173 |
+
out.append(
|
| 174 |
+
LabelSetInfo(
|
| 175 |
+
label_set_hash=bank.label_set_hash,
|
| 176 |
+
name=bank.name,
|
| 177 |
+
domain_count=len(bank.domains.ids),
|
| 178 |
+
label_count=label_count,
|
| 179 |
+
is_default=(registry.default_hash == bank.label_set_hash),
|
| 180 |
+
)
|
| 181 |
+
)
|
| 182 |
+
|
| 183 |
+
log_json(logger, event="label_sets.list", request_id=request_id, count=len(out))
|
| 184 |
+
return out
|
| 185 |
+
|
| 186 |
+
@app.post("/api/v1/label-sets/{label_set_hash}/activate", response_model=ActivateResponse)
|
| 187 |
+
def activate_label_set(
|
| 188 |
+
label_set_hash: str,
|
| 189 |
+
request_id: str = Depends(get_request_id),
|
| 190 |
+
registry: LabelSetRegistry = Depends(get_registry),
|
| 191 |
+
) -> ActivateResponse:
|
| 192 |
+
try:
|
| 193 |
+
registry.activate(label_set_hash)
|
| 194 |
+
except KeyError:
|
| 195 |
+
raise HTTPException(status_code=404, detail="Unknown label_set_hash")
|
| 196 |
+
|
| 197 |
+
log_json(logger, event="label_sets.activate", request_id=request_id, default_label_set_hash=label_set_hash)
|
| 198 |
+
return ActivateResponse(default_label_set_hash=label_set_hash)
|
| 199 |
+
|
| 200 |
+
@app.post("/api/v1/classify", response_model=ClassifyResponse)
|
| 201 |
+
def classify(
|
| 202 |
+
payload: ClassifyRequest,
|
| 203 |
+
request: Request,
|
| 204 |
+
request_id: str = Depends(get_request_id),
|
| 205 |
+
label_set_hash: Optional[str] = Query(default=None, description="If omitted, uses the default label set."),
|
| 206 |
+
classifier: TwoStageClassifier = Depends(get_classifier),
|
| 207 |
+
registry: LabelSetRegistry = Depends(get_registry),
|
| 208 |
+
) -> ClassifyResponse:
|
| 209 |
+
bank = resolve_bank(registry, label_set_hash)
|
| 210 |
+
|
| 211 |
+
image = load_image_from_base64(
|
| 212 |
+
payload.image_base64,
|
| 213 |
+
max_bytes=settings.max_image_mb * 1024 * 1024,
|
| 214 |
+
)
|
| 215 |
+
|
| 216 |
+
res = classifier.classify(
|
| 217 |
+
bank=bank,
|
| 218 |
+
image=image,
|
| 219 |
+
domain_top_n=payload.domain_top_n or settings.default_domain_top_n,
|
| 220 |
+
top_k=payload.top_k or settings.default_top_k,
|
| 221 |
+
)
|
| 222 |
+
|
| 223 |
+
log_json(
|
| 224 |
+
logger,
|
| 225 |
+
event="classify",
|
| 226 |
+
request_id=request_id,
|
| 227 |
+
label_set_hash=bank.label_set_hash,
|
| 228 |
+
model_id=settings.clip_model_id,
|
| 229 |
+
domain_top_n=payload.domain_top_n,
|
| 230 |
+
top_k=payload.top_k,
|
| 231 |
+
chosen_domains=res.chosen_domains,
|
| 232 |
+
elapsed_ms=res.timings.total_ms,
|
| 233 |
+
elapsed_domain_ms=res.timings.domain_ms,
|
| 234 |
+
elapsed_labels_ms=res.timings.labels_ms,
|
| 235 |
+
)
|
| 236 |
+
|
| 237 |
+
return ClassifyResponse(
|
| 238 |
+
label_set_hash=bank.label_set_hash,
|
| 239 |
+
model_id=settings.clip_model_id,
|
| 240 |
+
domain_hits=[Hit(id=i, score=s) for i, s in res.domain_hits],
|
| 241 |
+
chosen_domains=res.chosen_domains,
|
| 242 |
+
label_hits=[Hit(id=i, score=s) for i, s in res.label_hits],
|
| 243 |
+
elapsed_ms=res.timings.total_ms,
|
| 244 |
+
elapsed_domain_ms=res.timings.domain_ms,
|
| 245 |
+
elapsed_labels_ms=res.timings.labels_ms,
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
return app
|
| 249 |
+
|
| 250 |
+
|
| 251 |
+
def build_app(
|
| 252 |
+
store: ClipStore | None = None,
|
| 253 |
+
classifier: TwoStageClassifier | None = None,
|
| 254 |
+
registry: LabelSetRegistry | None = None,
|
| 255 |
+
) -> FastAPI:
|
| 256 |
+
if store is None and classifier is None and registry is None:
|
| 257 |
+
return create_app()
|
| 258 |
+
store = store or ClipStore()
|
| 259 |
+
classifier = classifier or TwoStageClassifier(store=store)
|
| 260 |
+
registry = registry or LabelSetRegistry(banks={})
|
| 261 |
+
resources = Resources(store=store, classifier=classifier, registry=registry)
|
| 262 |
+
return create_app(resources=resources)
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
app = create_app()
|
middleware.py β src/app/middleware.py
RENAMED
|
File without changes
|
registry.py β src/app/registry.py
RENAMED
|
File without changes
|
results.py β src/app/results.py
RENAMED
|
File without changes
|
schemas.py β src/app/schemas.py
RENAMED
|
@@ -60,7 +60,7 @@ class Hit(BaseModel):
|
|
| 60 |
|
| 61 |
|
| 62 |
class ClassifyResponse(BaseModel):
|
| 63 |
-
model_config = ConfigDict(extra="forbid")
|
| 64 |
label_set_hash: str
|
| 65 |
model_id: str
|
| 66 |
domain_hits: List[Hit]
|
|
|
|
| 60 |
|
| 61 |
|
| 62 |
class ClassifyResponse(BaseModel):
|
| 63 |
+
model_config = ConfigDict(extra="forbid", protected_namespaces=())
|
| 64 |
label_set_hash: str
|
| 65 |
model_id: str
|
| 66 |
domain_hits: List[Hit]
|
settings.py β src/app/settings.py
RENAMED
|
File without changes
|
src/photo_classification.egg-info/PKG-INFO
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Metadata-Version: 2.4
|
| 2 |
+
Name: photo-classification
|
| 3 |
+
Version: 0.1.0
|
| 4 |
+
Summary: Prompt-driven photo classification API built on CLIP
|
| 5 |
+
Requires-Python: <3.13,>=3.12
|
| 6 |
+
Description-Content-Type: text/markdown
|
| 7 |
+
Requires-Dist: fastapi==0.115.6
|
| 8 |
+
Requires-Dist: pillow==10.4.0
|
| 9 |
+
Requires-Dist: pydantic==2.8.2
|
| 10 |
+
Requires-Dist: torch==2.3.1
|
| 11 |
+
Requires-Dist: transformers==4.44.2
|
| 12 |
+
Requires-Dist: uvicorn[standard]==0.30.6
|
| 13 |
+
Provides-Extra: dev
|
| 14 |
+
Requires-Dist: httpx==0.27.2; extra == "dev"
|
| 15 |
+
Requires-Dist: pytest==8.3.2; extra == "dev"
|
| 16 |
+
|
| 17 |
+
---
|
| 18 |
+
title: Photo Classification API
|
| 19 |
+
emoji: π·
|
| 20 |
+
colorFrom: blue
|
| 21 |
+
colorTo: gray
|
| 22 |
+
sdk: docker
|
| 23 |
+
app_port: 7860
|
| 24 |
+
---
|
| 25 |
+
|
| 26 |
+
# Photo Classification API
|
| 27 |
+
|
| 28 |
+
```
|
| 29 |
+
____ _ _ ____ _
|
| 30 |
+
| _ \| |__ ___ | |_ ___ / ___| | __ _ ___ ___
|
| 31 |
+
| |_) | '_ \ / _ \| __/ _ \ | | | |/ _` / __/ __|
|
| 32 |
+
| __/| | | | (_) | || (_) | | |___| | (_| \__ \__ \
|
| 33 |
+
|_| |_| |_|\___/ \__\___/ \____|_|\__,_|___/___/
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
A small, prompt-driven photo classification API built on CLIP. You upload a label set
|
| 37 |
+
(domains + labels with prompts), then classify images against that taxonomy without
|
| 38 |
+
any fine-tuning.
|
| 39 |
+
|
| 40 |
+
## Why this exists
|
| 41 |
+
|
| 42 |
+
- Fast taxonomy iteration: change labels or prompts without retraining.
|
| 43 |
+
- Simple deployment: CPU-only CLIP inference by default.
|
| 44 |
+
- Clear outputs: domain hits, chosen domains, and label hits with scores.
|
| 45 |
+
|
| 46 |
+
## Models
|
| 47 |
+
|
| 48 |
+
- Text and image embeddings are produced by CLIP (`openai/clip-vit-base-patch32`).
|
| 49 |
+
- All inference runs on CPU unless you adapt `ClipStore` to use GPU.
|
| 50 |
+
- Scoring uses cosine-like similarity with CLIP's logit scale and a softmax.
|
| 51 |
+
|
| 52 |
+
## Label datasets
|
| 53 |
+
|
| 54 |
+
Label sets are JSON files with `domains` and `labels_by_domain`, each item defining:
|
| 55 |
+
|
| 56 |
+
- `id`: stable identifier
|
| 57 |
+
- `display`: human-readable name
|
| 58 |
+
- `prompt`: the text prompt used for CLIP embedding
|
| 59 |
+
|
| 60 |
+
Examples:
|
| 61 |
+
|
| 62 |
+
- `label-dataset/personal-photos-lite-v1.json`
|
| 63 |
+
- `label-dataset/personal-photos-large-v1.json`
|
| 64 |
+
- `label-dataset/scene-dance-formation-group-v1.json`
|
| 65 |
+
|
| 66 |
+
Use these as starting points or create your own taxonomy.
|
| 67 |
+
|
| 68 |
+
## API quickstart
|
| 69 |
+
|
| 70 |
+
1) Start the service (Docker or `uvicorn app.main:app`).
|
| 71 |
+
2) Upload a label set.
|
| 72 |
+
3) Optionally activate a label set.
|
| 73 |
+
4) Classify images.
|
| 74 |
+
|
| 75 |
+
Endpoints:
|
| 76 |
+
|
| 77 |
+
- `POST /api/v1/label-sets` (upload)
|
| 78 |
+
- `GET /api/v1/label-sets` (list)
|
| 79 |
+
- `POST /api/v1/label-sets/{label_set_hash}/activate` (set default)
|
| 80 |
+
- `POST /api/v1/classify` (classify image)
|
| 81 |
+
|
| 82 |
+
`/api/v1/classify` body:
|
| 83 |
+
|
| 84 |
+
```json
|
| 85 |
+
{
|
| 86 |
+
"image_base64": "<base64>",
|
| 87 |
+
"domain_top_n": 2,
|
| 88 |
+
"top_k": 5
|
| 89 |
+
}
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
Response includes `domain_hits`, `chosen_domains`, `label_hits`, and timings.
|
| 93 |
+
|
| 94 |
+
## Recommended runtime config
|
| 95 |
+
|
| 96 |
+
Default params for stable results:
|
| 97 |
+
|
| 98 |
+
```json
|
| 99 |
+
{
|
| 100 |
+
"domain_top_n": 1,
|
| 101 |
+
"top_k": 3
|
| 102 |
+
}
|
| 103 |
+
```
|
| 104 |
+
|
| 105 |
+
Guard policy example:
|
| 106 |
+
|
| 107 |
+
- Use `domain_top_n = 3`, `top_k = 4`.
|
| 108 |
+
- If `non_dance` appears in `chosen_domains` and its top label score is high vs
|
| 109 |
+
`dance`, treat the photo as "not dancing" and skip dance-style conclusions.
|
| 110 |
+
|
| 111 |
+
## Architecture
|
| 112 |
+
|
| 113 |
+
- API layer: FastAPI endpoints and request/response schemas (`src/app/main.py`, `src/app/schemas.py`).
|
| 114 |
+
- Use-case layer: two-stage classification (domain -> labels) (`src/app/clip_service.py`).
|
| 115 |
+
- Model layer: CLIP model + processor + embedding banks (`src/app/clip_store.py`, `src/app/banks.py`).
|
| 116 |
+
- Runtime support: registry, settings, logging, middleware (`src/app/registry.py`, `src/app/settings.py`,
|
| 117 |
+
`src/app/logging_utils.py`, `src/app/middleware.py`).
|
| 118 |
+
|
| 119 |
+
## Coding rules (deeper)
|
| 120 |
+
|
| 121 |
+
Separation of concerns:
|
| 122 |
+
|
| 123 |
+
- API layer does IO only: parse input, validate, load image, call use-case, return typed DTOs.
|
| 124 |
+
- Use-case layer owns business logic: the two-stage classification and result shaping.
|
| 125 |
+
- Model layer owns ML specifics: CLIP loading, text/image encoding, and logit scaling.
|
| 126 |
+
- Data layer owns taxonomy inputs: JSON label sets, hashing, and embedding banks.
|
| 127 |
+
|
| 128 |
+
API vs use-case vs torch:
|
| 129 |
+
|
| 130 |
+
- API should not import torch or transformers; it deals in base64, Pydantic models, and HTTP.
|
| 131 |
+
- Use-case should not depend on HTTP; it accepts a bank + image and returns a typed result.
|
| 132 |
+
- Torch code lives in `ClipStore` only; the rest of the code treats embeddings as opaque tensors.
|
| 133 |
+
|
| 134 |
+
Typed outputs and clean steps:
|
| 135 |
+
|
| 136 |
+
- Each step returns a typed value (`LabelSetBank`, `ClassificationResult`, `Hit` lists).
|
| 137 |
+
- Keep operations in small pure functions or methods that express a single step:
|
| 138 |
+
- validate input
|
| 139 |
+
- load/normalize image
|
| 140 |
+
- encode image
|
| 141 |
+
- score domains
|
| 142 |
+
- merge label banks
|
| 143 |
+
- score labels
|
| 144 |
+
|
| 145 |
+
Dataset usage:
|
| 146 |
+
|
| 147 |
+
- Label sets are data, not code. Changes to taxonomy are done in JSON files or user payloads.
|
| 148 |
+
- Stable hashes (`label_set_hash`) are derived from canonical JSON for reproducibility.
|
| 149 |
+
|
| 150 |
+
Avoid old PyTorch habits:
|
| 151 |
+
|
| 152 |
+
- No training loops, optimizers, or manual grad handling; this is inference-only.
|
| 153 |
+
- Use `torch.no_grad()` and normalized embeddings for stable cosine-like comparisons.
|
| 154 |
+
- Keep tensors on the same device; `ClipStore` owns device placement.
|
| 155 |
+
- Prefer small, readable tensor ops over complex pipelines.
|
| 156 |
+
|
| 157 |
+
Error handling and HTTP boundaries:
|
| 158 |
+
|
| 159 |
+
- Decode/validate base64 and size limits in `image_io`, not inside ML code.
|
| 160 |
+
- Convert internal errors to HTTP responses at the boundary (e.g., 400/404/413).
|
| 161 |
+
- Log JSON events with request IDs for traceability.
|
| 162 |
+
|
| 163 |
+
## Tests
|
| 164 |
+
|
| 165 |
+
- Fast, deterministic tests use fakes for classifier and store (`tests/fakes.py`).
|
| 166 |
+
- Integration test optionally loads real CLIP (`tests/test_integration_real_clip.py`).
|
| 167 |
+
- Run:
|
| 168 |
+
- `pytest -q`
|
| 169 |
+
- `pytest -q -m integration`
|
| 170 |
+
|
| 171 |
+
## Project layout
|
| 172 |
+
|
| 173 |
+
```
|
| 174 |
+
.
|
| 175 |
+
βββ Dockerfile
|
| 176 |
+
βββ requirements.txt
|
| 177 |
+
βββ src
|
| 178 |
+
βββ app
|
| 179 |
+
βββ banks.py
|
| 180 |
+
βββ clip_service.py
|
| 181 |
+
βββ clip_store.py
|
| 182 |
+
βββ deps.py
|
| 183 |
+
βββ image_io.py
|
| 184 |
+
βββ label_hash.py
|
| 185 |
+
βββ logging_utils.py
|
| 186 |
+
βββ main.py
|
| 187 |
+
βββ middleware.py
|
| 188 |
+
βββ registry.py
|
| 189 |
+
βββ results.py
|
| 190 |
+
βββ schemas.py
|
| 191 |
+
βββ settings.py
|
| 192 |
+
```
|
src/photo_classification.egg-info/SOURCES.txt
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
README.md
|
| 2 |
+
pyproject.toml
|
| 3 |
+
src/app/__init__.py
|
| 4 |
+
src/app/app_factory.py
|
| 5 |
+
src/app/banks.py
|
| 6 |
+
src/app/clip_service.py
|
| 7 |
+
src/app/clip_store.py
|
| 8 |
+
src/app/deps.py
|
| 9 |
+
src/app/image_io.py
|
| 10 |
+
src/app/label_hash.py
|
| 11 |
+
src/app/logging_utils.py
|
| 12 |
+
src/app/main.py
|
| 13 |
+
src/app/middleware.py
|
| 14 |
+
src/app/registry.py
|
| 15 |
+
src/app/results.py
|
| 16 |
+
src/app/schemas.py
|
| 17 |
+
src/app/settings.py
|
| 18 |
+
src/photo_classification.egg-info/PKG-INFO
|
| 19 |
+
src/photo_classification.egg-info/SOURCES.txt
|
| 20 |
+
src/photo_classification.egg-info/dependency_links.txt
|
| 21 |
+
src/photo_classification.egg-info/requires.txt
|
| 22 |
+
src/photo_classification.egg-info/top_level.txt
|
| 23 |
+
tests/test_api.py
|
| 24 |
+
tests/test_integration_real_clip.py
|
src/photo_classification.egg-info/dependency_links.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
src/photo_classification.egg-info/requires.txt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi==0.115.6
|
| 2 |
+
pillow==10.4.0
|
| 3 |
+
pydantic==2.8.2
|
| 4 |
+
torch==2.3.1
|
| 5 |
+
transformers==4.44.2
|
| 6 |
+
uvicorn[standard]==0.30.6
|
| 7 |
+
|
| 8 |
+
[dev]
|
| 9 |
+
httpx==0.27.2
|
| 10 |
+
pytest==8.3.2
|
src/photo_classification.egg-info/top_level.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
app
|
tests/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
"""Test package marker for src layout imports."""
|
tests/__pycache__/__init__.cpython-312.pyc
ADDED
|
Binary file (209 Bytes). View file
|
|
|
tests/__pycache__/conftest.cpython-312-pytest-8.3.2.pyc
ADDED
|
Binary file (2.3 kB). View file
|
|
|
tests/__pycache__/fakes.cpython-312.pyc
ADDED
|
Binary file (3.29 kB). View file
|
|
|
tests/__pycache__/test_api.cpython-312-pytest-8.3.2.pyc
ADDED
|
Binary file (14.2 kB). View file
|
|
|
tests/__pycache__/test_integration_real_clip.cpython-312-pytest-8.3.2.pyc
ADDED
|
Binary file (6.21 kB). View file
|
|
|
conftest.py β tests/conftest.py
RENAMED
|
File without changes
|
fakes.py β tests/fakes.py
RENAMED
|
File without changes
|
test_api.py β tests/test_api.py
RENAMED
|
File without changes
|
uv.lock
ADDED
|
@@ -0,0 +1,850 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version = 1
|
| 2 |
+
revision = 2
|
| 3 |
+
requires-python = "==3.12.*"
|
| 4 |
+
|
| 5 |
+
[[package]]
|
| 6 |
+
name = "annotated-types"
|
| 7 |
+
version = "0.7.0"
|
| 8 |
+
source = { registry = "https://pypi.org/simple" }
|
| 9 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
| 10 |
+
wheels = [
|
| 11 |
+
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
[[package]]
|
| 15 |
+
name = "anyio"
|
| 16 |
+
version = "4.12.1"
|
| 17 |
+
source = { registry = "https://pypi.org/simple" }
|
| 18 |
+
dependencies = [
|
| 19 |
+
{ name = "idna" },
|
| 20 |
+
{ name = "typing-extensions" },
|
| 21 |
+
]
|
| 22 |
+
sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" }
|
| 23 |
+
wheels = [
|
| 24 |
+
{ url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" },
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
[[package]]
|
| 28 |
+
name = "certifi"
|
| 29 |
+
version = "2026.1.4"
|
| 30 |
+
source = { registry = "https://pypi.org/simple" }
|
| 31 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" }
|
| 32 |
+
wheels = [
|
| 33 |
+
{ url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" },
|
| 34 |
+
]
|
| 35 |
+
|
| 36 |
+
[[package]]
|
| 37 |
+
name = "charset-normalizer"
|
| 38 |
+
version = "3.4.4"
|
| 39 |
+
source = { registry = "https://pypi.org/simple" }
|
| 40 |
+
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
|
| 41 |
+
wheels = [
|
| 42 |
+
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
|
| 43 |
+
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
|
| 44 |
+
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
|
| 45 |
+
{ url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
|
| 46 |
+
{ url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
|
| 47 |
+
{ url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
|
| 48 |
+
{ url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
|
| 49 |
+
{ url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
|
| 50 |
+
{ url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
|
| 51 |
+
{ url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
|
| 52 |
+
{ url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
|
| 53 |
+
{ url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
|
| 54 |
+
{ url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
|
| 55 |
+
{ url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
|
| 56 |
+
{ url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
|
| 57 |
+
{ url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
|
| 58 |
+
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
|
| 59 |
+
]
|
| 60 |
+
|
| 61 |
+
[[package]]
|
| 62 |
+
name = "click"
|
| 63 |
+
version = "8.3.1"
|
| 64 |
+
source = { registry = "https://pypi.org/simple" }
|
| 65 |
+
dependencies = [
|
| 66 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 67 |
+
]
|
| 68 |
+
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
| 69 |
+
wheels = [
|
| 70 |
+
{ url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" },
|
| 71 |
+
]
|
| 72 |
+
|
| 73 |
+
[[package]]
|
| 74 |
+
name = "colorama"
|
| 75 |
+
version = "0.4.6"
|
| 76 |
+
source = { registry = "https://pypi.org/simple" }
|
| 77 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
| 78 |
+
wheels = [
|
| 79 |
+
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
| 80 |
+
]
|
| 81 |
+
|
| 82 |
+
[[package]]
|
| 83 |
+
name = "fastapi"
|
| 84 |
+
version = "0.115.6"
|
| 85 |
+
source = { registry = "https://pypi.org/simple" }
|
| 86 |
+
dependencies = [
|
| 87 |
+
{ name = "pydantic" },
|
| 88 |
+
{ name = "starlette" },
|
| 89 |
+
{ name = "typing-extensions" },
|
| 90 |
+
]
|
| 91 |
+
sdist = { url = "https://files.pythonhosted.org/packages/93/72/d83b98cd106541e8f5e5bfab8ef2974ab45a62e8a6c5b5e6940f26d2ed4b/fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654", size = 301336, upload-time = "2024-12-03T22:46:01.629Z" }
|
| 92 |
+
wheels = [
|
| 93 |
+
{ url = "https://files.pythonhosted.org/packages/52/b3/7e4df40e585df024fac2f80d1a2d579c854ac37109675db2b0cc22c0bb9e/fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305", size = 94843, upload-time = "2024-12-03T22:45:59.368Z" },
|
| 94 |
+
]
|
| 95 |
+
|
| 96 |
+
[[package]]
|
| 97 |
+
name = "filelock"
|
| 98 |
+
version = "3.20.3"
|
| 99 |
+
source = { registry = "https://pypi.org/simple" }
|
| 100 |
+
sdist = { url = "https://files.pythonhosted.org/packages/1d/65/ce7f1b70157833bf3cb851b556a37d4547ceafc158aa9b34b36782f23696/filelock-3.20.3.tar.gz", hash = "sha256:18c57ee915c7ec61cff0ecf7f0f869936c7c30191bb0cf406f1341778d0834e1", size = 19485, upload-time = "2026-01-09T17:55:05.421Z" }
|
| 101 |
+
wheels = [
|
| 102 |
+
{ url = "https://files.pythonhosted.org/packages/b5/36/7fb70f04bf00bc646cd5bb45aa9eddb15e19437a28b8fb2b4a5249fac770/filelock-3.20.3-py3-none-any.whl", hash = "sha256:4b0dda527ee31078689fc205ec4f1c1bf7d56cf88b6dc9426c4f230e46c2dce1", size = 16701, upload-time = "2026-01-09T17:55:04.334Z" },
|
| 103 |
+
]
|
| 104 |
+
|
| 105 |
+
[[package]]
|
| 106 |
+
name = "fsspec"
|
| 107 |
+
version = "2026.1.0"
|
| 108 |
+
source = { registry = "https://pypi.org/simple" }
|
| 109 |
+
sdist = { url = "https://files.pythonhosted.org/packages/d5/7d/5df2650c57d47c57232af5ef4b4fdbff182070421e405e0d62c6cdbfaa87/fsspec-2026.1.0.tar.gz", hash = "sha256:e987cb0496a0d81bba3a9d1cee62922fb395e7d4c3b575e57f547953334fe07b", size = 310496, upload-time = "2026-01-09T15:21:35.562Z" }
|
| 110 |
+
wheels = [
|
| 111 |
+
{ url = "https://files.pythonhosted.org/packages/01/c9/97cc5aae1648dcb851958a3ddf73ccd7dbe5650d95203ecb4d7720b4cdbf/fsspec-2026.1.0-py3-none-any.whl", hash = "sha256:cb76aa913c2285a3b49bdd5fc55b1d7c708d7208126b60f2eb8194fe1b4cbdcc", size = 201838, upload-time = "2026-01-09T15:21:34.041Z" },
|
| 112 |
+
]
|
| 113 |
+
|
| 114 |
+
[[package]]
|
| 115 |
+
name = "h11"
|
| 116 |
+
version = "0.16.0"
|
| 117 |
+
source = { registry = "https://pypi.org/simple" }
|
| 118 |
+
sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
|
| 119 |
+
wheels = [
|
| 120 |
+
{ url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
|
| 121 |
+
]
|
| 122 |
+
|
| 123 |
+
[[package]]
|
| 124 |
+
name = "hf-xet"
|
| 125 |
+
version = "1.2.0"
|
| 126 |
+
source = { registry = "https://pypi.org/simple" }
|
| 127 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" }
|
| 128 |
+
wheels = [
|
| 129 |
+
{ url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" },
|
| 130 |
+
{ url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" },
|
| 131 |
+
{ url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" },
|
| 132 |
+
{ url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" },
|
| 133 |
+
{ url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" },
|
| 134 |
+
{ url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" },
|
| 135 |
+
{ url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" },
|
| 136 |
+
]
|
| 137 |
+
|
| 138 |
+
[[package]]
|
| 139 |
+
name = "httpcore"
|
| 140 |
+
version = "1.0.9"
|
| 141 |
+
source = { registry = "https://pypi.org/simple" }
|
| 142 |
+
dependencies = [
|
| 143 |
+
{ name = "certifi" },
|
| 144 |
+
{ name = "h11" },
|
| 145 |
+
]
|
| 146 |
+
sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" }
|
| 147 |
+
wheels = [
|
| 148 |
+
{ url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" },
|
| 149 |
+
]
|
| 150 |
+
|
| 151 |
+
[[package]]
|
| 152 |
+
name = "httptools"
|
| 153 |
+
version = "0.7.1"
|
| 154 |
+
source = { registry = "https://pypi.org/simple" }
|
| 155 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" }
|
| 156 |
+
wheels = [
|
| 157 |
+
{ url = "https://files.pythonhosted.org/packages/53/7f/403e5d787dc4942316e515e949b0c8a013d84078a915910e9f391ba9b3ed/httptools-0.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:38e0c83a2ea9746ebbd643bdfb521b9aa4a91703e2cd705c20443405d2fd16a5", size = 206280, upload-time = "2025-10-10T03:54:39.274Z" },
|
| 158 |
+
{ url = "https://files.pythonhosted.org/packages/2a/0d/7f3fd28e2ce311ccc998c388dd1c53b18120fda3b70ebb022b135dc9839b/httptools-0.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f25bbaf1235e27704f1a7b86cd3304eabc04f569c828101d94a0e605ef7205a5", size = 110004, upload-time = "2025-10-10T03:54:40.403Z" },
|
| 159 |
+
{ url = "https://files.pythonhosted.org/packages/84/a6/b3965e1e146ef5762870bbe76117876ceba51a201e18cc31f5703e454596/httptools-0.7.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2c15f37ef679ab9ecc06bfc4e6e8628c32a8e4b305459de7cf6785acd57e4d03", size = 517655, upload-time = "2025-10-10T03:54:41.347Z" },
|
| 160 |
+
{ url = "https://files.pythonhosted.org/packages/11/7d/71fee6f1844e6fa378f2eddde6c3e41ce3a1fb4b2d81118dd544e3441ec0/httptools-0.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7fe6e96090df46b36ccfaf746f03034e5ab723162bc51b0a4cf58305324036f2", size = 511440, upload-time = "2025-10-10T03:54:42.452Z" },
|
| 161 |
+
{ url = "https://files.pythonhosted.org/packages/22/a5/079d216712a4f3ffa24af4a0381b108aa9c45b7a5cc6eb141f81726b1823/httptools-0.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f72fdbae2dbc6e68b8239defb48e6a5937b12218e6ffc2c7846cc37befa84362", size = 495186, upload-time = "2025-10-10T03:54:43.937Z" },
|
| 162 |
+
{ url = "https://files.pythonhosted.org/packages/e9/9e/025ad7b65278745dee3bd0ebf9314934c4592560878308a6121f7f812084/httptools-0.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e99c7b90a29fd82fea9ef57943d501a16f3404d7b9ee81799d41639bdaae412c", size = 499192, upload-time = "2025-10-10T03:54:45.003Z" },
|
| 163 |
+
{ url = "https://files.pythonhosted.org/packages/6d/de/40a8f202b987d43afc4d54689600ff03ce65680ede2f31df348d7f368b8f/httptools-0.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3e14f530fefa7499334a79b0cf7e7cd2992870eb893526fb097d51b4f2d0f321", size = 86694, upload-time = "2025-10-10T03:54:45.923Z" },
|
| 164 |
+
]
|
| 165 |
+
|
| 166 |
+
[[package]]
|
| 167 |
+
name = "httpx"
|
| 168 |
+
version = "0.27.2"
|
| 169 |
+
source = { registry = "https://pypi.org/simple" }
|
| 170 |
+
dependencies = [
|
| 171 |
+
{ name = "anyio" },
|
| 172 |
+
{ name = "certifi" },
|
| 173 |
+
{ name = "httpcore" },
|
| 174 |
+
{ name = "idna" },
|
| 175 |
+
{ name = "sniffio" },
|
| 176 |
+
]
|
| 177 |
+
sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189, upload-time = "2024-08-27T12:54:01.334Z" }
|
| 178 |
+
wheels = [
|
| 179 |
+
{ url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395, upload-time = "2024-08-27T12:53:59.653Z" },
|
| 180 |
+
]
|
| 181 |
+
|
| 182 |
+
[[package]]
|
| 183 |
+
name = "huggingface-hub"
|
| 184 |
+
version = "0.36.0"
|
| 185 |
+
source = { registry = "https://pypi.org/simple" }
|
| 186 |
+
dependencies = [
|
| 187 |
+
{ name = "filelock" },
|
| 188 |
+
{ name = "fsspec" },
|
| 189 |
+
{ name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" },
|
| 190 |
+
{ name = "packaging" },
|
| 191 |
+
{ name = "pyyaml" },
|
| 192 |
+
{ name = "requests" },
|
| 193 |
+
{ name = "tqdm" },
|
| 194 |
+
{ name = "typing-extensions" },
|
| 195 |
+
]
|
| 196 |
+
sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" }
|
| 197 |
+
wheels = [
|
| 198 |
+
{ url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" },
|
| 199 |
+
]
|
| 200 |
+
|
| 201 |
+
[[package]]
|
| 202 |
+
name = "idna"
|
| 203 |
+
version = "3.11"
|
| 204 |
+
source = { registry = "https://pypi.org/simple" }
|
| 205 |
+
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" }
|
| 206 |
+
wheels = [
|
| 207 |
+
{ url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" },
|
| 208 |
+
]
|
| 209 |
+
|
| 210 |
+
[[package]]
|
| 211 |
+
name = "iniconfig"
|
| 212 |
+
version = "2.3.0"
|
| 213 |
+
source = { registry = "https://pypi.org/simple" }
|
| 214 |
+
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
| 215 |
+
wheels = [
|
| 216 |
+
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
| 217 |
+
]
|
| 218 |
+
|
| 219 |
+
[[package]]
|
| 220 |
+
name = "intel-openmp"
|
| 221 |
+
version = "2021.4.0"
|
| 222 |
+
source = { registry = "https://pypi.org/simple" }
|
| 223 |
+
wheels = [
|
| 224 |
+
{ url = "https://files.pythonhosted.org/packages/45/18/527f247d673ff84c38e0b353b6901539b99e83066cd505be42ad341ab16d/intel_openmp-2021.4.0-py2.py3-none-win32.whl", hash = "sha256:6e863d8fd3d7e8ef389d52cf97a50fe2afe1a19247e8c0d168ce021546f96fc9", size = 1860605, upload-time = "2021-09-28T17:03:44.748Z" },
|
| 225 |
+
{ url = "https://files.pythonhosted.org/packages/6f/21/b590c0cc3888b24f2ac9898c41d852d7454a1695fbad34bee85dba6dc408/intel_openmp-2021.4.0-py2.py3-none-win_amd64.whl", hash = "sha256:eef4c8bcc8acefd7f5cd3b9384dbf73d59e2c99fc56545712ded913f43c4a94f", size = 3516906, upload-time = "2021-09-28T17:03:50.453Z" },
|
| 226 |
+
]
|
| 227 |
+
|
| 228 |
+
[[package]]
|
| 229 |
+
name = "jinja2"
|
| 230 |
+
version = "3.1.6"
|
| 231 |
+
source = { registry = "https://pypi.org/simple" }
|
| 232 |
+
dependencies = [
|
| 233 |
+
{ name = "markupsafe" },
|
| 234 |
+
]
|
| 235 |
+
sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" }
|
| 236 |
+
wheels = [
|
| 237 |
+
{ url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" },
|
| 238 |
+
]
|
| 239 |
+
|
| 240 |
+
[[package]]
|
| 241 |
+
name = "markupsafe"
|
| 242 |
+
version = "3.0.3"
|
| 243 |
+
source = { registry = "https://pypi.org/simple" }
|
| 244 |
+
sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" }
|
| 245 |
+
wheels = [
|
| 246 |
+
{ url = "https://files.pythonhosted.org/packages/5a/72/147da192e38635ada20e0a2e1a51cf8823d2119ce8883f7053879c2199b5/markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e", size = 11615, upload-time = "2025-09-27T18:36:30.854Z" },
|
| 247 |
+
{ url = "https://files.pythonhosted.org/packages/9a/81/7e4e08678a1f98521201c3079f77db69fb552acd56067661f8c2f534a718/markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce", size = 12020, upload-time = "2025-09-27T18:36:31.971Z" },
|
| 248 |
+
{ url = "https://files.pythonhosted.org/packages/1e/2c/799f4742efc39633a1b54a92eec4082e4f815314869865d876824c257c1e/markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d", size = 24332, upload-time = "2025-09-27T18:36:32.813Z" },
|
| 249 |
+
{ url = "https://files.pythonhosted.org/packages/3c/2e/8d0c2ab90a8c1d9a24f0399058ab8519a3279d1bd4289511d74e909f060e/markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d", size = 22947, upload-time = "2025-09-27T18:36:33.86Z" },
|
| 250 |
+
{ url = "https://files.pythonhosted.org/packages/2c/54/887f3092a85238093a0b2154bd629c89444f395618842e8b0c41783898ea/markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a", size = 21962, upload-time = "2025-09-27T18:36:35.099Z" },
|
| 251 |
+
{ url = "https://files.pythonhosted.org/packages/c9/2f/336b8c7b6f4a4d95e91119dc8521402461b74a485558d8f238a68312f11c/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b", size = 23760, upload-time = "2025-09-27T18:36:36.001Z" },
|
| 252 |
+
{ url = "https://files.pythonhosted.org/packages/32/43/67935f2b7e4982ffb50a4d169b724d74b62a3964bc1a9a527f5ac4f1ee2b/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f", size = 21529, upload-time = "2025-09-27T18:36:36.906Z" },
|
| 253 |
+
{ url = "https://files.pythonhosted.org/packages/89/e0/4486f11e51bbba8b0c041098859e869e304d1c261e59244baa3d295d47b7/markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b", size = 23015, upload-time = "2025-09-27T18:36:37.868Z" },
|
| 254 |
+
{ url = "https://files.pythonhosted.org/packages/2f/e1/78ee7a023dac597a5825441ebd17170785a9dab23de95d2c7508ade94e0e/markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d", size = 14540, upload-time = "2025-09-27T18:36:38.761Z" },
|
| 255 |
+
{ url = "https://files.pythonhosted.org/packages/aa/5b/bec5aa9bbbb2c946ca2733ef9c4ca91c91b6a24580193e891b5f7dbe8e1e/markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c", size = 15105, upload-time = "2025-09-27T18:36:39.701Z" },
|
| 256 |
+
{ url = "https://files.pythonhosted.org/packages/e5/f1/216fc1bbfd74011693a4fd837e7026152e89c4bcf3e77b6692fba9923123/markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f", size = 13906, upload-time = "2025-09-27T18:36:40.689Z" },
|
| 257 |
+
]
|
| 258 |
+
|
| 259 |
+
[[package]]
|
| 260 |
+
name = "mkl"
|
| 261 |
+
version = "2021.4.0"
|
| 262 |
+
source = { registry = "https://pypi.org/simple" }
|
| 263 |
+
dependencies = [
|
| 264 |
+
{ name = "intel-openmp" },
|
| 265 |
+
{ name = "tbb" },
|
| 266 |
+
]
|
| 267 |
+
wheels = [
|
| 268 |
+
{ url = "https://files.pythonhosted.org/packages/ce/c6/892fe3bc91e811b78e4f85653864f2d92541d5e5c306b0cb3c2311e9ca64/mkl-2021.4.0-py2.py3-none-win32.whl", hash = "sha256:439c640b269a5668134e3dcbcea4350459c4a8bc46469669b2d67e07e3d330e8", size = 129048357, upload-time = "2021-09-28T17:08:58.256Z" },
|
| 269 |
+
{ url = "https://files.pythonhosted.org/packages/fe/1c/5f6dbf18e8b73e0a5472466f0ea8d48ce9efae39bd2ff38cebf8dce61259/mkl-2021.4.0-py2.py3-none-win_amd64.whl", hash = "sha256:ceef3cafce4c009dd25f65d7ad0d833a0fbadc3d8903991ec92351fe5de1e718", size = 228499609, upload-time = "2021-09-28T17:09:19.683Z" },
|
| 270 |
+
]
|
| 271 |
+
|
| 272 |
+
[[package]]
|
| 273 |
+
name = "mpmath"
|
| 274 |
+
version = "1.3.0"
|
| 275 |
+
source = { registry = "https://pypi.org/simple" }
|
| 276 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" }
|
| 277 |
+
wheels = [
|
| 278 |
+
{ url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" },
|
| 279 |
+
]
|
| 280 |
+
|
| 281 |
+
[[package]]
|
| 282 |
+
name = "networkx"
|
| 283 |
+
version = "3.6.1"
|
| 284 |
+
source = { registry = "https://pypi.org/simple" }
|
| 285 |
+
sdist = { url = "https://files.pythonhosted.org/packages/6a/51/63fe664f3908c97be9d2e4f1158eb633317598cfa6e1fc14af5383f17512/networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509", size = 2517025, upload-time = "2025-12-08T17:02:39.908Z" }
|
| 286 |
+
wheels = [
|
| 287 |
+
{ url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
|
| 288 |
+
]
|
| 289 |
+
|
| 290 |
+
[[package]]
|
| 291 |
+
name = "numpy"
|
| 292 |
+
version = "2.4.1"
|
| 293 |
+
source = { registry = "https://pypi.org/simple" }
|
| 294 |
+
sdist = { url = "https://files.pythonhosted.org/packages/24/62/ae72ff66c0f1fd959925b4c11f8c2dea61f47f6acaea75a08512cdfe3fed/numpy-2.4.1.tar.gz", hash = "sha256:a1ceafc5042451a858231588a104093474c6a5c57dcc724841f5c888d237d690", size = 20721320, upload-time = "2026-01-10T06:44:59.619Z" }
|
| 295 |
+
wheels = [
|
| 296 |
+
{ url = "https://files.pythonhosted.org/packages/78/7f/ec53e32bf10c813604edf07a3682616bd931d026fcde7b6d13195dfb684a/numpy-2.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d3703409aac693fa82c0aee023a1ae06a6e9d065dba10f5e8e80f642f1e9d0a2", size = 16656888, upload-time = "2026-01-10T06:42:40.913Z" },
|
| 297 |
+
{ url = "https://files.pythonhosted.org/packages/b8/e0/1f9585d7dae8f14864e948fd7fa86c6cb72dee2676ca2748e63b1c5acfe0/numpy-2.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7211b95ca365519d3596a1d8688a95874cc94219d417504d9ecb2df99fa7bfa8", size = 12373956, upload-time = "2026-01-10T06:42:43.091Z" },
|
| 298 |
+
{ url = "https://files.pythonhosted.org/packages/8e/43/9762e88909ff2326f5e7536fa8cb3c49fb03a7d92705f23e6e7f553d9cb3/numpy-2.4.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:5adf01965456a664fc727ed69cc71848f28d063217c63e1a0e200a118d5eec9a", size = 5202567, upload-time = "2026-01-10T06:42:45.107Z" },
|
| 299 |
+
{ url = "https://files.pythonhosted.org/packages/4b/ee/34b7930eb61e79feb4478800a4b95b46566969d837546aa7c034c742ef98/numpy-2.4.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26f0bcd9c79a00e339565b303badc74d3ea2bd6d52191eeca5f95936cad107d0", size = 6549459, upload-time = "2026-01-10T06:42:48.152Z" },
|
| 300 |
+
{ url = "https://files.pythonhosted.org/packages/79/e3/5f115fae982565771be994867c89bcd8d7208dbfe9469185497d70de5ddf/numpy-2.4.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0093e85df2960d7e4049664b26afc58b03236e967fb942354deef3208857a04c", size = 14404859, upload-time = "2026-01-10T06:42:49.947Z" },
|
| 301 |
+
{ url = "https://files.pythonhosted.org/packages/d9/7d/9c8a781c88933725445a859cac5d01b5871588a15969ee6aeb618ba99eee/numpy-2.4.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7ad270f438cbdd402c364980317fb6b117d9ec5e226fff5b4148dd9aa9fc6e02", size = 16371419, upload-time = "2026-01-10T06:42:52.409Z" },
|
| 302 |
+
{ url = "https://files.pythonhosted.org/packages/a6/d2/8aa084818554543f17cf4162c42f162acbd3bb42688aefdba6628a859f77/numpy-2.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:297c72b1b98100c2e8f873d5d35fb551fce7040ade83d67dd51d38c8d42a2162", size = 16182131, upload-time = "2026-01-10T06:42:54.694Z" },
|
| 303 |
+
{ url = "https://files.pythonhosted.org/packages/60/db/0425216684297c58a8df35f3284ef56ec4a043e6d283f8a59c53562caf1b/numpy-2.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf6470d91d34bf669f61d515499859fa7a4c2f7c36434afb70e82df7217933f9", size = 18295342, upload-time = "2026-01-10T06:42:56.991Z" },
|
| 304 |
+
{ url = "https://files.pythonhosted.org/packages/31/4c/14cb9d86240bd8c386c881bafbe43f001284b7cce3bc01623ac9475da163/numpy-2.4.1-cp312-cp312-win32.whl", hash = "sha256:b6bcf39112e956594b3331316d90c90c90fb961e39696bda97b89462f5f3943f", size = 5959015, upload-time = "2026-01-10T06:42:59.631Z" },
|
| 305 |
+
{ url = "https://files.pythonhosted.org/packages/51/cf/52a703dbeb0c65807540d29699fef5fda073434ff61846a564d5c296420f/numpy-2.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:e1a27bb1b2dee45a2a53f5ca6ff2d1a7f135287883a1689e930d44d1ff296c87", size = 12310730, upload-time = "2026-01-10T06:43:01.627Z" },
|
| 306 |
+
{ url = "https://files.pythonhosted.org/packages/69/80/a828b2d0ade5e74a9fe0f4e0a17c30fdc26232ad2bc8c9f8b3197cf7cf18/numpy-2.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:0e6e8f9d9ecf95399982019c01223dc130542960a12edfa8edd1122dfa66a8a8", size = 10312166, upload-time = "2026-01-10T06:43:03.673Z" },
|
| 307 |
+
]
|
| 308 |
+
|
| 309 |
+
[[package]]
|
| 310 |
+
name = "nvidia-cublas-cu12"
|
| 311 |
+
version = "12.1.3.1"
|
| 312 |
+
source = { registry = "https://pypi.org/simple" }
|
| 313 |
+
wheels = [
|
| 314 |
+
{ url = "https://files.pythonhosted.org/packages/37/6d/121efd7382d5b0284239f4ab1fc1590d86d34ed4a4a2fdb13b30ca8e5740/nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728", size = 410594774, upload-time = "2023-04-19T15:50:03.519Z" },
|
| 315 |
+
]
|
| 316 |
+
|
| 317 |
+
[[package]]
|
| 318 |
+
name = "nvidia-cuda-cupti-cu12"
|
| 319 |
+
version = "12.1.105"
|
| 320 |
+
source = { registry = "https://pypi.org/simple" }
|
| 321 |
+
wheels = [
|
| 322 |
+
{ url = "https://files.pythonhosted.org/packages/7e/00/6b218edd739ecfc60524e585ba8e6b00554dd908de2c9c66c1af3e44e18d/nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e", size = 14109015, upload-time = "2023-04-19T15:47:32.502Z" },
|
| 323 |
+
]
|
| 324 |
+
|
| 325 |
+
[[package]]
|
| 326 |
+
name = "nvidia-cuda-nvrtc-cu12"
|
| 327 |
+
version = "12.1.105"
|
| 328 |
+
source = { registry = "https://pypi.org/simple" }
|
| 329 |
+
wheels = [
|
| 330 |
+
{ url = "https://files.pythonhosted.org/packages/b6/9f/c64c03f49d6fbc56196664d05dba14e3a561038a81a638eeb47f4d4cfd48/nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2", size = 23671734, upload-time = "2023-04-19T15:48:32.42Z" },
|
| 331 |
+
]
|
| 332 |
+
|
| 333 |
+
[[package]]
|
| 334 |
+
name = "nvidia-cuda-runtime-cu12"
|
| 335 |
+
version = "12.1.105"
|
| 336 |
+
source = { registry = "https://pypi.org/simple" }
|
| 337 |
+
wheels = [
|
| 338 |
+
{ url = "https://files.pythonhosted.org/packages/eb/d5/c68b1d2cdfcc59e72e8a5949a37ddb22ae6cade80cd4a57a84d4c8b55472/nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40", size = 823596, upload-time = "2023-04-19T15:47:22.471Z" },
|
| 339 |
+
]
|
| 340 |
+
|
| 341 |
+
[[package]]
|
| 342 |
+
name = "nvidia-cudnn-cu12"
|
| 343 |
+
version = "8.9.2.26"
|
| 344 |
+
source = { registry = "https://pypi.org/simple" }
|
| 345 |
+
dependencies = [
|
| 346 |
+
{ name = "nvidia-cublas-cu12" },
|
| 347 |
+
]
|
| 348 |
+
wheels = [
|
| 349 |
+
{ url = "https://files.pythonhosted.org/packages/ff/74/a2e2be7fb83aaedec84f391f082cf765dfb635e7caa9b49065f73e4835d8/nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9", size = 731725872, upload-time = "2023-06-01T19:24:57.328Z" },
|
| 350 |
+
]
|
| 351 |
+
|
| 352 |
+
[[package]]
|
| 353 |
+
name = "nvidia-cufft-cu12"
|
| 354 |
+
version = "11.0.2.54"
|
| 355 |
+
source = { registry = "https://pypi.org/simple" }
|
| 356 |
+
wheels = [
|
| 357 |
+
{ url = "https://files.pythonhosted.org/packages/86/94/eb540db023ce1d162e7bea9f8f5aa781d57c65aed513c33ee9a5123ead4d/nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56", size = 121635161, upload-time = "2023-04-19T15:50:46Z" },
|
| 358 |
+
]
|
| 359 |
+
|
| 360 |
+
[[package]]
|
| 361 |
+
name = "nvidia-curand-cu12"
|
| 362 |
+
version = "10.3.2.106"
|
| 363 |
+
source = { registry = "https://pypi.org/simple" }
|
| 364 |
+
wheels = [
|
| 365 |
+
{ url = "https://files.pythonhosted.org/packages/44/31/4890b1c9abc496303412947fc7dcea3d14861720642b49e8ceed89636705/nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0", size = 56467784, upload-time = "2023-04-19T15:51:04.804Z" },
|
| 366 |
+
]
|
| 367 |
+
|
| 368 |
+
[[package]]
|
| 369 |
+
name = "nvidia-cusolver-cu12"
|
| 370 |
+
version = "11.4.5.107"
|
| 371 |
+
source = { registry = "https://pypi.org/simple" }
|
| 372 |
+
dependencies = [
|
| 373 |
+
{ name = "nvidia-cublas-cu12" },
|
| 374 |
+
{ name = "nvidia-cusparse-cu12" },
|
| 375 |
+
{ name = "nvidia-nvjitlink-cu12" },
|
| 376 |
+
]
|
| 377 |
+
wheels = [
|
| 378 |
+
{ url = "https://files.pythonhosted.org/packages/bc/1d/8de1e5c67099015c834315e333911273a8c6aaba78923dd1d1e25fc5f217/nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd", size = 124161928, upload-time = "2023-04-19T15:51:25.781Z" },
|
| 379 |
+
]
|
| 380 |
+
|
| 381 |
+
[[package]]
|
| 382 |
+
name = "nvidia-cusparse-cu12"
|
| 383 |
+
version = "12.1.0.106"
|
| 384 |
+
source = { registry = "https://pypi.org/simple" }
|
| 385 |
+
dependencies = [
|
| 386 |
+
{ name = "nvidia-nvjitlink-cu12" },
|
| 387 |
+
]
|
| 388 |
+
wheels = [
|
| 389 |
+
{ url = "https://files.pythonhosted.org/packages/65/5b/cfaeebf25cd9fdec14338ccb16f6b2c4c7fa9163aefcf057d86b9cc248bb/nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c", size = 195958278, upload-time = "2023-04-19T15:51:49.939Z" },
|
| 390 |
+
]
|
| 391 |
+
|
| 392 |
+
[[package]]
|
| 393 |
+
name = "nvidia-nccl-cu12"
|
| 394 |
+
version = "2.20.5"
|
| 395 |
+
source = { registry = "https://pypi.org/simple" }
|
| 396 |
+
wheels = [
|
| 397 |
+
{ url = "https://files.pythonhosted.org/packages/4b/2a/0a131f572aa09f741c30ccd45a8e56316e8be8dfc7bc19bf0ab7cfef7b19/nvidia_nccl_cu12-2.20.5-py3-none-manylinux2014_x86_64.whl", hash = "sha256:057f6bf9685f75215d0c53bf3ac4a10b3e6578351de307abad9e18a99182af56", size = 176249402, upload-time = "2024-03-06T04:30:20.663Z" },
|
| 398 |
+
]
|
| 399 |
+
|
| 400 |
+
[[package]]
|
| 401 |
+
name = "nvidia-nvjitlink-cu12"
|
| 402 |
+
version = "12.9.86"
|
| 403 |
+
source = { registry = "https://pypi.org/simple" }
|
| 404 |
+
wheels = [
|
| 405 |
+
{ url = "https://files.pythonhosted.org/packages/46/0c/c75bbfb967457a0b7670b8ad267bfc4fffdf341c074e0a80db06c24ccfd4/nvidia_nvjitlink_cu12-12.9.86-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:e3f1171dbdc83c5932a45f0f4c99180a70de9bd2718c1ab77d14104f6d7147f9", size = 39748338, upload-time = "2025-06-05T20:10:25.613Z" },
|
| 406 |
+
]
|
| 407 |
+
|
| 408 |
+
[[package]]
|
| 409 |
+
name = "nvidia-nvtx-cu12"
|
| 410 |
+
version = "12.1.105"
|
| 411 |
+
source = { registry = "https://pypi.org/simple" }
|
| 412 |
+
wheels = [
|
| 413 |
+
{ url = "https://files.pythonhosted.org/packages/da/d3/8057f0587683ed2fcd4dbfbdfdfa807b9160b809976099d36b8f60d08f03/nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5", size = 99138, upload-time = "2023-04-19T15:48:43.556Z" },
|
| 414 |
+
]
|
| 415 |
+
|
| 416 |
+
[[package]]
|
| 417 |
+
name = "packaging"
|
| 418 |
+
version = "25.0"
|
| 419 |
+
source = { registry = "https://pypi.org/simple" }
|
| 420 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" }
|
| 421 |
+
wheels = [
|
| 422 |
+
{ url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" },
|
| 423 |
+
]
|
| 424 |
+
|
| 425 |
+
[[package]]
|
| 426 |
+
name = "photo-classification"
|
| 427 |
+
version = "0.1.0"
|
| 428 |
+
source = { editable = "." }
|
| 429 |
+
dependencies = [
|
| 430 |
+
{ name = "fastapi" },
|
| 431 |
+
{ name = "pillow" },
|
| 432 |
+
{ name = "pydantic" },
|
| 433 |
+
{ name = "torch" },
|
| 434 |
+
{ name = "transformers" },
|
| 435 |
+
{ name = "uvicorn", extra = ["standard"] },
|
| 436 |
+
]
|
| 437 |
+
|
| 438 |
+
[package.optional-dependencies]
|
| 439 |
+
dev = [
|
| 440 |
+
{ name = "httpx" },
|
| 441 |
+
{ name = "pytest" },
|
| 442 |
+
]
|
| 443 |
+
|
| 444 |
+
[package.metadata]
|
| 445 |
+
requires-dist = [
|
| 446 |
+
{ name = "fastapi", specifier = "==0.115.6" },
|
| 447 |
+
{ name = "httpx", marker = "extra == 'dev'", specifier = "==0.27.2" },
|
| 448 |
+
{ name = "pillow", specifier = "==10.4.0" },
|
| 449 |
+
{ name = "pydantic", specifier = "==2.8.2" },
|
| 450 |
+
{ name = "pytest", marker = "extra == 'dev'", specifier = "==8.3.2" },
|
| 451 |
+
{ name = "torch", specifier = "==2.3.1" },
|
| 452 |
+
{ name = "transformers", specifier = "==4.44.2" },
|
| 453 |
+
{ name = "uvicorn", extras = ["standard"], specifier = "==0.30.6" },
|
| 454 |
+
]
|
| 455 |
+
provides-extras = ["dev"]
|
| 456 |
+
|
| 457 |
+
[[package]]
|
| 458 |
+
name = "pillow"
|
| 459 |
+
version = "10.4.0"
|
| 460 |
+
source = { registry = "https://pypi.org/simple" }
|
| 461 |
+
sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059, upload-time = "2024-07-01T09:48:43.583Z" }
|
| 462 |
+
wheels = [
|
| 463 |
+
{ url = "https://files.pythonhosted.org/packages/05/cb/0353013dc30c02a8be34eb91d25e4e4cf594b59e5a55ea1128fde1e5f8ea/pillow-10.4.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:673655af3eadf4df6b5457033f086e90299fdd7a47983a13827acf7459c15d94", size = 3509350, upload-time = "2024-07-01T09:46:17.177Z" },
|
| 464 |
+
{ url = "https://files.pythonhosted.org/packages/e7/cf/5c558a0f247e0bf9cec92bff9b46ae6474dd736f6d906315e60e4075f737/pillow-10.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:866b6942a92f56300012f5fbac71f2d610312ee65e22f1aa2609e491284e5597", size = 3374980, upload-time = "2024-07-01T09:46:19.169Z" },
|
| 465 |
+
{ url = "https://files.pythonhosted.org/packages/84/48/6e394b86369a4eb68b8a1382c78dc092245af517385c086c5094e3b34428/pillow-10.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29dbdc4207642ea6aad70fbde1a9338753d33fb23ed6956e706936706f52dd80", size = 4343799, upload-time = "2024-07-01T09:46:21.883Z" },
|
| 466 |
+
{ url = "https://files.pythonhosted.org/packages/3b/f3/a8c6c11fa84b59b9df0cd5694492da8c039a24cd159f0f6918690105c3be/pillow-10.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf2342ac639c4cf38799a44950bbc2dfcb685f052b9e262f446482afaf4bffca", size = 4459973, upload-time = "2024-07-01T09:46:24.321Z" },
|
| 467 |
+
{ url = "https://files.pythonhosted.org/packages/7d/1b/c14b4197b80150fb64453585247e6fb2e1d93761fa0fa9cf63b102fde822/pillow-10.4.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:f5b92f4d70791b4a67157321c4e8225d60b119c5cc9aee8ecf153aace4aad4ef", size = 4370054, upload-time = "2024-07-01T09:46:26.825Z" },
|
| 468 |
+
{ url = "https://files.pythonhosted.org/packages/55/77/40daddf677897a923d5d33329acd52a2144d54a9644f2a5422c028c6bf2d/pillow-10.4.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:86dcb5a1eb778d8b25659d5e4341269e8590ad6b4e8b44d9f4b07f8d136c414a", size = 4539484, upload-time = "2024-07-01T09:46:29.355Z" },
|
| 469 |
+
{ url = "https://files.pythonhosted.org/packages/40/54/90de3e4256b1207300fb2b1d7168dd912a2fb4b2401e439ba23c2b2cabde/pillow-10.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:780c072c2e11c9b2c7ca37f9a2ee8ba66f44367ac3e5c7832afcfe5104fd6d1b", size = 4477375, upload-time = "2024-07-01T09:46:31.756Z" },
|
| 470 |
+
{ url = "https://files.pythonhosted.org/packages/13/24/1bfba52f44193860918ff7c93d03d95e3f8748ca1de3ceaf11157a14cf16/pillow-10.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37fb69d905be665f68f28a8bba3c6d3223c8efe1edf14cc4cfa06c241f8c81d9", size = 4608773, upload-time = "2024-07-01T09:46:33.73Z" },
|
| 471 |
+
{ url = "https://files.pythonhosted.org/packages/55/04/5e6de6e6120451ec0c24516c41dbaf80cce1b6451f96561235ef2429da2e/pillow-10.4.0-cp312-cp312-win32.whl", hash = "sha256:7dfecdbad5c301d7b5bde160150b4db4c659cee2b69589705b6f8a0c509d9f42", size = 2235690, upload-time = "2024-07-01T09:46:36.587Z" },
|
| 472 |
+
{ url = "https://files.pythonhosted.org/packages/74/0a/d4ce3c44bca8635bd29a2eab5aa181b654a734a29b263ca8efe013beea98/pillow-10.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:1d846aea995ad352d4bdcc847535bd56e0fd88d36829d2c90be880ef1ee4668a", size = 2554951, upload-time = "2024-07-01T09:46:38.777Z" },
|
| 473 |
+
{ url = "https://files.pythonhosted.org/packages/b5/ca/184349ee40f2e92439be9b3502ae6cfc43ac4b50bc4fc6b3de7957563894/pillow-10.4.0-cp312-cp312-win_arm64.whl", hash = "sha256:e553cad5179a66ba15bb18b353a19020e73a7921296a7979c4a2b7f6a5cd57f9", size = 2243427, upload-time = "2024-07-01T09:46:43.15Z" },
|
| 474 |
+
]
|
| 475 |
+
|
| 476 |
+
[[package]]
|
| 477 |
+
name = "pluggy"
|
| 478 |
+
version = "1.6.0"
|
| 479 |
+
source = { registry = "https://pypi.org/simple" }
|
| 480 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
| 481 |
+
wheels = [
|
| 482 |
+
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
| 483 |
+
]
|
| 484 |
+
|
| 485 |
+
[[package]]
|
| 486 |
+
name = "pydantic"
|
| 487 |
+
version = "2.8.2"
|
| 488 |
+
source = { registry = "https://pypi.org/simple" }
|
| 489 |
+
dependencies = [
|
| 490 |
+
{ name = "annotated-types" },
|
| 491 |
+
{ name = "pydantic-core" },
|
| 492 |
+
{ name = "typing-extensions" },
|
| 493 |
+
]
|
| 494 |
+
sdist = { url = "https://files.pythonhosted.org/packages/8c/99/d0a5dca411e0a017762258013ba9905cd6e7baa9a3fd1fe8b6529472902e/pydantic-2.8.2.tar.gz", hash = "sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a", size = 739834, upload-time = "2024-07-04T02:59:49.416Z" }
|
| 495 |
+
wheels = [
|
| 496 |
+
{ url = "https://files.pythonhosted.org/packages/1f/fa/b7f815b8c9ad021c07f88875b601222ef5e70619391ade4a49234d12d278/pydantic-2.8.2-py3-none-any.whl", hash = "sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8", size = 423875, upload-time = "2024-07-04T02:59:45.33Z" },
|
| 497 |
+
]
|
| 498 |
+
|
| 499 |
+
[[package]]
|
| 500 |
+
name = "pydantic-core"
|
| 501 |
+
version = "2.20.1"
|
| 502 |
+
source = { registry = "https://pypi.org/simple" }
|
| 503 |
+
dependencies = [
|
| 504 |
+
{ name = "typing-extensions" },
|
| 505 |
+
]
|
| 506 |
+
sdist = { url = "https://files.pythonhosted.org/packages/12/e3/0d5ad91211dba310f7ded335f4dad871172b9cc9ce204f5a56d76ccd6247/pydantic_core-2.20.1.tar.gz", hash = "sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4", size = 388371, upload-time = "2024-07-03T17:04:13.963Z" }
|
| 507 |
+
wheels = [
|
| 508 |
+
{ url = "https://files.pythonhosted.org/packages/6f/47/ef0d60ae23c41aced42921728650460dc831a0adf604bfa66b76028cb4d0/pydantic_core-2.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231", size = 1839225, upload-time = "2024-07-03T17:01:15.981Z" },
|
| 509 |
+
{ url = "https://files.pythonhosted.org/packages/6a/23/430f2878c9cd977a61bb39f71751d9310ec55cee36b3d5bf1752c6341fd0/pydantic_core-2.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9", size = 1768604, upload-time = "2024-07-03T17:01:18.188Z" },
|
| 510 |
+
{ url = "https://files.pythonhosted.org/packages/9e/2b/ec4e7225dee79e0dc80ccc3c35ab33cc2c4bbb8a1a7ecf060e5e453651ec/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f", size = 1789767, upload-time = "2024-07-03T17:01:20.86Z" },
|
| 511 |
+
{ url = "https://files.pythonhosted.org/packages/64/b0/38b24a1fa6d2f96af3148362e10737ec073768cd44d3ec21dca3be40a519/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52", size = 1772061, upload-time = "2024-07-03T17:01:23.9Z" },
|
| 512 |
+
{ url = "https://files.pythonhosted.org/packages/5e/da/bb73274c42cb60decfa61e9eb0c9029da78b3b9af0a9de0309dbc8ff87b6/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237", size = 1974573, upload-time = "2024-07-03T17:01:26.318Z" },
|
| 513 |
+
{ url = "https://files.pythonhosted.org/packages/c8/65/41693110fb3552556180460daffdb8bbeefb87fc026fd9aa4b849374015c/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe", size = 2625596, upload-time = "2024-07-03T17:01:28.775Z" },
|
| 514 |
+
{ url = "https://files.pythonhosted.org/packages/09/b3/a5a54b47cccd1ab661ed5775235c5e06924753c2d4817737c5667bfa19a8/pydantic_core-2.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e", size = 2099064, upload-time = "2024-07-03T17:01:30.962Z" },
|
| 515 |
+
{ url = "https://files.pythonhosted.org/packages/52/fa/443a7a6ea54beaba45ff3a59f3d3e6e3004b7460bcfb0be77bcf98719d3b/pydantic_core-2.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24", size = 1900345, upload-time = "2024-07-03T17:01:33.634Z" },
|
| 516 |
+
{ url = "https://files.pythonhosted.org/packages/8e/e6/9aca9ffae60f9cdf0183069de3e271889b628d0fb175913fcb3db5618fb1/pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1", size = 1968252, upload-time = "2024-07-03T17:01:36.291Z" },
|
| 517 |
+
{ url = "https://files.pythonhosted.org/packages/46/5e/6c716810ea20a6419188992973a73c2fb4eb99cd382368d0637ddb6d3c99/pydantic_core-2.20.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd", size = 2119191, upload-time = "2024-07-03T17:01:38.905Z" },
|
| 518 |
+
{ url = "https://files.pythonhosted.org/packages/06/fc/6123b00a9240fbb9ae0babad7a005d51103d9a5d39c957a986f5cdd0c271/pydantic_core-2.20.1-cp312-none-win32.whl", hash = "sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688", size = 1717788, upload-time = "2024-07-03T17:01:41.329Z" },
|
| 519 |
+
{ url = "https://files.pythonhosted.org/packages/d5/36/e61ad5a46607a469e2786f398cd671ebafcd9fb17f09a2359985c7228df5/pydantic_core-2.20.1-cp312-none-win_amd64.whl", hash = "sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d", size = 1898188, upload-time = "2024-07-03T17:01:44.155Z" },
|
| 520 |
+
]
|
| 521 |
+
|
| 522 |
+
[[package]]
|
| 523 |
+
name = "pytest"
|
| 524 |
+
version = "8.3.2"
|
| 525 |
+
source = { registry = "https://pypi.org/simple" }
|
| 526 |
+
dependencies = [
|
| 527 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 528 |
+
{ name = "iniconfig" },
|
| 529 |
+
{ name = "packaging" },
|
| 530 |
+
{ name = "pluggy" },
|
| 531 |
+
]
|
| 532 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b4/8c/9862305bdcd6020bc7b45b1b5e7397a6caf1a33d3025b9a003b39075ffb2/pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce", size = 1439314, upload-time = "2024-07-25T10:40:00.159Z" }
|
| 533 |
+
wheels = [
|
| 534 |
+
{ url = "https://files.pythonhosted.org/packages/0f/f9/cf155cf32ca7d6fa3601bc4c5dd19086af4b320b706919d48a4c79081cf9/pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5", size = 341802, upload-time = "2024-07-25T10:39:57.834Z" },
|
| 535 |
+
]
|
| 536 |
+
|
| 537 |
+
[[package]]
|
| 538 |
+
name = "python-dotenv"
|
| 539 |
+
version = "1.2.1"
|
| 540 |
+
source = { registry = "https://pypi.org/simple" }
|
| 541 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" }
|
| 542 |
+
wheels = [
|
| 543 |
+
{ url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" },
|
| 544 |
+
]
|
| 545 |
+
|
| 546 |
+
[[package]]
|
| 547 |
+
name = "pyyaml"
|
| 548 |
+
version = "6.0.3"
|
| 549 |
+
source = { registry = "https://pypi.org/simple" }
|
| 550 |
+
sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" }
|
| 551 |
+
wheels = [
|
| 552 |
+
{ url = "https://files.pythonhosted.org/packages/d1/33/422b98d2195232ca1826284a76852ad5a86fe23e31b009c9886b2d0fb8b2/pyyaml-6.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7f047e29dcae44602496db43be01ad42fc6f1cc0d8cd6c83d342306c32270196", size = 182063, upload-time = "2025-09-25T21:32:11.445Z" },
|
| 553 |
+
{ url = "https://files.pythonhosted.org/packages/89/a0/6cf41a19a1f2f3feab0e9c0b74134aa2ce6849093d5517a0c550fe37a648/pyyaml-6.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc09d0aa354569bc501d4e787133afc08552722d3ab34836a80547331bb5d4a0", size = 173973, upload-time = "2025-09-25T21:32:12.492Z" },
|
| 554 |
+
{ url = "https://files.pythonhosted.org/packages/ed/23/7a778b6bd0b9a8039df8b1b1d80e2e2ad78aa04171592c8a5c43a56a6af4/pyyaml-6.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9149cad251584d5fb4981be1ecde53a1ca46c891a79788c0df828d2f166bda28", size = 775116, upload-time = "2025-09-25T21:32:13.652Z" },
|
| 555 |
+
{ url = "https://files.pythonhosted.org/packages/65/30/d7353c338e12baef4ecc1b09e877c1970bd3382789c159b4f89d6a70dc09/pyyaml-6.0.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5fdec68f91a0c6739b380c83b951e2c72ac0197ace422360e6d5a959d8d97b2c", size = 844011, upload-time = "2025-09-25T21:32:15.21Z" },
|
| 556 |
+
{ url = "https://files.pythonhosted.org/packages/8b/9d/b3589d3877982d4f2329302ef98a8026e7f4443c765c46cfecc8858c6b4b/pyyaml-6.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ba1cc08a7ccde2d2ec775841541641e4548226580ab850948cbfda66a1befcdc", size = 807870, upload-time = "2025-09-25T21:32:16.431Z" },
|
| 557 |
+
{ url = "https://files.pythonhosted.org/packages/05/c0/b3be26a015601b822b97d9149ff8cb5ead58c66f981e04fedf4e762f4bd4/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8dc52c23056b9ddd46818a57b78404882310fb473d63f17b07d5c40421e47f8e", size = 761089, upload-time = "2025-09-25T21:32:17.56Z" },
|
| 558 |
+
{ url = "https://files.pythonhosted.org/packages/be/8e/98435a21d1d4b46590d5459a22d88128103f8da4c2d4cb8f14f2a96504e1/pyyaml-6.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41715c910c881bc081f1e8872880d3c650acf13dfa8214bad49ed4cede7c34ea", size = 790181, upload-time = "2025-09-25T21:32:18.834Z" },
|
| 559 |
+
{ url = "https://files.pythonhosted.org/packages/74/93/7baea19427dcfbe1e5a372d81473250b379f04b1bd3c4c5ff825e2327202/pyyaml-6.0.3-cp312-cp312-win32.whl", hash = "sha256:96b533f0e99f6579b3d4d4995707cf36df9100d67e0c8303a0c55b27b5f99bc5", size = 137658, upload-time = "2025-09-25T21:32:20.209Z" },
|
| 560 |
+
{ url = "https://files.pythonhosted.org/packages/86/bf/899e81e4cce32febab4fb42bb97dcdf66bc135272882d1987881a4b519e9/pyyaml-6.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:5fcd34e47f6e0b794d17de1b4ff496c00986e1c83f7ab2fb8fcfe9616ff7477b", size = 154003, upload-time = "2025-09-25T21:32:21.167Z" },
|
| 561 |
+
{ url = "https://files.pythonhosted.org/packages/1a/08/67bd04656199bbb51dbed1439b7f27601dfb576fb864099c7ef0c3e55531/pyyaml-6.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:64386e5e707d03a7e172c0701abfb7e10f0fb753ee1d773128192742712a98fd", size = 140344, upload-time = "2025-09-25T21:32:22.617Z" },
|
| 562 |
+
]
|
| 563 |
+
|
| 564 |
+
[[package]]
|
| 565 |
+
name = "regex"
|
| 566 |
+
version = "2026.1.15"
|
| 567 |
+
source = { registry = "https://pypi.org/simple" }
|
| 568 |
+
sdist = { url = "https://files.pythonhosted.org/packages/0b/86/07d5056945f9ec4590b518171c4254a5925832eb727b56d3c38a7476f316/regex-2026.1.15.tar.gz", hash = "sha256:164759aa25575cbc0651bef59a0b18353e54300d79ace8084c818ad8ac72b7d5", size = 414811, upload-time = "2026-01-14T23:18:02.775Z" }
|
| 569 |
+
wheels = [
|
| 570 |
+
{ url = "https://files.pythonhosted.org/packages/92/81/10d8cf43c807d0326efe874c1b79f22bfb0fb226027b0b19ebc26d301408/regex-2026.1.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4c8fcc5793dde01641a35905d6731ee1548f02b956815f8f1cab89e515a5bdf1", size = 489398, upload-time = "2026-01-14T23:14:43.741Z" },
|
| 571 |
+
{ url = "https://files.pythonhosted.org/packages/90/b0/7c2a74e74ef2a7c32de724658a69a862880e3e4155cba992ba04d1c70400/regex-2026.1.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bfd876041a956e6a90ad7cdb3f6a630c07d491280bfeed4544053cd434901681", size = 291339, upload-time = "2026-01-14T23:14:45.183Z" },
|
| 572 |
+
{ url = "https://files.pythonhosted.org/packages/19/4d/16d0773d0c818417f4cc20aa0da90064b966d22cd62a8c46765b5bd2d643/regex-2026.1.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9250d087bc92b7d4899ccd5539a1b2334e44eee85d848c4c1aef8e221d3f8c8f", size = 289003, upload-time = "2026-01-14T23:14:47.25Z" },
|
| 573 |
+
{ url = "https://files.pythonhosted.org/packages/c6/e4/1fc4599450c9f0863d9406e944592d968b8d6dfd0d552a7d569e43bceada/regex-2026.1.15-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8a154cf6537ebbc110e24dabe53095e714245c272da9c1be05734bdad4a61aa", size = 798656, upload-time = "2026-01-14T23:14:48.77Z" },
|
| 574 |
+
{ url = "https://files.pythonhosted.org/packages/b2/e6/59650d73a73fa8a60b3a590545bfcf1172b4384a7df2e7fe7b9aab4e2da9/regex-2026.1.15-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8050ba2e3ea1d8731a549e83c18d2f0999fbc99a5f6bd06b4c91449f55291804", size = 864252, upload-time = "2026-01-14T23:14:50.528Z" },
|
| 575 |
+
{ url = "https://files.pythonhosted.org/packages/6e/ab/1d0f4d50a1638849a97d731364c9a80fa304fec46325e48330c170ee8e80/regex-2026.1.15-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf065240704cb8951cc04972cf107063917022511273e0969bdb34fc173456c", size = 912268, upload-time = "2026-01-14T23:14:52.952Z" },
|
| 576 |
+
{ url = "https://files.pythonhosted.org/packages/dd/df/0d722c030c82faa1d331d1921ee268a4e8fb55ca8b9042c9341c352f17fa/regex-2026.1.15-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c32bef3e7aeee75746748643667668ef941d28b003bfc89994ecf09a10f7a1b5", size = 803589, upload-time = "2026-01-14T23:14:55.182Z" },
|
| 577 |
+
{ url = "https://files.pythonhosted.org/packages/66/23/33289beba7ccb8b805c6610a8913d0131f834928afc555b241caabd422a9/regex-2026.1.15-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d5eaa4a4c5b1906bd0d2508d68927f15b81821f85092e06f1a34a4254b0e1af3", size = 775700, upload-time = "2026-01-14T23:14:56.707Z" },
|
| 578 |
+
{ url = "https://files.pythonhosted.org/packages/e7/65/bf3a42fa6897a0d3afa81acb25c42f4b71c274f698ceabd75523259f6688/regex-2026.1.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:86c1077a3cc60d453d4084d5b9649065f3bf1184e22992bd322e1f081d3117fb", size = 787928, upload-time = "2026-01-14T23:14:58.312Z" },
|
| 579 |
+
{ url = "https://files.pythonhosted.org/packages/f4/f5/13bf65864fc314f68cdd6d8ca94adcab064d4d39dbd0b10fef29a9da48fc/regex-2026.1.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:2b091aefc05c78d286657cd4db95f2e6313375ff65dcf085e42e4c04d9c8d410", size = 858607, upload-time = "2026-01-14T23:15:00.657Z" },
|
| 580 |
+
{ url = "https://files.pythonhosted.org/packages/a3/31/040e589834d7a439ee43fb0e1e902bc81bd58a5ba81acffe586bb3321d35/regex-2026.1.15-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:57e7d17f59f9ebfa9667e6e5a1c0127b96b87cb9cede8335482451ed00788ba4", size = 763729, upload-time = "2026-01-14T23:15:02.248Z" },
|
| 581 |
+
{ url = "https://files.pythonhosted.org/packages/9b/84/6921e8129687a427edf25a34a5594b588b6d88f491320b9de5b6339a4fcb/regex-2026.1.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:c6c4dcdfff2c08509faa15d36ba7e5ef5fcfab25f1e8f85a0c8f45bc3a30725d", size = 850697, upload-time = "2026-01-14T23:15:03.878Z" },
|
| 582 |
+
{ url = "https://files.pythonhosted.org/packages/8a/87/3d06143d4b128f4229158f2de5de6c8f2485170c7221e61bf381313314b2/regex-2026.1.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cf8ff04c642716a7f2048713ddc6278c5fd41faa3b9cab12607c7abecd012c22", size = 789849, upload-time = "2026-01-14T23:15:06.102Z" },
|
| 583 |
+
{ url = "https://files.pythonhosted.org/packages/77/69/c50a63842b6bd48850ebc7ab22d46e7a2a32d824ad6c605b218441814639/regex-2026.1.15-cp312-cp312-win32.whl", hash = "sha256:82345326b1d8d56afbe41d881fdf62f1926d7264b2fc1537f99ae5da9aad7913", size = 266279, upload-time = "2026-01-14T23:15:07.678Z" },
|
| 584 |
+
{ url = "https://files.pythonhosted.org/packages/f2/36/39d0b29d087e2b11fd8191e15e81cce1b635fcc845297c67f11d0d19274d/regex-2026.1.15-cp312-cp312-win_amd64.whl", hash = "sha256:4def140aa6156bc64ee9912383d4038f3fdd18fee03a6f222abd4de6357ce42a", size = 277166, upload-time = "2026-01-14T23:15:09.257Z" },
|
| 585 |
+
{ url = "https://files.pythonhosted.org/packages/28/32/5b8e476a12262748851fa8ab1b0be540360692325975b094e594dfebbb52/regex-2026.1.15-cp312-cp312-win_arm64.whl", hash = "sha256:c6c565d9a6e1a8d783c1948937ffc377dd5771e83bd56de8317c450a954d2056", size = 270415, upload-time = "2026-01-14T23:15:10.743Z" },
|
| 586 |
+
]
|
| 587 |
+
|
| 588 |
+
[[package]]
|
| 589 |
+
name = "requests"
|
| 590 |
+
version = "2.32.5"
|
| 591 |
+
source = { registry = "https://pypi.org/simple" }
|
| 592 |
+
dependencies = [
|
| 593 |
+
{ name = "certifi" },
|
| 594 |
+
{ name = "charset-normalizer" },
|
| 595 |
+
{ name = "idna" },
|
| 596 |
+
{ name = "urllib3" },
|
| 597 |
+
]
|
| 598 |
+
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" }
|
| 599 |
+
wheels = [
|
| 600 |
+
{ 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" },
|
| 601 |
+
]
|
| 602 |
+
|
| 603 |
+
[[package]]
|
| 604 |
+
name = "safetensors"
|
| 605 |
+
version = "0.7.0"
|
| 606 |
+
source = { registry = "https://pypi.org/simple" }
|
| 607 |
+
sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" }
|
| 608 |
+
wheels = [
|
| 609 |
+
{ url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" },
|
| 610 |
+
{ url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" },
|
| 611 |
+
{ url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" },
|
| 612 |
+
{ url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" },
|
| 613 |
+
{ url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" },
|
| 614 |
+
{ url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" },
|
| 615 |
+
{ url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" },
|
| 616 |
+
{ url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" },
|
| 617 |
+
{ url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" },
|
| 618 |
+
{ url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" },
|
| 619 |
+
{ url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" },
|
| 620 |
+
{ url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" },
|
| 621 |
+
{ url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" },
|
| 622 |
+
{ url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" },
|
| 623 |
+
]
|
| 624 |
+
|
| 625 |
+
[[package]]
|
| 626 |
+
name = "sniffio"
|
| 627 |
+
version = "1.3.1"
|
| 628 |
+
source = { registry = "https://pypi.org/simple" }
|
| 629 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
|
| 630 |
+
wheels = [
|
| 631 |
+
{ url = "https://files.pythonhosted.org/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" },
|
| 632 |
+
]
|
| 633 |
+
|
| 634 |
+
[[package]]
|
| 635 |
+
name = "starlette"
|
| 636 |
+
version = "0.41.3"
|
| 637 |
+
source = { registry = "https://pypi.org/simple" }
|
| 638 |
+
dependencies = [
|
| 639 |
+
{ name = "anyio" },
|
| 640 |
+
]
|
| 641 |
+
sdist = { url = "https://files.pythonhosted.org/packages/1a/4c/9b5764bd22eec91c4039ef4c55334e9187085da2d8a2df7bd570869aae18/starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835", size = 2574159, upload-time = "2024-11-18T19:45:04.283Z" }
|
| 642 |
+
wheels = [
|
| 643 |
+
{ url = "https://files.pythonhosted.org/packages/96/00/2b325970b3060c7cecebab6d295afe763365822b1306a12eeab198f74323/starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7", size = 73225, upload-time = "2024-11-18T19:45:02.027Z" },
|
| 644 |
+
]
|
| 645 |
+
|
| 646 |
+
[[package]]
|
| 647 |
+
name = "sympy"
|
| 648 |
+
version = "1.14.0"
|
| 649 |
+
source = { registry = "https://pypi.org/simple" }
|
| 650 |
+
dependencies = [
|
| 651 |
+
{ name = "mpmath" },
|
| 652 |
+
]
|
| 653 |
+
sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" }
|
| 654 |
+
wheels = [
|
| 655 |
+
{ url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" },
|
| 656 |
+
]
|
| 657 |
+
|
| 658 |
+
[[package]]
|
| 659 |
+
name = "tbb"
|
| 660 |
+
version = "2021.13.1"
|
| 661 |
+
source = { registry = "https://pypi.org/simple" }
|
| 662 |
+
wheels = [
|
| 663 |
+
{ url = "https://files.pythonhosted.org/packages/fb/8a/5062b00c378c051e26507e5eca8d3b5c91ed63f8a2139f6f0f422be84b02/tbb-2021.13.1-py3-none-win32.whl", hash = "sha256:00f5e5a70051650ddd0ab6247c0549521968339ec21002e475cd23b1cbf46d66", size = 248994, upload-time = "2024-08-07T15:10:08.934Z" },
|
| 664 |
+
{ url = "https://files.pythonhosted.org/packages/9b/24/84ce997e8ae6296168a74d0d9c4dde572d90fb23fd7c0b219c30ff71e00e/tbb-2021.13.1-py3-none-win_amd64.whl", hash = "sha256:cbf024b2463fdab3ebe3fa6ff453026358e6b903839c80d647e08ad6d0796ee9", size = 286908, upload-time = "2024-08-07T15:09:05.677Z" },
|
| 665 |
+
]
|
| 666 |
+
|
| 667 |
+
[[package]]
|
| 668 |
+
name = "tokenizers"
|
| 669 |
+
version = "0.19.1"
|
| 670 |
+
source = { registry = "https://pypi.org/simple" }
|
| 671 |
+
dependencies = [
|
| 672 |
+
{ name = "huggingface-hub" },
|
| 673 |
+
]
|
| 674 |
+
sdist = { url = "https://files.pythonhosted.org/packages/48/04/2071c150f374aab6d5e92aaec38d0f3c368d227dd9e0469a1f0966ac68d1/tokenizers-0.19.1.tar.gz", hash = "sha256:ee59e6680ed0fdbe6b724cf38bd70400a0c1dd623b07ac729087270caeac88e3", size = 321039, upload-time = "2024-04-17T21:40:41.849Z" }
|
| 675 |
+
wheels = [
|
| 676 |
+
{ url = "https://files.pythonhosted.org/packages/63/90/2890cd096898dcdb596ee172cde40c0f54a9cf43b0736aa260a5501252af/tokenizers-0.19.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:621d670e1b1c281a1c9698ed89451395d318802ff88d1fc1accff0867a06f153", size = 2530580, upload-time = "2024-04-17T21:37:10.688Z" },
|
| 677 |
+
{ url = "https://files.pythonhosted.org/packages/74/d1/f4e1e950adb36675dfd8f9d0f4be644f3f3aaf22a5677a4f5c81282b662e/tokenizers-0.19.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d924204a3dbe50b75630bd16f821ebda6a5f729928df30f582fb5aade90c818a", size = 2436682, upload-time = "2024-04-17T21:37:12.966Z" },
|
| 678 |
+
{ url = "https://files.pythonhosted.org/packages/ed/30/89b321a16c58d233e301ec15072c0d3ed5014825e72da98604cd3ab2fba1/tokenizers-0.19.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4f3fefdc0446b1a1e6d81cd4c07088ac015665d2e812f6dbba4a06267d1a2c95", size = 3693494, upload-time = "2024-04-17T21:37:14.755Z" },
|
| 679 |
+
{ url = "https://files.pythonhosted.org/packages/05/40/fa899f32de483500fbc78befd378fd7afba4270f17db707d1a78c0a4ddc3/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9620b78e0b2d52ef07b0d428323fb34e8ea1219c5eac98c2596311f20f1f9266", size = 3566541, upload-time = "2024-04-17T21:37:17.067Z" },
|
| 680 |
+
{ url = "https://files.pythonhosted.org/packages/67/14/e7da32ae5fb4971830f1ef335932fae3fa57e76b537e852f146c850aefdf/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:04ce49e82d100594715ac1b2ce87d1a36e61891a91de774755f743babcd0dd52", size = 3430792, upload-time = "2024-04-17T21:37:19.055Z" },
|
| 681 |
+
{ url = "https://files.pythonhosted.org/packages/f2/4b/aae61bdb6ab584d2612170801703982ee0e35f8b6adacbeefe5a3b277621/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c5c2ff13d157afe413bf7e25789879dd463e5a4abfb529a2d8f8473d8042e28f", size = 3962812, upload-time = "2024-04-17T21:37:21.008Z" },
|
| 682 |
+
{ url = "https://files.pythonhosted.org/packages/0a/b6/f7b7ef89c4da7b20256e6eab23d3835f05d1ca8f451d31c16cbfe3cd9eb6/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3174c76efd9d08f836bfccaca7cfec3f4d1c0a4cf3acbc7236ad577cc423c840", size = 4024688, upload-time = "2024-04-17T21:37:23.659Z" },
|
| 683 |
+
{ url = "https://files.pythonhosted.org/packages/80/54/12047a69f5b382d7ee72044dc89151a2dd0d13b2c9bdcc22654883704d31/tokenizers-0.19.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c9d5b6c0e7a1e979bec10ff960fae925e947aab95619a6fdb4c1d8ff3708ce3", size = 3610961, upload-time = "2024-04-17T21:37:26.234Z" },
|
| 684 |
+
{ url = "https://files.pythonhosted.org/packages/52/b7/1e8a913d18ac28feeda42d4d2d51781874398fb59cd1c1e2653a4b5742ed/tokenizers-0.19.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a179856d1caee06577220ebcfa332af046d576fb73454b8f4d4b0ba8324423ea", size = 9631367, upload-time = "2024-04-17T21:37:28.752Z" },
|
| 685 |
+
{ url = "https://files.pythonhosted.org/packages/ac/3d/2284f6d99f8f21d09352b88b8cfefa24ab88468d962aeb0aa15c20d76b32/tokenizers-0.19.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:952b80dac1a6492170f8c2429bd11fcaa14377e097d12a1dbe0ef2fb2241e16c", size = 9950121, upload-time = "2024-04-17T21:37:31.741Z" },
|
| 686 |
+
{ url = "https://files.pythonhosted.org/packages/2a/94/ec3369dbc9b7200c14c8c7a1a04c78b7a7398d0c001e1b7d1ffe30eb93a0/tokenizers-0.19.1-cp312-none-win32.whl", hash = "sha256:01d62812454c188306755c94755465505836fd616f75067abcae529c35edeb57", size = 2044069, upload-time = "2024-04-17T21:37:35.672Z" },
|
| 687 |
+
{ url = "https://files.pythonhosted.org/packages/0c/97/80bff6937e0c67d30c0facacd4f0bcf4254e581aa4995c73cef8c8640e56/tokenizers-0.19.1-cp312-none-win_amd64.whl", hash = "sha256:b70bfbe3a82d3e3fb2a5e9b22a39f8d1740c96c68b6ace0086b39074f08ab89a", size = 2214527, upload-time = "2024-04-17T21:37:39.19Z" },
|
| 688 |
+
]
|
| 689 |
+
|
| 690 |
+
[[package]]
|
| 691 |
+
name = "torch"
|
| 692 |
+
version = "2.3.1"
|
| 693 |
+
source = { registry = "https://pypi.org/simple" }
|
| 694 |
+
dependencies = [
|
| 695 |
+
{ name = "filelock" },
|
| 696 |
+
{ name = "fsspec" },
|
| 697 |
+
{ name = "jinja2" },
|
| 698 |
+
{ name = "mkl", marker = "sys_platform == 'win32'" },
|
| 699 |
+
{ name = "networkx" },
|
| 700 |
+
{ name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 701 |
+
{ name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 702 |
+
{ name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 703 |
+
{ name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 704 |
+
{ name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 705 |
+
{ name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 706 |
+
{ name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 707 |
+
{ name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 708 |
+
{ name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 709 |
+
{ name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 710 |
+
{ name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
|
| 711 |
+
{ name = "sympy" },
|
| 712 |
+
{ name = "typing-extensions" },
|
| 713 |
+
]
|
| 714 |
+
wheels = [
|
| 715 |
+
{ url = "https://files.pythonhosted.org/packages/f3/82/68ccd49add4d21937f087871350905ffc709f32c92bf95334e7abf442147/torch-2.3.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:a486c0b1976a118805fc7c9641d02df7afbb0c21e6b555d3bb985c9f9601b61a", size = 779079866, upload-time = "2024-06-05T16:39:11.615Z" },
|
| 716 |
+
{ url = "https://files.pythonhosted.org/packages/1b/a1/e8b286b85f19dd701a4b853c0554898b1fa69cea552c7d1ec39bc86f59aa/torch-2.3.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:224259821fe3e4c6f7edf1528e4fe4ac779c77addaa74215eb0b63a5c474d66c", size = 86853451, upload-time = "2024-06-05T16:42:05.146Z" },
|
| 717 |
+
{ url = "https://files.pythonhosted.org/packages/af/77/cf6ceb000f8a064c7b373fb3471d85bcc39917d175af82fead4a2857c669/torch-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:e5fdccbf6f1334b2203a61a0e03821d5845f1421defe311dabeae2fc8fbeac2d", size = 159727172, upload-time = "2024-06-05T16:41:33.436Z" },
|
| 718 |
+
{ url = "https://files.pythonhosted.org/packages/49/b6/1a2e3d43d4bc4ad7a4575b3745d707a68d5ed00ba263b205b6281bdd0921/torch-2.3.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:3c333dc2ebc189561514eda06e81df22bf8fb64e2384746b2cb9f04f96d1d4c8", size = 60978559, upload-time = "2024-06-05T16:41:27.77Z" },
|
| 719 |
+
]
|
| 720 |
+
|
| 721 |
+
[[package]]
|
| 722 |
+
name = "tqdm"
|
| 723 |
+
version = "4.67.1"
|
| 724 |
+
source = { registry = "https://pypi.org/simple" }
|
| 725 |
+
dependencies = [
|
| 726 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 727 |
+
]
|
| 728 |
+
sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" }
|
| 729 |
+
wheels = [
|
| 730 |
+
{ url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" },
|
| 731 |
+
]
|
| 732 |
+
|
| 733 |
+
[[package]]
|
| 734 |
+
name = "transformers"
|
| 735 |
+
version = "4.44.2"
|
| 736 |
+
source = { registry = "https://pypi.org/simple" }
|
| 737 |
+
dependencies = [
|
| 738 |
+
{ name = "filelock" },
|
| 739 |
+
{ name = "huggingface-hub" },
|
| 740 |
+
{ name = "numpy" },
|
| 741 |
+
{ name = "packaging" },
|
| 742 |
+
{ name = "pyyaml" },
|
| 743 |
+
{ name = "regex" },
|
| 744 |
+
{ name = "requests" },
|
| 745 |
+
{ name = "safetensors" },
|
| 746 |
+
{ name = "tokenizers" },
|
| 747 |
+
{ name = "tqdm" },
|
| 748 |
+
]
|
| 749 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f8/a3/81de49357a3c6ac4421d48d9662b53293838f217baf3f3bb9eb55f89fab6/transformers-4.44.2.tar.gz", hash = "sha256:36aa17cc92ee154058e426d951684a2dab48751b35b49437896f898931270826", size = 8110312, upload-time = "2024-08-22T16:56:33.522Z" }
|
| 750 |
+
wheels = [
|
| 751 |
+
{ url = "https://files.pythonhosted.org/packages/75/35/07c9879163b603f0e464b0f6e6e628a2340cfc7cdc5ca8e7d52d776710d4/transformers-4.44.2-py3-none-any.whl", hash = "sha256:1c02c65e7bfa5e52a634aff3da52138b583fc6f263c1f28d547dc144ba3d412d", size = 9465369, upload-time = "2024-08-22T16:56:29.207Z" },
|
| 752 |
+
]
|
| 753 |
+
|
| 754 |
+
[[package]]
|
| 755 |
+
name = "typing-extensions"
|
| 756 |
+
version = "4.15.0"
|
| 757 |
+
source = { registry = "https://pypi.org/simple" }
|
| 758 |
+
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
| 759 |
+
wheels = [
|
| 760 |
+
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
| 761 |
+
]
|
| 762 |
+
|
| 763 |
+
[[package]]
|
| 764 |
+
name = "urllib3"
|
| 765 |
+
version = "2.6.3"
|
| 766 |
+
source = { registry = "https://pypi.org/simple" }
|
| 767 |
+
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
| 768 |
+
wheels = [
|
| 769 |
+
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
| 770 |
+
]
|
| 771 |
+
|
| 772 |
+
[[package]]
|
| 773 |
+
name = "uvicorn"
|
| 774 |
+
version = "0.30.6"
|
| 775 |
+
source = { registry = "https://pypi.org/simple" }
|
| 776 |
+
dependencies = [
|
| 777 |
+
{ name = "click" },
|
| 778 |
+
{ name = "h11" },
|
| 779 |
+
]
|
| 780 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5a/01/5e637e7aa9dd031be5376b9fb749ec20b86f5a5b6a49b87fabd374d5fa9f/uvicorn-0.30.6.tar.gz", hash = "sha256:4b15decdda1e72be08209e860a1e10e92439ad5b97cf44cc945fcbee66fc5788", size = 42825, upload-time = "2024-08-13T09:27:35.098Z" }
|
| 781 |
+
wheels = [
|
| 782 |
+
{ url = "https://files.pythonhosted.org/packages/f5/8e/cdc7d6263db313030e4c257dd5ba3909ebc4e4fb53ad62d5f09b1a2f5458/uvicorn-0.30.6-py3-none-any.whl", hash = "sha256:65fd46fe3fda5bdc1b03b94eb634923ff18cd35b2f084813ea79d1f103f711b5", size = 62835, upload-time = "2024-08-13T09:27:33.536Z" },
|
| 783 |
+
]
|
| 784 |
+
|
| 785 |
+
[package.optional-dependencies]
|
| 786 |
+
standard = [
|
| 787 |
+
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 788 |
+
{ name = "httptools" },
|
| 789 |
+
{ name = "python-dotenv" },
|
| 790 |
+
{ name = "pyyaml" },
|
| 791 |
+
{ name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" },
|
| 792 |
+
{ name = "watchfiles" },
|
| 793 |
+
{ name = "websockets" },
|
| 794 |
+
]
|
| 795 |
+
|
| 796 |
+
[[package]]
|
| 797 |
+
name = "uvloop"
|
| 798 |
+
version = "0.22.1"
|
| 799 |
+
source = { registry = "https://pypi.org/simple" }
|
| 800 |
+
sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" }
|
| 801 |
+
wheels = [
|
| 802 |
+
{ url = "https://files.pythonhosted.org/packages/3d/ff/7f72e8170be527b4977b033239a83a68d5c881cc4775fca255c677f7ac5d/uvloop-0.22.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:fe94b4564e865d968414598eea1a6de60adba0c040ba4ed05ac1300de402cd42", size = 1359936, upload-time = "2025-10-16T22:16:29.436Z" },
|
| 803 |
+
{ url = "https://files.pythonhosted.org/packages/c3/c6/e5d433f88fd54d81ef4be58b2b7b0cea13c442454a1db703a1eea0db1a59/uvloop-0.22.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:51eb9bd88391483410daad430813d982010f9c9c89512321f5b60e2cddbdddd6", size = 752769, upload-time = "2025-10-16T22:16:30.493Z" },
|
| 804 |
+
{ url = "https://files.pythonhosted.org/packages/24/68/a6ac446820273e71aa762fa21cdcc09861edd3536ff47c5cd3b7afb10eeb/uvloop-0.22.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:700e674a166ca5778255e0e1dc4e9d79ab2acc57b9171b79e65feba7184b3370", size = 4317413, upload-time = "2025-10-16T22:16:31.644Z" },
|
| 805 |
+
{ url = "https://files.pythonhosted.org/packages/5f/6f/e62b4dfc7ad6518e7eff2516f680d02a0f6eb62c0c212e152ca708a0085e/uvloop-0.22.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b5b1ac819a3f946d3b2ee07f09149578ae76066d70b44df3fa990add49a82e4", size = 4426307, upload-time = "2025-10-16T22:16:32.917Z" },
|
| 806 |
+
{ url = "https://files.pythonhosted.org/packages/90/60/97362554ac21e20e81bcef1150cb2a7e4ffdaf8ea1e5b2e8bf7a053caa18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e047cc068570bac9866237739607d1313b9253c3051ad84738cbb095be0537b2", size = 4131970, upload-time = "2025-10-16T22:16:34.015Z" },
|
| 807 |
+
{ url = "https://files.pythonhosted.org/packages/99/39/6b3f7d234ba3964c428a6e40006340f53ba37993f46ed6e111c6e9141d18/uvloop-0.22.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:512fec6815e2dd45161054592441ef76c830eddaad55c8aa30952e6fe1ed07c0", size = 4296343, upload-time = "2025-10-16T22:16:35.149Z" },
|
| 808 |
+
]
|
| 809 |
+
|
| 810 |
+
[[package]]
|
| 811 |
+
name = "watchfiles"
|
| 812 |
+
version = "1.1.1"
|
| 813 |
+
source = { registry = "https://pypi.org/simple" }
|
| 814 |
+
dependencies = [
|
| 815 |
+
{ name = "anyio" },
|
| 816 |
+
]
|
| 817 |
+
sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" }
|
| 818 |
+
wheels = [
|
| 819 |
+
{ url = "https://files.pythonhosted.org/packages/74/d5/f039e7e3c639d9b1d09b07ea412a6806d38123f0508e5f9b48a87b0a76cc/watchfiles-1.1.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:8c89f9f2f740a6b7dcc753140dd5e1ab9215966f7a3530d0c0705c83b401bd7d", size = 404745, upload-time = "2025-10-14T15:04:46.731Z" },
|
| 820 |
+
{ url = "https://files.pythonhosted.org/packages/a5/96/a881a13aa1349827490dab2d363c8039527060cfcc2c92cc6d13d1b1049e/watchfiles-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd404be08018c37350f0d6e34676bd1e2889990117a2b90070b3007f172d0610", size = 391769, upload-time = "2025-10-14T15:04:48.003Z" },
|
| 821 |
+
{ url = "https://files.pythonhosted.org/packages/4b/5b/d3b460364aeb8da471c1989238ea0e56bec24b6042a68046adf3d9ddb01c/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8526e8f916bb5b9a0a777c8317c23ce65de259422bba5b31325a6fa6029d33af", size = 449374, upload-time = "2025-10-14T15:04:49.179Z" },
|
| 822 |
+
{ url = "https://files.pythonhosted.org/packages/b9/44/5769cb62d4ed055cb17417c0a109a92f007114a4e07f30812a73a4efdb11/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2edc3553362b1c38d9f06242416a5d8e9fe235c204a4072e988ce2e5bb1f69f6", size = 459485, upload-time = "2025-10-14T15:04:50.155Z" },
|
| 823 |
+
{ url = "https://files.pythonhosted.org/packages/19/0c/286b6301ded2eccd4ffd0041a1b726afda999926cf720aab63adb68a1e36/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30f7da3fb3f2844259cba4720c3fc7138eb0f7b659c38f3bfa65084c7fc7abce", size = 488813, upload-time = "2025-10-14T15:04:51.059Z" },
|
| 824 |
+
{ url = "https://files.pythonhosted.org/packages/c7/2b/8530ed41112dd4a22f4dcfdb5ccf6a1baad1ff6eed8dc5a5f09e7e8c41c7/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8979280bdafff686ba5e4d8f97840f929a87ed9cdf133cbbd42f7766774d2aa", size = 594816, upload-time = "2025-10-14T15:04:52.031Z" },
|
| 825 |
+
{ url = "https://files.pythonhosted.org/packages/ce/d2/f5f9fb49489f184f18470d4f99f4e862a4b3e9ac2865688eb2099e3d837a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcc5c24523771db3a294c77d94771abcfcb82a0e0ee8efd910c37c59ec1b31bb", size = 475186, upload-time = "2025-10-14T15:04:53.064Z" },
|
| 826 |
+
{ url = "https://files.pythonhosted.org/packages/cf/68/5707da262a119fb06fbe214d82dd1fe4a6f4af32d2d14de368d0349eb52a/watchfiles-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1db5d7ae38ff20153d542460752ff397fcf5c96090c1230803713cf3147a6803", size = 456812, upload-time = "2025-10-14T15:04:55.174Z" },
|
| 827 |
+
{ url = "https://files.pythonhosted.org/packages/66/ab/3cbb8756323e8f9b6f9acb9ef4ec26d42b2109bce830cc1f3468df20511d/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:28475ddbde92df1874b6c5c8aaeb24ad5be47a11f87cde5a28ef3835932e3e94", size = 630196, upload-time = "2025-10-14T15:04:56.22Z" },
|
| 828 |
+
{ url = "https://files.pythonhosted.org/packages/78/46/7152ec29b8335f80167928944a94955015a345440f524d2dfe63fc2f437b/watchfiles-1.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:36193ed342f5b9842edd3532729a2ad55c4160ffcfa3700e0d54be496b70dd43", size = 622657, upload-time = "2025-10-14T15:04:57.521Z" },
|
| 829 |
+
{ url = "https://files.pythonhosted.org/packages/0a/bf/95895e78dd75efe9a7f31733607f384b42eb5feb54bd2eb6ed57cc2e94f4/watchfiles-1.1.1-cp312-cp312-win32.whl", hash = "sha256:859e43a1951717cc8de7f4c77674a6d389b106361585951d9e69572823f311d9", size = 272042, upload-time = "2025-10-14T15:04:59.046Z" },
|
| 830 |
+
{ url = "https://files.pythonhosted.org/packages/87/0a/90eb755f568de2688cb220171c4191df932232c20946966c27a59c400850/watchfiles-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:91d4c9a823a8c987cce8fa2690923b069966dabb196dd8d137ea2cede885fde9", size = 288410, upload-time = "2025-10-14T15:05:00.081Z" },
|
| 831 |
+
{ url = "https://files.pythonhosted.org/packages/36/76/f322701530586922fbd6723c4f91ace21364924822a8772c549483abed13/watchfiles-1.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:a625815d4a2bdca61953dbba5a39d60164451ef34c88d751f6c368c3ea73d404", size = 278209, upload-time = "2025-10-14T15:05:01.168Z" },
|
| 832 |
+
]
|
| 833 |
+
|
| 834 |
+
[[package]]
|
| 835 |
+
name = "websockets"
|
| 836 |
+
version = "16.0"
|
| 837 |
+
source = { registry = "https://pypi.org/simple" }
|
| 838 |
+
sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" }
|
| 839 |
+
wheels = [
|
| 840 |
+
{ url = "https://files.pythonhosted.org/packages/84/7b/bac442e6b96c9d25092695578dda82403c77936104b5682307bd4deb1ad4/websockets-16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:71c989cbf3254fbd5e84d3bff31e4da39c43f884e64f2551d14bb3c186230f00", size = 177365, upload-time = "2026-01-10T09:22:46.787Z" },
|
| 841 |
+
{ url = "https://files.pythonhosted.org/packages/b0/fe/136ccece61bd690d9c1f715baaeefd953bb2360134de73519d5df19d29ca/websockets-16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8b6e209ffee39ff1b6d0fa7bfef6de950c60dfb91b8fcead17da4ee539121a79", size = 175038, upload-time = "2026-01-10T09:22:47.999Z" },
|
| 842 |
+
{ url = "https://files.pythonhosted.org/packages/40/1e/9771421ac2286eaab95b8575b0cb701ae3663abf8b5e1f64f1fd90d0a673/websockets-16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86890e837d61574c92a97496d590968b23c2ef0aeb8a9bc9421d174cd378ae39", size = 175328, upload-time = "2026-01-10T09:22:49.809Z" },
|
| 843 |
+
{ url = "https://files.pythonhosted.org/packages/18/29/71729b4671f21e1eaa5d6573031ab810ad2936c8175f03f97f3ff164c802/websockets-16.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9b5aca38b67492ef518a8ab76851862488a478602229112c4b0d58d63a7a4d5c", size = 184915, upload-time = "2026-01-10T09:22:51.071Z" },
|
| 844 |
+
{ url = "https://files.pythonhosted.org/packages/97/bb/21c36b7dbbafc85d2d480cd65df02a1dc93bf76d97147605a8e27ff9409d/websockets-16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0334872c0a37b606418ac52f6ab9cfd17317ac26365f7f65e203e2d0d0d359f", size = 186152, upload-time = "2026-01-10T09:22:52.224Z" },
|
| 845 |
+
{ url = "https://files.pythonhosted.org/packages/4a/34/9bf8df0c0cf88fa7bfe36678dc7b02970c9a7d5e065a3099292db87b1be2/websockets-16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a0b31e0b424cc6b5a04b8838bbaec1688834b2383256688cf47eb97412531da1", size = 185583, upload-time = "2026-01-10T09:22:53.443Z" },
|
| 846 |
+
{ url = "https://files.pythonhosted.org/packages/47/88/4dd516068e1a3d6ab3c7c183288404cd424a9a02d585efbac226cb61ff2d/websockets-16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:485c49116d0af10ac698623c513c1cc01c9446c058a4e61e3bf6c19dff7335a2", size = 184880, upload-time = "2026-01-10T09:22:55.033Z" },
|
| 847 |
+
{ url = "https://files.pythonhosted.org/packages/91/d6/7d4553ad4bf1c0421e1ebd4b18de5d9098383b5caa1d937b63df8d04b565/websockets-16.0-cp312-cp312-win32.whl", hash = "sha256:eaded469f5e5b7294e2bdca0ab06becb6756ea86894a47806456089298813c89", size = 178261, upload-time = "2026-01-10T09:22:56.251Z" },
|
| 848 |
+
{ url = "https://files.pythonhosted.org/packages/c3/f0/f3a17365441ed1c27f850a80b2bc680a0fa9505d733fe152fdf5e98c1c0b/websockets-16.0-cp312-cp312-win_amd64.whl", hash = "sha256:5569417dc80977fc8c2d43a86f78e0a5a22fee17565d78621b6bb264a115d4ea", size = 178693, upload-time = "2026-01-10T09:22:57.478Z" },
|
| 849 |
+
{ url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" },
|
| 850 |
+
]
|