Spaces:
Sleeping
Sleeping
feat(api): add POST /project UMAP projection for Galaxy VIEW
Browse filesBackend dimensionality reduction seam (umap-learn) so Galaxy can place tokens from embeddings without re-encoding; pca/tsne return 501 until later epics.
Co-authored-by: Cursor <cursoragent@cursor.com>
- architecture_spec.md +30 -0
- backend/projection.py +169 -0
- backend/pyproject.toml +1 -0
- backend/routers/core.py +47 -2
- backend/tests/test_project.py +198 -0
- backend/uv.lock +117 -63
architecture_spec.md
CHANGED
|
@@ -17,6 +17,7 @@ VHectorLab 3D is a 3D semantic vector visualizer and vector arithmetic explorer.
|
|
| 17 |
- `POST /tokenize`: Returns tokenization details.
|
| 18 |
- `POST /arithmetic`: Computes $V_{res} = V_A - V_B + V_C$ and returns top-$K$ nearest vocabulary words and component vectors.
|
| 19 |
- `POST /compare`: Batch-encodes 1–1024 texts, L2-normalizes embeddings, and returns per-item cosine vs the first token (anchor).
|
|
|
|
| 20 |
|
| 21 |
### Data Contracts
|
| 22 |
|
|
@@ -62,3 +63,32 @@ Returns:
|
|
| 62 |
}
|
| 63 |
```
|
| 64 |
`cosine_vs_first` is $\text{dot}(\hat{e}_i, \hat{e}_0)$ on L2-normalized embeddings. Frontend reorders may recompute scores in memory without re-calling `/compare`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
- `POST /tokenize`: Returns tokenization details.
|
| 18 |
- `POST /arithmetic`: Computes $V_{res} = V_A - V_B + V_C$ and returns top-$K$ nearest vocabulary words and component vectors.
|
| 19 |
- `POST /compare`: Batch-encodes 1–1024 texts, L2-normalizes embeddings, and returns per-item cosine vs the first token (anchor).
|
| 20 |
+
- `POST /project`: Projects precomputed embedding vectors to 2D/3D (does **not** re-encode text). v1 method = **`umap` only**; `pca` / `tsne` → **501**; other methods → **400**. Default seed `42`. When `dim > 50`, internal PCA→50 before UMAP. Positions are zero-mean and RMS-scaled server-side.
|
| 21 |
|
| 22 |
### Data Contracts
|
| 23 |
|
|
|
|
| 63 |
}
|
| 64 |
```
|
| 65 |
`cosine_vs_first` is $\text{dot}(\hat{e}_i, \hat{e}_0)$ on L2-normalized embeddings. Frontend reorders may recompute scores in memory without re-calling `/compare`.
|
| 66 |
+
|
| 67 |
+
#### Project (Galaxy / UMAP)
|
| 68 |
+
```json
|
| 69 |
+
{
|
| 70 |
+
"vectors": [[0.01, "..."], ["..."]],
|
| 71 |
+
"method": "umap",
|
| 72 |
+
"n_components": 3,
|
| 73 |
+
"seed": 42,
|
| 74 |
+
"params": { "n_neighbors": 15, "min_dist": 0.1, "metric": "cosine" }
|
| 75 |
+
}
|
| 76 |
+
```
|
| 77 |
+
Constraints: `len(vectors)` ∈ 1..1024; uniform row dim; `n_components` ∈ {2, 3}; `method` = `umap` (green path).
|
| 78 |
+
|
| 79 |
+
Returns:
|
| 80 |
+
```json
|
| 81 |
+
{
|
| 82 |
+
"method": "umap",
|
| 83 |
+
"n_components": 3,
|
| 84 |
+
"positions": [[x, y, z], "..."],
|
| 85 |
+
"meta": {
|
| 86 |
+
"seed": 42,
|
| 87 |
+
"n_neighbors": 15,
|
| 88 |
+
"min_dist": 0.1,
|
| 89 |
+
"metric": "cosine",
|
| 90 |
+
"pre_pca_dims": 50
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
```
|
| 94 |
+
`meta.pre_pca_dims` is present only when the internal PCA pre-step ran. Encoding stays on `/compare` (or SAE encode); `/project` is additive.
|
backend/projection.py
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Dimensionality reduction for Galaxy VIEW.
|
| 3 |
+
|
| 4 |
+
Deep seam: project_embeddings(vectors, ...) → positions + meta.
|
| 5 |
+
UMAP only in v1; PCA/t-SNE raise ProjectError(501).
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
from __future__ import annotations
|
| 9 |
+
|
| 10 |
+
from typing import Any
|
| 11 |
+
|
| 12 |
+
import numpy as np
|
| 13 |
+
|
| 14 |
+
PRE_PCA_DIMS = 50
|
| 15 |
+
MAX_VECTORS = 1024
|
| 16 |
+
DEFAULT_N_NEIGHBORS = 15
|
| 17 |
+
DEFAULT_MIN_DIST = 0.1
|
| 18 |
+
DEFAULT_METRIC = "cosine"
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
class ProjectError(Exception):
|
| 22 |
+
"""Validation / capability error with HTTP-ish status code."""
|
| 23 |
+
|
| 24 |
+
def __init__(self, message: str, status_code: int = 400) -> None:
|
| 25 |
+
super().__init__(message)
|
| 26 |
+
self.message = message
|
| 27 |
+
self.status_code = status_code
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
def _as_matrix(vectors: list[list[float]] | np.ndarray) -> np.ndarray:
|
| 31 |
+
if isinstance(vectors, np.ndarray):
|
| 32 |
+
mat = np.asarray(vectors, dtype=np.float64)
|
| 33 |
+
else:
|
| 34 |
+
if not vectors:
|
| 35 |
+
raise ProjectError("vectors list cannot be empty (need 1..1024)")
|
| 36 |
+
lengths = {len(row) for row in vectors}
|
| 37 |
+
if len(lengths) != 1:
|
| 38 |
+
raise ProjectError("all vectors must have the same dimension")
|
| 39 |
+
if next(iter(lengths)) < 1:
|
| 40 |
+
raise ProjectError("vector dimension must be >= 1")
|
| 41 |
+
mat = np.asarray(vectors, dtype=np.float64)
|
| 42 |
+
|
| 43 |
+
if mat.ndim != 2:
|
| 44 |
+
raise ProjectError("vectors must be a 2D matrix [n, dim]")
|
| 45 |
+
n, dim = mat.shape
|
| 46 |
+
if n < 1 or n > MAX_VECTORS:
|
| 47 |
+
raise ProjectError(f"len(vectors) must be in 1..{MAX_VECTORS}, got {n}")
|
| 48 |
+
if dim < 1:
|
| 49 |
+
raise ProjectError("vector dimension must be >= 1")
|
| 50 |
+
if not np.isfinite(mat).all():
|
| 51 |
+
raise ProjectError("vectors must contain only finite values")
|
| 52 |
+
return mat
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def _normalize_positions(pos: np.ndarray) -> np.ndarray:
|
| 56 |
+
"""Zero-mean; scale so RMS distance from origin is 1 (stable camera defaults)."""
|
| 57 |
+
centered = pos - pos.mean(axis=0, keepdims=True)
|
| 58 |
+
rms = float(np.sqrt(np.mean(np.sum(centered**2, axis=1))))
|
| 59 |
+
if rms < 1e-12:
|
| 60 |
+
return centered
|
| 61 |
+
return centered / rms
|
| 62 |
+
|
| 63 |
+
|
| 64 |
+
def _resolve_umap_params(
|
| 65 |
+
n_samples: int, params: dict[str, Any] | None
|
| 66 |
+
) -> dict[str, Any]:
|
| 67 |
+
raw = params or {}
|
| 68 |
+
n_neighbors = int(raw.get("n_neighbors", DEFAULT_N_NEIGHBORS))
|
| 69 |
+
min_dist = float(raw.get("min_dist", DEFAULT_MIN_DIST))
|
| 70 |
+
metric = str(raw.get("metric", DEFAULT_METRIC))
|
| 71 |
+
|
| 72 |
+
# UMAP requires n_neighbors < n_samples
|
| 73 |
+
max_nn = max(2, n_samples - 1)
|
| 74 |
+
n_neighbors = max(n_neighbors, 2)
|
| 75 |
+
n_neighbors = min(n_neighbors, max_nn)
|
| 76 |
+
|
| 77 |
+
if min_dist < 0.0:
|
| 78 |
+
raise ProjectError("params.min_dist must be >= 0")
|
| 79 |
+
|
| 80 |
+
return {
|
| 81 |
+
"n_neighbors": n_neighbors,
|
| 82 |
+
"min_dist": min_dist,
|
| 83 |
+
"metric": metric,
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def project_embeddings(
|
| 88 |
+
vectors: list[list[float]] | np.ndarray,
|
| 89 |
+
*,
|
| 90 |
+
method: str = "umap",
|
| 91 |
+
n_components: int = 3,
|
| 92 |
+
seed: int = 42,
|
| 93 |
+
params: dict[str, Any] | None = None,
|
| 94 |
+
) -> dict[str, Any]:
|
| 95 |
+
"""
|
| 96 |
+
Project embedding rows to 2D/3D.
|
| 97 |
+
|
| 98 |
+
Returns:
|
| 99 |
+
{ method, n_components, positions, meta }
|
| 100 |
+
"""
|
| 101 |
+
method_l = (method or "").strip().lower()
|
| 102 |
+
if method_l in ("pca", "tsne"):
|
| 103 |
+
raise ProjectError(
|
| 104 |
+
f"method '{method_l}' is not implemented yet; use 'umap'",
|
| 105 |
+
status_code=501,
|
| 106 |
+
)
|
| 107 |
+
if method_l != "umap":
|
| 108 |
+
raise ProjectError(
|
| 109 |
+
f"unsupported method '{method}'; v1 accepts 'umap' only "
|
| 110 |
+
"(pca/tsne coming later)",
|
| 111 |
+
status_code=400,
|
| 112 |
+
)
|
| 113 |
+
|
| 114 |
+
if n_components not in (2, 3):
|
| 115 |
+
raise ProjectError("n_components must be 2 or 3")
|
| 116 |
+
|
| 117 |
+
mat = _as_matrix(vectors)
|
| 118 |
+
n_samples, dim = mat.shape
|
| 119 |
+
|
| 120 |
+
# Need at least n_components + 1 points for a meaningful UMAP; allow smaller
|
| 121 |
+
# with clamped neighbors (smoke / edge cases).
|
| 122 |
+
if n_samples < 3:
|
| 123 |
+
raise ProjectError("UMAP requires at least 3 vectors")
|
| 124 |
+
|
| 125 |
+
umap_params = _resolve_umap_params(n_samples, params)
|
| 126 |
+
pre_pca_dims: int | None = None
|
| 127 |
+
work = mat
|
| 128 |
+
|
| 129 |
+
if dim > PRE_PCA_DIMS:
|
| 130 |
+
from sklearn.decomposition import PCA
|
| 131 |
+
|
| 132 |
+
pca_dims = min(PRE_PCA_DIMS, n_samples - 1, dim)
|
| 133 |
+
if pca_dims < n_components:
|
| 134 |
+
raise ProjectError(
|
| 135 |
+
f"cannot pre-reduce: need at least {n_components} PCA dims "
|
| 136 |
+
f"(n={n_samples}, dim={dim})"
|
| 137 |
+
)
|
| 138 |
+
pca = PCA(n_components=pca_dims, random_state=seed)
|
| 139 |
+
work = pca.fit_transform(mat)
|
| 140 |
+
pre_pca_dims = pca_dims
|
| 141 |
+
|
| 142 |
+
import umap
|
| 143 |
+
|
| 144 |
+
reducer = umap.UMAP(
|
| 145 |
+
n_components=n_components,
|
| 146 |
+
n_neighbors=umap_params["n_neighbors"],
|
| 147 |
+
min_dist=umap_params["min_dist"],
|
| 148 |
+
metric=umap_params["metric"],
|
| 149 |
+
random_state=seed,
|
| 150 |
+
n_jobs=1,
|
| 151 |
+
)
|
| 152 |
+
embedded = reducer.fit_transform(work)
|
| 153 |
+
positions = _normalize_positions(np.asarray(embedded, dtype=np.float64))
|
| 154 |
+
|
| 155 |
+
meta: dict[str, Any] = {
|
| 156 |
+
"seed": seed,
|
| 157 |
+
"n_neighbors": umap_params["n_neighbors"],
|
| 158 |
+
"min_dist": umap_params["min_dist"],
|
| 159 |
+
"metric": umap_params["metric"],
|
| 160 |
+
}
|
| 161 |
+
if pre_pca_dims is not None:
|
| 162 |
+
meta["pre_pca_dims"] = pre_pca_dims
|
| 163 |
+
|
| 164 |
+
return {
|
| 165 |
+
"method": "umap",
|
| 166 |
+
"n_components": n_components,
|
| 167 |
+
"positions": positions.tolist(),
|
| 168 |
+
"meta": meta,
|
| 169 |
+
}
|
backend/pyproject.toml
CHANGED
|
@@ -13,6 +13,7 @@ dependencies = [
|
|
| 13 |
"httpx>=0.27.0",
|
| 14 |
"huggingface-hub>=0.21.0",
|
| 15 |
"orjson>=3.11.9",
|
|
|
|
| 16 |
]
|
| 17 |
|
| 18 |
[project.optional-dependencies]
|
|
|
|
| 13 |
"httpx>=0.27.0",
|
| 14 |
"huggingface-hub>=0.21.0",
|
| 15 |
"orjson>=3.11.9",
|
| 16 |
+
"umap-learn==0.5.12",
|
| 17 |
]
|
| 18 |
|
| 19 |
[project.optional-dependencies]
|
backend/routers/core.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
| 1 |
"""
|
| 2 |
Core API Router for VHectorLab 3D.
|
| 3 |
-
Provides /health, /embed, /tokenize, and /
|
| 4 |
"""
|
| 5 |
|
| 6 |
-
from typing import Any
|
| 7 |
|
|
|
|
| 8 |
from backend.state import state
|
| 9 |
from fastapi import APIRouter, HTTPException
|
| 10 |
from pydantic import BaseModel, Field
|
|
@@ -42,6 +43,32 @@ class CompareRequest(BaseModel):
|
|
| 42 |
)
|
| 43 |
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
@router.get("/health")
|
| 46 |
def health_check() -> dict[str, Any]:
|
| 47 |
return {
|
|
@@ -117,3 +144,21 @@ def perform_compare(req: CompareRequest) -> dict[str, Any]:
|
|
| 117 |
except Exception as e: # noqa: BLE001
|
| 118 |
raise HTTPException(status_code=500, detail=str(e))
|
| 119 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
"""
|
| 2 |
Core API Router for VHectorLab 3D.
|
| 3 |
+
Provides /health, /embed, /tokenize, /arithmetic, /compare, and /project endpoints.
|
| 4 |
"""
|
| 5 |
|
| 6 |
+
from typing import Any, Literal
|
| 7 |
|
| 8 |
+
from backend.projection import ProjectError, project_embeddings
|
| 9 |
from backend.state import state
|
| 10 |
from fastapi import APIRouter, HTTPException
|
| 11 |
from pydantic import BaseModel, Field
|
|
|
|
| 43 |
)
|
| 44 |
|
| 45 |
|
| 46 |
+
class ProjectParams(BaseModel):
|
| 47 |
+
n_neighbors: int = Field(default=15, ge=2, le=200)
|
| 48 |
+
min_dist: float = Field(default=0.1, ge=0.0)
|
| 49 |
+
metric: str = Field(default="cosine")
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
class ProjectRequest(BaseModel):
|
| 53 |
+
vectors: list[list[float]] = Field(
|
| 54 |
+
...,
|
| 55 |
+
description="Precomputed embedding rows (1..1024); does not re-encode text",
|
| 56 |
+
)
|
| 57 |
+
method: str = Field(
|
| 58 |
+
default="umap",
|
| 59 |
+
description="Projection method; v1 accepts 'umap' only",
|
| 60 |
+
)
|
| 61 |
+
n_components: Literal[2, 3] = Field(
|
| 62 |
+
default=3,
|
| 63 |
+
description="Output dimensionality (Galaxy uses 3; 2 reserved for future 2D VIEW)",
|
| 64 |
+
)
|
| 65 |
+
seed: int = Field(default=42, description="RNG seed for reproducibility")
|
| 66 |
+
params: ProjectParams | None = Field(
|
| 67 |
+
default=None,
|
| 68 |
+
description="UMAP hyperparameters (n_neighbors, min_dist, metric)",
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
|
| 72 |
@router.get("/health")
|
| 73 |
def health_check() -> dict[str, Any]:
|
| 74 |
return {
|
|
|
|
| 144 |
except Exception as e: # noqa: BLE001
|
| 145 |
raise HTTPException(status_code=500, detail=str(e))
|
| 146 |
|
| 147 |
+
|
| 148 |
+
@router.post("/project")
|
| 149 |
+
def perform_project(req: ProjectRequest) -> dict[str, Any]:
|
| 150 |
+
"""Project embedding vectors to 2D/3D (UMAP). Does not encode text."""
|
| 151 |
+
params = req.params.model_dump() if req.params is not None else None
|
| 152 |
+
try:
|
| 153 |
+
return project_embeddings(
|
| 154 |
+
req.vectors,
|
| 155 |
+
method=req.method,
|
| 156 |
+
n_components=req.n_components,
|
| 157 |
+
seed=req.seed,
|
| 158 |
+
params=params,
|
| 159 |
+
)
|
| 160 |
+
except ProjectError as e:
|
| 161 |
+
raise HTTPException(status_code=e.status_code, detail=e.message)
|
| 162 |
+
except Exception as e: # noqa: BLE001
|
| 163 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 164 |
+
|
backend/tests/test_project.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Tests for POST /project (UMAP dimensionality reduction)."""
|
| 2 |
+
|
| 3 |
+
from __future__ import annotations
|
| 4 |
+
|
| 5 |
+
from contextlib import asynccontextmanager
|
| 6 |
+
|
| 7 |
+
import numpy as np
|
| 8 |
+
import pytest
|
| 9 |
+
from fastapi import FastAPI
|
| 10 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 11 |
+
from fastapi.testclient import TestClient
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
@pytest.fixture()
|
| 15 |
+
def client():
|
| 16 |
+
"""Lightweight app with core router only (no model load)."""
|
| 17 |
+
from backend.routers.core import router as core_router
|
| 18 |
+
|
| 19 |
+
@asynccontextmanager
|
| 20 |
+
async def _noop_lifespan(_app):
|
| 21 |
+
yield
|
| 22 |
+
|
| 23 |
+
app = FastAPI(lifespan=_noop_lifespan)
|
| 24 |
+
app.add_middleware(
|
| 25 |
+
CORSMiddleware,
|
| 26 |
+
allow_origins=["*"],
|
| 27 |
+
allow_credentials=False,
|
| 28 |
+
allow_methods=["*"],
|
| 29 |
+
allow_headers=["*"],
|
| 30 |
+
)
|
| 31 |
+
app.include_router(core_router)
|
| 32 |
+
app.include_router(core_router, prefix="/api")
|
| 33 |
+
|
| 34 |
+
with TestClient(app) as c:
|
| 35 |
+
yield c
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _random_vectors(n: int = 24, dim: int = 32, seed: int = 0) -> list[list[float]]:
|
| 39 |
+
rng = np.random.default_rng(seed)
|
| 40 |
+
mat = rng.standard_normal((n, dim)).astype(np.float64)
|
| 41 |
+
norms = np.linalg.norm(mat, axis=1, keepdims=True)
|
| 42 |
+
norms[norms == 0] = 1e-9
|
| 43 |
+
return (mat / norms).tolist()
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def test_project_rejects_empty_vectors(client: TestClient):
|
| 47 |
+
res = client.post(
|
| 48 |
+
"/project",
|
| 49 |
+
json={"vectors": [], "method": "umap", "n_components": 3, "seed": 42},
|
| 50 |
+
)
|
| 51 |
+
assert res.status_code == 400
|
| 52 |
+
assert "empty" in res.json()["detail"].lower() or "1" in res.json()["detail"]
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
def test_project_rejects_too_many_vectors(client: TestClient):
|
| 56 |
+
vecs = _random_vectors(n=2, dim=4)
|
| 57 |
+
bloated = vecs * 513 # 1026
|
| 58 |
+
res = client.post(
|
| 59 |
+
"/project",
|
| 60 |
+
json={"vectors": bloated, "method": "umap", "n_components": 3},
|
| 61 |
+
)
|
| 62 |
+
assert res.status_code == 400
|
| 63 |
+
assert "1024" in res.json()["detail"]
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def test_project_rejects_inconsistent_dims(client: TestClient):
|
| 67 |
+
res = client.post(
|
| 68 |
+
"/project",
|
| 69 |
+
json={
|
| 70 |
+
"vectors": [[1.0, 0.0], [0.0, 1.0, 0.0]],
|
| 71 |
+
"method": "umap",
|
| 72 |
+
"n_components": 2,
|
| 73 |
+
},
|
| 74 |
+
)
|
| 75 |
+
assert res.status_code == 400
|
| 76 |
+
assert "dim" in res.json()["detail"].lower()
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
def test_project_rejects_invalid_n_components(client: TestClient):
|
| 80 |
+
res = client.post(
|
| 81 |
+
"/project",
|
| 82 |
+
json={"vectors": _random_vectors(8, 8), "method": "umap", "n_components": 4},
|
| 83 |
+
)
|
| 84 |
+
assert res.status_code == 422 # pydantic Field constraint
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
@pytest.mark.parametrize("method", ["pca", "tsne"])
|
| 88 |
+
def test_project_pca_tsne_not_implemented(client: TestClient, method: str):
|
| 89 |
+
res = client.post(
|
| 90 |
+
"/project",
|
| 91 |
+
json={
|
| 92 |
+
"vectors": _random_vectors(12, 8),
|
| 93 |
+
"method": method,
|
| 94 |
+
"n_components": 3,
|
| 95 |
+
"seed": 42,
|
| 96 |
+
},
|
| 97 |
+
)
|
| 98 |
+
assert res.status_code == 501
|
| 99 |
+
detail = res.json()["detail"].lower()
|
| 100 |
+
assert method in detail
|
| 101 |
+
assert "not implemented" in detail or "umap" in detail
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
def test_project_rejects_unknown_method(client: TestClient):
|
| 105 |
+
res = client.post(
|
| 106 |
+
"/project",
|
| 107 |
+
json={
|
| 108 |
+
"vectors": _random_vectors(12, 8),
|
| 109 |
+
"method": "mds",
|
| 110 |
+
"n_components": 3,
|
| 111 |
+
},
|
| 112 |
+
)
|
| 113 |
+
assert res.status_code == 400
|
| 114 |
+
assert "umap" in res.json()["detail"].lower()
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
def test_project_umap_smoke_3d_seeded(client: TestClient):
|
| 118 |
+
vectors = _random_vectors(n=20, dim=16, seed=7)
|
| 119 |
+
payload = {
|
| 120 |
+
"vectors": vectors,
|
| 121 |
+
"method": "umap",
|
| 122 |
+
"n_components": 3,
|
| 123 |
+
"seed": 42,
|
| 124 |
+
"params": {"n_neighbors": 5, "min_dist": 0.1, "metric": "cosine"},
|
| 125 |
+
}
|
| 126 |
+
res = client.post("/project", json=payload)
|
| 127 |
+
assert res.status_code == 200, res.text
|
| 128 |
+
data = res.json()
|
| 129 |
+
assert data["method"] == "umap"
|
| 130 |
+
assert data["n_components"] == 3
|
| 131 |
+
assert len(data["positions"]) == 20
|
| 132 |
+
assert all(len(p) == 3 for p in data["positions"])
|
| 133 |
+
|
| 134 |
+
meta = data["meta"]
|
| 135 |
+
assert meta["seed"] == 42
|
| 136 |
+
assert meta["n_neighbors"] == 5
|
| 137 |
+
assert meta["min_dist"] == pytest.approx(0.1)
|
| 138 |
+
assert meta["metric"] == "cosine"
|
| 139 |
+
|
| 140 |
+
# Server-side normalize: approximately zero-mean
|
| 141 |
+
pos = np.asarray(data["positions"], dtype=np.float64)
|
| 142 |
+
means = pos.mean(axis=0)
|
| 143 |
+
assert np.allclose(means, 0.0, atol=1e-5)
|
| 144 |
+
|
| 145 |
+
# Same inputs → same positions (seeded)
|
| 146 |
+
res2 = client.post("/project", json=payload)
|
| 147 |
+
assert res2.status_code == 200
|
| 148 |
+
pos2 = np.asarray(res2.json()["positions"], dtype=np.float64)
|
| 149 |
+
assert np.allclose(pos, pos2, atol=1e-5)
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
def test_project_umap_n_components_2(client: TestClient):
|
| 153 |
+
vectors = _random_vectors(n=16, dim=12, seed=3)
|
| 154 |
+
res = client.post(
|
| 155 |
+
"/project",
|
| 156 |
+
json={
|
| 157 |
+
"vectors": vectors,
|
| 158 |
+
"method": "umap",
|
| 159 |
+
"n_components": 2,
|
| 160 |
+
"seed": 42,
|
| 161 |
+
"params": {"n_neighbors": 5},
|
| 162 |
+
},
|
| 163 |
+
)
|
| 164 |
+
assert res.status_code == 200
|
| 165 |
+
data = res.json()
|
| 166 |
+
assert data["n_components"] == 2
|
| 167 |
+
assert all(len(p) == 2 for p in data["positions"])
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
def test_project_umap_pre_pca_when_high_dim(client: TestClient):
|
| 171 |
+
"""dim > 50 triggers internal PCA→50 before UMAP; meta reports pre_pca_dims."""
|
| 172 |
+
vectors = _random_vectors(n=60, dim=128, seed=1)
|
| 173 |
+
res = client.post(
|
| 174 |
+
"/project",
|
| 175 |
+
json={
|
| 176 |
+
"vectors": vectors,
|
| 177 |
+
"method": "umap",
|
| 178 |
+
"n_components": 3,
|
| 179 |
+
"seed": 42,
|
| 180 |
+
"params": {"n_neighbors": 8},
|
| 181 |
+
},
|
| 182 |
+
)
|
| 183 |
+
assert res.status_code == 200, res.text
|
| 184 |
+
meta = res.json()["meta"]
|
| 185 |
+
assert meta["pre_pca_dims"] == 50
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def test_project_module_unit_rejects_method():
|
| 189 |
+
from backend.projection import ProjectError, project_embeddings
|
| 190 |
+
|
| 191 |
+
with pytest.raises(ProjectError) as ei:
|
| 192 |
+
project_embeddings(
|
| 193 |
+
_random_vectors(10, 8),
|
| 194 |
+
method="pca",
|
| 195 |
+
n_components=3,
|
| 196 |
+
seed=42,
|
| 197 |
+
)
|
| 198 |
+
assert ei.value.status_code == 501
|
backend/uv.lock
CHANGED
|
@@ -314,6 +314,38 @@ wheels = [
|
|
| 314 |
{ url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" },
|
| 315 |
]
|
| 316 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 317 |
[[package]]
|
| 318 |
name = "markdown-it-py"
|
| 319 |
version = "4.2.0"
|
|
@@ -463,6 +495,43 @@ wheels = [
|
|
| 463 |
{ url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
|
| 464 |
]
|
| 465 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 466 |
[[package]]
|
| 467 |
name = "numpy"
|
| 468 |
version = "2.2.6"
|
|
@@ -533,6 +602,7 @@ name = "numpy"
|
|
| 533 |
version = "2.4.6"
|
| 534 |
source = { registry = "https://pypi.org/simple" }
|
| 535 |
resolution-markers = [
|
|
|
|
| 536 |
"python_full_version == '3.11.*'",
|
| 537 |
]
|
| 538 |
sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" }
|
|
@@ -610,60 +680,6 @@ wheels = [
|
|
| 610 |
{ url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" },
|
| 611 |
]
|
| 612 |
|
| 613 |
-
[[package]]
|
| 614 |
-
name = "numpy"
|
| 615 |
-
version = "2.5.1"
|
| 616 |
-
source = { registry = "https://pypi.org/simple" }
|
| 617 |
-
resolution-markers = [
|
| 618 |
-
"python_full_version >= '3.12'",
|
| 619 |
-
]
|
| 620 |
-
sdist = { url = "https://files.pythonhosted.org/packages/22/fd/89965aa4ac08c74998539fcbf24fa3540f3e15237fbeb6bcf9c908f4aade/numpy-2.5.1.tar.gz", hash = "sha256:a48a113e6afea91f5608793bafa7ef2ad481fefbda87ec5069f483de61cb9fa3", size = 20755553, upload-time = "2026-07-04T17:08:00.933Z" }
|
| 621 |
-
wheels = [
|
| 622 |
-
{ url = "https://files.pythonhosted.org/packages/62/7b/14687aa674250e5e546f616f486b0d56d3631cd5b2415739141ce40bdcea/numpy-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c889b56fe48b1018f764b0eec8df59ab654e9148aa91faa12596043500de277", size = 16801574, upload-time = "2026-07-04T17:06:12.423Z" },
|
| 623 |
-
{ url = "https://files.pythonhosted.org/packages/e1/19/cc5bb2a3f2913d27d6dbb2c78d25921fabaedc6741d4a5a615a11f3c5bf3/numpy-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab451b59c5643c570974c43aef780703ef1d3b4965d2be07afd530615a9358d1", size = 11772250, upload-time = "2026-07-04T17:06:15.726Z" },
|
| 624 |
-
{ url = "https://files.pythonhosted.org/packages/42/77/fdf34a71dd30f54979b18603bee915e0aaf825b07afe79acd60b04b691e2/numpy-2.5.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:78798bd5b9ad744056af8efa90e3b9ddaa53272a0848a483084a1cc0a13b2dc0", size = 5331516, upload-time = "2026-07-04T17:06:17.913Z" },
|
| 625 |
-
{ url = "https://files.pythonhosted.org/packages/ce/e2/eb7efa015b4cce41e2517bf182a7fce0d7d5b9d9ed76a29bfa0f4fe4505c/numpy-2.5.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2ae0ca40bcb22d6ba59c1dfd5446f49940b0f2d821fde133f10dda11f816b84e", size = 6664863, upload-time = "2026-07-04T17:06:20.02Z" },
|
| 626 |
-
{ url = "https://files.pythonhosted.org/packages/a9/4b/a2b32dd94ee9ffbeecb28152240042a3949db33b1c834d44090b80e1b3b8/numpy-2.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61ac47e772e6b8ea489e1d2f441a34c5c3ac17327e7ce294cbdf535795ad4e75", size = 15167977, upload-time = "2026-07-04T17:06:21.621Z" },
|
| 627 |
-
{ url = "https://files.pythonhosted.org/packages/b8/a9/6e73d68500f80773f65f0654ea932019d6694329a0eb0ed0533de38df376/numpy-2.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59fda5e192b570217ec2580c96f00e9a7e12ef6866a900eb089b62c1a32545ca", size = 16672469, upload-time = "2026-07-04T17:06:24.064Z" },
|
| 628 |
-
{ url = "https://files.pythonhosted.org/packages/24/7d/ad3e59015135f5261c95fd4cafeff159c955febd83a99a1d9250c4233815/numpy-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7119ebff1a9829e9f431a4f9d28e703023bb6b9fe7c8f724467dbfc27c94ab3", size = 16527531, upload-time = "2026-07-04T17:06:26.69Z" },
|
| 629 |
-
{ url = "https://files.pythonhosted.org/packages/83/d0/a39b2fbcde9cb17a1dac678f254b33a6336298af9df338824c685425d5e8/numpy-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e824c2acf8862052246be5a44c15da1777940c60d010dd2aab897824d9c430f9", size = 18431940, upload-time = "2026-07-04T17:06:29.521Z" },
|
| 630 |
-
{ url = "https://files.pythonhosted.org/packages/04/12/cff070947791c1ed425ff76413189adbdc2fbe215eba7ce7fa454a03c7f8/numpy-2.5.1-cp312-cp312-win32.whl", hash = "sha256:08d60c810432eb83360958dea0999ac4cfb94531ea8efcbf0b7f277c2068aeb2", size = 6066764, upload-time = "2026-07-04T17:06:32.571Z" },
|
| 631 |
-
{ url = "https://files.pythonhosted.org/packages/65/66/53f31807a48a750f9d748da273bc3fcedd12b27ff1f3e373bfec55ef2dc0/numpy-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7d60026c0bdb1380e83bfa7a0419c4577ee4b9a08880afcb6dadeb74c649fa2", size = 12430966, upload-time = "2026-07-04T17:06:34.926Z" },
|
| 632 |
-
{ url = "https://files.pythonhosted.org/packages/2b/2a/d1a88066b1c14186f5d3c0d18c94f17b064511982bab0578d49ee9d43c29/numpy-2.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:17a25e09640602e10bc8de0e6fa2b3fd68eedd84ba6d7842dc8f32f9ab87bd0b", size = 10350488, upload-time = "2026-07-04T17:06:37.785Z" },
|
| 633 |
-
{ url = "https://files.pythonhosted.org/packages/eb/07/ec2a3f0c91761581d4b7104a740791800025983f9a4dc4e73f91a99aeac4/numpy-2.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0bfebd8695f9863592fe744be833a258120b14a9f39da255e8aa8fade2c0ddd1", size = 16796419, upload-time = "2026-07-04T17:06:40.37Z" },
|
| 634 |
-
{ url = "https://files.pythonhosted.org/packages/ab/ab/ddb499fc4f8780354395face5b65c7fd107bcd6e1d667a5f07d046956f6f/numpy-2.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:30b44a6b53a7ae63c54c089a8726e5563ed302716c5b7ccc85afade40b0e7ff6", size = 11765832, upload-time = "2026-07-04T17:06:42.768Z" },
|
| 635 |
-
{ url = "https://files.pythonhosted.org/packages/88/b3/3c28c558a09fc72100c646dac6d2fce8e834c471b0edca01a29996706117/numpy-2.5.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:6165343f81b56ef8f514f396989e529b61d9dc709b99421b07e9f3e698e2287d", size = 5325143, upload-time = "2026-07-04T17:06:45.466Z" },
|
| 636 |
-
{ url = "https://files.pythonhosted.org/packages/5e/0e/ce19b985bb15c596f4f05954e76cccc77c845083b3b8f938a6c68e523128/numpy-2.5.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4939237038ada79308dda3204ac6462df056b5672b2e25db1149cf873668b3e1", size = 6659749, upload-time = "2026-07-04T17:06:47.288Z" },
|
| 637 |
-
{ url = "https://files.pythonhosted.org/packages/2e/20/1ee6614d64332a1bba6411f38e68cb79eec1b2459e20a623777c5c5492a2/numpy-2.5.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c6759f538fb912fc46de0a6b1758ccf7b57bc7c7ebebc23974fdac3de8db0cd", size = 15164716, upload-time = "2026-07-04T17:06:49.494Z" },
|
| 638 |
-
{ url = "https://files.pythonhosted.org/packages/ed/a7/2bcd3fdbb87804755c35b729bf8709d62025c5f4cfd7d5b2415997097515/numpy-2.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9726558e8db4a5bf7929a70ae50f63abda4daf0efe810e3bfbab95976f75fc1a", size = 16661440, upload-time = "2026-07-04T17:06:52.061Z" },
|
| 639 |
-
{ url = "https://files.pythonhosted.org/packages/fc/d7/a41e3310c886fe457d36e670bbf24fae411aca8a7b6ad92a32afd924077c/numpy-2.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3935f3b419b244a02732676fa5317a9193cc596a4c0646db07e5b421229ac9f7", size = 16526305, upload-time = "2026-07-04T17:06:54.605Z" },
|
| 640 |
-
{ url = "https://files.pythonhosted.org/packages/53/75/4333a9a707c1edd3a4e1a0c58eca52c0f31e55089fa80db02b5565b24df7/numpy-2.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc932a65ded7ce9013d120845a2514dcccb1a67bfc8deb8d37633762951904a6", size = 18423008, upload-time = "2026-07-04T17:06:57.54Z" },
|
| 641 |
-
{ url = "https://files.pythonhosted.org/packages/ee/90/e314a32b1c11a2ffe818ddad3a57b50b4b6e1b6c487192eb50cdef0415d0/numpy-2.5.1-cp313-cp313-win32.whl", hash = "sha256:4b4ff1608417eb7a59da7b967bbb798cacfe071d2caf526a24281cd562072ed9", size = 6063885, upload-time = "2026-07-04T17:07:00.14Z" },
|
| 642 |
-
{ url = "https://files.pythonhosted.org/packages/10/70/800b3fca480af32df9e8ea9f3d4a0c8feb4b32d7f195d174eabbda4829ad/numpy-2.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:6c3fe51bc6a16453d452997053454f309e8e0ed7b42d6b361ce4ac8c32913d74", size = 12425674, upload-time = "2026-07-04T17:07:02.387Z" },
|
| 643 |
-
{ url = "https://files.pythonhosted.org/packages/8b/0b/196350c122f50f6ca56846f2d71efd5e0d24b7b2e07355e019b2e2c7a11e/numpy-2.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:f7feb014281029e628ba2d5a007407443b06e418b6fe451d1e2adcbc8eba0107", size = 10350256, upload-time = "2026-07-04T17:07:04.878Z" },
|
| 644 |
-
{ url = "https://files.pythonhosted.org/packages/db/f4/731b6085a83faf6ca843394cbd5e217280c214399f7e8b21b9f552af0ae2/numpy-2.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7c786fe9a5bbe360022e584c5a34cf6b54265c71bd7ec8ac3d8fec38968071f8", size = 16795063, upload-time = "2026-07-04T17:07:07.374Z" },
|
| 645 |
-
{ url = "https://files.pythonhosted.org/packages/bf/64/0e215f2048dd11a55bb989ed41b3585ef57452404e638d703a211a3e4157/numpy-2.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32985c896d897419ef8da6917872d80b78ad0ea26d85b23245c7366ffde76d75", size = 11776652, upload-time = "2026-07-04T17:07:09.907Z" },
|
| 646 |
-
{ url = "https://files.pythonhosted.org/packages/b5/59/2b844c7a6e9deff69b404a66221e1542937734f65d5e6e39411876053862/numpy-2.5.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:efd736408cc97c79b9e6917338dfc8f06013b2274f992e96b1d9a81a71e2a2c2", size = 5335944, upload-time = "2026-07-04T17:07:12.227Z" },
|
| 647 |
-
{ url = "https://files.pythonhosted.org/packages/86/51/9bf7cb2cabcebc9e017e4ec7e6322b378317a542c08b4cb68479c1efc716/numpy-2.5.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:ab84dc6b074fa881cae55bea94cc4f68e285181ba7f32497bf7dee6b1496165b", size = 6656266, upload-time = "2026-07-04T17:07:14.368Z" },
|
| 648 |
-
{ url = "https://files.pythonhosted.org/packages/83/3e/fb7615b211b82a32f44d5180a6d421b61f84d4fadd578b48ba4ac34e189f/numpy-2.5.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caf3e317d33d60c37986b452613f4ab51246d0691350c03d0cb4a898627f4a95", size = 15179720, upload-time = "2026-07-04T17:07:16.272Z" },
|
| 649 |
-
{ url = "https://files.pythonhosted.org/packages/41/5f/0f992cb24560673496c5d68de61913b57166ce530ffda07c1f280e0cc464/numpy-2.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54ad769f17bc2d833b620851989f62054fb9ab93c969d9e1dc3c8e3d56beea21", size = 16664835, upload-time = "2026-07-04T17:07:19.021Z" },
|
| 650 |
-
{ url = "https://files.pythonhosted.org/packages/a2/2f/97d6475ee91afe2587797d09446f9d3e475ad4cb681662d824809327b75a/numpy-2.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c12afb53450fa976d4c681c50a7423729a4c51c0465ed9f32b8a9cabbc472373", size = 16539135, upload-time = "2026-07-04T17:07:22.015Z" },
|
| 651 |
-
{ url = "https://files.pythonhosted.org/packages/c4/5b/4db81e4ba0be7e2776b1de68c82aa862c7f8ec27e1b4927d4ae075e20678/numpy-2.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e8c11c405efc5ff6816d5983c96cdfa215bab3428961243af3ff59b228490438", size = 18426684, upload-time = "2026-07-04T17:07:24.941Z" },
|
| 652 |
-
{ url = "https://files.pythonhosted.org/packages/1f/64/c0ba2d90724d450279a7df8f32057241070250a26a7e2b5337d77347f481/numpy-2.5.1-cp314-cp314-win32.whl", hash = "sha256:f2479a47f8d5932d1718168a681ad6e536a9df484c83cfcf9de365e164537ace", size = 6116103, upload-time = "2026-07-04T17:07:27.622Z" },
|
| 653 |
-
{ url = "https://files.pythonhosted.org/packages/c1/1a/837f9ed7405adcd7a40538792eb169eddd8fa5630c16a1ef49dae71a30f4/numpy-2.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:24d0eb82c0541d3415a33425db64ae439dffccd7b4dbcb30e7c35120205c506a", size = 12562177, upload-time = "2026-07-04T17:07:29.887Z" },
|
| 654 |
-
{ url = "https://files.pythonhosted.org/packages/22/ed/49707938b6dd0a78a9178dd93227dc89e4c11af47f5c798d70366e8d0483/numpy-2.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:5a4c988b38d261deeeaad9954e3deb091ad905c94e8bb6708654ef1d97f286b0", size = 10627739, upload-time = "2026-07-04T17:07:32.568Z" },
|
| 655 |
-
{ url = "https://files.pythonhosted.org/packages/a6/c7/bb4b882cfe7f299cbc8b66e42e7dd78cf9d14e40f9469fc5e3db7e15b3bd/numpy-2.5.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a33276be12fa045805f477f22482088b66bb758ffbe89a9d21457de863a32e22", size = 11894709, upload-time = "2026-07-04T17:07:34.941Z" },
|
| 656 |
-
{ url = "https://files.pythonhosted.org/packages/40/3f/5af7f4a7f6224aef48017aa82bb6174c7a659d724be0c75017b7e64a55b4/numpy-2.5.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:f089d7b00756190aacf1f5d34bdf38c3c430ac82b4f868f8cede73380460fce7", size = 5453810, upload-time = "2026-07-04T17:07:37.495Z" },
|
| 657 |
-
{ url = "https://files.pythonhosted.org/packages/20/c9/3474309bc94d634d3f9c3eddf03250ecb8c22cd948ef16fef69a77cc5d7b/numpy-2.5.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:09e9bfd8d2cf479c7d174804fb3811c53a8e9f20a37444008606b57d6b7a826d", size = 6761189, upload-time = "2026-07-04T17:07:39.563Z" },
|
| 658 |
-
{ url = "https://files.pythonhosted.org/packages/90/8a/558ae39fdd55d7e7f7fef9a84a6e964ac6b23edbd2a07e52bb084500507d/numpy-2.5.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e68d8dd1e7eba712948f2053a29ec86917bc70ba1358df869d9f06649ef9cf09", size = 15225039, upload-time = "2026-07-04T17:07:41.682Z" },
|
| 659 |
-
{ url = "https://files.pythonhosted.org/packages/63/27/ca7392b2d030277bdf0273e7d23255b3ee57d57a7c170a6f4fb3981e1e5d/numpy-2.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99d5095fa265a0c4152e7bb12759e14381ef5496152f1ce58f44bdf55c44beb4", size = 16701306, upload-time = "2026-07-04T17:07:44.611Z" },
|
| 660 |
-
{ url = "https://files.pythonhosted.org/packages/02/42/03d53ae7996c44d4374a8262e9dc41671fd56cbb98f7d47ef85cf5da4c6b/numpy-2.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ab87a91b3cc3382b8956095bd8f95e00cf679bb81554339be1a2ba404a1473c1", size = 16589955, upload-time = "2026-07-04T17:07:47.694Z" },
|
| 661 |
-
{ url = "https://files.pythonhosted.org/packages/7b/15/6c1784ae469640e65db111e9a34b3d0f14d91e8a38b9ce34810ced370dbb/numpy-2.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:224ca51130ef7da85bea2191625181cb4f337f9cb64b471f10c1a12aa8b60077", size = 18464252, upload-time = "2026-07-04T17:07:50.684Z" },
|
| 662 |
-
{ url = "https://files.pythonhosted.org/packages/94/a8/f98e50356cf167df656c526c2dfeec2d7dde182f2a3da4b458a5938e2776/numpy-2.5.1-cp314-cp314t-win32.whl", hash = "sha256:6eab239876581b2b3c5a242281b6007bbdbcd1c7085d7709bb57c5929b11e6bf", size = 6263298, upload-time = "2026-07-04T17:07:53.445Z" },
|
| 663 |
-
{ url = "https://files.pythonhosted.org/packages/72/ac/96ae880cdecad0b3275d9359fcec72667b49a4863c9f12942e43679dda02/numpy-2.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:83ce9c80d5b521b0d77ddcbe5447c218d247929b6cc056ca5351342accfff0af", size = 12748623, upload-time = "2026-07-04T17:07:55.384Z" },
|
| 664 |
-
{ url = "https://files.pythonhosted.org/packages/a1/5a/4d2b1601df3602dba7a14f3348ba9bfe94a18adb428e693df6154c293831/numpy-2.5.1-cp314-cp314t-win_arm64.whl", hash = "sha256:5a6db61f9aaa57e369905c67d852045d3c4f7126405b29d09b19dec118e9c9cb", size = 10697674, upload-time = "2026-07-04T17:07:58.506Z" },
|
| 665 |
-
]
|
| 666 |
-
|
| 667 |
[[package]]
|
| 668 |
name = "nvidia-cublas"
|
| 669 |
version = "13.1.1.3"
|
|
@@ -1055,6 +1071,25 @@ wheels = [
|
|
| 1055 |
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
| 1056 |
]
|
| 1057 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1058 |
[[package]]
|
| 1059 |
name = "pytest"
|
| 1060 |
version = "9.1.1"
|
|
@@ -1378,8 +1413,7 @@ resolution-markers = [
|
|
| 1378 |
dependencies = [
|
| 1379 |
{ name = "joblib", marker = "python_full_version >= '3.11'" },
|
| 1380 |
{ name = "narwhals", marker = "python_full_version >= '3.11'" },
|
| 1381 |
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version =
|
| 1382 |
-
{ name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1383 |
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
|
| 1384 |
{ name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1385 |
{ name = "threadpoolctl", marker = "python_full_version >= '3.11'" },
|
|
@@ -1559,7 +1593,7 @@ resolution-markers = [
|
|
| 1559 |
"python_full_version >= '3.12'",
|
| 1560 |
]
|
| 1561 |
dependencies = [
|
| 1562 |
-
{ name = "numpy", version = "2.
|
| 1563 |
]
|
| 1564 |
sdist = { url = "https://files.pythonhosted.org/packages/a7/25/c2700dfaf6442b4effaa91af24ebce5dc9d31bb4a69706313aae70d72cd0/scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378", size = 30774447, upload-time = "2026-06-19T15:01:43.456Z" }
|
| 1565 |
wheels = [
|
|
@@ -1612,8 +1646,7 @@ source = { registry = "https://pypi.org/simple" }
|
|
| 1612 |
dependencies = [
|
| 1613 |
{ name = "huggingface-hub" },
|
| 1614 |
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1615 |
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version =
|
| 1616 |
-
{ name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1617 |
{ name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1618 |
{ name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
| 1619 |
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
@@ -1832,8 +1865,7 @@ source = { registry = "https://pypi.org/simple" }
|
|
| 1832 |
dependencies = [
|
| 1833 |
{ name = "huggingface-hub" },
|
| 1834 |
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1835 |
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version =
|
| 1836 |
-
{ name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1837 |
{ name = "packaging" },
|
| 1838 |
{ name = "pyyaml" },
|
| 1839 |
{ name = "regex" },
|
|
@@ -1902,6 +1934,27 @@ wheels = [
|
|
| 1902 |
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
| 1903 |
]
|
| 1904 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1905 |
[[package]]
|
| 1906 |
name = "uvicorn"
|
| 1907 |
version = "0.52.1"
|
|
@@ -1925,11 +1978,11 @@ dependencies = [
|
|
| 1925 |
{ name = "httpx" },
|
| 1926 |
{ name = "huggingface-hub" },
|
| 1927 |
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1928 |
-
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version =
|
| 1929 |
-
{ name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1930 |
{ name = "orjson" },
|
| 1931 |
{ name = "sentence-transformers" },
|
| 1932 |
{ name = "torch" },
|
|
|
|
| 1933 |
{ name = "uvicorn" },
|
| 1934 |
]
|
| 1935 |
|
|
@@ -1952,6 +2005,7 @@ requires-dist = [
|
|
| 1952 |
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.3.0" },
|
| 1953 |
{ name = "sentence-transformers", specifier = ">=2.5.0" },
|
| 1954 |
{ name = "torch", specifier = ">=2.2.0" },
|
|
|
|
| 1955 |
{ name = "uvicorn", specifier = ">=0.28.0" },
|
| 1956 |
]
|
| 1957 |
provides-extras = ["dev"]
|
|
|
|
| 314 |
{ url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" },
|
| 315 |
]
|
| 316 |
|
| 317 |
+
[[package]]
|
| 318 |
+
name = "llvmlite"
|
| 319 |
+
version = "0.48.0"
|
| 320 |
+
source = { registry = "https://pypi.org/simple" }
|
| 321 |
+
sdist = { url = "https://files.pythonhosted.org/packages/dc/a0/acc8ffcd5bdc63df0097e22c719bfcd61b604358343089313a8aebbb24ab/llvmlite-0.48.0.tar.gz", hash = "sha256:543b19f9ef8f3c7c60d1468191e4ee1b1537bf9f8a3d56f64c0ddd98de92edd2", size = 184016, upload-time = "2026-07-02T20:20:05.308Z" }
|
| 322 |
+
wheels = [
|
| 323 |
+
{ url = "https://files.pythonhosted.org/packages/a2/4e/32543c42568fb321b3bdfcf9106e4116ab8f5a7bbcfd9ecf5569b0c07d83/llvmlite-0.48.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:614aad57df707e3172efd5165f2aa7da6a0c6897e40dce590bf756396815ba76", size = 40480650, upload-time = "2026-07-01T18:41:01.945Z" },
|
| 324 |
+
{ url = "https://files.pythonhosted.org/packages/a9/0d/6aa48abd423067139a129d1434b77bbcc56080db51d12a88510bb491ca3d/llvmlite-0.48.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:13532f248960ba888ad5ab8150494e2f3a3d20e5f59f264e63741ea5b0ba844c", size = 59890118, upload-time = "2026-07-01T18:41:10.608Z" },
|
| 325 |
+
{ url = "https://files.pythonhosted.org/packages/5a/c7/aa917444d871a79608af49149de1b28764e87d2ab41f933c5cd02431d03d/llvmlite-0.48.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3ee0c77685a18f5fca994ae21d0763007fca5c5c64b41de37accc78b69079176", size = 58343459, upload-time = "2026-07-01T18:41:06.21Z" },
|
| 326 |
+
{ url = "https://files.pythonhosted.org/packages/c5/2b/ceee1cdc263617109d514ac4d1b31f10a282662740ff7d5777baae25b3b5/llvmlite-0.48.0-cp310-cp310-win_amd64.whl", hash = "sha256:02853fe4214acb3780fc920c3fee10564b61d58a35e1b78afcc8a546c2deaba3", size = 41864734, upload-time = "2026-07-01T18:41:14.746Z" },
|
| 327 |
+
{ url = "https://files.pythonhosted.org/packages/9a/55/595981f14fbae9ba966feb12af552b1fe69889e44e64ac883a731ed335e0/llvmlite-0.48.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:56a7e24607d3f02d7b1bae8d29c7e1e423d53143d68b072999777f19678fe77b", size = 40480651, upload-time = "2026-07-01T18:41:18.438Z" },
|
| 328 |
+
{ url = "https://files.pythonhosted.org/packages/26/08/0109d1b9cb3f4603f3890e30bc66c65332b79185f12a045343b2ae431f67/llvmlite-0.48.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6fa532d6bb3fd3f0803567c736401c54aecfe1a396d3ad25d2440d220e09f0e7", size = 59890118, upload-time = "2026-07-01T18:41:28.184Z" },
|
| 329 |
+
{ url = "https://files.pythonhosted.org/packages/02/eb/c5281be180c789cdffbf45b671884c57d7e61345ef3b0f643a4965e108e8/llvmlite-0.48.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:979a66a3f28a02565383ff463527dce78e9b856298872a361283132488e83591", size = 58343458, upload-time = "2026-07-01T18:41:23.397Z" },
|
| 330 |
+
{ url = "https://files.pythonhosted.org/packages/aa/f7/b3222b13f2d424dae3c9e63fde476af25ebccf1f3faf0b52d1b79fc15c70/llvmlite-0.48.0-cp311-cp311-win_amd64.whl", hash = "sha256:efaee0276e5e17c2b99b92e0c974bd484ef5977cf5dbc9168e82b71578edb47f", size = 41864734, upload-time = "2026-07-01T18:41:31.932Z" },
|
| 331 |
+
{ url = "https://files.pythonhosted.org/packages/92/a2/28696a9e61e245d1a79816d29d106692a90a2b6e7d78c98b326db70827af/llvmlite-0.48.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:d66c3beb4209087ddd4cf4ed2a0856b6887e6a913bdcf1aacfec9851cf2cba4e", size = 40480651, upload-time = "2026-07-01T18:41:35.694Z" },
|
| 332 |
+
{ url = "https://files.pythonhosted.org/packages/80/f2/72409351db66d0a317ec5087e076f31fb7b773a640db8a90ce6b5cac9edd/llvmlite-0.48.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:416fa4c2c66c2c6dc6d0a402648c19206e548efa0aa1eff01ad5cdad0af8217d", size = 59890118, upload-time = "2026-07-01T18:41:44.886Z" },
|
| 333 |
+
{ url = "https://files.pythonhosted.org/packages/3a/27/5ae2f3722606360480707adb47f001ad89df8251d06b14ee80336e660b66/llvmlite-0.48.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f5e5a5131045b72345c71062ea1a91910dde913792b6c9b28ebb2c1c0a712e98", size = 58343459, upload-time = "2026-07-01T18:41:40.306Z" },
|
| 334 |
+
{ url = "https://files.pythonhosted.org/packages/16/78/d824ffff7521cd140dc2006e44ce2bc82e64b48d1b32e90e956308c85a74/llvmlite-0.48.0-cp312-cp312-win_amd64.whl", hash = "sha256:d45c7541a80934ec6d8ab0defe67439494ecd2193cbf852a44ba827808976ac1", size = 41865022, upload-time = "2026-07-01T18:41:48.663Z" },
|
| 335 |
+
{ url = "https://files.pythonhosted.org/packages/9c/23/fe9316d14626b42c73ef0b502e724705a6ee9450afe53759c0a99c37c2d7/llvmlite-0.48.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a83a99ef0c05b4ccddf9b6218ed9fe84b653a0caf7c1d9dbe148d6d16c67f518", size = 40480652, upload-time = "2026-07-01T18:41:52.216Z" },
|
| 336 |
+
{ url = "https://files.pythonhosted.org/packages/1b/4a/90715fa12006d681270b08d881195b6fab3ec39572e048764a1f7f59fed7/llvmlite-0.48.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8761b9e522f55207e24424fcd98370289eec2710bf8e915c82d1053f642450dc", size = 59890120, upload-time = "2026-07-01T18:42:00.748Z" },
|
| 337 |
+
{ url = "https://files.pythonhosted.org/packages/70/5e/7b3e20d64650ca3c80af0cdb664ec4b575ec83d9d4dd05bea8bd31f9bbb6/llvmlite-0.48.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2fe5cb59b2063bfa039dcb8ca6481c0181bf552f340d10dcf61d7996a665556e", size = 58343457, upload-time = "2026-07-01T18:41:56.41Z" },
|
| 338 |
+
{ url = "https://files.pythonhosted.org/packages/17/97/5a430055d1838cf1fb7a01cfa943300f5e4c026fc6333a522c5e4a03b0c1/llvmlite-0.48.0-cp313-cp313-win_amd64.whl", hash = "sha256:91c7e24e74cde3f02b88aa5acca678373f9e069f3b98531b3dbb3a142d9d10bb", size = 41865022, upload-time = "2026-07-01T18:42:04.57Z" },
|
| 339 |
+
{ url = "https://files.pythonhosted.org/packages/8d/8e/8170f2e0c217f88069c333d85bb976e536b332aecfcce606ddbdb249385f/llvmlite-0.48.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:321f1ac39b462603f0b589751aecf2d237d056f6d005749c1752b6f23ec3f074", size = 40480650, upload-time = "2026-07-01T18:42:07.935Z" },
|
| 340 |
+
{ url = "https://files.pythonhosted.org/packages/d6/e1/05b50692b647cac3c18200ac485b04f342f00ed173c9cc46767274469a15/llvmlite-0.48.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:05f0103c8f2f96a37441337e3643863c01b8e83e530aff38960dcb383c54a065", size = 59890115, upload-time = "2026-07-01T18:42:17.805Z" },
|
| 341 |
+
{ url = "https://files.pythonhosted.org/packages/f7/c3/470b8c4ff9ae2db2f9cf5c3e73de76ed908a32788ae9eb5602d43e6a476b/llvmlite-0.48.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:37d66fae72802175b0bfe1ea06e624b51e2d7aee6c3c34bbd09739b8f88e8e0b", size = 58343457, upload-time = "2026-07-01T18:42:13.217Z" },
|
| 342 |
+
{ url = "https://files.pythonhosted.org/packages/c9/2d/6a5171fb7236ac0895e1a02ccba3735bf291e8597239aa6421894d3c0ba8/llvmlite-0.48.0-cp314-cp314-win_amd64.whl", hash = "sha256:966dcab0a598e2bd8fb5f2cc082cf7b07bae564fc485a3a8692393caf986facf", size = 42986372, upload-time = "2026-07-01T18:42:21.483Z" },
|
| 343 |
+
{ url = "https://files.pythonhosted.org/packages/94/e3/7a93e09c9f94e637ca90209ceef0334a9a1d45b0bdb7c92ff922d25d6187/llvmlite-0.48.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7a5c413317050a1d67c34708bde97707f9b2257ef1017f7532d21fe7d9a9ff30", size = 40480654, upload-time = "2026-07-01T18:42:25.076Z" },
|
| 344 |
+
{ url = "https://files.pythonhosted.org/packages/27/98/a29133b4728671a175f7d616fab8b1c6e1d8c269d1523581d3160697bfb1/llvmlite-0.48.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d9f952dff6c350c529997423d4fa43abae9722a884ac7ffafc37a3af676e7db", size = 59890119, upload-time = "2026-07-01T18:42:33.88Z" },
|
| 345 |
+
{ url = "https://files.pythonhosted.org/packages/1a/cf/7aac11a1f1c7ec54b60c7f6814e87561fb6b55b2f290455d7941eb113420/llvmlite-0.48.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:054aa7d46595935565f276cf0c1659b4f10929c996dd4a606875fae26fba2a23", size = 58343460, upload-time = "2026-07-01T18:42:29.545Z" },
|
| 346 |
+
{ url = "https://files.pythonhosted.org/packages/db/41/b96f440c7df5ebba07872cad4e30fbc3560387755b1ea0b629adb76d5ca8/llvmlite-0.48.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d0b3c61aac83b42fb48cc96bffbf57c81b82b2aa92276b7ed6420c814629a99a", size = 42986383, upload-time = "2026-07-01T18:42:37.544Z" },
|
| 347 |
+
]
|
| 348 |
+
|
| 349 |
[[package]]
|
| 350 |
name = "markdown-it-py"
|
| 351 |
version = "4.2.0"
|
|
|
|
| 495 |
{ url = "https://files.pythonhosted.org/packages/9e/c9/b2622292ea83fbb4ec318f5b9ab867d0a28ab43c5717bb85b0a5f6b3b0a4/networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762", size = 2068504, upload-time = "2025-12-08T17:02:38.159Z" },
|
| 496 |
]
|
| 497 |
|
| 498 |
+
[[package]]
|
| 499 |
+
name = "numba"
|
| 500 |
+
version = "0.66.0"
|
| 501 |
+
source = { registry = "https://pypi.org/simple" }
|
| 502 |
+
dependencies = [
|
| 503 |
+
{ name = "llvmlite" },
|
| 504 |
+
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 505 |
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
| 506 |
+
]
|
| 507 |
+
sdist = { url = "https://files.pythonhosted.org/packages/ae/a0/570e3dc53e5602b49108f62a13e529f1eec8bfc7ef37d49c825924dcf546/numba-0.66.0.tar.gz", hash = "sha256:b900e63a0e26c05ea9a6d5a3a5a0a177cb64c5011887bf43edb8c3ed2c38d363", size = 2806181, upload-time = "2026-07-01T23:12:46.36Z" }
|
| 508 |
+
wheels = [
|
| 509 |
+
{ url = "https://files.pythonhosted.org/packages/2b/48/d139bde40f2359351bfe26ee1b261937f458ac177ab810d4f045ae1c9d92/numba-0.66.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:27951c47e0def9bf8afe580eb961102902e2fd23cb77924b7d9d7cc0f8b444cb", size = 2727368, upload-time = "2026-07-01T23:12:04.282Z" },
|
| 510 |
+
{ url = "https://files.pythonhosted.org/packages/36/e4/b780bfa9191410da50ba249cb3248a75014e17f611e72709cbddcb21f42d/numba-0.66.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc408c54b450f41582f4be1608f8981c1dcc44c7f40355cc150dd93015753407", size = 3803554, upload-time = "2026-07-01T23:12:06.379Z" },
|
| 511 |
+
{ url = "https://files.pythonhosted.org/packages/1c/b2/a051b96626bdf5c4d8fa6b8d450605c09638d85dc872ab63ef9a67096dca/numba-0.66.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c14c044c06b453ec3fa7715dfe75425e2ba72c73377a7ffde6d9ec511dfd94c", size = 3510065, upload-time = "2026-07-01T23:12:08.051Z" },
|
| 512 |
+
{ url = "https://files.pythonhosted.org/packages/34/01/24dcdc3e919522e2efbd92969c281ff40deb1d5f8a994bcd0057081c158c/numba-0.66.0-cp310-cp310-win_amd64.whl", hash = "sha256:2338cc0d43609fe448930848fd35a5bc688761b986f81b597a6f45cc0f8c9577", size = 2780379, upload-time = "2026-07-01T23:12:09.772Z" },
|
| 513 |
+
{ url = "https://files.pythonhosted.org/packages/9e/02/970796b4daa709604cde22e87a7cda9bde473c278ea4a75f59fe38cee47f/numba-0.66.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:bbd531c327557a9004507fa6bff06c53ab51a7a5776b75261bb9cef1efe2b2ea", size = 2727049, upload-time = "2026-07-01T23:12:11.296Z" },
|
| 514 |
+
{ url = "https://files.pythonhosted.org/packages/8c/99/33a6ed9c1a0b5e42efa98eb0edf617d61dca576c82625947377b1d4540c9/numba-0.66.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc6629becb21a867d85401ec89f426dd24c484a4193ade8a38309debfd1529ca", size = 3808870, upload-time = "2026-07-01T23:12:12.944Z" },
|
| 515 |
+
{ url = "https://files.pythonhosted.org/packages/04/20/8c51126025211659235b8de2866dfa226984ae0c8273461a3cf374716741/numba-0.66.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aac69f3ccb8af100f5913c1241edc9692bad1cdd2508721713f426eb06c9a659", size = 3514498, upload-time = "2026-07-01T23:12:15.307Z" },
|
| 516 |
+
{ url = "https://files.pythonhosted.org/packages/5e/c9/9476940bc6d5caf5c0cf2e4c5feecbf01244bbe6f914614082dd7a3e520e/numba-0.66.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb601841d9e02e6237bb6522e36d0741614be3cfe2b482a6f00a41b5ba209443", size = 2780225, upload-time = "2026-07-01T23:12:16.924Z" },
|
| 517 |
+
{ url = "https://files.pythonhosted.org/packages/62/a3/70deb7f88461c1cd5d16aa990c2380604102661a427667b8950dcdccc27f/numba-0.66.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:53ca5900b7cab15109796030113a6b28576bae5ad7bb507ad6dd1360ddd81ba4", size = 2727264, upload-time = "2026-07-01T23:12:18.669Z" },
|
| 518 |
+
{ url = "https://files.pythonhosted.org/packages/2d/55/25c319845e9a4e08f16611ddbda56a192eb7b6ed13e1a2bff2da272ffb97/numba-0.66.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0999e3ee1b18c48e1fb51d11af35ef59852c7f4f50569c9550c25faef0616ad1", size = 3866252, upload-time = "2026-07-01T23:12:20.429Z" },
|
| 519 |
+
{ url = "https://files.pythonhosted.org/packages/71/ef/a82d6fd6bf1b0fe461651e924d3647eeec9ac17f8eee4896264bf7480930/numba-0.66.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efe0d2d5099790df945e0cb6e1b3104bd965d7bbfac50d62f1d5d1d6ade0825d", size = 3566974, upload-time = "2026-07-01T23:12:22.116Z" },
|
| 520 |
+
{ url = "https://files.pythonhosted.org/packages/fc/eb/9e6171e378822ab191c7abcfd3d8cfc8644516f6c7834c22e210e4acc070/numba-0.66.0-cp312-cp312-win_amd64.whl", hash = "sha256:b075a4e7ebc43dc6294f223e2821659656209fd5e0ce53245877c23d66d6e1a9", size = 2797403, upload-time = "2026-07-01T23:12:23.724Z" },
|
| 521 |
+
{ url = "https://files.pythonhosted.org/packages/03/52/176c02d005c5c5143cde10a85bbcdcb6236d9e34c3aac089380e0506cd1d/numba-0.66.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:380b2556a2019ccd1e956ae77dd257eaa39403f7520768b626d44b755112785e", size = 2727084, upload-time = "2026-07-01T23:12:25.434Z" },
|
| 522 |
+
{ url = "https://files.pythonhosted.org/packages/44/b5/e930010965568fe7f2c6c962fd2849d458cb9f62c3ab7584af8a19a2b40a/numba-0.66.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:939316d5d8619751207b8972a67852b5a7646665298cb4de693cd6bf135152f4", size = 3873663, upload-time = "2026-07-01T23:12:27.308Z" },
|
| 523 |
+
{ url = "https://files.pythonhosted.org/packages/d0/ec/5b51457cbe96e4831141d83e892e65191b23a1b78728456c62909d231ace/numba-0.66.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cdf506775d9f02eb92a87bf5c5b1e0d25506fd18cafd769f4ed914a8feac73e7", size = 3573529, upload-time = "2026-07-01T23:12:28.944Z" },
|
| 524 |
+
{ url = "https://files.pythonhosted.org/packages/83/7e/cea7710e96913d3c7f2999f16db1b28e6c5be5171cbf40f77f98333a7243/numba-0.66.0-cp313-cp313-win_amd64.whl", hash = "sha256:c5bfe5350284509ab0474390321454c3a8627a188af5b68c910e83df3e2db4a7", size = 2797247, upload-time = "2026-07-01T23:12:30.774Z" },
|
| 525 |
+
{ url = "https://files.pythonhosted.org/packages/96/7a/7e0e73550eb4e41ede6e72fb5371f4539537a4d770a3b73fa9b61aea0622/numba-0.66.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:46ae5f2b19e2af3c33c2df100306a90ea2f981c8158b0390f8bf6c20eee7357e", size = 2727296, upload-time = "2026-07-01T23:12:32.39Z" },
|
| 526 |
+
{ url = "https://files.pythonhosted.org/packages/0f/26/885774c006de6620ed3d10f45d8e20fe0b8e6aad6d573211a2cbc8b3e528/numba-0.66.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e2b101f23b8b63978d334574d2039f27f0dccfe1d891756f33a2e2f3e4c88cf4", size = 3842720, upload-time = "2026-07-01T23:12:33.938Z" },
|
| 527 |
+
{ url = "https://files.pythonhosted.org/packages/93/99/edebf7de890b73973d839dd971cf73734adfb81ffa1b4504f84b9059c3e5/numba-0.66.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:63b943eb2c9ba371908ce2cd6dfc643db51fc40f7966993376a1701bc922f537", size = 3543537, upload-time = "2026-07-01T23:12:35.566Z" },
|
| 528 |
+
{ url = "https://files.pythonhosted.org/packages/66/c5/b46ad28ac3681d035ea21365c5e052149062e1a0a9affd0563d2760ea6ff/numba-0.66.0-cp314-cp314-win_amd64.whl", hash = "sha256:bd57790acd20f6a468e0ad333ef6b82355e309a92310fb7dff80e919f01a21a9", size = 2799250, upload-time = "2026-07-01T23:12:37.154Z" },
|
| 529 |
+
{ url = "https://files.pythonhosted.org/packages/10/6f/5e77a7397a37dd16f57a7b72e7e470db5227b68e3639df0d13a8e674883d/numba-0.66.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:db7735d15ea17a283d6485b9fa3504769f78fd86e5146638ad5e8da57c031b9e", size = 2730342, upload-time = "2026-07-01T23:12:38.758Z" },
|
| 530 |
+
{ url = "https://files.pythonhosted.org/packages/39/fd/e9c9680a3813f3d781c20e5d53c1074801b787d4feecca0472fdd7c05ce1/numba-0.66.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:651a2b53298340956db26ecbe7ab043106b50a40c2807e66d617a4917245a4ab", size = 3878695, upload-time = "2026-07-01T23:12:40.302Z" },
|
| 531 |
+
{ url = "https://files.pythonhosted.org/packages/61/3a/9b363287b85fcd4537ea3878793822878b2ac1008a78159d2096fea628de/numba-0.66.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8c1144ba1720ea59ad79f4f488ed54d149b2613b357f7e445678b7d0739c70e9", size = 3596323, upload-time = "2026-07-01T23:12:42.805Z" },
|
| 532 |
+
{ url = "https://files.pythonhosted.org/packages/4c/f2/dca53d50b8f2289dd01954ace9da261e0487d5b74b188b4304e4ecc3492c/numba-0.66.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d426178fb991a85714c43112a8ea7b9d9579ea856ad8dcdb9c1c3941903ba5be", size = 2804772, upload-time = "2026-07-01T23:12:44.399Z" },
|
| 533 |
+
]
|
| 534 |
+
|
| 535 |
[[package]]
|
| 536 |
name = "numpy"
|
| 537 |
version = "2.2.6"
|
|
|
|
| 602 |
version = "2.4.6"
|
| 603 |
source = { registry = "https://pypi.org/simple" }
|
| 604 |
resolution-markers = [
|
| 605 |
+
"python_full_version >= '3.12'",
|
| 606 |
"python_full_version == '3.11.*'",
|
| 607 |
]
|
| 608 |
sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" }
|
|
|
|
| 680 |
{ url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" },
|
| 681 |
]
|
| 682 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 683 |
[[package]]
|
| 684 |
name = "nvidia-cublas"
|
| 685 |
version = "13.1.1.3"
|
|
|
|
| 1071 |
{ url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" },
|
| 1072 |
]
|
| 1073 |
|
| 1074 |
+
[[package]]
|
| 1075 |
+
name = "pynndescent"
|
| 1076 |
+
version = "0.6.0"
|
| 1077 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1078 |
+
dependencies = [
|
| 1079 |
+
{ name = "joblib" },
|
| 1080 |
+
{ name = "llvmlite" },
|
| 1081 |
+
{ name = "numba" },
|
| 1082 |
+
{ name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1083 |
+
{ name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
| 1084 |
+
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1085 |
+
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
|
| 1086 |
+
{ name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1087 |
+
]
|
| 1088 |
+
sdist = { url = "https://files.pythonhosted.org/packages/4a/fb/7f58c397fb31666756457ee2ac4c0289ef2daad57f4ae4be8dec12f80b03/pynndescent-0.6.0.tar.gz", hash = "sha256:7ffde0fb5b400741e055a9f7d377e3702e02250616834231f6c209e39aac24f5", size = 2992987, upload-time = "2026-01-08T21:29:58.943Z" }
|
| 1089 |
+
wheels = [
|
| 1090 |
+
{ url = "https://files.pythonhosted.org/packages/b2/e6/94145d714402fd5ade00b5661f2d0ab981219e07f7db9bfa16786cdb9c04/pynndescent-0.6.0-py3-none-any.whl", hash = "sha256:dc8c74844e4c7f5cbd1e0cd6909da86fdc789e6ff4997336e344779c3d5538ef", size = 73511, upload-time = "2026-01-08T21:29:57.306Z" },
|
| 1091 |
+
]
|
| 1092 |
+
|
| 1093 |
[[package]]
|
| 1094 |
name = "pytest"
|
| 1095 |
version = "9.1.1"
|
|
|
|
| 1413 |
dependencies = [
|
| 1414 |
{ name = "joblib", marker = "python_full_version >= '3.11'" },
|
| 1415 |
{ name = "narwhals", marker = "python_full_version >= '3.11'" },
|
| 1416 |
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
|
|
| 1417 |
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
|
| 1418 |
{ name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1419 |
{ name = "threadpoolctl", marker = "python_full_version >= '3.11'" },
|
|
|
|
| 1593 |
"python_full_version >= '3.12'",
|
| 1594 |
]
|
| 1595 |
dependencies = [
|
| 1596 |
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1597 |
]
|
| 1598 |
sdist = { url = "https://files.pythonhosted.org/packages/a7/25/c2700dfaf6442b4effaa91af24ebce5dc9d31bb4a69706313aae70d72cd0/scipy-1.18.0.tar.gz", hash = "sha256:67b2ad2ad54c72ca6d04975a9b2df8c3638c34ddd5b28738e94fc2b57929d378", size = 30774447, upload-time = "2026-06-19T15:01:43.456Z" }
|
| 1599 |
wheels = [
|
|
|
|
| 1646 |
dependencies = [
|
| 1647 |
{ name = "huggingface-hub" },
|
| 1648 |
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1649 |
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
|
|
| 1650 |
{ name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1651 |
{ name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
| 1652 |
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
|
|
|
| 1865 |
dependencies = [
|
| 1866 |
{ name = "huggingface-hub" },
|
| 1867 |
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1868 |
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
|
|
| 1869 |
{ name = "packaging" },
|
| 1870 |
{ name = "pyyaml" },
|
| 1871 |
{ name = "regex" },
|
|
|
|
| 1934 |
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
| 1935 |
]
|
| 1936 |
|
| 1937 |
+
[[package]]
|
| 1938 |
+
name = "umap-learn"
|
| 1939 |
+
version = "0.5.12"
|
| 1940 |
+
source = { registry = "https://pypi.org/simple" }
|
| 1941 |
+
dependencies = [
|
| 1942 |
+
{ name = "numba" },
|
| 1943 |
+
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1944 |
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
| 1945 |
+
{ name = "pynndescent" },
|
| 1946 |
+
{ name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1947 |
+
{ name = "scikit-learn", version = "1.9.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
| 1948 |
+
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1949 |
+
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
|
| 1950 |
+
{ name = "scipy", version = "1.18.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
|
| 1951 |
+
{ name = "tqdm" },
|
| 1952 |
+
]
|
| 1953 |
+
sdist = { url = "https://files.pythonhosted.org/packages/02/ee/af4171241117f85c74b5ca6448ea1033cc28d599c13651d67289bacd4083/umap_learn-0.5.12.tar.gz", hash = "sha256:6aff02ecac5f2aad9f3c65ee518d7ae93e1a985ae38721fdcffceee4232c33c7", size = 96672, upload-time = "2026-04-08T20:03:54.012Z" }
|
| 1954 |
+
wheels = [
|
| 1955 |
+
{ url = "https://files.pythonhosted.org/packages/1b/98/f63318ccbe75c810011fe9233884c5d348d94d90005de1b79e5f93bef9c0/umap_learn-0.5.12-py3-none-any.whl", hash = "sha256:f2a85d2a2adcb52b541bed9b27a23ca169b56bb1b23283abeebfb8dfb8a42fe5", size = 91849, upload-time = "2026-04-08T20:03:52.561Z" },
|
| 1956 |
+
]
|
| 1957 |
+
|
| 1958 |
[[package]]
|
| 1959 |
name = "uvicorn"
|
| 1960 |
version = "0.52.1"
|
|
|
|
| 1978 |
{ name = "httpx" },
|
| 1979 |
{ name = "huggingface-hub" },
|
| 1980 |
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
|
| 1981 |
+
{ name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
|
|
|
|
| 1982 |
{ name = "orjson" },
|
| 1983 |
{ name = "sentence-transformers" },
|
| 1984 |
{ name = "torch" },
|
| 1985 |
+
{ name = "umap-learn" },
|
| 1986 |
{ name = "uvicorn" },
|
| 1987 |
]
|
| 1988 |
|
|
|
|
| 2005 |
{ name = "ruff", marker = "extra == 'dev'", specifier = ">=0.3.0" },
|
| 2006 |
{ name = "sentence-transformers", specifier = ">=2.5.0" },
|
| 2007 |
{ name = "torch", specifier = ">=2.2.0" },
|
| 2008 |
+
{ name = "umap-learn", specifier = "==0.5.12" },
|
| 2009 |
{ name = "uvicorn", specifier = ">=0.28.0" },
|
| 2010 |
]
|
| 2011 |
provides-extras = ["dev"]
|