Spaces:
Sleeping
Sleeping
Evaluation
Browse files- .gitignore +4 -0
- Makefile +33 -9
- README.md +46 -1
- label-dataset/{ersonal-photos-large-v1.json → personal-photos-large-v1.json} +0 -0
- pyproject.toml +3 -0
- scripts/classify_dataset.py +69 -11
- scripts/dataset_prep.py +280 -0
- scripts/eval_matrix.py +187 -0
- src/photo_classification.egg-info/PKG-INFO +44 -0
- src/photo_classification.egg-info/requires.txt +4 -0
- uv.lock +344 -12
.gitignore
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
data_eval/
|
| 4 |
+
data_results/
|
Makefile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
.PHONY: help docker-build docker-run local-install local-run local-test local-test-integration eval-photo-v1 eval-dance-v1
|
| 2 |
|
| 3 |
help:
|
| 4 |
@echo "---------------------------------------------------"
|
|
@@ -9,8 +9,12 @@ help:
|
|
| 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 |
-
@echo " eval-photo
|
| 13 |
-
@echo " eval-dance
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
|
| 15 |
docker-build:
|
| 16 |
docker build -t photo-classification .
|
|
@@ -30,14 +34,34 @@ local-test:
|
|
| 30 |
local-test-integration:
|
| 31 |
uv run pytest -q -m integration
|
| 32 |
|
| 33 |
-
eval-photo
|
| 34 |
uv run python scripts/classify_dataset.py \
|
| 35 |
--label-set label-dataset/personal-photos-lite-v1.json \
|
| 36 |
-
--images
|
| 37 |
-
--csv
|
| 38 |
|
| 39 |
-
eval-dance
|
| 40 |
uv run python scripts/classify_dataset.py \
|
| 41 |
--label-set label-dataset/scene-dance-formation-group-v1.json \
|
| 42 |
-
--images
|
| 43 |
-
--csv
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.PHONY: help docker-build docker-run local-install local-run local-test local-test-integration eval-photo-v1 eval-dance-v1 eval-photo-matrix eval-dance-matrix data-photos data-dance
|
| 2 |
|
| 3 |
help:
|
| 4 |
@echo "---------------------------------------------------"
|
|
|
|
| 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 |
+
@echo " eval-photo Run eval on personal-photos-lite-v1"
|
| 13 |
+
@echo " eval-dance Run eval on scene-dance-formation-group-v1"
|
| 14 |
+
@echo " eval-photo-matrix Run eval for all personal-photos label sets"
|
| 15 |
+
@echo " eval-dance-matrix Run eval for all dance label sets"
|
| 16 |
+
@echo " data-photos Download + normalize photo eval dataset"
|
| 17 |
+
@echo " data-dance Download + normalize dance eval dataset"
|
| 18 |
|
| 19 |
docker-build:
|
| 20 |
docker build -t photo-classification .
|
|
|
|
| 34 |
local-test-integration:
|
| 35 |
uv run pytest -q -m integration
|
| 36 |
|
| 37 |
+
eval-photo:
|
| 38 |
uv run python scripts/classify_dataset.py \
|
| 39 |
--label-set label-dataset/personal-photos-lite-v1.json \
|
| 40 |
+
--images data_eval/photos/normalized \
|
| 41 |
+
--csv data_results/personal-photos-lite-v1.csv
|
| 42 |
|
| 43 |
+
eval-dance:
|
| 44 |
uv run python scripts/classify_dataset.py \
|
| 45 |
--label-set label-dataset/scene-dance-formation-group-v1.json \
|
| 46 |
+
--images data_eval/dance/normalized \
|
| 47 |
+
--csv data_results/scene-dance-formation-group-v1.csv
|
| 48 |
+
|
| 49 |
+
eval-photo-matrix:
|
| 50 |
+
uv run python scripts/eval_matrix.py \
|
| 51 |
+
--label-sets "label-dataset/personal-photos-*.json" \
|
| 52 |
+
--images data_eval/photos/normalized \
|
| 53 |
+
--out-dir data_results \
|
| 54 |
+
--summary-csv data_results/personal-photos-summary.csv
|
| 55 |
+
|
| 56 |
+
eval-dance-matrix:
|
| 57 |
+
uv run python scripts/eval_matrix.py \
|
| 58 |
+
--label-sets "label-dataset/scene-dance-*.json" \
|
| 59 |
+
--images data_eval/dance/normalized \
|
| 60 |
+
--out-dir data_results \
|
| 61 |
+
--summary-csv data_results/dance-summary.csv
|
| 62 |
+
|
| 63 |
+
data-photos:
|
| 64 |
+
uv run python scripts/dataset_prep.py --out data_eval --target photos --n 50 --normalize
|
| 65 |
+
|
| 66 |
+
data-dance:
|
| 67 |
+
uv run python scripts/dataset_prep.py --out data_eval --target dance --n 50 --normalize
|
README.md
CHANGED
|
@@ -161,13 +161,58 @@ local images and capture timings:
|
|
| 161 |
uv run python scripts/classify_dataset.py \
|
| 162 |
--label-set label-dataset/personal-photos-lite-v1.json \
|
| 163 |
--images /path/to/images \
|
| 164 |
-
--csv
|
| 165 |
```
|
| 166 |
|
| 167 |
Makefile shortcuts:
|
| 168 |
|
| 169 |
- `make eval-photo-v1`
|
| 170 |
- `make eval-dance-v1`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
|
| 172 |
## Project layout
|
| 173 |
|
|
|
|
| 161 |
uv run python scripts/classify_dataset.py \
|
| 162 |
--label-set label-dataset/personal-photos-lite-v1.json \
|
| 163 |
--images /path/to/images \
|
| 164 |
+
--csv data_results/summary.csv
|
| 165 |
```
|
| 166 |
|
| 167 |
Makefile shortcuts:
|
| 168 |
|
| 169 |
- `make eval-photo-v1`
|
| 170 |
- `make eval-dance-v1`
|
| 171 |
+
- `make eval-photo-matrix`
|
| 172 |
+
- `make eval-dance-matrix`
|
| 173 |
+
|
| 174 |
+
Matrix eval (multiple label sets against the same images):
|
| 175 |
+
|
| 176 |
+
```bash
|
| 177 |
+
uv run python scripts/eval_matrix.py \
|
| 178 |
+
--label-sets "label-dataset/personal-photos-*.json" \
|
| 179 |
+
--images data_eval/photos/normalized \
|
| 180 |
+
--out-dir data_results \
|
| 181 |
+
--summary-csv data_results/personal-photos-summary.csv
|
| 182 |
+
```
|
| 183 |
+
|
| 184 |
+
## Eval datasets (download schema)
|
| 185 |
+
|
| 186 |
+
We use a simple, reproducible layout for evaluation datasets created by `scripts/dataset_prep.py`:
|
| 187 |
+
|
| 188 |
+
```
|
| 189 |
+
data_eval/
|
| 190 |
+
photos/
|
| 191 |
+
raw/ # downloaded originals
|
| 192 |
+
normalized/ # normalized JPEGs
|
| 193 |
+
dance/
|
| 194 |
+
raw/ # downloaded originals
|
| 195 |
+
normalized/ # normalized JPEGs
|
| 196 |
+
```
|
| 197 |
+
|
| 198 |
+
Download and normalize (recommended):
|
| 199 |
+
|
| 200 |
+
```bash
|
| 201 |
+
uv run python scripts/dataset_prep.py --out data_eval --target photos --n 50 --normalize
|
| 202 |
+
uv run python scripts/dataset_prep.py --out data_eval --target dance --n 50 --normalize
|
| 203 |
+
```
|
| 204 |
+
|
| 205 |
+
Reset existing files and start fresh:
|
| 206 |
+
|
| 207 |
+
```bash
|
| 208 |
+
uv run python scripts/dataset_prep.py --out data_eval --target photos --n 50 --normalize --reset
|
| 209 |
+
```
|
| 210 |
+
|
| 211 |
+
Normalize your own folder into the same schema:
|
| 212 |
+
|
| 213 |
+
```bash
|
| 214 |
+
uv run python scripts/dataset_prep.py --normalize-only --in-dir /path/to/images --out data_eval/photos
|
| 215 |
+
```
|
| 216 |
|
| 217 |
## Project layout
|
| 218 |
|
label-dataset/{ersonal-photos-large-v1.json → personal-photos-large-v1.json}
RENAMED
|
File without changes
|
pyproject.toml
CHANGED
|
@@ -20,8 +20,11 @@ dependencies = [
|
|
| 20 |
[project.optional-dependencies]
|
| 21 |
dev = [
|
| 22 |
"click==8.1.7",
|
|
|
|
| 23 |
"httpx==0.27.2",
|
| 24 |
"pytest==8.3.2",
|
|
|
|
|
|
|
| 25 |
]
|
| 26 |
|
| 27 |
[tool.setuptools]
|
|
|
|
| 20 |
[project.optional-dependencies]
|
| 21 |
dev = [
|
| 22 |
"click==8.1.7",
|
| 23 |
+
"datasets==2.21.0",
|
| 24 |
"httpx==0.27.2",
|
| 25 |
"pytest==8.3.2",
|
| 26 |
+
"requests==2.32.3",
|
| 27 |
+
"tqdm==4.66.5",
|
| 28 |
]
|
| 29 |
|
| 30 |
[tool.setuptools]
|
scripts/classify_dataset.py
CHANGED
|
@@ -5,6 +5,7 @@ import base64
|
|
| 5 |
import csv
|
| 6 |
import json
|
| 7 |
from dataclasses import dataclass
|
|
|
|
| 8 |
from pathlib import Path
|
| 9 |
from typing import Iterable
|
| 10 |
|
|
@@ -21,7 +22,9 @@ class Config:
|
|
| 21 |
top_k: int
|
| 22 |
activate: bool
|
| 23 |
limit: int
|
|
|
|
| 24 |
csv_path: Path | None
|
|
|
|
| 25 |
|
| 26 |
|
| 27 |
def iter_images(paths: list[Path]) -> Iterable[Path]:
|
|
@@ -63,11 +66,15 @@ def classify_one(client: httpx.Client, label_set_hash: str, image: Path, domain_
|
|
| 63 |
|
| 64 |
|
| 65 |
def to_row(image: Path, data: dict) -> dict[str, str]:
|
|
|
|
|
|
|
| 66 |
return {
|
| 67 |
"image": str(image),
|
| 68 |
"label_set_hash": data.get("label_set_hash", ""),
|
| 69 |
"model_id": data.get("model_id", ""),
|
| 70 |
"chosen_domains": "|".join(data.get("chosen_domains", [])),
|
|
|
|
|
|
|
| 71 |
"elapsed_ms": str(data.get("elapsed_ms", "")),
|
| 72 |
"elapsed_domain_ms": str(data.get("elapsed_domain_ms", "")),
|
| 73 |
"elapsed_labels_ms": str(data.get("elapsed_labels_ms", "")),
|
|
@@ -79,18 +86,54 @@ def write_csv(path: Path, rows: list[dict[str, str]]) -> None:
|
|
| 79 |
with path.open("w", newline="", encoding="utf-8") as f:
|
| 80 |
writer = csv.DictWriter(
|
| 81 |
f,
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
writer.writeheader()
|
| 93 |
-
writer.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
|
| 95 |
|
| 96 |
def run(cfg: Config) -> int:
|
|
@@ -113,6 +156,15 @@ def run(cfg: Config) -> int:
|
|
| 113 |
|
| 114 |
if cfg.csv_path and rows:
|
| 115 |
write_csv(cfg.csv_path, rows)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
return 0
|
| 118 |
|
|
@@ -125,7 +177,9 @@ def run(cfg: Config) -> int:
|
|
| 125 |
@click.option("--top-k", default=5, show_default=True, type=int)
|
| 126 |
@click.option("--activate", is_flag=True, default=False)
|
| 127 |
@click.option("--limit", default=0, show_default=True, type=int)
|
|
|
|
| 128 |
@click.option("--csv", "csv_path", type=click.Path(path_type=Path))
|
|
|
|
| 129 |
def cli(
|
| 130 |
api: str,
|
| 131 |
label_set: Path,
|
|
@@ -134,7 +188,9 @@ def cli(
|
|
| 134 |
top_k: int,
|
| 135 |
activate: bool,
|
| 136 |
limit: int,
|
|
|
|
| 137 |
csv_path: Path | None,
|
|
|
|
| 138 |
) -> None:
|
| 139 |
cfg = Config(
|
| 140 |
api=api,
|
|
@@ -144,7 +200,9 @@ def cli(
|
|
| 144 |
top_k=top_k,
|
| 145 |
activate=activate,
|
| 146 |
limit=limit,
|
|
|
|
| 147 |
csv_path=csv_path,
|
|
|
|
| 148 |
)
|
| 149 |
raise SystemExit(run(cfg))
|
| 150 |
|
|
|
|
| 5 |
import csv
|
| 6 |
import json
|
| 7 |
from dataclasses import dataclass
|
| 8 |
+
from datetime import datetime, timezone
|
| 9 |
from pathlib import Path
|
| 10 |
from typing import Iterable
|
| 11 |
|
|
|
|
| 22 |
top_k: int
|
| 23 |
activate: bool
|
| 24 |
limit: int
|
| 25 |
+
out_dir: Path
|
| 26 |
csv_path: Path | None
|
| 27 |
+
summary: bool
|
| 28 |
|
| 29 |
|
| 30 |
def iter_images(paths: list[Path]) -> Iterable[Path]:
|
|
|
|
| 66 |
|
| 67 |
|
| 68 |
def to_row(image: Path, data: dict) -> dict[str, str]:
|
| 69 |
+
domain_hits = data.get("domain_hits", [])
|
| 70 |
+
label_hits = data.get("label_hits", [])
|
| 71 |
return {
|
| 72 |
"image": str(image),
|
| 73 |
"label_set_hash": data.get("label_set_hash", ""),
|
| 74 |
"model_id": data.get("model_id", ""),
|
| 75 |
"chosen_domains": "|".join(data.get("chosen_domains", [])),
|
| 76 |
+
"domain_hits": "|".join(f"{d.get('id')}:{d.get('score'):.4f}" for d in domain_hits),
|
| 77 |
+
"label_hits": "|".join(f"{l.get('id')}:{l.get('score'):.4f}" for l in label_hits),
|
| 78 |
"elapsed_ms": str(data.get("elapsed_ms", "")),
|
| 79 |
"elapsed_domain_ms": str(data.get("elapsed_domain_ms", "")),
|
| 80 |
"elapsed_labels_ms": str(data.get("elapsed_labels_ms", "")),
|
|
|
|
| 86 |
with path.open("w", newline="", encoding="utf-8") as f:
|
| 87 |
writer = csv.DictWriter(
|
| 88 |
f,
|
| 89 |
+
fieldnames=[
|
| 90 |
+
"image",
|
| 91 |
+
"label_set_hash",
|
| 92 |
+
"model_id",
|
| 93 |
+
"chosen_domains",
|
| 94 |
+
"domain_hits",
|
| 95 |
+
"label_hits",
|
| 96 |
+
"elapsed_ms",
|
| 97 |
+
"elapsed_domain_ms",
|
| 98 |
+
"elapsed_labels_ms",
|
| 99 |
+
],
|
| 100 |
+
)
|
| 101 |
+
writer.writeheader()
|
| 102 |
+
writer.writerows(rows)
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def _percentile(values: list[int], q: float) -> int:
|
| 106 |
+
if not values:
|
| 107 |
+
return 0
|
| 108 |
+
values = sorted(values)
|
| 109 |
+
idx = int(round((len(values) - 1) * q))
|
| 110 |
+
return values[idx]
|
| 111 |
+
|
| 112 |
+
|
| 113 |
+
def write_summary(path: Path, rows: list[dict[str, str]]) -> None:
|
| 114 |
+
times: list[int] = []
|
| 115 |
+
for row in rows:
|
| 116 |
+
try:
|
| 117 |
+
times.append(int(row["elapsed_ms"]))
|
| 118 |
+
except Exception:
|
| 119 |
+
continue
|
| 120 |
+
summary = {
|
| 121 |
+
"count": str(len(times)),
|
| 122 |
+
"avg_elapsed_ms": str(int(sum(times) / max(1, len(times)))),
|
| 123 |
+
"p50_elapsed_ms": str(_percentile(times, 0.50)),
|
| 124 |
+
"p90_elapsed_ms": str(_percentile(times, 0.90)),
|
| 125 |
+
"p95_elapsed_ms": str(_percentile(times, 0.95)),
|
| 126 |
+
"p99_elapsed_ms": str(_percentile(times, 0.99)),
|
| 127 |
+
}
|
| 128 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 129 |
+
with path.open("w", newline="", encoding="utf-8") as f:
|
| 130 |
+
writer = csv.DictWriter(f, fieldnames=list(summary.keys()))
|
| 131 |
writer.writeheader()
|
| 132 |
+
writer.writerow(summary)
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def _timestamp() -> str:
|
| 136 |
+
return datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
|
| 137 |
|
| 138 |
|
| 139 |
def run(cfg: Config) -> int:
|
|
|
|
| 156 |
|
| 157 |
if cfg.csv_path and rows:
|
| 158 |
write_csv(cfg.csv_path, rows)
|
| 159 |
+
elif rows:
|
| 160 |
+
ts = _timestamp()
|
| 161 |
+
out_path = cfg.out_dir / f"{cfg.label_set.stem}_{ts}.csv"
|
| 162 |
+
write_csv(out_path, rows)
|
| 163 |
+
|
| 164 |
+
if cfg.summary:
|
| 165 |
+
ts = _timestamp()
|
| 166 |
+
summary_path = cfg.out_dir / f"{cfg.label_set.stem}_summary_{ts}.csv"
|
| 167 |
+
write_summary(summary_path, rows)
|
| 168 |
|
| 169 |
return 0
|
| 170 |
|
|
|
|
| 177 |
@click.option("--top-k", default=5, show_default=True, type=int)
|
| 178 |
@click.option("--activate", is_flag=True, default=False)
|
| 179 |
@click.option("--limit", default=0, show_default=True, type=int)
|
| 180 |
+
@click.option("--out-dir", default="data_results", show_default=True, type=click.Path(path_type=Path))
|
| 181 |
@click.option("--csv", "csv_path", type=click.Path(path_type=Path))
|
| 182 |
+
@click.option("--summary", is_flag=True, default=False)
|
| 183 |
def cli(
|
| 184 |
api: str,
|
| 185 |
label_set: Path,
|
|
|
|
| 188 |
top_k: int,
|
| 189 |
activate: bool,
|
| 190 |
limit: int,
|
| 191 |
+
out_dir: Path,
|
| 192 |
csv_path: Path | None,
|
| 193 |
+
summary: bool,
|
| 194 |
) -> None:
|
| 195 |
cfg = Config(
|
| 196 |
api=api,
|
|
|
|
| 200 |
top_k=top_k,
|
| 201 |
activate=activate,
|
| 202 |
limit=limit,
|
| 203 |
+
out_dir=out_dir,
|
| 204 |
csv_path=csv_path,
|
| 205 |
+
summary=summary,
|
| 206 |
)
|
| 207 |
raise SystemExit(run(cfg))
|
| 208 |
|
scripts/dataset_prep.py
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import io
|
| 5 |
+
from dataclasses import dataclass
|
| 6 |
+
from pathlib import Path
|
| 7 |
+
from typing import Iterable, Optional
|
| 8 |
+
|
| 9 |
+
import click
|
| 10 |
+
import requests
|
| 11 |
+
from PIL import Image, ImageOps
|
| 12 |
+
from tqdm import tqdm
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
@dataclass(frozen=True)
|
| 16 |
+
class Config:
|
| 17 |
+
out_dir: Path
|
| 18 |
+
target: str
|
| 19 |
+
n: int
|
| 20 |
+
seed: int
|
| 21 |
+
normalize: bool
|
| 22 |
+
max_side: int
|
| 23 |
+
jpeg_quality: int
|
| 24 |
+
normalize_only: bool
|
| 25 |
+
in_dir: Optional[Path]
|
| 26 |
+
reset: bool
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def ensure_dir(path: Path) -> None:
|
| 30 |
+
path.mkdir(parents=True, exist_ok=True)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def normalize_image_bytes(img_bytes: bytes, max_side: int, jpeg_quality: int) -> bytes:
|
| 34 |
+
with Image.open(io.BytesIO(img_bytes)) as im:
|
| 35 |
+
im = ImageOps.exif_transpose(im)
|
| 36 |
+
im = im.convert("RGB")
|
| 37 |
+
|
| 38 |
+
w, h = im.size
|
| 39 |
+
scale = max_side / float(max(w, h))
|
| 40 |
+
if scale < 1.0:
|
| 41 |
+
new_w = max(1, int(round(w * scale)))
|
| 42 |
+
new_h = max(1, int(round(h * scale)))
|
| 43 |
+
im = im.resize((new_w, new_h), Image.Resampling.LANCZOS)
|
| 44 |
+
|
| 45 |
+
out = io.BytesIO()
|
| 46 |
+
im.save(out, format="JPEG", quality=jpeg_quality, optimize=True, progressive=True)
|
| 47 |
+
return out.getvalue()
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def download_url(url: str, timeout_s: float = 20.0) -> Optional[bytes]:
|
| 51 |
+
try:
|
| 52 |
+
resp = requests.get(url, timeout=timeout_s)
|
| 53 |
+
resp.raise_for_status()
|
| 54 |
+
return resp.content
|
| 55 |
+
except Exception:
|
| 56 |
+
return None
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
def save_bytes(path: Path, data: bytes) -> None:
|
| 60 |
+
ensure_dir(path.parent)
|
| 61 |
+
path.write_bytes(data)
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def iter_images(paths: Iterable[Path]) -> Iterable[Path]:
|
| 65 |
+
exts = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".tif", ".tiff"}
|
| 66 |
+
for path in paths:
|
| 67 |
+
if path.is_dir():
|
| 68 |
+
for p in sorted(path.rglob("*")):
|
| 69 |
+
if p.is_file() and p.suffix.lower() in exts:
|
| 70 |
+
yield p
|
| 71 |
+
elif path.is_file() and path.suffix.lower() in exts:
|
| 72 |
+
yield path
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def normalize_existing(in_dir: Path, out_dir: Path, max_side: int, jpeg_quality: int) -> None:
|
| 76 |
+
files = list(iter_images([in_dir]))
|
| 77 |
+
ensure_dir(out_dir)
|
| 78 |
+
|
| 79 |
+
for p in tqdm(files, desc=f"Normalizing {in_dir.name}"):
|
| 80 |
+
try:
|
| 81 |
+
raw = p.read_bytes()
|
| 82 |
+
norm = normalize_image_bytes(raw, max_side=max_side, jpeg_quality=jpeg_quality)
|
| 83 |
+
rel = p.relative_to(in_dir)
|
| 84 |
+
out_path = (out_dir / rel).with_suffix(".jpg")
|
| 85 |
+
save_bytes(out_path, norm)
|
| 86 |
+
except Exception:
|
| 87 |
+
continue
|
| 88 |
+
|
| 89 |
+
print(f"Normalized images written to: {out_dir}")
|
| 90 |
+
|
| 91 |
+
|
| 92 |
+
def _next_index(dir_path: Path, prefix: str) -> int:
|
| 93 |
+
if not dir_path.exists():
|
| 94 |
+
return 0
|
| 95 |
+
max_idx = -1
|
| 96 |
+
for p in dir_path.glob(f"{prefix}_*.bin"):
|
| 97 |
+
stem = p.stem
|
| 98 |
+
try:
|
| 99 |
+
idx = int(stem.split("_")[-1])
|
| 100 |
+
except ValueError:
|
| 101 |
+
continue
|
| 102 |
+
max_idx = max(max_idx, idx)
|
| 103 |
+
return max_idx + 1
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
def download_photos_open_images(
|
| 107 |
+
out_dir: Path,
|
| 108 |
+
n: int,
|
| 109 |
+
seed: int,
|
| 110 |
+
normalize: bool,
|
| 111 |
+
max_side: int,
|
| 112 |
+
jpeg_quality: int,
|
| 113 |
+
reset: bool,
|
| 114 |
+
) -> None:
|
| 115 |
+
from datasets import load_dataset
|
| 116 |
+
|
| 117 |
+
ds = load_dataset("bitmind/open-images-v7", split="train", streaming=True)
|
| 118 |
+
|
| 119 |
+
saved = 0
|
| 120 |
+
|
| 121 |
+
raw_dir = out_dir / "photos" / "raw"
|
| 122 |
+
norm_dir = out_dir / "photos" / "normalized"
|
| 123 |
+
if reset:
|
| 124 |
+
for p in raw_dir.glob("openimages_*.bin"):
|
| 125 |
+
p.unlink()
|
| 126 |
+
for p in norm_dir.glob("openimages_*.jpg"):
|
| 127 |
+
p.unlink()
|
| 128 |
+
start_idx = _next_index(raw_dir, "openimages")
|
| 129 |
+
|
| 130 |
+
for row in tqdm(ds, desc="Streaming Open Images V7"):
|
| 131 |
+
if saved >= n:
|
| 132 |
+
break
|
| 133 |
+
url = row.get("image_url") or row.get("url") or row.get("imageUrl") or row.get("ImageURL")
|
| 134 |
+
if not url:
|
| 135 |
+
continue
|
| 136 |
+
|
| 137 |
+
img = download_url(url)
|
| 138 |
+
if not img:
|
| 139 |
+
continue
|
| 140 |
+
|
| 141 |
+
idx = start_idx + saved
|
| 142 |
+
raw_name = f"openimages_{idx:06d}.bin"
|
| 143 |
+
save_bytes(raw_dir / raw_name, img)
|
| 144 |
+
|
| 145 |
+
if normalize:
|
| 146 |
+
norm = normalize_image_bytes(img, max_side=max_side, jpeg_quality=jpeg_quality)
|
| 147 |
+
norm_name = f"openimages_{idx:06d}.jpg"
|
| 148 |
+
save_bytes(norm_dir / norm_name, norm)
|
| 149 |
+
saved += 1
|
| 150 |
+
|
| 151 |
+
print(f"Saved {saved} images to: {raw_dir}")
|
| 152 |
+
if normalize:
|
| 153 |
+
print(f"Normalized images written to: {norm_dir}")
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
def download_dance_x_dance(
|
| 157 |
+
out_dir: Path,
|
| 158 |
+
n: int,
|
| 159 |
+
seed: int,
|
| 160 |
+
normalize: bool,
|
| 161 |
+
max_side: int,
|
| 162 |
+
jpeg_quality: int,
|
| 163 |
+
reset: bool,
|
| 164 |
+
) -> None:
|
| 165 |
+
from datasets import load_dataset
|
| 166 |
+
|
| 167 |
+
ds = load_dataset("MCG-NJU/X-Dance", split="train", streaming=True)
|
| 168 |
+
|
| 169 |
+
raw_dir = out_dir / "dance" / "raw"
|
| 170 |
+
norm_dir = out_dir / "dance" / "normalized"
|
| 171 |
+
if reset:
|
| 172 |
+
for p in raw_dir.glob("xdance_*.bin"):
|
| 173 |
+
p.unlink()
|
| 174 |
+
for p in norm_dir.glob("xdance_*.jpg"):
|
| 175 |
+
p.unlink()
|
| 176 |
+
start_idx = _next_index(raw_dir, "xdance")
|
| 177 |
+
|
| 178 |
+
saved = 0
|
| 179 |
+
for row in tqdm(ds, desc="Streaming X-Dance"):
|
| 180 |
+
if saved >= n:
|
| 181 |
+
break
|
| 182 |
+
img_obj = row.get("image")
|
| 183 |
+
img_bytes: Optional[bytes] = None
|
| 184 |
+
if img_obj is not None and hasattr(img_obj, "convert"):
|
| 185 |
+
out = io.BytesIO()
|
| 186 |
+
img_obj.convert("RGB").save(out, format="PNG")
|
| 187 |
+
img_bytes = out.getvalue()
|
| 188 |
+
else:
|
| 189 |
+
url = row.get("image_url") or row.get("url")
|
| 190 |
+
if url:
|
| 191 |
+
img_bytes = download_url(url)
|
| 192 |
+
|
| 193 |
+
if not img_bytes:
|
| 194 |
+
continue
|
| 195 |
+
|
| 196 |
+
idx = start_idx + saved
|
| 197 |
+
raw_name = f"xdance_{idx:06d}.bin"
|
| 198 |
+
save_bytes(raw_dir / raw_name, img_bytes)
|
| 199 |
+
|
| 200 |
+
if normalize:
|
| 201 |
+
norm = normalize_image_bytes(img_bytes, max_side=max_side, jpeg_quality=jpeg_quality)
|
| 202 |
+
norm_name = f"xdance_{idx:06d}.jpg"
|
| 203 |
+
save_bytes(norm_dir / norm_name, norm)
|
| 204 |
+
saved += 1
|
| 205 |
+
|
| 206 |
+
print(f"Saved {saved} images to: {raw_dir}")
|
| 207 |
+
if normalize:
|
| 208 |
+
print(f"Normalized images written to: {norm_dir}")
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def run(cfg: Config) -> None:
|
| 212 |
+
if cfg.normalize_only:
|
| 213 |
+
if not cfg.in_dir:
|
| 214 |
+
raise SystemExit("--in-dir is required with --normalize-only")
|
| 215 |
+
normalize_existing(cfg.in_dir, cfg.out_dir, cfg.max_side, cfg.jpeg_quality)
|
| 216 |
+
return
|
| 217 |
+
|
| 218 |
+
ensure_dir(cfg.out_dir)
|
| 219 |
+
if cfg.target == "photos":
|
| 220 |
+
download_photos_open_images(
|
| 221 |
+
out_dir=cfg.out_dir,
|
| 222 |
+
n=cfg.n,
|
| 223 |
+
seed=cfg.seed,
|
| 224 |
+
normalize=cfg.normalize,
|
| 225 |
+
max_side=cfg.max_side,
|
| 226 |
+
jpeg_quality=cfg.jpeg_quality,
|
| 227 |
+
reset=cfg.reset,
|
| 228 |
+
)
|
| 229 |
+
else:
|
| 230 |
+
download_dance_x_dance(
|
| 231 |
+
out_dir=cfg.out_dir,
|
| 232 |
+
n=cfg.n,
|
| 233 |
+
seed=cfg.seed,
|
| 234 |
+
normalize=cfg.normalize,
|
| 235 |
+
max_side=cfg.max_side,
|
| 236 |
+
jpeg_quality=cfg.jpeg_quality,
|
| 237 |
+
reset=cfg.reset,
|
| 238 |
+
)
|
| 239 |
+
|
| 240 |
+
|
| 241 |
+
@click.command()
|
| 242 |
+
@click.option("--out", "out_dir", required=True, type=click.Path(path_type=Path))
|
| 243 |
+
@click.option("--target", type=click.Choice(["photos", "dance"], case_sensitive=False), required=True)
|
| 244 |
+
@click.option("--n", default=500, show_default=True, type=int)
|
| 245 |
+
@click.option("--seed", default=0, show_default=True, type=int)
|
| 246 |
+
@click.option("--normalize", is_flag=True, default=False)
|
| 247 |
+
@click.option("--max-side", default=512, show_default=True, type=int)
|
| 248 |
+
@click.option("--jpeg-quality", default=92, show_default=True, type=int)
|
| 249 |
+
@click.option("--normalize-only", is_flag=True, default=False)
|
| 250 |
+
@click.option("--in-dir", type=click.Path(path_type=Path))
|
| 251 |
+
@click.option("--reset", is_flag=True, default=False, help="Delete existing raw/normalized files before download.")
|
| 252 |
+
def cli(
|
| 253 |
+
out_dir: Path,
|
| 254 |
+
target: str,
|
| 255 |
+
n: int,
|
| 256 |
+
seed: int,
|
| 257 |
+
normalize: bool,
|
| 258 |
+
max_side: int,
|
| 259 |
+
jpeg_quality: int,
|
| 260 |
+
normalize_only: bool,
|
| 261 |
+
in_dir: Optional[Path],
|
| 262 |
+
reset: bool,
|
| 263 |
+
) -> None:
|
| 264 |
+
cfg = Config(
|
| 265 |
+
out_dir=out_dir,
|
| 266 |
+
target=target,
|
| 267 |
+
n=n,
|
| 268 |
+
seed=seed,
|
| 269 |
+
normalize=normalize,
|
| 270 |
+
max_side=max_side,
|
| 271 |
+
jpeg_quality=jpeg_quality,
|
| 272 |
+
normalize_only=normalize_only,
|
| 273 |
+
in_dir=in_dir,
|
| 274 |
+
reset=reset,
|
| 275 |
+
)
|
| 276 |
+
run(cfg)
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
if __name__ == "__main__":
|
| 280 |
+
cli()
|
scripts/eval_matrix.py
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
from __future__ import annotations
|
| 3 |
+
|
| 4 |
+
import csv
|
| 5 |
+
import json
|
| 6 |
+
from dataclasses import dataclass
|
| 7 |
+
import base64
|
| 8 |
+
from pathlib import Path
|
| 9 |
+
from typing import Iterable
|
| 10 |
+
|
| 11 |
+
import click
|
| 12 |
+
import httpx
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
@dataclass(frozen=True)
|
| 16 |
+
class Config:
|
| 17 |
+
api: str
|
| 18 |
+
label_sets: list[Path]
|
| 19 |
+
images: list[Path]
|
| 20 |
+
domain_top_n: int
|
| 21 |
+
top_k: int
|
| 22 |
+
out_dir: Path
|
| 23 |
+
summary_csv: Path | None
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def iter_images(paths: Iterable[Path]) -> Iterable[Path]:
|
| 27 |
+
exts = {".jpg", ".jpeg", ".png", ".webp"}
|
| 28 |
+
for path in paths:
|
| 29 |
+
if path.is_dir():
|
| 30 |
+
for p in sorted(path.rglob("*")):
|
| 31 |
+
if p.is_file() and p.suffix.lower() in exts:
|
| 32 |
+
yield p
|
| 33 |
+
elif path.is_file() and path.suffix.lower() in exts:
|
| 34 |
+
yield path
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def expand_label_sets(paths: Iterable[str]) -> list[Path]:
|
| 38 |
+
out: list[Path] = []
|
| 39 |
+
for raw in paths:
|
| 40 |
+
p = Path(raw)
|
| 41 |
+
if any(ch in raw for ch in ["*", "?", "["]):
|
| 42 |
+
out.extend(sorted(Path().glob(raw)))
|
| 43 |
+
else:
|
| 44 |
+
out.append(p)
|
| 45 |
+
return [p for p in out if p.is_file()]
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def upload_label_set(client: httpx.Client, label_set: Path) -> str:
|
| 49 |
+
payload = json.loads(label_set.read_text())
|
| 50 |
+
r = client.post("/api/v1/label-sets", json=payload)
|
| 51 |
+
r.raise_for_status()
|
| 52 |
+
return r.json()["label_set_hash"]
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def classify_one(
|
| 56 |
+
client: httpx.Client,
|
| 57 |
+
label_set_hash: str,
|
| 58 |
+
image_b64: str,
|
| 59 |
+
domain_top_n: int,
|
| 60 |
+
top_k: int,
|
| 61 |
+
) -> dict:
|
| 62 |
+
payload = {
|
| 63 |
+
"image_base64": image_b64,
|
| 64 |
+
"domain_top_n": domain_top_n,
|
| 65 |
+
"top_k": top_k,
|
| 66 |
+
}
|
| 67 |
+
r = client.post(f"/api/v1/classify?label_set_hash={label_set_hash}", json=payload)
|
| 68 |
+
r.raise_for_status()
|
| 69 |
+
return r.json()
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
def to_row(label_set: Path, image: Path, data: dict) -> dict[str, str]:
|
| 73 |
+
return {
|
| 74 |
+
"label_set": label_set.name,
|
| 75 |
+
"image": str(image),
|
| 76 |
+
"label_set_hash": data.get("label_set_hash", ""),
|
| 77 |
+
"model_id": data.get("model_id", ""),
|
| 78 |
+
"chosen_domains": "|".join(data.get("chosen_domains", [])),
|
| 79 |
+
"elapsed_ms": str(data.get("elapsed_ms", "")),
|
| 80 |
+
"elapsed_domain_ms": str(data.get("elapsed_domain_ms", "")),
|
| 81 |
+
"elapsed_labels_ms": str(data.get("elapsed_labels_ms", "")),
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def write_csv(path: Path, rows: list[dict[str, str]]) -> None:
|
| 86 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 87 |
+
with path.open("w", newline="", encoding="utf-8") as f:
|
| 88 |
+
writer = csv.DictWriter(
|
| 89 |
+
f,
|
| 90 |
+
fieldnames=[
|
| 91 |
+
"label_set",
|
| 92 |
+
"image",
|
| 93 |
+
"label_set_hash",
|
| 94 |
+
"model_id",
|
| 95 |
+
"chosen_domains",
|
| 96 |
+
"elapsed_ms",
|
| 97 |
+
"elapsed_domain_ms",
|
| 98 |
+
"elapsed_labels_ms",
|
| 99 |
+
],
|
| 100 |
+
)
|
| 101 |
+
writer.writeheader()
|
| 102 |
+
writer.writerows(rows)
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def write_summary(path: Path, rows: list[dict[str, str]]) -> None:
|
| 106 |
+
summary: dict[str, list[int]] = {}
|
| 107 |
+
for row in rows:
|
| 108 |
+
label = row["label_set"]
|
| 109 |
+
try:
|
| 110 |
+
elapsed = int(row["elapsed_ms"])
|
| 111 |
+
except Exception:
|
| 112 |
+
continue
|
| 113 |
+
summary.setdefault(label, []).append(elapsed)
|
| 114 |
+
|
| 115 |
+
out_rows: list[dict[str, str]] = []
|
| 116 |
+
for label, times in summary.items():
|
| 117 |
+
avg = int(sum(times) / max(1, len(times)))
|
| 118 |
+
out_rows.append({"label_set": label, "count": str(len(times)), "avg_elapsed_ms": str(avg)})
|
| 119 |
+
|
| 120 |
+
path.parent.mkdir(parents=True, exist_ok=True)
|
| 121 |
+
with path.open("w", newline="", encoding="utf-8") as f:
|
| 122 |
+
writer = csv.DictWriter(f, fieldnames=["label_set", "count", "avg_elapsed_ms"])
|
| 123 |
+
writer.writeheader()
|
| 124 |
+
writer.writerows(out_rows)
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def run(cfg: Config) -> None:
|
| 128 |
+
images = list(iter_images(cfg.images))
|
| 129 |
+
if not images:
|
| 130 |
+
raise SystemExit("No images found.")
|
| 131 |
+
if not cfg.label_sets:
|
| 132 |
+
raise SystemExit("No label sets found.")
|
| 133 |
+
|
| 134 |
+
rows: list[dict[str, str]] = []
|
| 135 |
+
with httpx.Client(base_url=cfg.api, timeout=30) as client:
|
| 136 |
+
for label_set in cfg.label_sets:
|
| 137 |
+
label_set_hash = upload_label_set(client, label_set)
|
| 138 |
+
for image in images:
|
| 139 |
+
image_b64 = image.read_bytes()
|
| 140 |
+
data = classify_one(
|
| 141 |
+
client,
|
| 142 |
+
label_set_hash,
|
| 143 |
+
image_b64=base64.b64encode(image_b64).decode("utf-8"),
|
| 144 |
+
domain_top_n=cfg.domain_top_n,
|
| 145 |
+
top_k=cfg.top_k,
|
| 146 |
+
)
|
| 147 |
+
print(json.dumps({"label_set": label_set.name, "image": str(image), "result": data}))
|
| 148 |
+
rows.append(to_row(label_set, image, data))
|
| 149 |
+
|
| 150 |
+
out_path = cfg.out_dir / "eval_matrix.csv"
|
| 151 |
+
write_csv(out_path, rows)
|
| 152 |
+
if cfg.summary_csv:
|
| 153 |
+
write_summary(cfg.summary_csv, rows)
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
@click.command()
|
| 157 |
+
@click.option("--api", default="http://localhost:7860", show_default=True)
|
| 158 |
+
@click.option("--label-sets", "label_sets_raw", multiple=True, required=True)
|
| 159 |
+
@click.option("--images", multiple=True, required=True, type=click.Path(path_type=Path))
|
| 160 |
+
@click.option("--domain-top-n", default=2, show_default=True, type=int)
|
| 161 |
+
@click.option("--top-k", default=5, show_default=True, type=int)
|
| 162 |
+
@click.option("--out-dir", default="data_results", show_default=True, type=click.Path(path_type=Path))
|
| 163 |
+
@click.option("--summary-csv", type=click.Path(path_type=Path))
|
| 164 |
+
def cli(
|
| 165 |
+
api: str,
|
| 166 |
+
label_sets_raw: tuple[str, ...],
|
| 167 |
+
images: tuple[Path, ...],
|
| 168 |
+
domain_top_n: int,
|
| 169 |
+
top_k: int,
|
| 170 |
+
out_dir: Path,
|
| 171 |
+
summary_csv: Path | None,
|
| 172 |
+
) -> None:
|
| 173 |
+
label_sets = expand_label_sets(label_sets_raw)
|
| 174 |
+
cfg = Config(
|
| 175 |
+
api=api,
|
| 176 |
+
label_sets=label_sets,
|
| 177 |
+
images=list(images),
|
| 178 |
+
domain_top_n=domain_top_n,
|
| 179 |
+
top_k=top_k,
|
| 180 |
+
out_dir=out_dir,
|
| 181 |
+
summary_csv=summary_csv,
|
| 182 |
+
)
|
| 183 |
+
run(cfg)
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
if __name__ == "__main__":
|
| 187 |
+
cli()
|
src/photo_classification.egg-info/PKG-INFO
CHANGED
|
@@ -11,8 +11,12 @@ 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
|
|
@@ -168,6 +172,46 @@ Error handling and HTTP boundaries:
|
|
| 168 |
- `pytest -q`
|
| 169 |
- `pytest -q -m integration`
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
## Project layout
|
| 172 |
|
| 173 |
```
|
|
|
|
| 11 |
Requires-Dist: transformers==4.44.2
|
| 12 |
Requires-Dist: uvicorn[standard]==0.30.6
|
| 13 |
Provides-Extra: dev
|
| 14 |
+
Requires-Dist: click==8.1.7; extra == "dev"
|
| 15 |
+
Requires-Dist: datasets==2.21.0; extra == "dev"
|
| 16 |
Requires-Dist: httpx==0.27.2; extra == "dev"
|
| 17 |
Requires-Dist: pytest==8.3.2; extra == "dev"
|
| 18 |
+
Requires-Dist: requests==2.32.3; extra == "dev"
|
| 19 |
+
Requires-Dist: tqdm==4.66.5; extra == "dev"
|
| 20 |
|
| 21 |
---
|
| 22 |
title: Photo Classification API
|
|
|
|
| 172 |
- `pytest -q`
|
| 173 |
- `pytest -q -m integration`
|
| 174 |
|
| 175 |
+
## Eval scripts
|
| 176 |
+
|
| 177 |
+
Use the lightweight evaluator in `scripts/classify_dataset.py` to run a label set against
|
| 178 |
+
local images and capture timings:
|
| 179 |
+
|
| 180 |
+
```bash
|
| 181 |
+
uv run python scripts/classify_dataset.py \
|
| 182 |
+
--label-set label-dataset/personal-photos-lite-v1.json \
|
| 183 |
+
--images /path/to/images \
|
| 184 |
+
--csv results/summary.csv
|
| 185 |
+
```
|
| 186 |
+
|
| 187 |
+
Makefile shortcuts:
|
| 188 |
+
|
| 189 |
+
- `make eval-photo-v1`
|
| 190 |
+
- `make eval-dance-v1`
|
| 191 |
+
|
| 192 |
+
## Eval datasets (download schema)
|
| 193 |
+
|
| 194 |
+
We use a simple, reproducible layout for evaluation datasets created by `scripts/dataset_prep.py`:
|
| 195 |
+
|
| 196 |
+
```
|
| 197 |
+
data_eval/
|
| 198 |
+
photos/ # normalized images from Open Images V7 sample
|
| 199 |
+
dance/ # normalized images from X-Dance sample
|
| 200 |
+
```
|
| 201 |
+
|
| 202 |
+
Download and normalize (recommended):
|
| 203 |
+
|
| 204 |
+
```bash
|
| 205 |
+
uv run python scripts/dataset_prep.py --out data_eval --target photos --n 800 --normalize
|
| 206 |
+
uv run python scripts/dataset_prep.py --out data_eval --target dance --n 800 --normalize
|
| 207 |
+
```
|
| 208 |
+
|
| 209 |
+
Normalize your own folder into the same schema:
|
| 210 |
+
|
| 211 |
+
```bash
|
| 212 |
+
uv run python scripts/dataset_prep.py --normalize-only --in-dir /path/to/images --out data_eval/photos
|
| 213 |
+
```
|
| 214 |
+
|
| 215 |
## Project layout
|
| 216 |
|
| 217 |
```
|
src/photo_classification.egg-info/requires.txt
CHANGED
|
@@ -6,5 +6,9 @@ transformers==4.44.2
|
|
| 6 |
uvicorn[standard]==0.30.6
|
| 7 |
|
| 8 |
[dev]
|
|
|
|
|
|
|
| 9 |
httpx==0.27.2
|
| 10 |
pytest==8.3.2
|
|
|
|
|
|
|
|
|
| 6 |
uvicorn[standard]==0.30.6
|
| 7 |
|
| 8 |
[dev]
|
| 9 |
+
click==8.1.7
|
| 10 |
+
datasets==2.21.0
|
| 11 |
httpx==0.27.2
|
| 12 |
pytest==8.3.2
|
| 13 |
+
requests==2.32.3
|
| 14 |
+
tqdm==4.66.5
|
uv.lock
CHANGED
|
@@ -2,6 +2,62 @@ version = 1
|
|
| 2 |
revision = 2
|
| 3 |
requires-python = "==3.12.*"
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
[[package]]
|
| 6 |
name = "annotated-types"
|
| 7 |
version = "0.7.0"
|
|
@@ -24,6 +80,15 @@ 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"
|
|
@@ -60,14 +125,14 @@ wheels = [
|
|
| 60 |
|
| 61 |
[[package]]
|
| 62 |
name = "click"
|
| 63 |
-
version = "8.
|
| 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/
|
| 69 |
wheels = [
|
| 70 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 71 |
]
|
| 72 |
|
| 73 |
[[package]]
|
|
@@ -79,6 +144,40 @@ 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"
|
|
@@ -102,13 +201,43 @@ 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 = "
|
| 108 |
source = { registry = "https://pypi.org/simple" }
|
| 109 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 110 |
wheels = [
|
| 111 |
-
{ url = "https://files.pythonhosted.org/packages/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
]
|
| 113 |
|
| 114 |
[[package]]
|
|
@@ -278,6 +407,49 @@ 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"
|
|
@@ -422,6 +594,27 @@ 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"
|
|
@@ -437,18 +630,26 @@ dependencies = [
|
|
| 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 |
]
|
|
@@ -482,6 +683,45 @@ 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"
|
|
@@ -534,6 +774,18 @@ 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"
|
|
@@ -543,6 +795,15 @@ 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"
|
|
@@ -587,7 +848,7 @@ wheels = [
|
|
| 587 |
|
| 588 |
[[package]]
|
| 589 |
name = "requests"
|
| 590 |
-
version = "2.32.
|
| 591 |
source = { registry = "https://pypi.org/simple" }
|
| 592 |
dependencies = [
|
| 593 |
{ name = "certifi" },
|
|
@@ -595,9 +856,9 @@ dependencies = [
|
|
| 595 |
{ name = "idna" },
|
| 596 |
{ name = "urllib3" },
|
| 597 |
]
|
| 598 |
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
| 599 |
wheels = [
|
| 600 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 601 |
]
|
| 602 |
|
| 603 |
[[package]]
|
|
@@ -622,6 +883,15 @@ wheels = [
|
|
| 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"
|
|
@@ -720,14 +990,14 @@ wheels = [
|
|
| 720 |
|
| 721 |
[[package]]
|
| 722 |
name = "tqdm"
|
| 723 |
-
version = "4.
|
| 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/
|
| 729 |
wheels = [
|
| 730 |
-
{ url = "https://files.pythonhosted.org/packages/
|
| 731 |
]
|
| 732 |
|
| 733 |
[[package]]
|
|
@@ -760,6 +1030,15 @@ 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"
|
|
@@ -848,3 +1127,56 @@ wheels = [
|
|
| 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 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
revision = 2
|
| 3 |
requires-python = "==3.12.*"
|
| 4 |
|
| 5 |
+
[[package]]
|
| 6 |
+
name = "aiohappyeyeballs"
|
| 7 |
+
version = "2.6.1"
|
| 8 |
+
source = { registry = "https://pypi.org/simple" }
|
| 9 |
+
sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" }
|
| 10 |
+
wheels = [
|
| 11 |
+
{ url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" },
|
| 12 |
+
]
|
| 13 |
+
|
| 14 |
+
[[package]]
|
| 15 |
+
name = "aiohttp"
|
| 16 |
+
version = "3.13.3"
|
| 17 |
+
source = { registry = "https://pypi.org/simple" }
|
| 18 |
+
dependencies = [
|
| 19 |
+
{ name = "aiohappyeyeballs" },
|
| 20 |
+
{ name = "aiosignal" },
|
| 21 |
+
{ name = "attrs" },
|
| 22 |
+
{ name = "frozenlist" },
|
| 23 |
+
{ name = "multidict" },
|
| 24 |
+
{ name = "propcache" },
|
| 25 |
+
{ name = "yarl" },
|
| 26 |
+
]
|
| 27 |
+
sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" }
|
| 28 |
+
wheels = [
|
| 29 |
+
{ url = "https://files.pythonhosted.org/packages/a0/be/4fc11f202955a69e0db803a12a062b8379c970c7c84f4882b6da17337cc1/aiohttp-3.13.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:b903a4dfee7d347e2d87697d0713be59e0b87925be030c9178c5faa58ea58d5c", size = 739732, upload-time = "2026-01-03T17:30:14.23Z" },
|
| 30 |
+
{ url = "https://files.pythonhosted.org/packages/97/2c/621d5b851f94fa0bb7430d6089b3aa970a9d9b75196bc93bb624b0db237a/aiohttp-3.13.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a45530014d7a1e09f4a55f4f43097ba0fd155089372e105e4bff4ca76cb1b168", size = 494293, upload-time = "2026-01-03T17:30:15.96Z" },
|
| 31 |
+
{ url = "https://files.pythonhosted.org/packages/5d/43/4be01406b78e1be8320bb8316dc9c42dbab553d281c40364e0f862d5661c/aiohttp-3.13.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27234ef6d85c914f9efeb77ff616dbf4ad2380be0cda40b4db086ffc7ddd1b7d", size = 493533, upload-time = "2026-01-03T17:30:17.431Z" },
|
| 32 |
+
{ url = "https://files.pythonhosted.org/packages/8d/a8/5a35dc56a06a2c90d4742cbf35294396907027f80eea696637945a106f25/aiohttp-3.13.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d32764c6c9aafb7fb55366a224756387cd50bfa720f32b88e0e6fa45b27dcf29", size = 1737839, upload-time = "2026-01-03T17:30:19.422Z" },
|
| 33 |
+
{ url = "https://files.pythonhosted.org/packages/bf/62/4b9eeb331da56530bf2e198a297e5303e1c1ebdceeb00fe9b568a65c5a0c/aiohttp-3.13.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b1a6102b4d3ebc07dad44fbf07b45bb600300f15b552ddf1851b5390202ea2e3", size = 1703932, upload-time = "2026-01-03T17:30:21.756Z" },
|
| 34 |
+
{ url = "https://files.pythonhosted.org/packages/7c/f6/af16887b5d419e6a367095994c0b1332d154f647e7dc2bd50e61876e8e3d/aiohttp-3.13.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c014c7ea7fb775dd015b2d3137378b7be0249a448a1612268b5a90c2d81de04d", size = 1771906, upload-time = "2026-01-03T17:30:23.932Z" },
|
| 35 |
+
{ url = "https://files.pythonhosted.org/packages/ce/83/397c634b1bcc24292fa1e0c7822800f9f6569e32934bdeef09dae7992dfb/aiohttp-3.13.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2b8d8ddba8f95ba17582226f80e2de99c7a7948e66490ef8d947e272a93e9463", size = 1871020, upload-time = "2026-01-03T17:30:26Z" },
|
| 36 |
+
{ url = "https://files.pythonhosted.org/packages/86/f6/a62cbbf13f0ac80a70f71b1672feba90fdb21fd7abd8dbf25c0105fb6fa3/aiohttp-3.13.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ae8dd55c8e6c4257eae3a20fd2c8f41edaea5992ed67156642493b8daf3cecc", size = 1755181, upload-time = "2026-01-03T17:30:27.554Z" },
|
| 37 |
+
{ url = "https://files.pythonhosted.org/packages/0a/87/20a35ad487efdd3fba93d5843efdfaa62d2f1479eaafa7453398a44faf13/aiohttp-3.13.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:01ad2529d4b5035578f5081606a465f3b814c542882804e2e8cda61adf5c71bf", size = 1561794, upload-time = "2026-01-03T17:30:29.254Z" },
|
| 38 |
+
{ url = "https://files.pythonhosted.org/packages/de/95/8fd69a66682012f6716e1bc09ef8a1a2a91922c5725cb904689f112309c4/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bb4f7475e359992b580559e008c598091c45b5088f28614e855e42d39c2f1033", size = 1697900, upload-time = "2026-01-03T17:30:31.033Z" },
|
| 39 |
+
{ url = "https://files.pythonhosted.org/packages/e5/66/7b94b3b5ba70e955ff597672dad1691333080e37f50280178967aff68657/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c19b90316ad3b24c69cd78d5c9b4f3aa4497643685901185b65166293d36a00f", size = 1728239, upload-time = "2026-01-03T17:30:32.703Z" },
|
| 40 |
+
{ url = "https://files.pythonhosted.org/packages/47/71/6f72f77f9f7d74719692ab65a2a0252584bf8d5f301e2ecb4c0da734530a/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:96d604498a7c782cb15a51c406acaea70d8c027ee6b90c569baa6e7b93073679", size = 1740527, upload-time = "2026-01-03T17:30:34.695Z" },
|
| 41 |
+
{ url = "https://files.pythonhosted.org/packages/fa/b4/75ec16cbbd5c01bdaf4a05b19e103e78d7ce1ef7c80867eb0ace42ff4488/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:084911a532763e9d3dd95adf78a78f4096cd5f58cdc18e6fdbc1b58417a45423", size = 1554489, upload-time = "2026-01-03T17:30:36.864Z" },
|
| 42 |
+
{ url = "https://files.pythonhosted.org/packages/52/8f/bc518c0eea29f8406dcf7ed1f96c9b48e3bc3995a96159b3fc11f9e08321/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7a4a94eb787e606d0a09404b9c38c113d3b099d508021faa615d70a0131907ce", size = 1767852, upload-time = "2026-01-03T17:30:39.433Z" },
|
| 43 |
+
{ url = "https://files.pythonhosted.org/packages/9d/f2/a07a75173124f31f11ea6f863dc44e6f09afe2bca45dd4e64979490deab1/aiohttp-3.13.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:87797e645d9d8e222e04160ee32aa06bc5c163e8499f24db719e7852ec23093a", size = 1722379, upload-time = "2026-01-03T17:30:41.081Z" },
|
| 44 |
+
{ url = "https://files.pythonhosted.org/packages/3c/4a/1a3fee7c21350cac78e5c5cef711bac1b94feca07399f3d406972e2d8fcd/aiohttp-3.13.3-cp312-cp312-win32.whl", hash = "sha256:b04be762396457bef43f3597c991e192ee7da460a4953d7e647ee4b1c28e7046", size = 428253, upload-time = "2026-01-03T17:30:42.644Z" },
|
| 45 |
+
{ url = "https://files.pythonhosted.org/packages/d9/b7/76175c7cb4eb73d91ad63c34e29fc4f77c9386bba4a65b53ba8e05ee3c39/aiohttp-3.13.3-cp312-cp312-win_amd64.whl", hash = "sha256:e3531d63d3bdfa7e3ac5e9b27b2dd7ec9df3206a98e0b3445fa906f233264c57", size = 455407, upload-time = "2026-01-03T17:30:44.195Z" },
|
| 46 |
+
]
|
| 47 |
+
|
| 48 |
+
[[package]]
|
| 49 |
+
name = "aiosignal"
|
| 50 |
+
version = "1.4.0"
|
| 51 |
+
source = { registry = "https://pypi.org/simple" }
|
| 52 |
+
dependencies = [
|
| 53 |
+
{ name = "frozenlist" },
|
| 54 |
+
{ name = "typing-extensions" },
|
| 55 |
+
]
|
| 56 |
+
sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" }
|
| 57 |
+
wheels = [
|
| 58 |
+
{ url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" },
|
| 59 |
+
]
|
| 60 |
+
|
| 61 |
[[package]]
|
| 62 |
name = "annotated-types"
|
| 63 |
version = "0.7.0"
|
|
|
|
| 80 |
{ 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" },
|
| 81 |
]
|
| 82 |
|
| 83 |
+
[[package]]
|
| 84 |
+
name = "attrs"
|
| 85 |
+
version = "25.4.0"
|
| 86 |
+
source = { registry = "https://pypi.org/simple" }
|
| 87 |
+
sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" }
|
| 88 |
+
wheels = [
|
| 89 |
+
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
|
| 90 |
+
]
|
| 91 |
+
|
| 92 |
[[package]]
|
| 93 |
name = "certifi"
|
| 94 |
version = "2026.1.4"
|
|
|
|
| 125 |
|
| 126 |
[[package]]
|
| 127 |
name = "click"
|
| 128 |
+
version = "8.1.7"
|
| 129 |
source = { registry = "https://pypi.org/simple" }
|
| 130 |
dependencies = [
|
| 131 |
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 132 |
]
|
| 133 |
+
sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121, upload-time = "2023-08-17T17:29:11.868Z" }
|
| 134 |
wheels = [
|
| 135 |
+
{ url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941, upload-time = "2023-08-17T17:29:10.08Z" },
|
| 136 |
]
|
| 137 |
|
| 138 |
[[package]]
|
|
|
|
| 144 |
{ 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" },
|
| 145 |
]
|
| 146 |
|
| 147 |
+
[[package]]
|
| 148 |
+
name = "datasets"
|
| 149 |
+
version = "2.21.0"
|
| 150 |
+
source = { registry = "https://pypi.org/simple" }
|
| 151 |
+
dependencies = [
|
| 152 |
+
{ name = "aiohttp" },
|
| 153 |
+
{ name = "dill" },
|
| 154 |
+
{ name = "filelock" },
|
| 155 |
+
{ name = "fsspec", extra = ["http"] },
|
| 156 |
+
{ name = "huggingface-hub" },
|
| 157 |
+
{ name = "multiprocess" },
|
| 158 |
+
{ name = "numpy" },
|
| 159 |
+
{ name = "packaging" },
|
| 160 |
+
{ name = "pandas" },
|
| 161 |
+
{ name = "pyarrow" },
|
| 162 |
+
{ name = "pyyaml" },
|
| 163 |
+
{ name = "requests" },
|
| 164 |
+
{ name = "tqdm" },
|
| 165 |
+
{ name = "xxhash" },
|
| 166 |
+
]
|
| 167 |
+
sdist = { url = "https://files.pythonhosted.org/packages/e5/a5/38719e5cff7aa0537a6be37d21cc1fdd7096e9565e8fce2d46a822e10b5b/datasets-2.21.0.tar.gz", hash = "sha256:998f85a8460f1bd982e5bd058f8a0808eef424249e3df1e8cdd594ccd0dc8ba2", size = 2215317, upload-time = "2024-08-14T06:40:44.314Z" }
|
| 168 |
+
wheels = [
|
| 169 |
+
{ url = "https://files.pythonhosted.org/packages/72/b3/33c4ad44fa020e3757e9b2fad8a5de53d9079b501e6bbc45bdd18f82f893/datasets-2.21.0-py3-none-any.whl", hash = "sha256:25e4e097110ce28824b746a107727ada94024cba11db8bc588d468414692b65a", size = 527251, upload-time = "2024-08-14T06:40:39.612Z" },
|
| 170 |
+
]
|
| 171 |
+
|
| 172 |
+
[[package]]
|
| 173 |
+
name = "dill"
|
| 174 |
+
version = "0.3.8"
|
| 175 |
+
source = { registry = "https://pypi.org/simple" }
|
| 176 |
+
sdist = { url = "https://files.pythonhosted.org/packages/17/4d/ac7ffa80c69ea1df30a8aa11b3578692a5118e7cd1aa157e3ef73b092d15/dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", size = 184847, upload-time = "2024-01-27T23:42:16.145Z" }
|
| 177 |
+
wheels = [
|
| 178 |
+
{ url = "https://files.pythonhosted.org/packages/c9/7a/cef76fd8438a42f96db64ddaa85280485a9c395e7df3db8158cfec1eee34/dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7", size = 116252, upload-time = "2024-01-27T23:42:14.239Z" },
|
| 179 |
+
]
|
| 180 |
+
|
| 181 |
[[package]]
|
| 182 |
name = "fastapi"
|
| 183 |
version = "0.115.6"
|
|
|
|
| 201 |
{ 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" },
|
| 202 |
]
|
| 203 |
|
| 204 |
+
[[package]]
|
| 205 |
+
name = "frozenlist"
|
| 206 |
+
version = "1.8.0"
|
| 207 |
+
source = { registry = "https://pypi.org/simple" }
|
| 208 |
+
sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" }
|
| 209 |
+
wheels = [
|
| 210 |
+
{ url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" },
|
| 211 |
+
{ url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" },
|
| 212 |
+
{ url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" },
|
| 213 |
+
{ url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" },
|
| 214 |
+
{ url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" },
|
| 215 |
+
{ url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" },
|
| 216 |
+
{ url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" },
|
| 217 |
+
{ url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" },
|
| 218 |
+
{ url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" },
|
| 219 |
+
{ url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" },
|
| 220 |
+
{ url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" },
|
| 221 |
+
{ url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" },
|
| 222 |
+
{ url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" },
|
| 223 |
+
{ url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" },
|
| 224 |
+
{ url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" },
|
| 225 |
+
{ url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" },
|
| 226 |
+
{ url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" },
|
| 227 |
+
]
|
| 228 |
+
|
| 229 |
[[package]]
|
| 230 |
name = "fsspec"
|
| 231 |
+
version = "2024.6.1"
|
| 232 |
source = { registry = "https://pypi.org/simple" }
|
| 233 |
+
sdist = { url = "https://files.pythonhosted.org/packages/90/b6/eba5024a9889fcfff396db543a34bef0ab9d002278f163129f9f01005960/fsspec-2024.6.1.tar.gz", hash = "sha256:fad7d7e209dd4c1208e3bbfda706620e0da5142bebbd9c384afb95b07e798e49", size = 284584, upload-time = "2024-06-27T14:35:45.467Z" }
|
| 234 |
wheels = [
|
| 235 |
+
{ url = "https://files.pythonhosted.org/packages/5e/44/73bea497ac69bafde2ee4269292fa3b41f1198f4bb7bbaaabde30ad29d4a/fsspec-2024.6.1-py3-none-any.whl", hash = "sha256:3cb443f8bcd2efb31295a5b9fdb02aee81d8452c80d28f97a6d0959e6cee101e", size = 177561, upload-time = "2024-06-27T14:35:42.023Z" },
|
| 236 |
+
]
|
| 237 |
+
|
| 238 |
+
[package.optional-dependencies]
|
| 239 |
+
http = [
|
| 240 |
+
{ name = "aiohttp" },
|
| 241 |
]
|
| 242 |
|
| 243 |
[[package]]
|
|
|
|
| 407 |
{ 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" },
|
| 408 |
]
|
| 409 |
|
| 410 |
+
[[package]]
|
| 411 |
+
name = "multidict"
|
| 412 |
+
version = "6.7.0"
|
| 413 |
+
source = { registry = "https://pypi.org/simple" }
|
| 414 |
+
sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" }
|
| 415 |
+
wheels = [
|
| 416 |
+
{ url = "https://files.pythonhosted.org/packages/c2/9e/9f61ac18d9c8b475889f32ccfa91c9f59363480613fc807b6e3023d6f60b/multidict-6.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8a3862568a36d26e650a19bb5cbbba14b71789032aebc0423f8cc5f150730184", size = 76877, upload-time = "2025-10-06T14:49:20.884Z" },
|
| 417 |
+
{ url = "https://files.pythonhosted.org/packages/38/6f/614f09a04e6184f8824268fce4bc925e9849edfa654ddd59f0b64508c595/multidict-6.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:960c60b5849b9b4f9dcc9bea6e3626143c252c74113df2c1540aebce70209b45", size = 45467, upload-time = "2025-10-06T14:49:22.054Z" },
|
| 418 |
+
{ url = "https://files.pythonhosted.org/packages/b3/93/c4f67a436dd026f2e780c433277fff72be79152894d9fc36f44569cab1a6/multidict-6.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2049be98fb57a31b4ccf870bf377af2504d4ae35646a19037ec271e4c07998aa", size = 43834, upload-time = "2025-10-06T14:49:23.566Z" },
|
| 419 |
+
{ url = "https://files.pythonhosted.org/packages/7f/f5/013798161ca665e4a422afbc5e2d9e4070142a9ff8905e482139cd09e4d0/multidict-6.7.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0934f3843a1860dd465d38895c17fce1f1cb37295149ab05cd1b9a03afacb2a7", size = 250545, upload-time = "2025-10-06T14:49:24.882Z" },
|
| 420 |
+
{ url = "https://files.pythonhosted.org/packages/71/2f/91dbac13e0ba94669ea5119ba267c9a832f0cb65419aca75549fcf09a3dc/multidict-6.7.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b3e34f3a1b8131ba06f1a73adab24f30934d148afcd5f5de9a73565a4404384e", size = 258305, upload-time = "2025-10-06T14:49:26.778Z" },
|
| 421 |
+
{ url = "https://files.pythonhosted.org/packages/ef/b0/754038b26f6e04488b48ac621f779c341338d78503fb45403755af2df477/multidict-6.7.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:efbb54e98446892590dc2458c19c10344ee9a883a79b5cec4bc34d6656e8d546", size = 242363, upload-time = "2025-10-06T14:49:28.562Z" },
|
| 422 |
+
{ url = "https://files.pythonhosted.org/packages/87/15/9da40b9336a7c9fa606c4cf2ed80a649dffeb42b905d4f63a1d7eb17d746/multidict-6.7.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a35c5fc61d4f51eb045061e7967cfe3123d622cd500e8868e7c0c592a09fedc4", size = 268375, upload-time = "2025-10-06T14:49:29.96Z" },
|
| 423 |
+
{ url = "https://files.pythonhosted.org/packages/82/72/c53fcade0cc94dfaad583105fd92b3a783af2091eddcb41a6d5a52474000/multidict-6.7.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29fe6740ebccba4175af1b9b87bf553e9c15cd5868ee967e010efcf94e4fd0f1", size = 269346, upload-time = "2025-10-06T14:49:31.404Z" },
|
| 424 |
+
{ url = "https://files.pythonhosted.org/packages/0d/e2/9baffdae21a76f77ef8447f1a05a96ec4bc0a24dae08767abc0a2fe680b8/multidict-6.7.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:123e2a72e20537add2f33a79e605f6191fba2afda4cbb876e35c1a7074298a7d", size = 256107, upload-time = "2025-10-06T14:49:32.974Z" },
|
| 425 |
+
{ url = "https://files.pythonhosted.org/packages/3c/06/3f06f611087dc60d65ef775f1fb5aca7c6d61c6db4990e7cda0cef9b1651/multidict-6.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b284e319754366c1aee2267a2036248b24eeb17ecd5dc16022095e747f2f4304", size = 253592, upload-time = "2025-10-06T14:49:34.52Z" },
|
| 426 |
+
{ url = "https://files.pythonhosted.org/packages/20/24/54e804ec7945b6023b340c412ce9c3f81e91b3bf5fa5ce65558740141bee/multidict-6.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:803d685de7be4303b5a657b76e2f6d1240e7e0a8aa2968ad5811fa2285553a12", size = 251024, upload-time = "2025-10-06T14:49:35.956Z" },
|
| 427 |
+
{ url = "https://files.pythonhosted.org/packages/14/48/011cba467ea0b17ceb938315d219391d3e421dfd35928e5dbdc3f4ae76ef/multidict-6.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c04a328260dfd5db8c39538f999f02779012268f54614902d0afc775d44e0a62", size = 251484, upload-time = "2025-10-06T14:49:37.631Z" },
|
| 428 |
+
{ url = "https://files.pythonhosted.org/packages/0d/2f/919258b43bb35b99fa127435cfb2d91798eb3a943396631ef43e3720dcf4/multidict-6.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8a19cdb57cd3df4cd865849d93ee14920fb97224300c88501f16ecfa2604b4e0", size = 263579, upload-time = "2025-10-06T14:49:39.502Z" },
|
| 429 |
+
{ url = "https://files.pythonhosted.org/packages/31/22/a0e884d86b5242b5a74cf08e876bdf299e413016b66e55511f7a804a366e/multidict-6.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b2fd74c52accced7e75de26023b7dccee62511a600e62311b918ec5c168fc2a", size = 259654, upload-time = "2025-10-06T14:49:41.32Z" },
|
| 430 |
+
{ url = "https://files.pythonhosted.org/packages/b2/e5/17e10e1b5c5f5a40f2fcbb45953c9b215f8a4098003915e46a93f5fcaa8f/multidict-6.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3e8bfdd0e487acf992407a140d2589fe598238eaeffa3da8448d63a63cd363f8", size = 251511, upload-time = "2025-10-06T14:49:46.021Z" },
|
| 431 |
+
{ url = "https://files.pythonhosted.org/packages/e3/9a/201bb1e17e7af53139597069c375e7b0dcbd47594604f65c2d5359508566/multidict-6.7.0-cp312-cp312-win32.whl", hash = "sha256:dd32a49400a2c3d52088e120ee00c1e3576cbff7e10b98467962c74fdb762ed4", size = 41895, upload-time = "2025-10-06T14:49:48.718Z" },
|
| 432 |
+
{ url = "https://files.pythonhosted.org/packages/46/e2/348cd32faad84eaf1d20cce80e2bb0ef8d312c55bca1f7fa9865e7770aaf/multidict-6.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:92abb658ef2d7ef22ac9f8bb88e8b6c3e571671534e029359b6d9e845923eb1b", size = 46073, upload-time = "2025-10-06T14:49:50.28Z" },
|
| 433 |
+
{ url = "https://files.pythonhosted.org/packages/25/ec/aad2613c1910dce907480e0c3aa306905830f25df2e54ccc9dea450cb5aa/multidict-6.7.0-cp312-cp312-win_arm64.whl", hash = "sha256:490dab541a6a642ce1a9d61a4781656b346a55c13038f0b1244653828e3a83ec", size = 43226, upload-time = "2025-10-06T14:49:52.304Z" },
|
| 434 |
+
{ url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" },
|
| 435 |
+
]
|
| 436 |
+
|
| 437 |
+
[[package]]
|
| 438 |
+
name = "multiprocess"
|
| 439 |
+
version = "0.70.16"
|
| 440 |
+
source = { registry = "https://pypi.org/simple" }
|
| 441 |
+
dependencies = [
|
| 442 |
+
{ name = "dill" },
|
| 443 |
+
]
|
| 444 |
+
sdist = { url = "https://files.pythonhosted.org/packages/b5/ae/04f39c5d0d0def03247c2893d6f2b83c136bf3320a2154d7b8858f2ba72d/multiprocess-0.70.16.tar.gz", hash = "sha256:161af703d4652a0e1410be6abccecde4a7ddffd19341be0a7011b94aeb171ac1", size = 1772603, upload-time = "2024-01-28T18:52:34.85Z" }
|
| 445 |
+
wheels = [
|
| 446 |
+
{ url = "https://files.pythonhosted.org/packages/bc/f7/7ec7fddc92e50714ea3745631f79bd9c96424cb2702632521028e57d3a36/multiprocess-0.70.16-py310-none-any.whl", hash = "sha256:c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02", size = 134824, upload-time = "2024-01-28T18:52:26.062Z" },
|
| 447 |
+
{ url = "https://files.pythonhosted.org/packages/50/15/b56e50e8debaf439f44befec5b2af11db85f6e0f344c3113ae0be0593a91/multiprocess-0.70.16-py311-none-any.whl", hash = "sha256:af4cabb0dac72abfb1e794fa7855c325fd2b55a10a44628a3c1ad3311c04127a", size = 143519, upload-time = "2024-01-28T18:52:28.115Z" },
|
| 448 |
+
{ url = "https://files.pythonhosted.org/packages/0a/7d/a988f258104dcd2ccf1ed40fdc97e26c4ac351eeaf81d76e266c52d84e2f/multiprocess-0.70.16-py312-none-any.whl", hash = "sha256:fc0544c531920dde3b00c29863377f87e1632601092ea2daca74e4beb40faa2e", size = 146741, upload-time = "2024-01-28T18:52:29.395Z" },
|
| 449 |
+
{ url = "https://files.pythonhosted.org/packages/ea/89/38df130f2c799090c978b366cfdf5b96d08de5b29a4a293df7f7429fa50b/multiprocess-0.70.16-py38-none-any.whl", hash = "sha256:a71d82033454891091a226dfc319d0cfa8019a4e888ef9ca910372a446de4435", size = 132628, upload-time = "2024-01-28T18:52:30.853Z" },
|
| 450 |
+
{ url = "https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", size = 133351, upload-time = "2024-01-28T18:52:31.981Z" },
|
| 451 |
+
]
|
| 452 |
+
|
| 453 |
[[package]]
|
| 454 |
name = "networkx"
|
| 455 |
version = "3.6.1"
|
|
|
|
| 594 |
{ 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" },
|
| 595 |
]
|
| 596 |
|
| 597 |
+
[[package]]
|
| 598 |
+
name = "pandas"
|
| 599 |
+
version = "2.3.3"
|
| 600 |
+
source = { registry = "https://pypi.org/simple" }
|
| 601 |
+
dependencies = [
|
| 602 |
+
{ name = "numpy" },
|
| 603 |
+
{ name = "python-dateutil" },
|
| 604 |
+
{ name = "pytz" },
|
| 605 |
+
{ name = "tzdata" },
|
| 606 |
+
]
|
| 607 |
+
sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" }
|
| 608 |
+
wheels = [
|
| 609 |
+
{ url = "https://files.pythonhosted.org/packages/9c/fb/231d89e8637c808b997d172b18e9d4a4bc7bf31296196c260526055d1ea0/pandas-2.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d21f6d74eb1725c2efaa71a2bfc661a0689579b58e9c0ca58a739ff0b002b53", size = 11597846, upload-time = "2025-09-29T23:19:48.856Z" },
|
| 610 |
+
{ url = "https://files.pythonhosted.org/packages/5c/bd/bf8064d9cfa214294356c2d6702b716d3cf3bb24be59287a6a21e24cae6b/pandas-2.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3fd2f887589c7aa868e02632612ba39acb0b8948faf5cc58f0850e165bd46f35", size = 10729618, upload-time = "2025-09-29T23:39:08.659Z" },
|
| 611 |
+
{ url = "https://files.pythonhosted.org/packages/57/56/cf2dbe1a3f5271370669475ead12ce77c61726ffd19a35546e31aa8edf4e/pandas-2.3.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ecaf1e12bdc03c86ad4a7ea848d66c685cb6851d807a26aa245ca3d2017a1908", size = 11737212, upload-time = "2025-09-29T23:19:59.765Z" },
|
| 612 |
+
{ url = "https://files.pythonhosted.org/packages/e5/63/cd7d615331b328e287d8233ba9fdf191a9c2d11b6af0c7a59cfcec23de68/pandas-2.3.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b3d11d2fda7eb164ef27ffc14b4fcab16a80e1ce67e9f57e19ec0afaf715ba89", size = 12362693, upload-time = "2025-09-29T23:20:14.098Z" },
|
| 613 |
+
{ url = "https://files.pythonhosted.org/packages/a6/de/8b1895b107277d52f2b42d3a6806e69cfef0d5cf1d0ba343470b9d8e0a04/pandas-2.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a68e15f780eddf2b07d242e17a04aa187a7ee12b40b930bfdd78070556550e98", size = 12771002, upload-time = "2025-09-29T23:20:26.76Z" },
|
| 614 |
+
{ url = "https://files.pythonhosted.org/packages/87/21/84072af3187a677c5893b170ba2c8fbe450a6ff911234916da889b698220/pandas-2.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:371a4ab48e950033bcf52b6527eccb564f52dc826c02afd9a1bc0ab731bba084", size = 13450971, upload-time = "2025-09-29T23:20:41.344Z" },
|
| 615 |
+
{ url = "https://files.pythonhosted.org/packages/86/41/585a168330ff063014880a80d744219dbf1dd7a1c706e75ab3425a987384/pandas-2.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:a16dcec078a01eeef8ee61bf64074b4e524a2a3f4b3be9326420cabe59c4778b", size = 10992722, upload-time = "2025-09-29T23:20:54.139Z" },
|
| 616 |
+
]
|
| 617 |
+
|
| 618 |
[[package]]
|
| 619 |
name = "photo-classification"
|
| 620 |
version = "0.1.0"
|
|
|
|
| 630 |
|
| 631 |
[package.optional-dependencies]
|
| 632 |
dev = [
|
| 633 |
+
{ name = "click" },
|
| 634 |
+
{ name = "datasets" },
|
| 635 |
{ name = "httpx" },
|
| 636 |
{ name = "pytest" },
|
| 637 |
+
{ name = "requests" },
|
| 638 |
+
{ name = "tqdm" },
|
| 639 |
]
|
| 640 |
|
| 641 |
[package.metadata]
|
| 642 |
requires-dist = [
|
| 643 |
+
{ name = "click", marker = "extra == 'dev'", specifier = "==8.1.7" },
|
| 644 |
+
{ name = "datasets", marker = "extra == 'dev'", specifier = "==2.21.0" },
|
| 645 |
{ name = "fastapi", specifier = "==0.115.6" },
|
| 646 |
{ name = "httpx", marker = "extra == 'dev'", specifier = "==0.27.2" },
|
| 647 |
{ name = "pillow", specifier = "==10.4.0" },
|
| 648 |
{ name = "pydantic", specifier = "==2.8.2" },
|
| 649 |
{ name = "pytest", marker = "extra == 'dev'", specifier = "==8.3.2" },
|
| 650 |
+
{ name = "requests", marker = "extra == 'dev'", specifier = "==2.32.3" },
|
| 651 |
{ name = "torch", specifier = "==2.3.1" },
|
| 652 |
+
{ name = "tqdm", marker = "extra == 'dev'", specifier = "==4.66.5" },
|
| 653 |
{ name = "transformers", specifier = "==4.44.2" },
|
| 654 |
{ name = "uvicorn", extras = ["standard"], specifier = "==0.30.6" },
|
| 655 |
]
|
|
|
|
| 683 |
{ 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" },
|
| 684 |
]
|
| 685 |
|
| 686 |
+
[[package]]
|
| 687 |
+
name = "propcache"
|
| 688 |
+
version = "0.4.1"
|
| 689 |
+
source = { registry = "https://pypi.org/simple" }
|
| 690 |
+
sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" }
|
| 691 |
+
wheels = [
|
| 692 |
+
{ url = "https://files.pythonhosted.org/packages/a2/0f/f17b1b2b221d5ca28b4b876e8bb046ac40466513960646bda8e1853cdfa2/propcache-0.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e153e9cd40cc8945138822807139367f256f89c6810c2634a4f6902b52d3b4e2", size = 80061, upload-time = "2025-10-08T19:46:46.075Z" },
|
| 693 |
+
{ url = "https://files.pythonhosted.org/packages/76/47/8ccf75935f51448ba9a16a71b783eb7ef6b9ee60f5d14c7f8a8a79fbeed7/propcache-0.4.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cd547953428f7abb73c5ad82cbb32109566204260d98e41e5dfdc682eb7f8403", size = 46037, upload-time = "2025-10-08T19:46:47.23Z" },
|
| 694 |
+
{ url = "https://files.pythonhosted.org/packages/0a/b6/5c9a0e42df4d00bfb4a3cbbe5cf9f54260300c88a0e9af1f47ca5ce17ac0/propcache-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f048da1b4f243fc44f205dfd320933a951b8d89e0afd4c7cacc762a8b9165207", size = 47324, upload-time = "2025-10-08T19:46:48.384Z" },
|
| 695 |
+
{ url = "https://files.pythonhosted.org/packages/9e/d3/6c7ee328b39a81ee877c962469f1e795f9db87f925251efeb0545e0020d0/propcache-0.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec17c65562a827bba85e3872ead335f95405ea1674860d96483a02f5c698fa72", size = 225505, upload-time = "2025-10-08T19:46:50.055Z" },
|
| 696 |
+
{ url = "https://files.pythonhosted.org/packages/01/5d/1c53f4563490b1d06a684742cc6076ef944bc6457df6051b7d1a877c057b/propcache-0.4.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:405aac25c6394ef275dee4c709be43745d36674b223ba4eb7144bf4d691b7367", size = 230242, upload-time = "2025-10-08T19:46:51.815Z" },
|
| 697 |
+
{ url = "https://files.pythonhosted.org/packages/20/e1/ce4620633b0e2422207c3cb774a0ee61cac13abc6217763a7b9e2e3f4a12/propcache-0.4.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0013cb6f8dde4b2a2f66903b8ba740bdfe378c943c4377a200551ceb27f379e4", size = 238474, upload-time = "2025-10-08T19:46:53.208Z" },
|
| 698 |
+
{ url = "https://files.pythonhosted.org/packages/46/4b/3aae6835b8e5f44ea6a68348ad90f78134047b503765087be2f9912140ea/propcache-0.4.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15932ab57837c3368b024473a525e25d316d8353016e7cc0e5ba9eb343fbb1cf", size = 221575, upload-time = "2025-10-08T19:46:54.511Z" },
|
| 699 |
+
{ url = "https://files.pythonhosted.org/packages/6e/a5/8a5e8678bcc9d3a1a15b9a29165640d64762d424a16af543f00629c87338/propcache-0.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:031dce78b9dc099f4c29785d9cf5577a3faf9ebf74ecbd3c856a7b92768c3df3", size = 216736, upload-time = "2025-10-08T19:46:56.212Z" },
|
| 700 |
+
{ url = "https://files.pythonhosted.org/packages/f1/63/b7b215eddeac83ca1c6b934f89d09a625aa9ee4ba158338854c87210cc36/propcache-0.4.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ab08df6c9a035bee56e31af99be621526bd237bea9f32def431c656b29e41778", size = 213019, upload-time = "2025-10-08T19:46:57.595Z" },
|
| 701 |
+
{ url = "https://files.pythonhosted.org/packages/57/74/f580099a58c8af587cac7ba19ee7cb418506342fbbe2d4a4401661cca886/propcache-0.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4d7af63f9f93fe593afbf104c21b3b15868efb2c21d07d8732c0c4287e66b6a6", size = 220376, upload-time = "2025-10-08T19:46:59.067Z" },
|
| 702 |
+
{ url = "https://files.pythonhosted.org/packages/c4/ee/542f1313aff7eaf19c2bb758c5d0560d2683dac001a1c96d0774af799843/propcache-0.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cfc27c945f422e8b5071b6e93169679e4eb5bf73bbcbf1ba3ae3a83d2f78ebd9", size = 226988, upload-time = "2025-10-08T19:47:00.544Z" },
|
| 703 |
+
{ url = "https://files.pythonhosted.org/packages/8f/18/9c6b015dd9c6930f6ce2229e1f02fb35298b847f2087ea2b436a5bfa7287/propcache-0.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35c3277624a080cc6ec6f847cbbbb5b49affa3598c4535a0a4682a697aaa5c75", size = 215615, upload-time = "2025-10-08T19:47:01.968Z" },
|
| 704 |
+
{ url = "https://files.pythonhosted.org/packages/80/9e/e7b85720b98c45a45e1fca6a177024934dc9bc5f4d5dd04207f216fc33ed/propcache-0.4.1-cp312-cp312-win32.whl", hash = "sha256:671538c2262dadb5ba6395e26c1731e1d52534bfe9ae56d0b5573ce539266aa8", size = 38066, upload-time = "2025-10-08T19:47:03.503Z" },
|
| 705 |
+
{ url = "https://files.pythonhosted.org/packages/54/09/d19cff2a5aaac632ec8fc03737b223597b1e347416934c1b3a7df079784c/propcache-0.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:cb2d222e72399fcf5890d1d5cc1060857b9b236adff2792ff48ca2dfd46c81db", size = 41655, upload-time = "2025-10-08T19:47:04.973Z" },
|
| 706 |
+
{ url = "https://files.pythonhosted.org/packages/68/ab/6b5c191bb5de08036a8c697b265d4ca76148efb10fa162f14af14fb5f076/propcache-0.4.1-cp312-cp312-win_arm64.whl", hash = "sha256:204483131fb222bdaaeeea9f9e6c6ed0cac32731f75dfc1d4a567fc1926477c1", size = 37789, upload-time = "2025-10-08T19:47:06.077Z" },
|
| 707 |
+
{ url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" },
|
| 708 |
+
]
|
| 709 |
+
|
| 710 |
+
[[package]]
|
| 711 |
+
name = "pyarrow"
|
| 712 |
+
version = "22.0.0"
|
| 713 |
+
source = { registry = "https://pypi.org/simple" }
|
| 714 |
+
sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" }
|
| 715 |
+
wheels = [
|
| 716 |
+
{ url = "https://files.pythonhosted.org/packages/af/63/ba23862d69652f85b615ca14ad14f3bcfc5bf1b99ef3f0cd04ff93fdad5a/pyarrow-22.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bea79263d55c24a32b0d79c00a1c58bb2ee5f0757ed95656b01c0fb310c5af3d", size = 34211578, upload-time = "2025-10-24T10:05:21.583Z" },
|
| 717 |
+
{ url = "https://files.pythonhosted.org/packages/b1/d0/f9ad86fe809efd2bcc8be32032fa72e8b0d112b01ae56a053006376c5930/pyarrow-22.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:12fe549c9b10ac98c91cf791d2945e878875d95508e1a5d14091a7aaa66d9cf8", size = 35989906, upload-time = "2025-10-24T10:05:29.485Z" },
|
| 718 |
+
{ url = "https://files.pythonhosted.org/packages/b4/a8/f910afcb14630e64d673f15904ec27dd31f1e009b77033c365c84e8c1e1d/pyarrow-22.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:334f900ff08ce0423407af97e6c26ad5d4e3b0763645559ece6fbf3747d6a8f5", size = 45021677, upload-time = "2025-10-24T10:05:38.274Z" },
|
| 719 |
+
{ url = "https://files.pythonhosted.org/packages/13/95/aec81f781c75cd10554dc17a25849c720d54feafb6f7847690478dcf5ef8/pyarrow-22.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c6c791b09c57ed76a18b03f2631753a4960eefbbca80f846da8baefc6491fcfe", size = 47726315, upload-time = "2025-10-24T10:05:47.314Z" },
|
| 720 |
+
{ url = "https://files.pythonhosted.org/packages/bb/d4/74ac9f7a54cfde12ee42734ea25d5a3c9a45db78f9def949307a92720d37/pyarrow-22.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c3200cb41cdbc65156e5f8c908d739b0dfed57e890329413da2748d1a2cd1a4e", size = 47990906, upload-time = "2025-10-24T10:05:58.254Z" },
|
| 721 |
+
{ url = "https://files.pythonhosted.org/packages/2e/71/fedf2499bf7a95062eafc989ace56572f3343432570e1c54e6599d5b88da/pyarrow-22.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ac93252226cf288753d8b46280f4edf3433bf9508b6977f8dd8526b521a1bbb9", size = 50306783, upload-time = "2025-10-24T10:06:08.08Z" },
|
| 722 |
+
{ url = "https://files.pythonhosted.org/packages/68/ed/b202abd5a5b78f519722f3d29063dda03c114711093c1995a33b8e2e0f4b/pyarrow-22.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:44729980b6c50a5f2bfcc2668d36c569ce17f8b17bccaf470c4313dcbbf13c9d", size = 27972883, upload-time = "2025-10-24T10:06:14.204Z" },
|
| 723 |
+
]
|
| 724 |
+
|
| 725 |
[[package]]
|
| 726 |
name = "pydantic"
|
| 727 |
version = "2.8.2"
|
|
|
|
| 774 |
{ 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" },
|
| 775 |
]
|
| 776 |
|
| 777 |
+
[[package]]
|
| 778 |
+
name = "python-dateutil"
|
| 779 |
+
version = "2.9.0.post0"
|
| 780 |
+
source = { registry = "https://pypi.org/simple" }
|
| 781 |
+
dependencies = [
|
| 782 |
+
{ name = "six" },
|
| 783 |
+
]
|
| 784 |
+
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
| 785 |
+
wheels = [
|
| 786 |
+
{ url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" },
|
| 787 |
+
]
|
| 788 |
+
|
| 789 |
[[package]]
|
| 790 |
name = "python-dotenv"
|
| 791 |
version = "1.2.1"
|
|
|
|
| 795 |
{ 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" },
|
| 796 |
]
|
| 797 |
|
| 798 |
+
[[package]]
|
| 799 |
+
name = "pytz"
|
| 800 |
+
version = "2025.2"
|
| 801 |
+
source = { registry = "https://pypi.org/simple" }
|
| 802 |
+
sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" }
|
| 803 |
+
wheels = [
|
| 804 |
+
{ url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" },
|
| 805 |
+
]
|
| 806 |
+
|
| 807 |
[[package]]
|
| 808 |
name = "pyyaml"
|
| 809 |
version = "6.0.3"
|
|
|
|
| 848 |
|
| 849 |
[[package]]
|
| 850 |
name = "requests"
|
| 851 |
+
version = "2.32.3"
|
| 852 |
source = { registry = "https://pypi.org/simple" }
|
| 853 |
dependencies = [
|
| 854 |
{ name = "certifi" },
|
|
|
|
| 856 |
{ name = "idna" },
|
| 857 |
{ name = "urllib3" },
|
| 858 |
]
|
| 859 |
+
sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload-time = "2024-05-29T15:37:49.536Z" }
|
| 860 |
wheels = [
|
| 861 |
+
{ url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload-time = "2024-05-29T15:37:47.027Z" },
|
| 862 |
]
|
| 863 |
|
| 864 |
[[package]]
|
|
|
|
| 883 |
{ 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" },
|
| 884 |
]
|
| 885 |
|
| 886 |
+
[[package]]
|
| 887 |
+
name = "six"
|
| 888 |
+
version = "1.17.0"
|
| 889 |
+
source = { registry = "https://pypi.org/simple" }
|
| 890 |
+
sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" }
|
| 891 |
+
wheels = [
|
| 892 |
+
{ url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" },
|
| 893 |
+
]
|
| 894 |
+
|
| 895 |
[[package]]
|
| 896 |
name = "sniffio"
|
| 897 |
version = "1.3.1"
|
|
|
|
| 990 |
|
| 991 |
[[package]]
|
| 992 |
name = "tqdm"
|
| 993 |
+
version = "4.66.5"
|
| 994 |
source = { registry = "https://pypi.org/simple" }
|
| 995 |
dependencies = [
|
| 996 |
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
| 997 |
]
|
| 998 |
+
sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504, upload-time = "2024-08-03T22:35:40.339Z" }
|
| 999 |
wheels = [
|
| 1000 |
+
{ url = "https://files.pythonhosted.org/packages/48/5d/acf5905c36149bbaec41ccf7f2b68814647347b72075ac0b1fe3022fdc73/tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", size = 78351, upload-time = "2024-08-03T22:35:36.644Z" },
|
| 1001 |
]
|
| 1002 |
|
| 1003 |
[[package]]
|
|
|
|
| 1030 |
{ 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" },
|
| 1031 |
]
|
| 1032 |
|
| 1033 |
+
[[package]]
|
| 1034 |
+
name = "tzdata"
|
| 1035 |
+
version = "2025.3"
|
| 1036 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1037 |
+
sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" }
|
| 1038 |
+
wheels = [
|
| 1039 |
+
{ url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" },
|
| 1040 |
+
]
|
| 1041 |
+
|
| 1042 |
[[package]]
|
| 1043 |
name = "urllib3"
|
| 1044 |
version = "2.6.3"
|
|
|
|
| 1127 |
{ 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" },
|
| 1128 |
{ 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" },
|
| 1129 |
]
|
| 1130 |
+
|
| 1131 |
+
[[package]]
|
| 1132 |
+
name = "xxhash"
|
| 1133 |
+
version = "3.6.0"
|
| 1134 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1135 |
+
sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" }
|
| 1136 |
+
wheels = [
|
| 1137 |
+
{ url = "https://files.pythonhosted.org/packages/9a/07/d9412f3d7d462347e4511181dea65e47e0d0e16e26fbee2ea86a2aefb657/xxhash-3.6.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:01362c4331775398e7bb34e3ab403bc9ee9f7c497bc7dee6272114055277dd3c", size = 32744, upload-time = "2025-10-02T14:34:34.622Z" },
|
| 1138 |
+
{ url = "https://files.pythonhosted.org/packages/79/35/0429ee11d035fc33abe32dca1b2b69e8c18d236547b9a9b72c1929189b9a/xxhash-3.6.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b7b2df81a23f8cb99656378e72501b2cb41b1827c0f5a86f87d6b06b69f9f204", size = 30816, upload-time = "2025-10-02T14:34:36.043Z" },
|
| 1139 |
+
{ url = "https://files.pythonhosted.org/packages/b7/f2/57eb99aa0f7d98624c0932c5b9a170e1806406cdbcdb510546634a1359e0/xxhash-3.6.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:dc94790144e66b14f67b10ac8ed75b39ca47536bf8800eb7c24b50271ea0c490", size = 194035, upload-time = "2025-10-02T14:34:37.354Z" },
|
| 1140 |
+
{ url = "https://files.pythonhosted.org/packages/4c/ed/6224ba353690d73af7a3f1c7cdb1fc1b002e38f783cb991ae338e1eb3d79/xxhash-3.6.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93f107c673bccf0d592cdba077dedaf52fe7f42dcd7676eba1f6d6f0c3efffd2", size = 212914, upload-time = "2025-10-02T14:34:38.6Z" },
|
| 1141 |
+
{ url = "https://files.pythonhosted.org/packages/38/86/fb6b6130d8dd6b8942cc17ab4d90e223653a89aa32ad2776f8af7064ed13/xxhash-3.6.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2aa5ee3444c25b69813663c9f8067dcfaa2e126dc55e8dddf40f4d1c25d7effa", size = 212163, upload-time = "2025-10-02T14:34:39.872Z" },
|
| 1142 |
+
{ url = "https://files.pythonhosted.org/packages/ee/dc/e84875682b0593e884ad73b2d40767b5790d417bde603cceb6878901d647/xxhash-3.6.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7f99123f0e1194fa59cc69ad46dbae2e07becec5df50a0509a808f90a0f03f0", size = 445411, upload-time = "2025-10-02T14:34:41.569Z" },
|
| 1143 |
+
{ url = "https://files.pythonhosted.org/packages/11/4f/426f91b96701ec2f37bb2b8cec664eff4f658a11f3fa9d94f0a887ea6d2b/xxhash-3.6.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49e03e6fe2cac4a1bc64952dd250cf0dbc5ef4ebb7b8d96bce82e2de163c82a2", size = 193883, upload-time = "2025-10-02T14:34:43.249Z" },
|
| 1144 |
+
{ url = "https://files.pythonhosted.org/packages/53/5a/ddbb83eee8e28b778eacfc5a85c969673e4023cdeedcfcef61f36731610b/xxhash-3.6.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bd17fede52a17a4f9a7bc4472a5867cb0b160deeb431795c0e4abe158bc784e9", size = 210392, upload-time = "2025-10-02T14:34:45.042Z" },
|
| 1145 |
+
{ url = "https://files.pythonhosted.org/packages/1e/c2/ff69efd07c8c074ccdf0a4f36fcdd3d27363665bcdf4ba399abebe643465/xxhash-3.6.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:6fb5f5476bef678f69db04f2bd1efbed3030d2aba305b0fc1773645f187d6a4e", size = 197898, upload-time = "2025-10-02T14:34:46.302Z" },
|
| 1146 |
+
{ url = "https://files.pythonhosted.org/packages/58/ca/faa05ac19b3b622c7c9317ac3e23954187516298a091eb02c976d0d3dd45/xxhash-3.6.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:843b52f6d88071f87eba1631b684fcb4b2068cd2180a0224122fe4ef011a9374", size = 210655, upload-time = "2025-10-02T14:34:47.571Z" },
|
| 1147 |
+
{ url = "https://files.pythonhosted.org/packages/d4/7a/06aa7482345480cc0cb597f5c875b11a82c3953f534394f620b0be2f700c/xxhash-3.6.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:7d14a6cfaf03b1b6f5f9790f76880601ccc7896aff7ab9cd8978a939c1eb7e0d", size = 414001, upload-time = "2025-10-02T14:34:49.273Z" },
|
| 1148 |
+
{ url = "https://files.pythonhosted.org/packages/23/07/63ffb386cd47029aa2916b3d2f454e6cc5b9f5c5ada3790377d5430084e7/xxhash-3.6.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:418daf3db71e1413cfe211c2f9a528456936645c17f46b5204705581a45390ae", size = 191431, upload-time = "2025-10-02T14:34:50.798Z" },
|
| 1149 |
+
{ url = "https://files.pythonhosted.org/packages/0f/93/14fde614cadb4ddf5e7cebf8918b7e8fac5ae7861c1875964f17e678205c/xxhash-3.6.0-cp312-cp312-win32.whl", hash = "sha256:50fc255f39428a27299c20e280d6193d8b63b8ef8028995323bf834a026b4fbb", size = 30617, upload-time = "2025-10-02T14:34:51.954Z" },
|
| 1150 |
+
{ url = "https://files.pythonhosted.org/packages/13/5d/0d125536cbe7565a83d06e43783389ecae0c0f2ed037b48ede185de477c0/xxhash-3.6.0-cp312-cp312-win_amd64.whl", hash = "sha256:c0f2ab8c715630565ab8991b536ecded9416d615538be8ecddce43ccf26cbc7c", size = 31534, upload-time = "2025-10-02T14:34:53.276Z" },
|
| 1151 |
+
{ url = "https://files.pythonhosted.org/packages/54/85/6ec269b0952ec7e36ba019125982cf11d91256a778c7c3f98a4c5043d283/xxhash-3.6.0-cp312-cp312-win_arm64.whl", hash = "sha256:eae5c13f3bc455a3bbb68bdc513912dc7356de7e2280363ea235f71f54064829", size = 27876, upload-time = "2025-10-02T14:34:54.371Z" },
|
| 1152 |
+
]
|
| 1153 |
+
|
| 1154 |
+
[[package]]
|
| 1155 |
+
name = "yarl"
|
| 1156 |
+
version = "1.22.0"
|
| 1157 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1158 |
+
dependencies = [
|
| 1159 |
+
{ name = "idna" },
|
| 1160 |
+
{ name = "multidict" },
|
| 1161 |
+
{ name = "propcache" },
|
| 1162 |
+
]
|
| 1163 |
+
sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" }
|
| 1164 |
+
wheels = [
|
| 1165 |
+
{ url = "https://files.pythonhosted.org/packages/75/ff/46736024fee3429b80a165a732e38e5d5a238721e634ab41b040d49f8738/yarl-1.22.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e340382d1afa5d32b892b3ff062436d592ec3d692aeea3bef3a5cfe11bbf8c6f", size = 142000, upload-time = "2025-10-06T14:09:44.631Z" },
|
| 1166 |
+
{ url = "https://files.pythonhosted.org/packages/5a/9a/b312ed670df903145598914770eb12de1bac44599549b3360acc96878df8/yarl-1.22.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f1e09112a2c31ffe8d80be1b0988fa6a18c5d5cad92a9ffbb1c04c91bfe52ad2", size = 94338, upload-time = "2025-10-06T14:09:46.372Z" },
|
| 1167 |
+
{ url = "https://files.pythonhosted.org/packages/ba/f5/0601483296f09c3c65e303d60c070a5c19fcdbc72daa061e96170785bc7d/yarl-1.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:939fe60db294c786f6b7c2d2e121576628468f65453d86b0fe36cb52f987bd74", size = 94909, upload-time = "2025-10-06T14:09:48.648Z" },
|
| 1168 |
+
{ url = "https://files.pythonhosted.org/packages/60/41/9a1fe0b73dbcefce72e46cf149b0e0a67612d60bfc90fb59c2b2efdfbd86/yarl-1.22.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1651bf8e0398574646744c1885a41198eba53dc8a9312b954073f845c90a8df", size = 372940, upload-time = "2025-10-06T14:09:50.089Z" },
|
| 1169 |
+
{ url = "https://files.pythonhosted.org/packages/17/7a/795cb6dfee561961c30b800f0ed616b923a2ec6258b5def2a00bf8231334/yarl-1.22.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b8a0588521a26bf92a57a1705b77b8b59044cdceccac7151bd8d229e66b8dedb", size = 345825, upload-time = "2025-10-06T14:09:52.142Z" },
|
| 1170 |
+
{ url = "https://files.pythonhosted.org/packages/d7/93/a58f4d596d2be2ae7bab1a5846c4d270b894958845753b2c606d666744d3/yarl-1.22.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:42188e6a615c1a75bcaa6e150c3fe8f3e8680471a6b10150c5f7e83f47cc34d2", size = 386705, upload-time = "2025-10-06T14:09:54.128Z" },
|
| 1171 |
+
{ url = "https://files.pythonhosted.org/packages/61/92/682279d0e099d0e14d7fd2e176bd04f48de1484f56546a3e1313cd6c8e7c/yarl-1.22.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f6d2cb59377d99718913ad9a151030d6f83ef420a2b8f521d94609ecc106ee82", size = 396518, upload-time = "2025-10-06T14:09:55.762Z" },
|
| 1172 |
+
{ url = "https://files.pythonhosted.org/packages/db/0f/0d52c98b8a885aeda831224b78f3be7ec2e1aa4a62091f9f9188c3c65b56/yarl-1.22.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50678a3b71c751d58d7908edc96d332af328839eea883bb554a43f539101277a", size = 377267, upload-time = "2025-10-06T14:09:57.958Z" },
|
| 1173 |
+
{ url = "https://files.pythonhosted.org/packages/22/42/d2685e35908cbeaa6532c1fc73e89e7f2efb5d8a7df3959ea8e37177c5a3/yarl-1.22.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e8fbaa7cec507aa24ea27a01456e8dd4b6fab829059b69844bd348f2d467124", size = 365797, upload-time = "2025-10-06T14:09:59.527Z" },
|
| 1174 |
+
{ url = "https://files.pythonhosted.org/packages/a2/83/cf8c7bcc6355631762f7d8bdab920ad09b82efa6b722999dfb05afa6cfac/yarl-1.22.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:433885ab5431bc3d3d4f2f9bd15bfa1614c522b0f1405d62c4f926ccd69d04fa", size = 365535, upload-time = "2025-10-06T14:10:01.139Z" },
|
| 1175 |
+
{ url = "https://files.pythonhosted.org/packages/25/e1/5302ff9b28f0c59cac913b91fe3f16c59a033887e57ce9ca5d41a3a94737/yarl-1.22.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:b790b39c7e9a4192dc2e201a282109ed2985a1ddbd5ac08dc56d0e121400a8f7", size = 382324, upload-time = "2025-10-06T14:10:02.756Z" },
|
| 1176 |
+
{ url = "https://files.pythonhosted.org/packages/bf/cd/4617eb60f032f19ae3a688dc990d8f0d89ee0ea378b61cac81ede3e52fae/yarl-1.22.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:31f0b53913220599446872d757257be5898019c85e7971599065bc55065dc99d", size = 383803, upload-time = "2025-10-06T14:10:04.552Z" },
|
| 1177 |
+
{ url = "https://files.pythonhosted.org/packages/59/65/afc6e62bb506a319ea67b694551dab4a7e6fb7bf604e9bd9f3e11d575fec/yarl-1.22.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a49370e8f711daec68d09b821a34e1167792ee2d24d405cbc2387be4f158b520", size = 374220, upload-time = "2025-10-06T14:10:06.489Z" },
|
| 1178 |
+
{ url = "https://files.pythonhosted.org/packages/e7/3d/68bf18d50dc674b942daec86a9ba922d3113d8399b0e52b9897530442da2/yarl-1.22.0-cp312-cp312-win32.whl", hash = "sha256:70dfd4f241c04bd9239d53b17f11e6ab672b9f1420364af63e8531198e3f5fe8", size = 81589, upload-time = "2025-10-06T14:10:09.254Z" },
|
| 1179 |
+
{ url = "https://files.pythonhosted.org/packages/c8/9a/6ad1a9b37c2f72874f93e691b2e7ecb6137fb2b899983125db4204e47575/yarl-1.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:8884d8b332a5e9b88e23f60bb166890009429391864c685e17bd73a9eda9105c", size = 87213, upload-time = "2025-10-06T14:10:11.369Z" },
|
| 1180 |
+
{ url = "https://files.pythonhosted.org/packages/44/c5/c21b562d1680a77634d748e30c653c3ca918beb35555cff24986fff54598/yarl-1.22.0-cp312-cp312-win_arm64.whl", hash = "sha256:ea70f61a47f3cc93bdf8b2f368ed359ef02a01ca6393916bc8ff877427181e74", size = 81330, upload-time = "2025-10-06T14:10:13.112Z" },
|
| 1181 |
+
{ url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" },
|
| 1182 |
+
]
|