merge main

This commit is contained in:
martabal 2023-08-29 17:21:32 +02:00
commit 1cb58728b2
No known key found for this signature in database
GPG key ID: C00196E3148A52BD
76 changed files with 9241 additions and 5829 deletions

View file

@ -862,6 +862,53 @@ export interface BulkIdsDto {
*/ */
'ids': Array<string>; 'ids': Array<string>;
} }
/**
*
* @export
* @interface CLIPConfig
*/
export interface CLIPConfig {
/**
*
* @type {boolean}
* @memberof CLIPConfig
*/
'enabled': boolean;
/**
*
* @type {CLIPMode}
* @memberof CLIPConfig
*/
'mode'?: CLIPMode;
/**
*
* @type {string}
* @memberof CLIPConfig
*/
'modelName': string;
/**
*
* @type {ModelType}
* @memberof CLIPConfig
*/
'modelType'?: ModelType;
}
/**
*
* @export
* @enum {string}
*/
export const CLIPMode = {
Vision: 'vision',
Text: 'text'
} as const;
export type CLIPMode = typeof CLIPMode[keyof typeof CLIPMode];
/** /**
* *
* @export * @export
@ -951,6 +998,39 @@ export interface CheckExistingAssetsResponseDto {
*/ */
'existingIds': Array<string>; 'existingIds': Array<string>;
} }
/**
*
* @export
* @interface ClassificationConfig
*/
export interface ClassificationConfig {
/**
*
* @type {boolean}
* @memberof ClassificationConfig
*/
'enabled': boolean;
/**
*
* @type {number}
* @memberof ClassificationConfig
*/
'minScore': number;
/**
*
* @type {string}
* @memberof ClassificationConfig
*/
'modelName': string;
/**
*
* @type {ModelType}
* @memberof ClassificationConfig
*/
'modelType'?: ModelType;
}
/** /**
* *
* @export * @export
@ -1766,6 +1846,21 @@ export interface MergePersonDto {
*/ */
'ids': Array<string>; 'ids': Array<string>;
} }
/**
*
* @export
* @enum {string}
*/
export const ModelType = {
ImageClassification: 'image-classification',
FacialRecognition: 'facial-recognition',
Clip: 'clip'
} as const;
export type ModelType = typeof ModelType[keyof typeof ModelType];
/** /**
* *
* @export * @export
@ -1991,6 +2086,45 @@ export interface QueueStatusDto {
*/ */
'isPaused': boolean; 'isPaused': boolean;
} }
/**
*
* @export
* @interface RecognitionConfig
*/
export interface RecognitionConfig {
/**
*
* @type {boolean}
* @memberof RecognitionConfig
*/
'enabled': boolean;
/**
*
* @type {number}
* @memberof RecognitionConfig
*/
'maxDistance': number;
/**
*
* @type {number}
* @memberof RecognitionConfig
*/
'minScore': number;
/**
*
* @type {string}
* @memberof RecognitionConfig
*/
'modelName': string;
/**
*
* @type {ModelType}
* @memberof RecognitionConfig
*/
'modelType'?: ModelType;
}
/** /**
* *
* @export * @export
@ -2803,10 +2937,16 @@ export interface SystemConfigJobDto {
export interface SystemConfigMachineLearningDto { export interface SystemConfigMachineLearningDto {
/** /**
* *
* @type {boolean} * @type {ClassificationConfig}
* @memberof SystemConfigMachineLearningDto * @memberof SystemConfigMachineLearningDto
*/ */
'clipEncodeEnabled': boolean; 'classification': ClassificationConfig;
/**
*
* @type {CLIPConfig}
* @memberof SystemConfigMachineLearningDto
*/
'clip': CLIPConfig;
/** /**
* *
* @type {boolean} * @type {boolean}
@ -2815,16 +2955,10 @@ export interface SystemConfigMachineLearningDto {
'enabled': boolean; 'enabled': boolean;
/** /**
* *
* @type {boolean} * @type {RecognitionConfig}
* @memberof SystemConfigMachineLearningDto * @memberof SystemConfigMachineLearningDto
*/ */
'facialRecognitionEnabled': boolean; 'facialRecognition': RecognitionConfig;
/**
*
* @type {boolean}
* @memberof SystemConfigMachineLearningDto
*/
'tagImageEnabled': boolean;
/** /**
* *
* @type {string} * @type {string}

View file

@ -8,17 +8,11 @@ from .schemas import ModelType
class Settings(BaseSettings): class Settings(BaseSettings):
cache_folder: str = "/cache" cache_folder: str = "/cache"
classification_model: str = "microsoft/resnet-50"
clip_image_model: str = "ViT-B-32::openai"
clip_text_model: str = "ViT-B-32::openai"
facial_recognition_model: str = "buffalo_l"
min_tag_score: float = 0.9
eager_startup: bool = False eager_startup: bool = False
model_ttl: int = 0 model_ttl: int = 0
host: str = "0.0.0.0" host: str = "0.0.0.0"
port: int = 3003 port: int = 3003
workers: int = 1 workers: int = 1
min_face_score: float = 0.7
test_full: bool = False test_full: bool = False
request_threads: int = os.cpu_count() or 4 request_threads: int = os.cpu_count() or 4
model_inter_op_threads: int = 1 model_inter_op_threads: int = 1

View file

@ -1,29 +1,26 @@
import asyncio import asyncio
import os import os
from concurrent.futures import ThreadPoolExecutor from concurrent.futures import ThreadPoolExecutor
from io import BytesIO
from typing import Any from typing import Any
import cv2 import orjson
import numpy as np
import uvicorn import uvicorn
from fastapi import Body, Depends, FastAPI from fastapi import FastAPI, Form, HTTPException, UploadFile
from PIL import Image from fastapi.responses import ORJSONResponse
from starlette.formparsers import MultiPartParser
from app.models.base import InferenceModel from app.models.base import InferenceModel
from .config import settings from .config import settings
from .models.cache import ModelCache from .models.cache import ModelCache
from .schemas import ( from .schemas import (
EmbeddingResponse,
FaceResponse,
MessageResponse, MessageResponse,
ModelType, ModelType,
TagResponse,
TextModelRequest,
TextResponse, TextResponse,
) )
MultiPartParser.max_file_size = 2**24 # spools to disk if payload is 16 MiB or larger
app = FastAPI() app = FastAPI()
@ -33,37 +30,9 @@ def init_state() -> None:
app.state.thread_pool = ThreadPoolExecutor(settings.request_threads) app.state.thread_pool = ThreadPoolExecutor(settings.request_threads)
async def load_models() -> None:
models: list[tuple[str, ModelType, dict[str, Any]]] = [
(settings.classification_model, ModelType.IMAGE_CLASSIFICATION, {}),
(settings.clip_image_model, ModelType.CLIP, {"mode": "vision"}),
(settings.clip_text_model, ModelType.CLIP, {"mode": "text"}),
(settings.facial_recognition_model, ModelType.FACIAL_RECOGNITION, {}),
]
# Get all models
for model_name, model_type, model_kwargs in models:
await app.state.model_cache.get(model_name, model_type, eager=settings.eager_startup, **model_kwargs)
@app.on_event("startup") @app.on_event("startup")
async def startup_event() -> None: async def startup_event() -> None:
init_state() init_state()
await load_models()
@app.on_event("shutdown")
async def shutdown_event() -> None:
app.state.thread_pool.shutdown()
def dep_pil_image(byte_image: bytes = Body(...)) -> Image.Image:
return Image.open(BytesIO(byte_image))
def dep_cv_image(byte_image: bytes = Body(...)) -> np.ndarray[int, np.dtype[Any]]:
byte_image_np = np.frombuffer(byte_image, np.uint8)
return cv2.imdecode(byte_image_np, cv2.IMREAD_COLOR)
@app.get("/", response_model=MessageResponse) @app.get("/", response_model=MessageResponse)
@ -76,57 +45,27 @@ def ping() -> str:
return "pong" return "pong"
@app.post( @app.post("/predict")
"/image-classifier/tag-image", async def predict(
response_model=TagResponse, model_name: str = Form(alias="modelName"),
status_code=200, model_type: ModelType = Form(alias="modelType"),
) options: str = Form(default="{}"),
async def image_classification( text: str | None = Form(default=None),
image: Image.Image = Depends(dep_pil_image), image: UploadFile | None = None,
) -> list[str]: ) -> Any:
model = await app.state.model_cache.get(settings.classification_model, ModelType.IMAGE_CLASSIFICATION) if image is not None:
labels = await predict(model, image) inputs: str | bytes = await image.read()
return labels elif text is not None:
inputs = text
else:
raise HTTPException(400, "Either image or text must be provided")
model: InferenceModel = await app.state.model_cache.get(model_name, model_type, **orjson.loads(options))
outputs = await run(model, inputs)
return ORJSONResponse(outputs)
@app.post( async def run(model: InferenceModel, inputs: Any) -> Any:
"/sentence-transformer/encode-image",
response_model=EmbeddingResponse,
status_code=200,
)
async def clip_encode_image(
image: Image.Image = Depends(dep_pil_image),
) -> list[float]:
model = await app.state.model_cache.get(settings.clip_image_model, ModelType.CLIP, mode="vision")
embedding = await predict(model, image)
return embedding
@app.post(
"/sentence-transformer/encode-text",
response_model=EmbeddingResponse,
status_code=200,
)
async def clip_encode_text(payload: TextModelRequest) -> list[float]:
model = await app.state.model_cache.get(settings.clip_text_model, ModelType.CLIP, mode="text")
embedding = await predict(model, payload.text)
return embedding
@app.post(
"/facial-recognition/detect-faces",
response_model=FaceResponse,
status_code=200,
)
async def facial_recognition(
image: cv2.Mat = Depends(dep_cv_image),
) -> list[dict[str, Any]]:
model = await app.state.model_cache.get(settings.facial_recognition_model, ModelType.FACIAL_RECOGNITION)
faces = await predict(model, image)
return faces
async def predict(model: InferenceModel, inputs: Any) -> Any:
return await asyncio.get_running_loop().run_in_executor(app.state.thread_pool, model.predict, inputs) return await asyncio.get_running_loop().run_in_executor(app.state.thread_pool, model.predict, inputs)

View file

@ -60,16 +60,21 @@ class InferenceModel(ABC):
self._load(**model_kwargs) self._load(**model_kwargs)
self._loaded = True self._loaded = True
def predict(self, inputs: Any) -> Any: def predict(self, inputs: Any, **model_kwargs: Any) -> Any:
if not self._loaded: if not self._loaded:
print(f"Loading {self.model_type.value.replace('_', ' ')} model...") print(f"Loading {self.model_type.value.replace('_', ' ')} model...")
self.load() self.load()
if model_kwargs:
self.configure(**model_kwargs)
return self._predict(inputs) return self._predict(inputs)
@abstractmethod @abstractmethod
def _predict(self, inputs: Any) -> Any: def _predict(self, inputs: Any) -> Any:
... ...
def configure(self, **model_kwargs: Any) -> None:
pass
@abstractmethod @abstractmethod
def _download(self, **model_kwargs: Any) -> None: def _download(self, **model_kwargs: Any) -> None:
... ...

View file

@ -1,5 +1,6 @@
import os import os
import zipfile import zipfile
from io import BytesIO
from typing import Any, Literal from typing import Any, Literal
import onnxruntime as ort import onnxruntime as ort
@ -8,7 +9,7 @@ from clip_server.model.clip import BICUBIC, _convert_image_to_rgb
from clip_server.model.clip_onnx import _MODELS, _S3_BUCKET_V2, CLIPOnnxModel, download_model from clip_server.model.clip_onnx import _MODELS, _S3_BUCKET_V2, CLIPOnnxModel, download_model
from clip_server.model.pretrained_models import _VISUAL_MODEL_IMAGE_SIZE from clip_server.model.pretrained_models import _VISUAL_MODEL_IMAGE_SIZE
from clip_server.model.tokenization import Tokenizer from clip_server.model.tokenization import Tokenizer
from PIL.Image import Image from PIL import Image
from torchvision.transforms import CenterCrop, Compose, Normalize, Resize, ToTensor from torchvision.transforms import CenterCrop, Compose, Normalize, Resize, ToTensor
from ..schemas import ModelType from ..schemas import ModelType
@ -74,9 +75,12 @@ class CLIPEncoder(InferenceModel):
image_size = _VISUAL_MODEL_IMAGE_SIZE[CLIPOnnxModel.get_model_name(self.model_name)] image_size = _VISUAL_MODEL_IMAGE_SIZE[CLIPOnnxModel.get_model_name(self.model_name)]
self.transform = _transform_pil_image(image_size) self.transform = _transform_pil_image(image_size)
def _predict(self, image_or_text: Image | str) -> list[float]: def _predict(self, image_or_text: Image.Image | str) -> list[float]:
if isinstance(image_or_text, bytes):
image_or_text = Image.open(BytesIO(image_or_text))
match image_or_text: match image_or_text:
case Image(): case Image.Image():
if self.mode == "text": if self.mode == "text":
raise TypeError("Cannot encode image as text-only model") raise TypeError("Cannot encode image as text-only model")
pixel_values = self.transform(image_or_text) pixel_values = self.transform(image_or_text)

View file

@ -9,7 +9,6 @@ from insightface.model_zoo import ArcFaceONNX, RetinaFace
from insightface.utils.face_align import norm_crop from insightface.utils.face_align import norm_crop
from insightface.utils.storage import BASE_REPO_URL, download_file from insightface.utils.storage import BASE_REPO_URL, download_file
from ..config import settings
from ..schemas import ModelType from ..schemas import ModelType
from .base import InferenceModel from .base import InferenceModel
@ -20,7 +19,7 @@ class FaceRecognizer(InferenceModel):
def __init__( def __init__(
self, self,
model_name: str, model_name: str,
min_score: float = settings.min_face_score, min_score: float = 0.7,
cache_dir: Path | str | None = None, cache_dir: Path | str | None = None,
**model_kwargs: Any, **model_kwargs: Any,
) -> None: ) -> None:
@ -69,11 +68,13 @@ class FaceRecognizer(InferenceModel):
) )
self.rec_model.prepare(ctx_id=0) self.rec_model.prepare(ctx_id=0)
def _predict(self, image: cv2.Mat) -> list[dict[str, Any]]: def _predict(self, image: np.ndarray[int, np.dtype[Any]] | bytes) -> list[dict[str, Any]]:
if isinstance(image, bytes):
image = cv2.imdecode(np.frombuffer(image, np.uint8), cv2.IMREAD_COLOR)
bboxes, kpss = self.det_model.detect(image) bboxes, kpss = self.det_model.detect(image)
if bboxes.size == 0: if bboxes.size == 0:
return [] return []
assert isinstance(kpss, np.ndarray) assert isinstance(image, np.ndarray) and isinstance(kpss, np.ndarray)
scores = bboxes[:, 4].tolist() scores = bboxes[:, 4].tolist()
bboxes = bboxes[:, :4].round().tolist() bboxes = bboxes[:, :4].round().tolist()
@ -102,3 +103,6 @@ class FaceRecognizer(InferenceModel):
@property @property
def cached(self) -> bool: def cached(self) -> bool:
return self.cache_dir.is_dir() and any(self.cache_dir.glob("*.onnx")) return self.cache_dir.is_dir() and any(self.cache_dir.glob("*.onnx"))
def configure(self, **model_kwargs: Any) -> None:
self.det_model.det_thresh = model_kwargs.get("min_score", self.det_model.det_thresh)

View file

@ -1,13 +1,13 @@
from io import BytesIO
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any
from huggingface_hub import snapshot_download from huggingface_hub import snapshot_download
from optimum.onnxruntime import ORTModelForImageClassification from optimum.onnxruntime import ORTModelForImageClassification
from optimum.pipelines import pipeline from optimum.pipelines import pipeline
from PIL.Image import Image from PIL import Image
from transformers import AutoImageProcessor from transformers import AutoImageProcessor
from ..config import settings
from ..schemas import ModelType from ..schemas import ModelType
from .base import InferenceModel from .base import InferenceModel
@ -18,7 +18,7 @@ class ImageClassifier(InferenceModel):
def __init__( def __init__(
self, self,
model_name: str, model_name: str,
min_score: float = settings.min_tag_score, min_score: float = 0.9,
cache_dir: Path | str | None = None, cache_dir: Path | str | None = None,
**model_kwargs: Any, **model_kwargs: Any,
) -> None: ) -> None:
@ -56,8 +56,13 @@ class ImageClassifier(InferenceModel):
feature_extractor=processor, feature_extractor=processor,
) )
def _predict(self, image: Image) -> list[str]: def _predict(self, image: Image.Image | bytes) -> list[str]:
if isinstance(image, bytes):
image = Image.open(BytesIO(image))
predictions: list[dict[str, Any]] = self.model(image) # type: ignore predictions: list[dict[str, Any]] = self.model(image) # type: ignore
tags = [tag for pred in predictions for tag in pred["label"].split(", ") if pred["score"] >= self.min_score] tags = [tag for pred in predictions for tag in pred["label"].split(", ") if pred["score"] >= self.min_score]
return tags return tags
def configure(self, **model_kwargs: Any) -> None:
self.min_score = model_kwargs.get("min_score", self.min_score)

View file

@ -1,4 +1,4 @@
from enum import Enum from enum import StrEnum
from pydantic import BaseModel from pydantic import BaseModel
@ -20,18 +20,6 @@ class MessageResponse(BaseModel):
message: str message: str
class TagResponse(BaseModel):
__root__: list[str]
class Embedding(BaseModel):
__root__: list[float]
class EmbeddingResponse(BaseModel):
__root__: Embedding
class BoundingBox(BaseModel): class BoundingBox(BaseModel):
x1: int x1: int
y1: int y1: int
@ -39,23 +27,7 @@ class BoundingBox(BaseModel):
y2: int y2: int
class Face(BaseModel): class ModelType(StrEnum):
image_width: int
image_height: int
bounding_box: BoundingBox
score: float
embedding: Embedding
class Config:
alias_generator = to_lower_camel
allow_population_by_field_name = True
class FaceResponse(BaseModel):
__root__: list[Face]
class ModelType(Enum):
IMAGE_CLASSIFICATION = "image-classification" IMAGE_CLASSIFICATION = "image-classification"
CLIP = "clip" CLIP = "clip"
FACIAL_RECOGNITION = "facial-recognition" FACIAL_RECOGNITION = "facial-recognition"

View file

@ -720,69 +720,69 @@ files = [
[[package]] [[package]]
name = "cython" name = "cython"
version = "3.0.0" version = "3.0.2"
description = "The Cython compiler for writing C extensions in the Python language." description = "The Cython compiler for writing C extensions in the Python language."
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
files = [ files = [
{file = "Cython-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c7d728e1a49ad01d41181e3a9ea80b8d14e825f4679e4dd837cbf7bca7998a5"}, {file = "Cython-3.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ccb91d2254e34724f1541b2a6fcdfacdb88284185b0097ae84e0ddf476c7a38"},
{file = "Cython-3.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:626a4a6ef4b7ced87c348ea805488e4bd39dad9d0b39659aa9e1040b62bbfedf"}, {file = "Cython-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c298b1589205ecaaed0457ad05e0c8a43e7db2053607f48ed4a899cb6aa114df"},
{file = "Cython-3.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c900d1ca9f622b969ac7d8fc44bdae140a4a6c7d8819413b51f3ccd0586a09"}, {file = "Cython-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e825e682cef76d0c33384f38b56b7e87c76152482a914dfc78faed6ff66ce05a"},
{file = "Cython-3.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a65bc50dc1bc2faeafd9425defbdef6a468974f5c4192497ff7f14adccfdcd32"}, {file = "Cython-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:77ec0134fc1b10aebef2013936a91c07bff2498ec283bc2eca099ee0cb94d12e"},
{file = "Cython-3.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3b71b399b10b038b056ad12dce1e317a8aa7a96e99de7e4fa2fa5d1c9415cfb9"}, {file = "Cython-3.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c90eeb94395315e65fd758a2f86b92904fce7b50060b4d45a878ef6767f9276e"},
{file = "Cython-3.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f42f304c097cc53e9eb5f1a1d150380353d5018a3191f1b77f0de353c762181e"}, {file = "Cython-3.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:38085523fa7a299638d051ae08144222785639882f6291bd275c0b12db1034ff"},
{file = "Cython-3.0.0-cp310-cp310-win32.whl", hash = "sha256:3e234e2549e808d9259fdb23ebcfd145be30c638c65118326ec33a8d29248dc2"}, {file = "Cython-3.0.2-cp310-cp310-win32.whl", hash = "sha256:b032cb0c69082f0665b2c5fb416d041157062f1538336d0edf823b9ee500e39c"},
{file = "Cython-3.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:829c8333195100448a23863cf64a07e1334fae6a275aefe871458937911531b6"}, {file = "Cython-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:067b2b9eb487bd61367b296f11b7c1c70a084b3eb7d5a572f607cd1fc5ca5586"},
{file = "Cython-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06db81b1a01858fcc406616f8528e686ffb6cf7c3d78fb83767832bfecea8ad8"}, {file = "Cython-3.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:213ff9f95de319e54b520bf31edd6aa7a1fa4fbf617c2beb0f92362595e6476a"},
{file = "Cython-3.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c93634845238645ce7abf63a56b1c5b6248189005c7caff898fd4a0dac1c5e1e"}, {file = "Cython-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bebbca13078125a35937966137af4bd0300a0c66fd7ae4ce36adc049b13bdf3"},
{file = "Cython-3.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa606675c6bd23478b1d174e2a84e3c5a2c660968f97dc455afe0fae198f9d3d"}, {file = "Cython-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5e5587128e8c2423aefcffa4ded4ddf60d44898938fbb7c0f236636a750a94f"},
{file = "Cython-3.0.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3355e6f690184f984eeb108b0f5bbc4bcf8b9444f8168933acf79603abf7baf"}, {file = "Cython-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78e2853d484643c6b7ac3bdb48392753442da1c71b689468fa3176b619bebe54"},
{file = "Cython-3.0.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:93a34e1ca8afa4b7075b02ed14a7e4969256297029fb1bfd4cbe48f7290dbcff"}, {file = "Cython-3.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c5e722732e9aa9bde667ed6d87525234823eb7766ca234cfb19d7e0c095a2ef4"},
{file = "Cython-3.0.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb1165ca9e78823f9ad1efa5b3d83156f868eabd679a615d140a3021bb92cd65"}, {file = "Cython-3.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:989787fc24a95100a26918b6577d06e15a8868a3ed267009c5cfcf1a906179ac"},
{file = "Cython-3.0.0-cp311-cp311-win32.whl", hash = "sha256:2fadde1da055944f5e1e17625055f54ddd11f451889110278ef30e07bd5e1695"}, {file = "Cython-3.0.2-cp311-cp311-win32.whl", hash = "sha256:d21801981db44b7e9f9768f121317946461d56b51de1e6eff3c42e8914048696"},
{file = "Cython-3.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:254ed1f03a6c237fa64f0c6e44862058de65bfa2e6a3b48ca3c205492e0653aa"}, {file = "Cython-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:809617cf4825b2138ce0ec827e1f28e39668743c81ac8286373f8d148c05f088"},
{file = "Cython-3.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:4e212237b7531759befb92699c452cd65074a78051ae4ee36ff8b237395ecf3d"}, {file = "Cython-3.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5682293d344b7dbad97ce6eceb9e887aca6e53499709db9da726ca3424e5559d"},
{file = "Cython-3.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f29307463eba53747b31f71394ed087e3e3e264dcc433e62de1d51f5c0c966c"}, {file = "Cython-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e08ff5da5f5b969639784b1bffcd880a0c0f048d182aed7cba9945ee8b367c2"},
{file = "Cython-3.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53328a8af0806bebbdb48a4191883b11ee9d9dfb084d84f58fa5a8ab58baefc9"}, {file = "Cython-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8850269ff59f77a1629e26d0576701925360d732011d6d3516ccdc5b2c2bc310"},
{file = "Cython-3.0.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5962e70b15e863e72bed6910e8c6ffef77d36cc98e2b31c474378f3b9e49b0e3"}, {file = "Cython-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:550b3fbe9b3c555b44ded934f4822f9fcc04dfcee512167ebcbbd370ccede20e"},
{file = "Cython-3.0.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9e69139f4e60ab14c50767a568612ea64d6907e9c8e0289590a170eb495e005f"}, {file = "Cython-3.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4db017b104f47b1185237702f6ed2651839c8124614683efa7c489f3fa4e19d9"},
{file = "Cython-3.0.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c40bdbcb2286f0aeeb5df9ce53d45da2d2a9b36a16b331cd0809d212d22a8fc7"}, {file = "Cython-3.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:75a2395cc7b78cff59be6e9b7f92bbb5d7b8d25203f6d3fb6f72bdb7d3f49777"},
{file = "Cython-3.0.0-cp312-cp312-win32.whl", hash = "sha256:8abb8915eb2e57fa53d918afe641c05d1bcc6ed1913682ec1f28de71f4e3f398"}, {file = "Cython-3.0.2-cp312-cp312-win32.whl", hash = "sha256:786b6034a91e886116bb562fe42f8bf0f97c3e00c02e56791d02675959ed65b1"},
{file = "Cython-3.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:30a4bd2481e59bd7ab2539f835b78edc19fc455811e476916f56026b93afd28b"}, {file = "Cython-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc9d173ab8b167cae674f6deed8c65ba816574797a2bd6d8aa623277d1fa81ca"},
{file = "Cython-3.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0e1e4b7e4bfbf22fecfa5b852f0e499c442d4853b7ebd33ae37cdec9826ed5d8"}, {file = "Cython-3.0.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8948504338d7a140ce588333177dcabf0743a68dbc83b0174f214f5b959634d5"},
{file = "Cython-3.0.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b00df42cdd1a285a64491ba23de08ab14169d3257c840428d40eb7e8e9979af"}, {file = "Cython-3.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a51efba0e136b2af358e5a347bae09678b17460c35cf1eab24f0476820348991"},
{file = "Cython-3.0.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:650d03ddddc08b051b4659778733f0f173ca7d327415755c05d265a6c1ba02fb"}, {file = "Cython-3.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05cb2a73810f045d328b7579cf98f550a9e601df5e282d1fea0512d8ad589011"},
{file = "Cython-3.0.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4965f2ebade17166f21a508d66dd60d2a0b3a3b90abe3f72003baa17ae020dd6"}, {file = "Cython-3.0.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22ba78e48bdb65977928ecb275ac8c82df7b0eefa075078a1363a5af4606b42e"},
{file = "Cython-3.0.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4123c8d03167803df31da6b39de167cb9c04ac0aa4e35d4e5aa9d08ad511b84d"}, {file = "Cython-3.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:302281b927409b3e0ef8cd9251eab782cf1acd2578eab305519fbae5d184b7e9"},
{file = "Cython-3.0.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:296c53b6c0030cf82987eef163444e8d7631cc139d995f9d58679d9fd1ddbf31"}, {file = "Cython-3.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:a1c3675394b81024aaf56e4f53c2b4f81d9a116c7049e9d4706f810899c9134e"},
{file = "Cython-3.0.0-cp36-cp36m-win32.whl", hash = "sha256:0d2c1e172f1c81bafcca703093608e10dc16e3e2d24c5644c17606c7fdb1792c"}, {file = "Cython-3.0.2-cp36-cp36m-win32.whl", hash = "sha256:34f7b014ebce5d325c8084e396c81cdafbd8d82be56780dffe6b67b28c891f1b"},
{file = "Cython-3.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:bc816d8eb3686d6f8d165f4156bac18c1147e1035dc28a76742d0b7fb5b7c032"}, {file = "Cython-3.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:477cd3549597f09a1608da7b05e16ba641e9aedd171b868533a5a07790ed886f"},
{file = "Cython-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8d86651347bbdbac1aca1824696c5e4c0a3b162946c422edcca2be12a03744d1"}, {file = "Cython-3.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a49dde9f9e29ea82f29aaf3bb1a270b6eb90b75d627c7ff2f5dd3764540ae646"},
{file = "Cython-3.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84176bd04ce9f3cc8799b47ec6d1959fa1ea5e71424507df7bbf0b0915bbedef"}, {file = "Cython-3.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc1c8013fad0933f5201186eccc5f2be223cafd6a8dcd586d3f7bb6ba84dc845"},
{file = "Cython-3.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35abcf07b8277ec95bbe49a07b5c8760a2d941942ccfe759a94c8d2fe5602e9f"}, {file = "Cython-3.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b75e9c9d7ad7c9dd85d45241d1d4e3c5f66079c1f84eec91689c26d98bc3349"},
{file = "Cython-3.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a44d6b9a29b2bff38bb648577b2fcf6a68cf8b1783eee89c2eb749f69494b98d"}, {file = "Cython-3.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f43c4d3ecd9e3b8b7afe834e519f55cf4249b1088f96d11b96f02c55cbaeff7"},
{file = "Cython-3.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4dc6bbe7cf079db37f1ebb9b0f10d0d7f29e293bb8688e92d50b5ea7a91d82f3"}, {file = "Cython-3.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:dab6a923e21e212aa3dc6dde9b22a190f5d7c449315a94e57ddc019ea74a979b"},
{file = "Cython-3.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e28763e75e380b8be62b02266a7995a781997c97c119efbdccb8fb954bcd7574"}, {file = "Cython-3.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae453cfa933b919c0a19d2cc5dc9fb28486268e95dc2ab7a11ab7f99cf8c3883"},
{file = "Cython-3.0.0-cp37-cp37m-win32.whl", hash = "sha256:edae615cb4af51d5173e76ba9aea212424d025c57012e9cdf2f131f774c5ba71"}, {file = "Cython-3.0.2-cp37-cp37m-win32.whl", hash = "sha256:b1f023d36a3829069ed11017c670128be3f135a9c17bd64c35d3b3442243b05c"},
{file = "Cython-3.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:20c604e974832aaf8b7a1f5455ee7274b34df62a35ee095cd7d2ed7e818e6c53"}, {file = "Cython-3.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:011c4e0b75baee1843334562487eb4fbc0c59ddb2cc32a978b972a81eedcbdcc"},
{file = "Cython-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c85fd2b1cbd9400d60ebe074795bb9a9188752f1612be3b35b0831a24879b91f"}, {file = "Cython-3.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:832bbee87bca760efeae248ddf19ccd77f9a2355cb6f8a64f20cc377e56957b3"},
{file = "Cython-3.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:090256c687106932339f87f888b95f0d69c617bc9b18801555545b695d29d8ab"}, {file = "Cython-3.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fe806d154b6b7f0ab746dac36c022889e2e7cf47546ff9afdc29a62cfa692d0"},
{file = "Cython-3.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cec2a67a0a7d9d4399758c0657ca03e5912e37218859cfbf046242cc532bfb3b"}, {file = "Cython-3.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e486331a29e7700b1ad5f4f753bef483c81412a5e64a873df46d6cb66f9a65de"},
{file = "Cython-3.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1cdd01ce45333bc264a218c6e183700d6b998f029233f586a53c9b13455c2d2"}, {file = "Cython-3.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54d41a1dfbaab74449873e7f8e6cd4239850fe7a50f7f784dd99a560927f3bac"},
{file = "Cython-3.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ecee663d2d50ca939fc5db81f2f8a219c2417b4651ad84254c50a03a9cb1aadd"}, {file = "Cython-3.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4dca13c86d6cd523c7d8bbf8db1b2bbf8faedd0addedb229158d8015ad1819e1"},
{file = "Cython-3.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:30f10e79393b411af7677c270ea69807acb9fc30205c8ff25561f4deef780ec1"}, {file = "Cython-3.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:10cbfb37f31938371a6213cc8b5459c639954aed053efeded3c012d4c5915db9"},
{file = "Cython-3.0.0-cp38-cp38-win32.whl", hash = "sha256:609777d3a7a0a23b225e84d967af4ad2485c8bdfcacef8037cf197e87d431ca0"}, {file = "Cython-3.0.2-cp38-cp38-win32.whl", hash = "sha256:e663c237579c033deaa2cb362b74651da7712f56e441c11382510a8c4c4f2dd7"},
{file = "Cython-3.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:7f4a6dfd42ae0a45797f50fc4f6add702abf46ab3e7cd61811a6c6a97a40e1a2"}, {file = "Cython-3.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:2f84bd6cefa5130750c492038170c44f1cbd6f42e9ed85e168fd9cb453f85160"},
{file = "Cython-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2d8158277c8942c0b20ff4c074fe6a51c5b89e6ac60cef606818de8c92773596"}, {file = "Cython-3.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f37e4287f520f3748a06ad5eaae09ba4ac68f52e155d70de5f75780d83575c43"},
{file = "Cython-3.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54e34f99b2a8c1e11478541b2822e6408c132b98b6b8f5ed89411e5e906631ea"}, {file = "Cython-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd30826ca8b27b2955a63c8ffe8aacc9f0779582b4bd154cf7b441ac10dae2cb"},
{file = "Cython-3.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877d1c8745df59dd2061a0636c602729e9533ba13f13aa73a498f68662e1cbde"}, {file = "Cython-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08d67c7225a09eeb77e090c8d4f60677165b052ccf76e3a57d8237064e5c2de2"},
{file = "Cython-3.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204690be60f0ff32eb70b04f28ef0d1e50ffd7b3f77ba06a7dc2389ee3b848e0"}, {file = "Cython-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e625eec8c5c9a8cb062a318b257cc469d301bed952c7daf86e38bbd3afe7c91"},
{file = "Cython-3.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06fcb4628ccce2ba5abc8630adbeaf4016f63a359b4c6c3827b2d80e0673981c"}, {file = "Cython-3.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1b12a8f23270675b537d1c3b988f845bea4bbcc66ae0468857f5ede0526d4522"},
{file = "Cython-3.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:090e24cfa31c926d0b13d8bb2ef48175acdd061ae1413343c94a2b12a4a4fa6f"}, {file = "Cython-3.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:62dd78afdf748a58dae9c9b9c42a1519ae30787b28ce5f84a0e1bb54144142ca"},
{file = "Cython-3.0.0-cp39-cp39-win32.whl", hash = "sha256:4cd00f2158dc00f7f93a92444d0f663eda124c9c29bbbd658964f4e89c357fe8"}, {file = "Cython-3.0.2-cp39-cp39-win32.whl", hash = "sha256:d0d0cc4ecc05f41c5e02af14ac0083552d22efed976f79eb7bade55fed63b25d"},
{file = "Cython-3.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:5b4cc896d49ce2bae8d6a030f9a4c64965b59c38acfbf4617685e17f7fcf1731"}, {file = "Cython-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:147cc1d3dda8b06de9d86df5e59cdf15f0a522620168b7349a5ec88b48104d7d"},
{file = "Cython-3.0.0-py2.py3-none-any.whl", hash = "sha256:ff1aef1a03cfe293237c7a86ae9625b0411b2df30c53d1a7f29a8d381f38a1df"}, {file = "Cython-3.0.2-py2.py3-none-any.whl", hash = "sha256:8f1c9e4b8e413da211dd7942440cf410ff0eafb081309e04e81f4fafbb146bf2"},
{file = "Cython-3.0.0.tar.gz", hash = "sha256:350b18f9673e63101dbbfcf774ee2f57c20ac4636d255741d76ca79016b1bd82"}, {file = "Cython-3.0.2.tar.gz", hash = "sha256:9594818dca8bb22ae6580c5222da2bc5cc32334350bd2d294a00d8669bcc61b5"},
] ]
[[package]] [[package]]
@ -889,13 +889,13 @@ testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "p
[[package]] [[package]]
name = "flask" name = "flask"
version = "2.3.2" version = "2.3.3"
description = "A simple framework for building complex web applications." description = "A simple framework for building complex web applications."
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
files = [ files = [
{file = "Flask-2.3.2-py3-none-any.whl", hash = "sha256:77fd4e1249d8c9923de34907236b747ced06e5467ecac1a7bb7115ae0e9670b0"}, {file = "flask-2.3.3-py3-none-any.whl", hash = "sha256:f69fcd559dc907ed196ab9df0e48471709175e696d6e698dd4dbe940f96ce66b"},
{file = "Flask-2.3.2.tar.gz", hash = "sha256:8c2f9abd47a9e8df7f0c3f091ce9497d011dc3b31effcf4c85a6e2b50f4114ef"}, {file = "flask-2.3.3.tar.gz", hash = "sha256:09c347a92aa7ff4a8e7f3206795f30d826654baf38b873d0744cd571ca609efc"},
] ]
[package.dependencies] [package.dependencies]
@ -903,7 +903,7 @@ blinker = ">=1.6.2"
click = ">=8.1.3" click = ">=8.1.3"
itsdangerous = ">=2.1.2" itsdangerous = ">=2.1.2"
Jinja2 = ">=3.1.2" Jinja2 = ">=3.1.2"
Werkzeug = ">=2.3.3" Werkzeug = ">=2.3.7"
[package.extras] [package.extras]
async = ["asgiref (>=3.2)"] async = ["asgiref (>=3.2)"]
@ -1185,101 +1185,119 @@ test = ["cffi (>=1.12.2)", "coverage (>=5.0)", "dnspython (>=1.16.0,<2.0)", "idn
[[package]] [[package]]
name = "geventhttpclient" name = "geventhttpclient"
version = "2.0.9" version = "2.0.10"
description = "http client library for gevent" description = "http client library for gevent"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "geventhttpclient-2.0.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f4dcd420c74f68ffc493abdc0964583f762e0f03c9ccd62b8dcfa589f8cabe49"}, {file = "geventhttpclient-2.0.10-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2ba6814f4a31286573f7fd24154bdb9cbe4ae01e754f48d71b1944798bf663"},
{file = "geventhttpclient-2.0.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe8766994434ed6dc807d2e5726e9cec536b5593885b50598fe763908242054"}, {file = "geventhttpclient-2.0.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c01dfb0de68f219b7a534121caa71481e32574bba7fe547fa37ee47a73a7b224"},
{file = "geventhttpclient-2.0.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c23aacbe40f767d4bfb4215b51302d68f9611f2e730521e65c7239854177c30f"}, {file = "geventhttpclient-2.0.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1b2c7e6bb15910a2e86f8da375adfd63ac07587a1c764cedc082b00390bcd76e"},
{file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f9ead0e6eb8302b394744c8ad7df71b1482e40402ecc208b446dba870bbafa1"}, {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:022801e2323e3e673e3c7034f6bc5440b4651649df03396eb1b3a86a6aba899d"},
{file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:15393cf588d24bf90b430299733ed161829065d14df99db250b40a83ec7978aa"}, {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bcfc1489e71b010d8ce8857578cdb1b8ba348626807aa9d077fc73c9864e51e1"},
{file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41b35daa9fe8217f295bc162492260daf4d4e1d9e3e8ed1fa2085a003cb5bb86"}, {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aef527f67653488000218283368e526fa699604e03e98ce4e0e588e89116977d"},
{file = "geventhttpclient-2.0.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0373b1d920cb2c1d65913258e2abe1534f5c6d1e687ed9322ad47858d75fd7d0"}, {file = "geventhttpclient-2.0.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a673a4b6b1839c8491372e43208912040c25a34254c60bf1d084489ddc300ee"},
{file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:344f22ce6cc959e67c32c9992422ee623b2e92da80b7774f939a03a8f66a823b"}, {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2ceae04de8bdb4ef1d0ca7724cd9cad77c6611aac3830a24a7f13747e8b748c7"},
{file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2f467fc073631dd7c13f289ab59e82ae9b181a1faabcc8b23be48a48e8e45ba9"}, {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:dc3effc56065a5c26292ca26127e6fdd0f68429b413e847a8b7bad38972aab53"},
{file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:9f1395906e79b7d3db97199625ae9050c1249e2cb8073bb32495c375af351849"}, {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:304c1d24d33b19cae53614ffc91c68d1e682d8b60a4d9eefcf87fcd099b1c2f2"},
{file = "geventhttpclient-2.0.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3c8f035c55f8db9b3a976d813dd20965ecf957e268e420e66b88cba81a66f3ac"}, {file = "geventhttpclient-2.0.10-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d39b468aba4dbec358eb0205d41791afc53651eee789566239e544ed6c8b7dbb"},
{file = "geventhttpclient-2.0.9-cp310-cp310-win32.whl", hash = "sha256:372776cdcad9a34a8635da4002f1614a36269ee02e968750c4fbde6ea83360d7"}, {file = "geventhttpclient-2.0.10-cp310-cp310-win32.whl", hash = "sha256:91cd3f680ee413cc83819f0e1f63e49297c550099e85bbee92e73960d3eba041"},
{file = "geventhttpclient-2.0.9-cp310-cp310-win_amd64.whl", hash = "sha256:9a11b88ce228f91bd47acacb573acbcdf8276b933e2fd7e4f7aa6259c279271e"}, {file = "geventhttpclient-2.0.10-cp310-cp310-win_amd64.whl", hash = "sha256:9a9c02c44b1e4e6edf929aa7c98b665f4db9cdcd406e4a9b4897f48127a6dd6b"},
{file = "geventhttpclient-2.0.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:273cde2893c13cbdfcad46e6a0fb906aa3f6b050e712cba0e46cfa59aca4c330"}, {file = "geventhttpclient-2.0.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cb079f45fdc8e2bf7157ef55727d8c2bb7c95fb4f754dac61d7a9b91da0c5c1a"},
{file = "geventhttpclient-2.0.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba0f8863526a2cf44567fda5981da90278583d3006aef02482a92b7d7e38e610"}, {file = "geventhttpclient-2.0.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd657ba277f4888b5a4b5da72a587641d6725d1e6ab0dd6875f29ad0a3458ad5"},
{file = "geventhttpclient-2.0.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f8da5696d055883cef55fe52246ea2a686bae865d4d38900f67c7c3df7d01eaa"}, {file = "geventhttpclient-2.0.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fd589226e908a6c2556572ff3b13fe00308849b44dec47bb794de27afa0339de"},
{file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e25e14c91898217f3a69346c2704e4629634b3429cdff226e716e6d830c402e1"}, {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e38a4123ed63935ccaf18054135e50fe4f798744f10d37faa9d2eaddfcff12f"},
{file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46b08a7de94a3db62ebeb41e68097db1e3836eef2e2febccb2d710add8943838"}, {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9711c629559b1f0be4977a2be79899fb90085a5a1f85ca435ec91d6a5648ff3f"},
{file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0e33f23168824338a84e05e47808a48895e78e77c5d2ec353a6e77a0b727057"}, {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7435458eada516d1caf8499a2618db1160e62bbe0c8e4d6f3ab03fc507587dff"},
{file = "geventhttpclient-2.0.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f505a7060aeafd7ed94acc8c234690717ed03aa6421580847ade8d4a6d8741c1"}, {file = "geventhttpclient-2.0.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:446b17f342315d8c63c020732b9ab939a874014c84cf250d66ffd96c877f6d96"},
{file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bc0cd15d51b5817efeef98d6ffe51bebd371c0c81731b239d0c6e81923c3b986"}, {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:68279ab30e20f48fbac4371cd5850c77ecc37f24ef656f8c37afd5454576bc57"},
{file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9a7e72d38e3a4d4f84c11dbfd74b70e70c3c9099ea7336a6c6227e0628c83a67"}, {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0823827d029aed708d6ed577994cdd3b4c1466690be0b7f27f3b459783ab7c6a"},
{file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:62edef5141ea260caa91618b133d8888d9af6767e11a2e972dbb5be0e297ff8e"}, {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:505722ef30d680c983812795e047dbb2d09dc0f476015e5d3411251bb960e3b1"},
{file = "geventhttpclient-2.0.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:40cc9acfb7096b8fa3a4c4634dcc0a1cfc6a0a5501c597d1c4a5574fde1bb1be"}, {file = "geventhttpclient-2.0.10-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ebf2ce3ca1308ffc9daae1f45860b2f5a3c1a75f6c46b2d12b9a478f7c4f05e"},
{file = "geventhttpclient-2.0.9-cp311-cp311-win32.whl", hash = "sha256:44e7de9925356486988f72b239d1608597b6d1462664a7fa7ad5b8704a3f6f4e"}, {file = "geventhttpclient-2.0.10-cp311-cp311-win32.whl", hash = "sha256:4ad20f6f03e34e44366e6794a28bd0b35b09e1dca3350bbf0a72c50d64c9c266"},
{file = "geventhttpclient-2.0.9-cp311-cp311-win_amd64.whl", hash = "sha256:03b3c64fcd16795a5acbdf8588e05a58fde498cd550285cf3ea6e1c6cc28378c"}, {file = "geventhttpclient-2.0.10-cp311-cp311-win_amd64.whl", hash = "sha256:c1883adee9c69374e30f43f7bea85dd4a7b4cc440e3c6ecf975bef04e1f8a972"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:be198e668c8573e4cc7fa8e6b71e32a94765c424bc6a8cdd5fc23ab23769864c"}, {file = "geventhttpclient-2.0.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7525bd48fadc93a79d13383cf38a10eed6c9f2f3c65e1f3a8cd4978dfcf023a0"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f550e6ceb67a6cac9e42915612a10c0f799666fa309be796db65585690d8262"}, {file = "geventhttpclient-2.0.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c6820591122c4444652238806c0c97f6c0de76d790bab255fd242962c8026654"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5210e91b1a1d9f2bcd414238cae2593b66172098db7bde396ae2fdb8e658eb85"}, {file = "geventhttpclient-2.0.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:34a06879a2dbc2a78edf8cfcabbcc67a177d0642b0e4490b771b72ebceea4537"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97f4c7f57bf24b669bc2e71de725067a4b73f280fc20875fd8c7cee712b754f3"}, {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:441a16eb8743b44c7b6f0acbbdc38d6f407f0763eb859ae0ae6e61427ac86c3e"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01869edfc3f9b892dfdd0b3ef102c97dd250725e8364de2e450d9ee2e3bf74db"}, {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf3a7a5c6b244c6d55de9d28245f70ee33cca8353355a9b10ea0c2e08ff24a0"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a85f9d272af4bc599a54496cb420ee0654c35023d6cd7f2a49c36d5a5d30e375"}, {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e65a91c7a4e559d0f60dab4439d15355ade9c30f5c73276bb748b000a062e8f"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:9f78d0bda2583a7f9d87cc987ab9976bf4e85d467af7d8fa39f51bed1918e812"}, {file = "geventhttpclient-2.0.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d051f15c3c92140ce142336ae05a76868ce05a86b4e15c5becb5431beaf53a07"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:2e8013742b22586c25c797d7d7bfb8882b2eed43051f28f7617ea302cf4e5098"}, {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:224d1f34e32d683889f8a92f92ce3a1e4bb2f3f4a3d85b931a8df493dd59e9e7"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:1eb410b5522ef617923470f036774388c191eda3ae47abf5a175f628cff75928"}, {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:309a35f033766476765a48a9c2712ffb988c3e3d50cd4b98eaa77e34b470af7e"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-win32.whl", hash = "sha256:12de78429c420ac3dbfd4e89fbd1d9d2cf9a60c06a82fc39a398f92d5f717c95"}, {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:d9d09579969cfb244e88bb599ac93549d8c0b56018de1f1ffade4a986951ad1d"},
{file = "geventhttpclient-2.0.9-cp36-cp36m-win_amd64.whl", hash = "sha256:5eb747774ed72467b3b77913bfe041f0be4a22958dd7538a654bf24107d1b917"}, {file = "geventhttpclient-2.0.10-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:15ecc1599646755d7e2e5648606c21ace00c3337c2d72d33b4e2de5d66b4ed65"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:36e9c7e4f86db9335123a12b343c2b91d8d7fe4724428ac418bcfcd471248bc9"}, {file = "geventhttpclient-2.0.10-cp312-cp312-win32.whl", hash = "sha256:c99dd907622f28523c3f90b8718643c103ce6519be7128e75730c398fd23d157"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a7d8a7d7ee6b08e44e58e92e47ca4b50edf8ed64b8906bd0a6cbb481aeae69b"}, {file = "geventhttpclient-2.0.10-cp312-cp312-win_amd64.whl", hash = "sha256:9532ee9066072737fe0eac1714c99792d7007769d529a056bc0c238946f67fdf"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:186d3e4f549a004f0ae8857db81f05798d48dd9e6cbfa97dfa46f6177883458d"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:7197223e650b9e07e1b3ddc1b41b8cdc1c2c4b408f392bdf827efa8c0cb6c67b"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c0ed350c0f4598f6d07d6fdc2d3546a1611ebf15fcdc83bc77dea6d22f2ef38"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:304b9d67c91db96633d89b938b68020d7f787ff962580b1cff819d4218d7eb45"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0c557aeb45a005c72200842fddfb507bbd7f2ec9296059c7ea3977ea226d4e7"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bdd4aa396f69f4063b7fcddb2c400c9eea933bcce63f3c65fc28a1869c88179c"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6c9ea74c83e94ea7c9869e383f93fa20a5fbde9cfb020400cdb75c39e029507a"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8da6f49e65cdcc19fbc37978d9e3e14ba30c949d9a5492e0f96e1e5270f2305"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9b072c041993b3242aeccce0d436bcb951f83e83517d5f5c0b9b97efe6ee273e"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba65c48a63042deadc8e4f1f5348409d851d6fa06f8a1b5a58fd6fd24e50daaf"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:d17ea1282fef41aa1b43e193869f0b9119fab919fe90092dfa5754fd6a012982"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f3dcbf4a53852498128937e870c4b0ced1ed49b9153c68d12a52a0711652b9cf"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4941aa5e45479a6595469754d6395e5d1a76cf555d0d111aa4c128d8f4ebd41b"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:976e86d63fd1cd3bda4f78ec469b6d1c8dec4259abeb62191464e8dd4d40bb8e"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-win32.whl", hash = "sha256:2d36b3a241a4c64a094622c4da67b98141295ab9ba24a79671235bb8735047f5"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:05be35bc7d2bd3ad6f0aa5042ae5a0b171ff19ec75ffeae1b4a2698572dd67a4"},
{file = "geventhttpclient-2.0.9-cp37-cp37m-win_amd64.whl", hash = "sha256:f7a99e0976ac64d21f54be87083b6ec440753db50db36d83b2b2b0b6edaacad7"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b3556a97e1c71d6b323076e6153f3afcf4f2e37ad79c3fe6d5bf006d3c1b5436"},
{file = "geventhttpclient-2.0.9-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:f46848b5c6610c671a7258757bf4d34032c56a80ead880e69890d9ef5c1e63a1"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-win32.whl", hash = "sha256:2b2d801205000f673f879b4edc1064b7dfc1bdd0dc5257bf565e6e7386b818bf"},
{file = "geventhttpclient-2.0.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b671b736468e35e588f24d2219d9f84f3c69c466fdc76ce47774106eb3af2c10"}, {file = "geventhttpclient-2.0.10-cp36-cp36m-win_amd64.whl", hash = "sha256:7fd672aa9186607ac802b09efd3c835eb808f930a5c3489553dbfcbe78539129"},
{file = "geventhttpclient-2.0.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b290897e50e0f378d4cabdafffe2f51950d1c820722ee39b37657eda7339a3a8"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:551b147e4c2ea60bfefc4f12dd061bfe84792497a32a369f8dab7f503da5aa05"},
{file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41cad9ddc365edf77cb62a4e3a8168dee9ee37109b410a42c5ec0691403dbe37"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:113c001d339b9e5c209f6f9da9271b0011341c25a4171d142c1d802bc0889ec4"},
{file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0b69bc9632827b108aba11d85e7c604290e413486e7dc9ddf471303ceab4381"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fcdfdbbbf3c96265aca110433a5ce68e807336fa58bd7ef0651e66032037575"},
{file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:988121fdd5b8939c4071ce45b26f9e3aa1cb050e3087ee02b28e7c21bcada35c"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:223daf689883680eef2aa1b773a2bd7e6500749615332b0a0949ee11afeeeff9"},
{file = "geventhttpclient-2.0.9-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db4db1ceaa88d648c43a318af16690fb59f13ad1fc48603e054c563490950034"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45343be209224de6e525611938a41a4269c36df3b3c1f6e12f99af188d192a4"},
{file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:192be8b440e6512c384cc5be98b3b3e8b39dcae0f7c10aee3c3491f30a20e676"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c268f7573f2b3cceabdc086abca96a59fb2766acbf60fb349ccbc208b6051e7c"},
{file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ffed7591e612cb80935ed11c1fb0a752aed3f014a48b9404cd0c77182e82335c"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c8117ef8e405fa05f5ea50fd9eb1d538bb7eeb86dba2849fb25d8296fabb70fc"},
{file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:c2b06ccac902fb243384da12692be240e7a9ddcd2efedcde2444872546ada83c"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:fb70548781b3ba3531ec3572ae6f4cd87f387822c412fff1ee6fe52c2e4b66cf"},
{file = "geventhttpclient-2.0.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8257d9538a1d342a2052c0df099a318d7611562a4725985ac652a356c5cd45c9"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b87dcef1ca6eb9127fd60844f1dd77063081335079b498bc1e1cd8e4764b6863"},
{file = "geventhttpclient-2.0.9-cp38-cp38-win32.whl", hash = "sha256:ce61c0be828e10dbfac91ed7160f651ecc2fbad44ed1815eaac6e9d41e09a87a"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-win32.whl", hash = "sha256:8ff70f24183705f2cb63dc132b4dd4e0eec58b8f182fde76f5a205e4608266cd"},
{file = "geventhttpclient-2.0.9-cp38-cp38-win_amd64.whl", hash = "sha256:aa2b47489bd229fce3ab626c370eb8d18fd6116611552de9d8979c37238fc62b"}, {file = "geventhttpclient-2.0.10-cp37-cp37m-win_amd64.whl", hash = "sha256:f30d83152339779650a97471f27ef2fb2e6804ce660c96790c0d01c66648483f"},
{file = "geventhttpclient-2.0.9-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a16bde611a76ada61c9af9acc20b88d5ee6c025deede2680fde084838a3bfbae"}, {file = "geventhttpclient-2.0.10-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:786e120946a4dc1c7ede5a04943119540a1ccc22227029cdb7988a3d216885b1"},
{file = "geventhttpclient-2.0.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:780d04ea934e254af9de90402f29804e6a3455c3bfa44acc1e8ccb65ce5115a9"}, {file = "geventhttpclient-2.0.10-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c27943dff539c4bc19f31ea8bffbb79a215e3b3f72b87686791956af39586ac4"},
{file = "geventhttpclient-2.0.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3033399fcbe1fbafbe6ff56afb587725aa993ab549845ebbd8a2206be6082cb"}, {file = "geventhttpclient-2.0.10-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a377934706416ef04b92291540b609c7dde004a7ccb3b4e047873af2432d78e4"},
{file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d32d3f6f413a6a16ac3bfe4cb53f0935c52f33820d2da21d9929ec6a910519b"}, {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b91c1a73e99ef4542e7098a997d1a4bce08cafb935e24a7b6d02c6da2359c91d"},
{file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6684b82fd3719d4823ef2eda1edd5bfbf3154e5c2241db0ed858ffb99f8a4ad9"}, {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80683052062f4cb6f18e7d2b1dba91f9536f7955a12660d599ed64bb4aa56d1e"},
{file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38f5c6cfa9387ad741f0b5033b6de12eeb670870149a50b7a64444c84f8e7167"}, {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44c06c9882cc50201e5c7fe667eae73a491b6590018aa43c54c79e88c30abdb0"},
{file = "geventhttpclient-2.0.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d654ae061852c842a75b1a38f42b5523389475fe9015de732a55242f6d221e"}, {file = "geventhttpclient-2.0.10-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271834908b41954fedc777478ffdc10050387bb5863805e19301b80e0fd85618"},
{file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:491ee724ba4057b076610be20da6345a66c630d82ed52f12014ce8bad5a699ab"}, {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f2f48dfd37d341c8433e7a2f76108b3d21614ccf2fbe00051d9dd29b3258efa6"},
{file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:eab149b7119ac7a6243cad85173f9f9e9ae004e299358181641dddc39233a2d1"}, {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d6110eb2f685c6dcaff56e9b3b161da2eb432eea15b68cee0f51ec5d28c886ea"},
{file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f6ad2c5590a68b7e959ab5f4adab78008ba3a661482c1fb56a38eba09744b899"}, {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:a9e9c1c080a527dd9047e0421231cdd2394eeb92f94836f4ad7d7fece937ba26"},
{file = "geventhttpclient-2.0.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:47bb3025950cc9bf0fd627b101380cf5b0efbbaa591198b851352b24966931cb"}, {file = "geventhttpclient-2.0.10-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fa34492682347420384e49bd7c15886330af685924fc64badefce642867e4856"},
{file = "geventhttpclient-2.0.9-cp39-cp39-win32.whl", hash = "sha256:549756ac0e3cc916d6830f0d6147803a5c93beae96f8504f685e4e841d6ace29"}, {file = "geventhttpclient-2.0.10-cp38-cp38-win32.whl", hash = "sha256:ea66408103b4c8954cbd3cc464be0e968a139d073987555a280760fb56fed41f"},
{file = "geventhttpclient-2.0.9-cp39-cp39-win_amd64.whl", hash = "sha256:e3133d3e492c5dfb78f9c0f87e1ede78545e7f4bb4851a063df2321669540004"}, {file = "geventhttpclient-2.0.10-cp38-cp38-win_amd64.whl", hash = "sha256:ef45b4facbaf7793373a32cab3f3e9460b76eb5f854b066f53b4753eca0efa7d"},
{file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3fca4415c9d9282a8b5f4de03661be3b1083b97b3e43a1f4b56cec4b933b9705"}, {file = "geventhttpclient-2.0.10-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75e09f122824d1d4aa3e9e48089a5e6f5c0925c817dfb99a65aeafa173243a27"},
{file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b85ca16b34170787a48ac2c69622bba2f2a3541ee55b442576a12f63181f13e"}, {file = "geventhttpclient-2.0.10-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c9b4269873ce14bdd0977ae7b3b29e55ba2dc187b1088665cfe78fc094fc6795"},
{file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:711f3522ce20d2de5abe22cafdeee0896f9f682de7690622510c5f8a859c50d2"}, {file = "geventhttpclient-2.0.10-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39db24bf426471cf81530675459ea209355032bf73f55a6e111f28853fe7564f"},
{file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96479cafe8cca4e24a1ba53efe3c3c6cf9f10e8cb0398f4cbcf23b4233e103f2"}, {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9148ce0072e6f2c644522b38d22d2749367dd599a4b32991ca9fc5feb112c5"},
{file = "geventhttpclient-2.0.9-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:d742f4288844ec5dbed2af4396fca8d37b5f4d2730ca31fe3575d67a2910e28f"}, {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:452624f7e1b16e27c5df5b4f639a5a45f9372d9d9a8e7d2754f2f034b04d43d3"},
{file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:53e929c7920fb7841d4b2cde50ed3fdde803948977a333de33a924a9ccfccd38"}, {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57ecf4d4a09b502d2d4b25bc074b10290d595d80b6ce86294ecdd992cff80fb9"},
{file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4693365990aa6d5cb104cea80dd831b8032f6a4f77790fa8b837fc25e86f8e5"}, {file = "geventhttpclient-2.0.10-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e338a3b23d05c7550a6163b8d367de953be25f1d94949d043b325390df72d527"},
{file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99bb292a4f4fa4a23d22e6bf1799530d0cb675dae87d81d77079abe98f71150d"}, {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6d2b0b87bb933911dadb702df74a7da91a4cdd86b6d75800db8494d7e5709e70"},
{file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4533b7023a90cb9766213f70d15bc76bb66b7b441c3976f27e254403a6c738fa"}, {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:5396759194bef95b92128dfd8b80d332f809de23193a2529071a519afd6e9250"},
{file = "geventhttpclient-2.0.9-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:a9b6341c937d01ba48028a3d605fded6fd2eed692bb1ddc941d2aa3dd317eed9"}, {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c13ba845f042d0807f6024b80c458b22b615028cc4f4ad23bd67c6db9de9969e"},
{file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a05a3345796accd0a9acb3fc133a0e4cd949d3e63becec34fcb2e8d001dd92fe"}, {file = "geventhttpclient-2.0.10-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:24b33b88fc7b815139b80736bb46a7f6113abc7edd3d846cd99fc8d8c31d8439"},
{file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32cc9bd3518aa0772065175aa6eddadff8b05688683940bfd583cb468b518987"}, {file = "geventhttpclient-2.0.10-cp39-cp39-win32.whl", hash = "sha256:e545fa59f298f6fc5219403f06819271f77a67216d1352f5cf703f292be05c3e"},
{file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e7185e91b52f6d2cdab849ba24c8ac24b3bd1ad8eb9917e4ed86f4e93f718b1"}, {file = "geventhttpclient-2.0.10-cp39-cp39-win_amd64.whl", hash = "sha256:216e451ea72fe2372bc72e34f214ef8bc9d62b049d9048f88f81338e1c6008a5"},
{file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62a47451abf94422b3f0efda4f147111f2f4a75f7e55db974cf4b35acaee0131"}, {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:71a224032b2da3fe30d75fb57fb9d3e8ff323895e14facd9374e585d5bf52d01"},
{file = "geventhttpclient-2.0.9-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:dc75486b0847c185856f981b728a2bbfe09e8a754676e57a8549660157918d2f"}, {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bed5b6051582bdf39c7ff15051ec0758d1a0ebcb6ff09b6ae600717caf3f379e"},
{file = "geventhttpclient-2.0.9.tar.gz", hash = "sha256:8abc39d346e923bd6a7b405d38dd01e19146594b6304032f382eda8b0f631513"}, {file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e2e2eed1d821854f9f32f475d258af605a87ce12dc4d93abe61c022bf2bb06e"},
{file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2cd1ecc9a389ca54a5e538769c3f35a82478006dc50eb505989d2ff6c3cf518"},
{file = "geventhttpclient-2.0.10-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:fb7018bfd4f6808d4e3b9cdda2dcb52cc01236a4bb65e18021fb8816996e9cd3"},
{file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6df4957678eb05a6ccfbbb96a9490345758620b53fe5653052979df94819765b"},
{file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:508bcc82f7259e316f2060025e7ff899acc8032c645e765bb780083e39060c07"},
{file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:961dac20f0f4b8cfa4e2eaafe2d20d74448a5a04239135fa1867a9a1bc3fd986"},
{file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:826fa6487ba1c1b7186dcdc300c216fd9b8cf34e307335b4cad1769736988ce9"},
{file = "geventhttpclient-2.0.10-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:b30c9495b43b2f67b6a0102ee3fd497762b6bf972e435e5974fd8d2cb5263235"},
{file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e2a9a5e52abc8d3275902c1199ff810264b033e346bcf19da920f9b6de1ea916"},
{file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:993b653c7c3d4e0683067b2e324fd749649e87b453205def6a4809dd30498b44"},
{file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6aa110a66936c37a8bbc2a51515fc0f7e99404e245ef15af8346fa2f6b4f6698"},
{file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ce4699fcadc17786cba0b461ff59d0231277155439b274fa12861f93fa764c8"},
{file = "geventhttpclient-2.0.10-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:23fedc0bf219cc42f9b3d565953a08a429c09642859b86174535977bb281f1c1"},
{file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a9e99fa203a43a8393cf01e5a6433e74524c97bf67e39c4f062c8fff27f49360"},
{file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0dfcfdc3a05e2145fe15f8b9cc7dd8b9fcd545dd42d051be0a2a828b8b3cc4a3"},
{file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b56abccfea3fe154f29dbc518737c70d63c1f44da4c956e31e9a5ff65074de19"},
{file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9f8d335e7e3579608904e001ba9b055d3f30b184db550c32901b3b86af71b92"},
{file = "geventhttpclient-2.0.10-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:96f1a63f18eb4a66ea9d6ab211d756afe8b6d5c6e80beff298cd7b65a3d710c7"},
{file = "geventhttpclient-2.0.10.tar.gz", hash = "sha256:b7c97b26511957a36a894ec54651c08890a69e118b69755f8e74bfc37c63391b"},
] ]
[package.dependencies] [package.dependencies]
@ -1614,13 +1632,13 @@ files = [
[[package]] [[package]]
name = "imageio" name = "imageio"
version = "2.31.1" version = "2.31.2"
description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats." description = "Library for reading and writing a wide range of image, video, scientific, and volumetric data formats."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "imageio-2.31.1-py3-none-any.whl", hash = "sha256:4106fb395ef7f8dc0262d6aa1bb03daba818445c381ca8b7d5dfc7a2089b04df"}, {file = "imageio-2.31.2-py3-none-any.whl", hash = "sha256:a78fbcb33432042a4d6993c87f3ea1f136d908318ce7dda857846ccff73294de"},
{file = "imageio-2.31.1.tar.gz", hash = "sha256:f8436a02af02fd63f272dab50f7d623547a38f0e04a4a73e2b02ae1b8b180f27"}, {file = "imageio-2.31.2.tar.gz", hash = "sha256:ae19221f4a8f118f1c9451e8f5357faeeacdf956198cf374bc8ab00f1ff7d525"},
] ]
[package.dependencies] [package.dependencies]
@ -1720,79 +1738,115 @@ files = [
[[package]] [[package]]
name = "kiwisolver" name = "kiwisolver"
version = "1.4.4" version = "1.4.5"
description = "A fast implementation of the Cassowary constraint solver" description = "A fast implementation of the Cassowary constraint solver"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"},
{file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"},
{file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"},
{file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"},
{file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"},
{file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"},
{file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"},
{file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"},
{file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"},
{file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"},
{file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"},
{file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"},
{file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"},
{file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"},
{file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"},
{file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"},
{file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"},
{file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"},
{file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"},
{file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"},
{file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"},
{file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"},
{file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"},
{file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"},
{file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"},
{file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"},
{file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"},
{file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"},
{file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"},
{file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"},
{file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"},
{file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"},
{file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"},
{file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"},
{file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"},
{file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"},
{file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"},
{file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"},
{file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"},
{file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"},
{file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"},
{file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"},
{file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"},
{file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"},
{file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"},
{file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"},
{file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"},
{file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"},
{file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"},
{file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"},
{file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"},
{file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"},
{file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"},
{file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"},
{file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"},
{file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"},
{file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"},
{file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"},
{file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"},
{file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"},
{file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"},
{file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"},
{file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"},
{file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"},
{file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"},
{file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"},
{file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"},
{file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"},
{file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"},
] ]
[[package]] [[package]]
@ -2302,42 +2356,42 @@ files = [
[[package]] [[package]]
name = "onnx" name = "onnx"
version = "1.14.0" version = "1.14.1"
description = "Open Neural Network Exchange" description = "Open Neural Network Exchange"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "onnx-1.14.0-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:fb35c2c347486416f87f41557242c05d7ee804d3676c6c8c98eef6f5b1889e7b"}, {file = "onnx-1.14.1-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:05d8609b4148f8ee4bd5d8186875ccb288300106242fc5201b8b575681bbd5c4"},
{file = "onnx-1.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd683d4aa6d55365582055a6c1e10a55d6c08a59e9216cbb67e37ad3a5b2b980"}, {file = "onnx-1.14.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f131c2fd36f7848437be9de3b1fa5449a94245e16c6f275f66ac7cf8f183ec26"},
{file = "onnx-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00b0d2620c10dcb9ec33441e807dc5851d2843d445e0faab5e22c8ad6874a67a"}, {file = "onnx-1.14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea8d7abe048d0e9e31541dc62e9e40b8411b11377d2a22ed842e678802b4e1aa"},
{file = "onnx-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01893a4a2d70b68e8ee20269ccde4069a6fd243dc9e296643e2afeb0050527bc"}, {file = "onnx-1.14.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:921ad325b17484698d9d65978e123b1f351328ea50de6f84f25d09d5c7dde361"},
{file = "onnx-1.14.0-cp310-cp310-win32.whl", hash = "sha256:0753b0f118be71ff109dd994a3d6769e5871e9feaddfada77931c63f9de534b3"}, {file = "onnx-1.14.1-cp310-cp310-win32.whl", hash = "sha256:6c8156be97762814c7c835d597320ef1f6630f034344fbc672cd6edddbbf78ee"},
{file = "onnx-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:d8c3a2354d9d997c7a4a5e467b5373c98dc549d4a33c77d5723e1eda7e87559c"}, {file = "onnx-1.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:776ab461515c20cc4e24dbd75af32b6b1e64de931dc5873b049f13bfec1c96e9"},
{file = "onnx-1.14.0-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:5e780fd1ed25493596a141e93303d0b2897acb9ebfdee7047a916d8f8e525ab3"}, {file = "onnx-1.14.1-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:93e614edaf87ea1adba24663780ac62e30f421c117d695379daa9ff816de821b"},
{file = "onnx-1.14.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9d28d64cbac3ebdc0c9761a300340c60ec60316099906e354e5059e90335fb3b"}, {file = "onnx-1.14.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:65672ae827ea5f0e59dc0d1cef1c0ed5083d5e8348946f98f1715ebb123573e9"},
{file = "onnx-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba92fed1aa27cba385bc3890fbbe6484603e837e67c957b22899f93c70990cc4"}, {file = "onnx-1.14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efa7375d91b1da10badd1d2701a94b0e9b111a5e1a227be1bf877450cea84ac"},
{file = "onnx-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fab7e6e1c2d9d6479edad8e9088cdfd87ea293cb08f31565adabfb33c6e5789"}, {file = "onnx-1.14.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9cd91b85cfbb0d6478f4a1a0aee4d95cf8839adc48c69130a0cf8452f21db4"},
{file = "onnx-1.14.0-cp311-cp311-win32.whl", hash = "sha256:6e966f5ef38a0521595cad6a1d14d9ae205c593d2824d8c1fa044fa5ba15370d"}, {file = "onnx-1.14.1-cp311-cp311-win32.whl", hash = "sha256:1072baf93e04bbbed45f8f997cbbe96e179080b4cd95bc676882fe64aa709dd6"},
{file = "onnx-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:1fe8ba794d261d722018bd1385f02f966aace0fcb5448881ab5dd55ab0ebb81b"}, {file = "onnx-1.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:16a6667aff34431ab828b393ed8153c0a0cf15152d76f8d93aa48fb206217827"},
{file = "onnx-1.14.0-cp37-cp37m-macosx_10_12_universal2.whl", hash = "sha256:c16dacf577700ff9cb076c61c880d1a4bc612eed96280396a54ee1e1bd7e2d68"}, {file = "onnx-1.14.1-cp37-cp37m-macosx_10_12_universal2.whl", hash = "sha256:3fde9e1854e525aae93b403c1174bf68dc86ac92b6f8fb4af0fe3ec0d1440631"},
{file = "onnx-1.14.0-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:bbdca51da9fa9ec43eebd8c640bf71c05daa2afbeaa2c6478466470e28e41111"}, {file = "onnx-1.14.1-cp37-cp37m-macosx_10_12_x86_64.whl", hash = "sha256:58e6eb27c99dbefc84b4234388f5f668b49a1aaeced1580cb96f5fe05800a77c"},
{file = "onnx-1.14.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3315c304d23a06ebd07fffe2456ab7f1e0a8dba317393d5c17a671ae2da6645e"}, {file = "onnx-1.14.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84653e8e19f5d051f9e7ed9cf7285527fd34e093e3b50554121849664e97c254"},
{file = "onnx-1.14.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1545159f2e7fbc5b4a3ae032cd4d9ddeafc62c4f27fe22cbc3ecff49338992"}, {file = "onnx-1.14.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b4a0e029b3604dc5294a7333f622d8c04d6a6a1bc4f51054195074f61b8f41a"},
{file = "onnx-1.14.0-cp37-cp37m-win32.whl", hash = "sha256:18cd98f7e234e268cb60c47a1f8ea5f6ffba50fe11de924b17498b1571d0cd2c"}, {file = "onnx-1.14.1-cp37-cp37m-win32.whl", hash = "sha256:f5046bfbe7f9bab59fc53984aaa5b47a35c8f8e98787053e1650049a1aaf12de"},
{file = "onnx-1.14.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a8f7454acded506b6359ee0837c8527c64964973d7d25ed6b16b7d4314599502"}, {file = "onnx-1.14.1-cp37-cp37m-win_amd64.whl", hash = "sha256:b37e7bd8baf75efa78ecce713273e2aa29c8c06f69cee6107b413cd03bf59b20"},
{file = "onnx-1.14.0-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:a9702e7dd120bca421a820020151cbb1003077e17ded29cc8d44ff32a9a57ad8"}, {file = "onnx-1.14.1-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:758dc585885e997f1086019f098e7ce0a4b3ab7d5a89bb2093572bb68ea906c1"},
{file = "onnx-1.14.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:369c3ecace7e8c7df6efbcbc712b262626796ae4a83decd29111afafa025a30c"}, {file = "onnx-1.14.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:486ced7588437ff08a03914ac110d64caa686ff7fa766123d15c8d8eeec29210"},
{file = "onnx-1.14.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fbcdc1a0c1057785bc5f7254aca0cf0b49d19c74696f1ade107638054157315"}, {file = "onnx-1.14.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:498ecc3e545b80685501c26b62eeeda0b8ae2f2ba8ff3f650ce1f526924aa699"},
{file = "onnx-1.14.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed099fbdada4accead109a4479d5f73fb974566cce8d3c6fca94774f9645934c"}, {file = "onnx-1.14.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e991e867b799df0d7ed4cdad94c6a3ed9bebaceef3e574ac9eed314e1bfca0ef"},
{file = "onnx-1.14.0-cp38-cp38-win32.whl", hash = "sha256:296e689aa54a9ae4e560b2bb149a64e96775699a0624af5f631665b9cda90482"}, {file = "onnx-1.14.1-cp38-cp38-win32.whl", hash = "sha256:a8c3b1398b156f8bae9882ed8c602e1aa5171180fffcbeb1f9a337fe307c1df4"},
{file = "onnx-1.14.0-cp38-cp38-win_amd64.whl", hash = "sha256:e1607f97007515df303c1f40b77363545af99a1f32d2f73240c8aa526cdbd109"}, {file = "onnx-1.14.1-cp38-cp38-win_amd64.whl", hash = "sha256:cf20e7a346d22468a128a40c5cc1f4d20c3939e21e74fc8e3be8ba66c6f82444"},
{file = "onnx-1.14.0-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:7800b6ec74b1fe3fbb3bf4a2380e2f4007c1a7f2d6927599ad40eead6eae5e19"}, {file = "onnx-1.14.1-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:17f78637d2f6c3c9afad0611fe4c583b6ba4839ac724af0846e5db24dc8dadc0"},
{file = "onnx-1.14.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:45d3effe59e20d0a9fdc51f5bb8f38299086c79576b894ed945e6a058c4b210a"}, {file = "onnx-1.14.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:60ad73263a06056f9aa288b082887c6330be08475471c3a009f62439b2a67dca"},
{file = "onnx-1.14.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a593b46015326feb949781d030cb1d0d5d388cca52bff2e2995badf55d56b38d"}, {file = "onnx-1.14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030aa47e28337fd81f4d884032660e40912a4763ce4e5a4b4144380271390e82"},
{file = "onnx-1.14.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54614942574415ef3f0bce0800c6f41ecea8201f8042754e204ee8c0a8e473e1"}, {file = "onnx-1.14.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b113fa0183034743e6477fec928e478a6d94eee8d9a4376c144d20d736cdc45"},
{file = "onnx-1.14.0-cp39-cp39-win32.whl", hash = "sha256:dcfaeb2d15e93c456003fac13ffa35144ba9d2666a83e2cef650dd5c90a2b768"}, {file = "onnx-1.14.1-cp39-cp39-win32.whl", hash = "sha256:b9c28a99d4a620cb1d31120d35e0fab54073b9725ed50c3cd3ec7beb876e8dba"},
{file = "onnx-1.14.0-cp39-cp39-win_amd64.whl", hash = "sha256:0639427ac61e5a0181f4f7c89f9fc82b3c9715c95071f9c3de79bbe303a4ae65"}, {file = "onnx-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:bdb15fc4b7f2a8a19abb52ac9672db876f9505e7219e206bcb7530e7c1274e55"},
{file = "onnx-1.14.0.tar.gz", hash = "sha256:43b85087c6b919de66872a043c7f4899fe6f840e11ffca7e662b2ce9e4cc2927"}, {file = "onnx-1.14.1.tar.gz", hash = "sha256:70903afe163643bd71195c78cedcc3f4fa05a2af651fd950ef3acbb15175b2d1"},
] ]
[package.dependencies] [package.dependencies]
@ -2442,13 +2496,13 @@ numpy = [
[[package]] [[package]]
name = "optimum" name = "optimum"
version = "1.11.2" version = "1.12.0"
description = "Optimum Library is an extension of the Hugging Face Transformers library, providing a framework to integrate third-party libraries from Hardware Partners and interface with their specific functionality." description = "Optimum Library is an extension of the Hugging Face Transformers library, providing a framework to integrate third-party libraries from Hardware Partners and interface with their specific functionality."
optional = false optional = false
python-versions = ">=3.7.0" python-versions = ">=3.7.0"
files = [ files = [
{file = "optimum-1.11.2-py3-none-any.whl", hash = "sha256:1382d923f95e053db677b1bc84803828921b41dd15d094cc61deab33ab5d4fb2"}, {file = "optimum-1.12.0-py3-none-any.whl", hash = "sha256:4eb2e800b5ef52aa4c744b7494aa2000be8b583dfc99dddd5c0e9384ea0d77a0"},
{file = "optimum-1.11.2.tar.gz", hash = "sha256:664fa01aa4734d13ba291d41e7b901d333cea45b6c55d66098f43160bf7533ab"}, {file = "optimum-1.12.0.tar.gz", hash = "sha256:a74e051c4d776a900b6452a12a36e0afadbebee112a8205a30adac9216a4991b"},
] ]
[package.dependencies] [package.dependencies]
@ -2468,7 +2522,7 @@ diffusers = ["diffusers"]
doc-build = ["accelerate"] doc-build = ["accelerate"]
exporters = ["onnx", "onnxruntime", "timm"] exporters = ["onnx", "onnxruntime", "timm"]
exporters-gpu = ["onnx", "onnxruntime-gpu", "timm"] exporters-gpu = ["onnx", "onnxruntime-gpu", "timm"]
exporters-tf = ["h5py", "numpy (<1.24.0)", "onnx", "onnxruntime", "tensorflow (>=2.4)", "tf2onnx", "timm"] exporters-tf = ["h5py", "numpy (<1.24.0)", "onnx", "onnxruntime", "tensorflow (>=2.4,<=2.12.1)", "tf2onnx", "timm"]
furiosa = ["optimum-furiosa"] furiosa = ["optimum-furiosa"]
graphcore = ["optimum-graphcore"] graphcore = ["optimum-graphcore"]
habana = ["optimum-habana"] habana = ["optimum-habana"]
@ -2483,6 +2537,75 @@ openvino = ["optimum-intel[openvino] (>=1.10.1)"]
quality = ["black (>=23.1,<24.0)", "ruff (>=0.0.241,<=0.0.259)"] quality = ["black (>=23.1,<24.0)", "ruff (>=0.0.241,<=0.0.259)"]
tests = ["Pillow", "diffusers (>=0.17.0)", "einops", "invisible-watermark", "parameterized", "pytest", "pytest-xdist", "requests", "sacremoses", "torchaudio", "torchvision"] tests = ["Pillow", "diffusers (>=0.17.0)", "einops", "invisible-watermark", "parameterized", "pytest", "pytest-xdist", "requests", "sacremoses", "torchaudio", "torchvision"]
[[package]]
name = "orjson"
version = "3.9.5"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
optional = false
python-versions = ">=3.7"
files = [
{file = "orjson-3.9.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:ad6845912a71adcc65df7c8a7f2155eba2096cf03ad2c061c93857de70d699ad"},
{file = "orjson-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e298e0aacfcc14ef4476c3f409e85475031de24e5b23605a465e9bf4b2156273"},
{file = "orjson-3.9.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:83c9939073281ef7dd7c5ca7f54cceccb840b440cec4b8a326bda507ff88a0a6"},
{file = "orjson-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e174cc579904a48ee1ea3acb7045e8a6c5d52c17688dfcb00e0e842ec378cabf"},
{file = "orjson-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f8d51702f42c785b115401e1d64a27a2ea767ae7cf1fb8edaa09c7cf1571c660"},
{file = "orjson-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f13d61c0c7414ddee1ef4d0f303e2222f8cced5a2e26d9774751aecd72324c9e"},
{file = "orjson-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d748cc48caf5a91c883d306ab648df1b29e16b488c9316852844dd0fd000d1c2"},
{file = "orjson-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bd19bc08fa023e4c2cbf8294ad3f2b8922f4de9ba088dbc71e6b268fdf54591c"},
{file = "orjson-3.9.5-cp310-none-win32.whl", hash = "sha256:5793a21a21bf34e1767e3d61a778a25feea8476dcc0bdf0ae1bc506dc34561ea"},
{file = "orjson-3.9.5-cp310-none-win_amd64.whl", hash = "sha256:2bcec0b1024d0031ab3eab7a8cb260c8a4e4a5e35993878a2da639d69cdf6a65"},
{file = "orjson-3.9.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:8547b95ca0e2abd17e1471973e6d676f1d8acedd5f8fb4f739e0612651602d66"},
{file = "orjson-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87ce174d6a38d12b3327f76145acbd26f7bc808b2b458f61e94d83cd0ebb4d76"},
{file = "orjson-3.9.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a960bb1bc9a964d16fcc2d4af5a04ce5e4dfddca84e3060c35720d0a062064fe"},
{file = "orjson-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a7aa5573a949760d6161d826d34dc36db6011926f836851fe9ccb55b5a7d8e8"},
{file = "orjson-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8b2852afca17d7eea85f8e200d324e38c851c96598ac7b227e4f6c4e59fbd3df"},
{file = "orjson-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa185959c082475288da90f996a82e05e0c437216b96f2a8111caeb1d54ef926"},
{file = "orjson-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:89c9332695b838438ea4b9a482bce8ffbfddde4df92750522d928fb00b7b8dce"},
{file = "orjson-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2493f1351a8f0611bc26e2d3d407efb873032b4f6b8926fed8cfed39210ca4ba"},
{file = "orjson-3.9.5-cp311-none-win32.whl", hash = "sha256:ffc544e0e24e9ae69301b9a79df87a971fa5d1c20a6b18dca885699709d01be0"},
{file = "orjson-3.9.5-cp311-none-win_amd64.whl", hash = "sha256:89670fe2732e3c0c54406f77cad1765c4c582f67b915c74fda742286809a0cdc"},
{file = "orjson-3.9.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:15df211469625fa27eced4aa08dc03e35f99c57d45a33855cc35f218ea4071b8"},
{file = "orjson-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9f17c59fe6c02bc5f89ad29edb0253d3059fe8ba64806d789af89a45c35269a"},
{file = "orjson-3.9.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ca6b96659c7690773d8cebb6115c631f4a259a611788463e9c41e74fa53bf33f"},
{file = "orjson-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26fafe966e9195b149950334bdbe9026eca17fe8ffe2d8fa87fdc30ca925d30"},
{file = "orjson-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9006b1eb645ecf460da067e2dd17768ccbb8f39b01815a571bfcfab7e8da5e52"},
{file = "orjson-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ebfdbf695734b1785e792a1315e41835ddf2a3e907ca0e1c87a53f23006ce01d"},
{file = "orjson-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4a3943234342ab37d9ed78fb0a8f81cd4b9532f67bf2ac0d3aa45fa3f0a339f3"},
{file = "orjson-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e6762755470b5c82f07b96b934af32e4d77395a11768b964aaa5eb092817bc31"},
{file = "orjson-3.9.5-cp312-none-win_amd64.whl", hash = "sha256:c74df28749c076fd6e2157190df23d43d42b2c83e09d79b51694ee7315374ad5"},
{file = "orjson-3.9.5-cp37-cp37m-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:88e18a74d916b74f00d0978d84e365c6bf0e7ab846792efa15756b5fb2f7d49d"},
{file = "orjson-3.9.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d28514b5b6dfaf69097be70d0cf4f1407ec29d0f93e0b4131bf9cc8fd3f3e374"},
{file = "orjson-3.9.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b81aca8c7be61e2566246b6a0ca49f8aece70dd3f38c7f5c837f398c4cb142"},
{file = "orjson-3.9.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:385c1c713b1e47fd92e96cf55fd88650ac6dfa0b997e8aa7ecffd8b5865078b1"},
{file = "orjson-3.9.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f9850c03a8e42fba1a508466e6a0f99472fd2b4a5f30235ea49b2a1b32c04c11"},
{file = "orjson-3.9.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4449f84bbb13bcef493d8aa669feadfced0f7c5eea2d0d88b5cc21f812183af8"},
{file = "orjson-3.9.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:86127bf194f3b873135e44ce5dc9212cb152b7e06798d5667a898a00f0519be4"},
{file = "orjson-3.9.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0abcd039f05ae9ab5b0ff11624d0b9e54376253b7d3217a358d09c3edf1d36f7"},
{file = "orjson-3.9.5-cp37-none-win32.whl", hash = "sha256:10cc8ad5ff7188efcb4bec196009d61ce525a4e09488e6d5db41218c7fe4f001"},
{file = "orjson-3.9.5-cp37-none-win_amd64.whl", hash = "sha256:ff27e98532cb87379d1a585837d59b187907228268e7b0a87abe122b2be6968e"},
{file = "orjson-3.9.5-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5bfa79916ef5fef75ad1f377e54a167f0de334c1fa4ebb8d0224075f3ec3d8c0"},
{file = "orjson-3.9.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e87dfa6ac0dae764371ab19b35eaaa46dfcb6ef2545dfca03064f21f5d08239f"},
{file = "orjson-3.9.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50ced24a7b23058b469ecdb96e36607fc611cbaee38b58e62a55c80d1b3ad4e1"},
{file = "orjson-3.9.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b1b74ea2a3064e1375da87788897935832e806cc784de3e789fd3c4ab8eb3fa5"},
{file = "orjson-3.9.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7cb961efe013606913d05609f014ad43edfaced82a576e8b520a5574ce3b2b9"},
{file = "orjson-3.9.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1225d2d5ee76a786bda02f8c5e15017462f8432bb960de13d7c2619dba6f0275"},
{file = "orjson-3.9.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f39f4b99199df05c7ecdd006086259ed25886cdbd7b14c8cdb10c7675cfcca7d"},
{file = "orjson-3.9.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a461dc9fb60cac44f2d3218c36a0c1c01132314839a0e229d7fb1bba69b810d8"},
{file = "orjson-3.9.5-cp38-none-win32.whl", hash = "sha256:dedf1a6173748202df223aea29de814b5836732a176b33501375c66f6ab7d822"},
{file = "orjson-3.9.5-cp38-none-win_amd64.whl", hash = "sha256:fa504082f53efcbacb9087cc8676c163237beb6e999d43e72acb4bb6f0db11e6"},
{file = "orjson-3.9.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:6900f0248edc1bec2a2a3095a78a7e3ef4e63f60f8ddc583687eed162eedfd69"},
{file = "orjson-3.9.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:17404333c40047888ac40bd8c4d49752a787e0a946e728a4e5723f111b6e55a5"},
{file = "orjson-3.9.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0eefb7cfdd9c2bc65f19f974a5d1dfecbac711dae91ed635820c6b12da7a3c11"},
{file = "orjson-3.9.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:68c78b2a3718892dc018adbc62e8bab6ef3c0d811816d21e6973dee0ca30c152"},
{file = "orjson-3.9.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:591ad7d9e4a9f9b104486ad5d88658c79ba29b66c5557ef9edf8ca877a3f8d11"},
{file = "orjson-3.9.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6cc2cbf302fbb2d0b2c3c142a663d028873232a434d89ce1b2604ebe5cc93ce8"},
{file = "orjson-3.9.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b26b5aa5e9ee1bad2795b925b3adb1b1b34122cb977f30d89e0a1b3f24d18450"},
{file = "orjson-3.9.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ef84724f7d29dcfe3aafb1fc5fc7788dca63e8ae626bb9298022866146091a3e"},
{file = "orjson-3.9.5-cp39-none-win32.whl", hash = "sha256:664cff27f85939059472afd39acff152fbac9a091b7137092cb651cf5f7747b5"},
{file = "orjson-3.9.5-cp39-none-win_amd64.whl", hash = "sha256:91dda66755795ac6100e303e206b636568d42ac83c156547634256a2e68de694"},
{file = "orjson-3.9.5.tar.gz", hash = "sha256:6daf5ee0b3cf530b9978cdbf71024f1c16ed4a67d05f6ec435c6e7fe7a52724c"},
]
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "23.1" version = "23.1"
@ -2667,13 +2790,13 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co
[[package]] [[package]]
name = "pluggy" name = "pluggy"
version = "1.2.0" version = "1.3.0"
description = "plugin and hook calling mechanisms for python" description = "plugin and hook calling mechanisms for python"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"},
{file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"},
] ]
[package.extras] [package.extras]
@ -2755,36 +2878,40 @@ test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
[[package]] [[package]]
name = "pyarrow" name = "pyarrow"
version = "12.0.1" version = "13.0.0"
description = "Python library for Apache Arrow" description = "Python library for Apache Arrow"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.8"
files = [ files = [
{file = "pyarrow-12.0.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:6d288029a94a9bb5407ceebdd7110ba398a00412c5b0155ee9813a40d246c5df"}, {file = "pyarrow-13.0.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:1afcc2c33f31f6fb25c92d50a86b7a9f076d38acbcb6f9e74349636109550148"},
{file = "pyarrow-12.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345e1828efdbd9aa4d4de7d5676778aba384a2c3add896d995b23d368e60e5af"}, {file = "pyarrow-13.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:70fa38cdc66b2fc1349a082987f2b499d51d072faaa6b600f71931150de2e0e3"},
{file = "pyarrow-12.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d6009fdf8986332b2169314da482baed47ac053311c8934ac6651e614deacd6"}, {file = "pyarrow-13.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd57b13a6466822498238877892a9b287b0a58c2e81e4bdb0b596dbb151cbb73"},
{file = "pyarrow-12.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d3c4cbbf81e6dd23fe921bc91dc4619ea3b79bc58ef10bce0f49bdafb103daf"}, {file = "pyarrow-13.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8ce69f7bf01de2e2764e14df45b8404fc6f1a5ed9871e8e08a12169f87b7a26"},
{file = "pyarrow-12.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdacf515ec276709ac8042c7d9bd5be83b4f5f39c6c037a17a60d7ebfd92c890"}, {file = "pyarrow-13.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:588f0d2da6cf1b1680974d63be09a6530fd1bd825dc87f76e162404779a157dc"},
{file = "pyarrow-12.0.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:749be7fd2ff260683f9cc739cb862fb11be376de965a2a8ccbf2693b098db6c7"}, {file = "pyarrow-13.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6241afd72b628787b4abea39e238e3ff9f34165273fad306c7acf780dd850956"},
{file = "pyarrow-12.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6895b5fb74289d055c43db3af0de6e16b07586c45763cb5e558d38b86a91e3a7"}, {file = "pyarrow-13.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:fda7857e35993673fcda603c07d43889fca60a5b254052a462653f8656c64f44"},
{file = "pyarrow-12.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1887bdae17ec3b4c046fcf19951e71b6a619f39fa674f9881216173566c8f718"}, {file = "pyarrow-13.0.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:aac0ae0146a9bfa5e12d87dda89d9ef7c57a96210b899459fc2f785303dcbb67"},
{file = "pyarrow-12.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c9cb8eeabbadf5fcfc3d1ddea616c7ce893db2ce4dcef0ac13b099ad7ca082"}, {file = "pyarrow-13.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d7759994217c86c161c6a8060509cfdf782b952163569606bb373828afdd82e8"},
{file = "pyarrow-12.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:ce4aebdf412bd0eeb800d8e47db854f9f9f7e2f5a0220440acf219ddfddd4f63"}, {file = "pyarrow-13.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:868a073fd0ff6468ae7d869b5fc1f54de5c4255b37f44fb890385eb68b68f95d"},
{file = "pyarrow-12.0.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:e0d8730c7f6e893f6db5d5b86eda42c0a130842d101992b581e2138e4d5663d3"}, {file = "pyarrow-13.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51be67e29f3cfcde263a113c28e96aa04362ed8229cb7c6e5f5c719003659d33"},
{file = "pyarrow-12.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43364daec02f69fec89d2315f7fbfbeec956e0d991cbbef471681bd77875c40f"}, {file = "pyarrow-13.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:d1b4e7176443d12610874bb84d0060bf080f000ea9ed7c84b2801df851320295"},
{file = "pyarrow-12.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:051f9f5ccf585f12d7de836e50965b3c235542cc896959320d9776ab93f3b33d"}, {file = "pyarrow-13.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:69b6f9a089d116a82c3ed819eea8fe67dae6105f0d81eaf0fdd5e60d0c6e0944"},
{file = "pyarrow-12.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:be2757e9275875d2a9c6e6052ac7957fbbfc7bc7370e4a036a9b893e96fedaba"}, {file = "pyarrow-13.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ab1268db81aeb241200e321e220e7cd769762f386f92f61b898352dd27e402ce"},
{file = "pyarrow-12.0.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:cf812306d66f40f69e684300f7af5111c11f6e0d89d6b733e05a3de44961529d"}, {file = "pyarrow-13.0.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:ee7490f0f3f16a6c38f8c680949551053c8194e68de5046e6c288e396dccee80"},
{file = "pyarrow-12.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:459a1c0ed2d68671188b2118c63bac91eaef6fc150c77ddd8a583e3c795737bf"}, {file = "pyarrow-13.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e3ad79455c197a36eefbd90ad4aa832bece7f830a64396c15c61a0985e337287"},
{file = "pyarrow-12.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85e705e33eaf666bbe508a16fd5ba27ca061e177916b7a317ba5a51bee43384c"}, {file = "pyarrow-13.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68fcd2dc1b7d9310b29a15949cdd0cb9bc34b6de767aff979ebf546020bf0ba0"},
{file = "pyarrow-12.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9120c3eb2b1f6f516a3b7a9714ed860882d9ef98c4b17edcdc91d95b7528db60"}, {file = "pyarrow-13.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc6fd330fd574c51d10638e63c0d00ab456498fc804c9d01f2a61b9264f2c5b2"},
{file = "pyarrow-12.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:c780f4dc40460015d80fcd6a6140de80b615349ed68ef9adb653fe351778c9b3"}, {file = "pyarrow-13.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e66442e084979a97bb66939e18f7b8709e4ac5f887e636aba29486ffbf373763"},
{file = "pyarrow-12.0.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:a3c63124fc26bf5f95f508f5d04e1ece8cc23a8b0af2a1e6ab2b1ec3fdc91b24"}, {file = "pyarrow-13.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:0f6eff839a9e40e9c5610d3ff8c5bdd2f10303408312caf4c8003285d0b49565"},
{file = "pyarrow-12.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b13329f79fa4472324f8d32dc1b1216616d09bd1e77cfb13104dec5463632c36"}, {file = "pyarrow-13.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b30a27f1cddf5c6efcb67e598d7823a1e253d743d92ac32ec1eb4b6a1417867"},
{file = "pyarrow-12.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb656150d3d12ec1396f6dde542db1675a95c0cc8366d507347b0beed96e87ca"}, {file = "pyarrow-13.0.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:09552dad5cf3de2dc0aba1c7c4b470754c69bd821f5faafc3d774bedc3b04bb7"},
{file = "pyarrow-12.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6251e38470da97a5b2e00de5c6a049149f7b2bd62f12fa5dbb9ac674119ba71a"}, {file = "pyarrow-13.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3896ae6c205d73ad192d2fc1489cd0edfab9f12867c85b4c277af4d37383c18c"},
{file = "pyarrow-12.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:3de26da901216149ce086920547dfff5cd22818c9eab67ebc41e863a5883bac7"}, {file = "pyarrow-13.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6647444b21cb5e68b593b970b2a9a07748dd74ea457c7dadaa15fd469c48ada1"},
{file = "pyarrow-12.0.1.tar.gz", hash = "sha256:cce317fc96e5b71107bf1f9f184d5e54e2bd14bbf3f9a3d62819961f0af86fec"}, {file = "pyarrow-13.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47663efc9c395e31d09c6aacfa860f4473815ad6804311c5433f7085415d62a7"},
{file = "pyarrow-13.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:b9ba6b6d34bd2563345488cf444510588ea42ad5613df3b3509f48eb80250afd"},
{file = "pyarrow-13.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:d00d374a5625beeb448a7fa23060df79adb596074beb3ddc1838adb647b6ef09"},
{file = "pyarrow-13.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:c51afd87c35c8331b56f796eff954b9c7f8d4b7fef5903daf4e05fcf017d23a8"},
{file = "pyarrow-13.0.0.tar.gz", hash = "sha256:83333726e83ed44b0ac94d8d7a21bbdee4a05029c3b1e8db58a863eec8fd8a33"},
] ]
[package.dependencies] [package.dependencies]
@ -2993,6 +3120,20 @@ files = [
[package.extras] [package.extras]
cli = ["click (>=5.0)"] cli = ["click (>=5.0)"]
[[package]]
name = "python-multipart"
version = "0.0.6"
description = "A streaming multipart parser for Python"
optional = false
python-versions = ">=3.7"
files = [
{file = "python_multipart-0.0.6-py3-none-any.whl", hash = "sha256:ee698bab5ef148b0a760751c261902cd096e57e10558e11aca17646b74ee1c18"},
{file = "python_multipart-0.0.6.tar.gz", hash = "sha256:e9925a80bb668529f1b67c7fdb0a5dacdd7cbfc6fb0bff3ea443fe22bdd62132"},
]
[package.extras]
dev = ["atomicwrites (==1.2.1)", "attrs (==19.2.0)", "coverage (==6.5.0)", "hatch", "invoke (==1.7.3)", "more-itertools (==4.3.0)", "pbr (==4.3.0)", "pluggy (==1.0.0)", "py (==1.11.0)", "pytest (==7.2.0)", "pytest-cov (==4.0.0)", "pytest-timeout (==2.1.0)", "pyyaml (==5.1)"]
[[package]] [[package]]
name = "pytz" name = "pytz"
version = "2023.3" version = "2023.3"
@ -3736,13 +3877,13 @@ files = [
[[package]] [[package]]
name = "tifffile" name = "tifffile"
version = "2023.8.12" version = "2023.8.25"
description = "Read and write TIFF files" description = "Read and write TIFF files"
optional = false optional = false
python-versions = ">=3.9" python-versions = ">=3.9"
files = [ files = [
{file = "tifffile-2023.8.12-py3-none-any.whl", hash = "sha256:d1ef06461a947a6800ba6121b330b54a57fb9cbf7e5bc0adab8307081297d66b"}, {file = "tifffile-2023.8.25-py3-none-any.whl", hash = "sha256:40318485b59e9acb62e7139f22bd46e6760f92daea562b79900bfce3ee2613b7"},
{file = "tifffile-2023.8.12.tar.gz", hash = "sha256:824956b6d974b9d346aae59932bea862a2ad18fcc2b1a820b6941b7f6ddb2bca"}, {file = "tifffile-2023.8.25.tar.gz", hash = "sha256:0a3ebcdfe71eb61a487dd22eaf21ed8962c511e6eb692153c7ac15f81798dfa4"},
] ]
[package.dependencies] [package.dependencies]
@ -3985,18 +4126,18 @@ telegram = ["requests"]
[[package]] [[package]]
name = "transformers" name = "transformers"
version = "4.31.0" version = "4.32.0"
description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow"
optional = false optional = false
python-versions = ">=3.8.0" python-versions = ">=3.8.0"
files = [ files = [
{file = "transformers-4.31.0-py3-none-any.whl", hash = "sha256:8487aab0195ce1c2a5ae189305118b9720daddbc7b688edb09ccd79e3b149f6b"}, {file = "transformers-4.32.0-py3-none-any.whl", hash = "sha256:32d8adf0ed76285508e7fd66657b4448ec1f882599ae6bf6f9c36bd7bf798402"},
{file = "transformers-4.31.0.tar.gz", hash = "sha256:4302fba920a1c24d3a429a29efff6a63eac03f3f3cf55b55927fc795d01cb273"}, {file = "transformers-4.32.0.tar.gz", hash = "sha256:ca510f9688d2fe7347abbbfbd13f2f6dcd3c8349870c8d0ed98beed5f579b354"},
] ]
[package.dependencies] [package.dependencies]
filelock = "*" filelock = "*"
huggingface-hub = ">=0.14.1,<1.0" huggingface-hub = ">=0.15.1,<1.0"
numpy = ">=1.17" numpy = ">=1.17"
packaging = ">=20.0" packaging = ">=20.0"
protobuf = {version = "*", optional = true, markers = "extra == \"sentencepiece\""} protobuf = {version = "*", optional = true, markers = "extra == \"sentencepiece\""}
@ -4011,18 +4152,18 @@ tqdm = ">=4.27"
[package.extras] [package.extras]
accelerate = ["accelerate (>=0.20.3)"] accelerate = ["accelerate (>=0.20.3)"]
agents = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch (>=1.9,!=1.12.0)"] agents = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch (>=1.9,!=1.12.0)"]
all = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision"] all = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision"]
audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"]
codecarbon = ["codecarbon (==1.2.0)"] codecarbon = ["codecarbon (==1.2.0)"]
deepspeed = ["accelerate (>=0.20.3)", "deepspeed (>=0.9.3)"] deepspeed = ["accelerate (>=0.20.3)", "deepspeed (>=0.9.3)"]
deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.20.3)", "beautifulsoup4", "black (>=23.1,<24.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "timeout-decorator"] deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.20.3)", "beautifulsoup4", "black (>=23.1,<24.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "timeout-decorator"]
dev = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "beautifulsoup4", "black (>=23.1,<24.0)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune]", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] dev = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "beautifulsoup4", "black (>=23.1,<24.0)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune]", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"]
dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "beautifulsoup4", "black (>=23.1,<24.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "urllib3 (<2.0.0)"] dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "beautifulsoup4", "black (>=23.1,<24.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "urllib3 (<2.0.0)"]
dev-torch = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "accelerate (>=0.20.3)", "beautifulsoup4", "black (>=23.1,<24.0)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune]", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] dev-torch = ["GitPython (<3.1.19)", "Pillow (<10.0.0)", "accelerate (>=0.20.3)", "beautifulsoup4", "black (>=23.1,<24.0)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pytest (>=7.2.0)", "pytest-timeout", "pytest-xdist", "ray[tune]", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (>=0.0.241,<=0.0.259)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"]
docs = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "hf-doc-builder", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision"] docs = ["Pillow (<10.0.0)", "accelerate (>=0.20.3)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "hf-doc-builder", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.6,<2.14)", "tensorflow-text (<2.14)", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "torchaudio", "torchvision"]
docs-specific = ["hf-doc-builder"] docs-specific = ["hf-doc-builder"]
fairscale = ["fairscale (>0.3)"] fairscale = ["fairscale (>0.3)"]
flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.2.8,!=0.3.2,<=0.4.13)", "jaxlib (>=0.1.65,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)"] flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)"]
flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"]
ftfy = ["ftfy"] ftfy = ["ftfy"]
integrations = ["optuna", "ray[tune]", "sigopt"] integrations = ["optuna", "ray[tune]", "sigopt"]
@ -4050,7 +4191,7 @@ tokenizers = ["tokenizers (>=0.11.1,!=0.11.3,<0.14)"]
torch = ["accelerate (>=0.20.3)", "torch (>=1.9,!=1.12.0)"] torch = ["accelerate (>=0.20.3)", "torch (>=1.9,!=1.12.0)"]
torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"]
torch-vision = ["Pillow (<10.0.0)", "torchvision"] torch-vision = ["Pillow (<10.0.0)", "torchvision"]
torchhub = ["filelock", "huggingface-hub (>=0.14.1,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "tqdm (>=4.27)"] torchhub = ["filelock", "huggingface-hub (>=0.15.1,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.9,!=1.12.0)", "tqdm (>=4.27)"]
video = ["av (==9.2.0)", "decord (==0.6.0)"] video = ["av (==9.2.0)", "decord (==0.6.0)"]
vision = ["Pillow (<10.0.0)"] vision = ["Pillow (<10.0.0)"]
@ -4164,33 +4305,33 @@ test = ["Cython (>=0.29.32,<0.30.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "my
[[package]] [[package]]
name = "watchfiles" name = "watchfiles"
version = "0.19.0" version = "0.20.0"
description = "Simple, modern and high performance file watching and code reload in python." description = "Simple, modern and high performance file watching and code reload in python."
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
files = [ files = [
{file = "watchfiles-0.19.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:91633e64712df3051ca454ca7d1b976baf842d7a3640b87622b323c55f3345e7"}, {file = "watchfiles-0.20.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9"},
{file = "watchfiles-0.19.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:b6577b8c6c8701ba8642ea9335a129836347894b666dd1ec2226830e263909d3"}, {file = "watchfiles-0.20.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:18b28f6ad871b82df9542ff958d0c86bb0d8310bb09eb8e87d97318a3b5273af"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fac19dc9cbc34052394dbe81e149411a62e71999c0a19e1e09ce537867f95ae0"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:09ea3397aecbc81c19ed7f025e051a7387feefdb789cf768ff994c1228182fda"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0376deac92377817e4fb8f347bf559b7d44ff556d9bc6f6208dd3f79f104aaf"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c75eff897786ee262c9f17a48886f4e98e6cfd335e011c591c305e5d083c056"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95"},
{file = "watchfiles-0.19.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb5d45c4143c1dd60f98a16187fd123eda7248f84ef22244818c18d531a249d1"}, {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf"},
{file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:79c533ff593db861ae23436541f481ec896ee3da4e5db8962429b441bbaae16e"}, {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db"},
{file = "watchfiles-0.19.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:3d7d267d27aceeeaa3de0dd161a0d64f0a282264d592e335fff7958cc0cbae7c"}, {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164"},
{file = "watchfiles-0.19.0-cp37-abi3-win32.whl", hash = "sha256:176a9a7641ec2c97b24455135d58012a5be5c6217fc4d5fef0b2b9f75dbf5154"}, {file = "watchfiles-0.20.0-cp37-abi3-win32.whl", hash = "sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5"},
{file = "watchfiles-0.19.0-cp37-abi3-win_amd64.whl", hash = "sha256:945be0baa3e2440151eb3718fd8846751e8b51d8de7b884c90b17d271d34cae8"}, {file = "watchfiles-0.20.0-cp37-abi3-win_amd64.whl", hash = "sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3"},
{file = "watchfiles-0.19.0-cp37-abi3-win_arm64.whl", hash = "sha256:0089c6dc24d436b373c3c57657bf4f9a453b13767150d17284fc6162b2791911"}, {file = "watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cae3dde0b4b2078f31527acff6f486e23abed307ba4d3932466ba7cdd5ecec79"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d97db179f7566dcf145c5179ddb2ae2a4450e3a634eb864b09ea04e68c252e8e"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f3920b1285a7d3ce898e303d84791b7bf40d57b7695ad549dc04e6a44c9f120"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:835df2da7a5df5464c4a23b2d963e1a9d35afa422c83bf4ff4380b3114603644"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9afd0d69429172c796164fd7fe8e821ade9be983f51c659a38da3faaaaac44dc"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608cd94a8767f49521901aff9ae0c92cc8f5a24d528db7d6b0295290f9d41193"},
{file = "watchfiles-0.19.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68dce92b29575dda0f8d30c11742a8e2b9b8ec768ae414b54f7453f27bdf9545"}, {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d1de8218874925bce7bb2ae9657efc504411528930d7a83f98b1749864f2ef"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:5569fc7f967429d4bc87e355cdfdcee6aabe4b620801e2cf5805ea245c06097c"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:13f995d5152a8ba4ed7c2bbbaeee4e11a5944defc7cacd0ccb4dcbdcfd78029a"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5471582658ea56fca122c0f0d0116a36807c63fefd6fdc92c71ca9a4491b6b48"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b5c8d3be7b502f8c43a33c63166ada8828dbb0c6d49c8f9ce990a96de2f5a49"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b538014a87f94d92f98f34d3e6d2635478e6be6423a9ea53e4dd96210065e193"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e43af4464daa08723c04b43cf978ab86cc55c684c16172622bdac64b34e36af0"},
{file = "watchfiles-0.19.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20b44221764955b1e703f012c74015306fb7e79a00c15370785f309b1ed9aa8d"}, {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d9e1f75c4f86c93d73b5bd1ebe667558357548f11b4f8af4e0e272f79413ce"},
{file = "watchfiles-0.19.0.tar.gz", hash = "sha256:d9b073073e048081e502b6c6b0b88714c026a1a4c890569238d04aca5f9ca74b"}, {file = "watchfiles-0.20.0.tar.gz", hash = "sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019"},
] ]
[package.dependencies] [package.dependencies]
@ -4552,4 +4693,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"]
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.11" python-versions = "^3.11"
content-hash = "1a8981686295b3de58b41192c608a69a2c05983c47f93451c8a6ed50304b7cb3" content-hash = "6d200d3ea1ccf9fb89f44043e3e0845e70f19aac374b96227559375f44508dc5"

View file

@ -30,6 +30,9 @@ rich = "^13.4.2"
ftfy = "^6.1.1" ftfy = "^6.1.1"
setuptools = "^68.0.0" setuptools = "^68.0.0"
open-clip-torch = "^2.20.0" open-clip-torch = "^2.20.0"
python-multipart = "^0.0.6"
orjson = "^3.9.5"
safetensors = "0.3.2"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
mypy = "^1.3.0" mypy = "^1.3.0"

View file

@ -255,7 +255,7 @@ class ExifBottomSheet extends HookConsumerWidget {
), ),
), ),
subtitle: Text( subtitle: Text(
"ƒ/${exifInfo.fNumber} ${exifInfo.exposureTime} ${exifInfo.focalLength} mm ISO${exifInfo.iso} ", "ƒ/${exifInfo.fNumber} ${exifInfo.exposureTime} ${exifInfo.focalLength} mm ISO ${exifInfo.iso ?? ''} ",
), ),
), ),
], ],

View file

@ -35,11 +35,14 @@ doc/AuthDeviceResponseDto.md
doc/AuthenticationApi.md doc/AuthenticationApi.md
doc/BulkIdResponseDto.md doc/BulkIdResponseDto.md
doc/BulkIdsDto.md doc/BulkIdsDto.md
doc/CLIPConfig.md
doc/CLIPMode.md
doc/ChangePasswordDto.md doc/ChangePasswordDto.md
doc/CheckDuplicateAssetDto.md doc/CheckDuplicateAssetDto.md
doc/CheckDuplicateAssetResponseDto.md doc/CheckDuplicateAssetResponseDto.md
doc/CheckExistingAssetsDto.md doc/CheckExistingAssetsDto.md
doc/CheckExistingAssetsResponseDto.md doc/CheckExistingAssetsResponseDto.md
doc/ClassificationConfig.md
doc/CreateAlbumDto.md doc/CreateAlbumDto.md
doc/CreateProfileImageResponseDto.md doc/CreateProfileImageResponseDto.md
doc/CreateTagDto.md doc/CreateTagDto.md
@ -68,6 +71,7 @@ doc/LogoutResponseDto.md
doc/MapMarkerResponseDto.md doc/MapMarkerResponseDto.md
doc/MemoryLaneResponseDto.md doc/MemoryLaneResponseDto.md
doc/MergePersonDto.md doc/MergePersonDto.md
doc/ModelType.md
doc/OAuthApi.md doc/OAuthApi.md
doc/OAuthCallbackDto.md doc/OAuthCallbackDto.md
doc/OAuthConfigDto.md doc/OAuthConfigDto.md
@ -80,6 +84,7 @@ doc/PersonApi.md
doc/PersonResponseDto.md doc/PersonResponseDto.md
doc/PersonUpdateDto.md doc/PersonUpdateDto.md
doc/QueueStatusDto.md doc/QueueStatusDto.md
doc/RecognitionConfig.md
doc/SearchAlbumResponseDto.md doc/SearchAlbumResponseDto.md
doc/SearchApi.md doc/SearchApi.md
doc/SearchAssetDto.md doc/SearchAssetDto.md
@ -189,6 +194,9 @@ lib/model/check_duplicate_asset_dto.dart
lib/model/check_duplicate_asset_response_dto.dart lib/model/check_duplicate_asset_response_dto.dart
lib/model/check_existing_assets_dto.dart lib/model/check_existing_assets_dto.dart
lib/model/check_existing_assets_response_dto.dart lib/model/check_existing_assets_response_dto.dart
lib/model/classification_config.dart
lib/model/clip_config.dart
lib/model/clip_mode.dart
lib/model/create_album_dto.dart lib/model/create_album_dto.dart
lib/model/create_profile_image_response_dto.dart lib/model/create_profile_image_response_dto.dart
lib/model/create_tag_dto.dart lib/model/create_tag_dto.dart
@ -216,6 +224,7 @@ lib/model/logout_response_dto.dart
lib/model/map_marker_response_dto.dart lib/model/map_marker_response_dto.dart
lib/model/memory_lane_response_dto.dart lib/model/memory_lane_response_dto.dart
lib/model/merge_person_dto.dart lib/model/merge_person_dto.dart
lib/model/model_type.dart
lib/model/o_auth_callback_dto.dart lib/model/o_auth_callback_dto.dart
lib/model/o_auth_config_dto.dart lib/model/o_auth_config_dto.dart
lib/model/o_auth_config_response_dto.dart lib/model/o_auth_config_response_dto.dart
@ -225,6 +234,7 @@ lib/model/people_update_item.dart
lib/model/person_response_dto.dart lib/model/person_response_dto.dart
lib/model/person_update_dto.dart lib/model/person_update_dto.dart
lib/model/queue_status_dto.dart lib/model/queue_status_dto.dart
lib/model/recognition_config.dart
lib/model/search_album_response_dto.dart lib/model/search_album_response_dto.dart
lib/model/search_asset_dto.dart lib/model/search_asset_dto.dart
lib/model/search_asset_response_dto.dart lib/model/search_asset_response_dto.dart
@ -309,6 +319,9 @@ test/check_duplicate_asset_dto_test.dart
test/check_duplicate_asset_response_dto_test.dart test/check_duplicate_asset_response_dto_test.dart
test/check_existing_assets_dto_test.dart test/check_existing_assets_dto_test.dart
test/check_existing_assets_response_dto_test.dart test/check_existing_assets_response_dto_test.dart
test/classification_config_test.dart
test/clip_config_test.dart
test/clip_mode_test.dart
test/create_album_dto_test.dart test/create_album_dto_test.dart
test/create_profile_image_response_dto_test.dart test/create_profile_image_response_dto_test.dart
test/create_tag_dto_test.dart test/create_tag_dto_test.dart
@ -337,6 +350,7 @@ test/logout_response_dto_test.dart
test/map_marker_response_dto_test.dart test/map_marker_response_dto_test.dart
test/memory_lane_response_dto_test.dart test/memory_lane_response_dto_test.dart
test/merge_person_dto_test.dart test/merge_person_dto_test.dart
test/model_type_test.dart
test/o_auth_api_test.dart test/o_auth_api_test.dart
test/o_auth_callback_dto_test.dart test/o_auth_callback_dto_test.dart
test/o_auth_config_dto_test.dart test/o_auth_config_dto_test.dart
@ -349,6 +363,7 @@ test/person_api_test.dart
test/person_response_dto_test.dart test/person_response_dto_test.dart
test/person_update_dto_test.dart test/person_update_dto_test.dart
test/queue_status_dto_test.dart test/queue_status_dto_test.dart
test/recognition_config_test.dart
test/search_album_response_dto_test.dart test/search_album_response_dto_test.dart
test/search_api_test.dart test/search_api_test.dart
test/search_asset_dto_test.dart test/search_asset_dto_test.dart

View file

@ -208,11 +208,14 @@ Class | Method | HTTP request | Description
- [AuthDeviceResponseDto](doc//AuthDeviceResponseDto.md) - [AuthDeviceResponseDto](doc//AuthDeviceResponseDto.md)
- [BulkIdResponseDto](doc//BulkIdResponseDto.md) - [BulkIdResponseDto](doc//BulkIdResponseDto.md)
- [BulkIdsDto](doc//BulkIdsDto.md) - [BulkIdsDto](doc//BulkIdsDto.md)
- [CLIPConfig](doc//CLIPConfig.md)
- [CLIPMode](doc//CLIPMode.md)
- [ChangePasswordDto](doc//ChangePasswordDto.md) - [ChangePasswordDto](doc//ChangePasswordDto.md)
- [CheckDuplicateAssetDto](doc//CheckDuplicateAssetDto.md) - [CheckDuplicateAssetDto](doc//CheckDuplicateAssetDto.md)
- [CheckDuplicateAssetResponseDto](doc//CheckDuplicateAssetResponseDto.md) - [CheckDuplicateAssetResponseDto](doc//CheckDuplicateAssetResponseDto.md)
- [CheckExistingAssetsDto](doc//CheckExistingAssetsDto.md) - [CheckExistingAssetsDto](doc//CheckExistingAssetsDto.md)
- [CheckExistingAssetsResponseDto](doc//CheckExistingAssetsResponseDto.md) - [CheckExistingAssetsResponseDto](doc//CheckExistingAssetsResponseDto.md)
- [ClassificationConfig](doc//ClassificationConfig.md)
- [CreateAlbumDto](doc//CreateAlbumDto.md) - [CreateAlbumDto](doc//CreateAlbumDto.md)
- [CreateProfileImageResponseDto](doc//CreateProfileImageResponseDto.md) - [CreateProfileImageResponseDto](doc//CreateProfileImageResponseDto.md)
- [CreateTagDto](doc//CreateTagDto.md) - [CreateTagDto](doc//CreateTagDto.md)
@ -240,6 +243,7 @@ Class | Method | HTTP request | Description
- [MapMarkerResponseDto](doc//MapMarkerResponseDto.md) - [MapMarkerResponseDto](doc//MapMarkerResponseDto.md)
- [MemoryLaneResponseDto](doc//MemoryLaneResponseDto.md) - [MemoryLaneResponseDto](doc//MemoryLaneResponseDto.md)
- [MergePersonDto](doc//MergePersonDto.md) - [MergePersonDto](doc//MergePersonDto.md)
- [ModelType](doc//ModelType.md)
- [OAuthCallbackDto](doc//OAuthCallbackDto.md) - [OAuthCallbackDto](doc//OAuthCallbackDto.md)
- [OAuthConfigDto](doc//OAuthConfigDto.md) - [OAuthConfigDto](doc//OAuthConfigDto.md)
- [OAuthConfigResponseDto](doc//OAuthConfigResponseDto.md) - [OAuthConfigResponseDto](doc//OAuthConfigResponseDto.md)
@ -249,6 +253,7 @@ Class | Method | HTTP request | Description
- [PersonResponseDto](doc//PersonResponseDto.md) - [PersonResponseDto](doc//PersonResponseDto.md)
- [PersonUpdateDto](doc//PersonUpdateDto.md) - [PersonUpdateDto](doc//PersonUpdateDto.md)
- [QueueStatusDto](doc//QueueStatusDto.md) - [QueueStatusDto](doc//QueueStatusDto.md)
- [RecognitionConfig](doc//RecognitionConfig.md)
- [SearchAlbumResponseDto](doc//SearchAlbumResponseDto.md) - [SearchAlbumResponseDto](doc//SearchAlbumResponseDto.md)
- [SearchAssetDto](doc//SearchAssetDto.md) - [SearchAssetDto](doc//SearchAssetDto.md)
- [SearchAssetResponseDto](doc//SearchAssetResponseDto.md) - [SearchAssetResponseDto](doc//SearchAssetResponseDto.md)

18
mobile/openapi/doc/CLIPConfig.md generated Normal file
View file

@ -0,0 +1,18 @@
# openapi.model.CLIPConfig
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**enabled** | **bool** | |
**mode** | [**CLIPMode**](CLIPMode.md) | | [optional]
**modelName** | **String** | |
**modelType** | [**ModelType**](ModelType.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

14
mobile/openapi/doc/CLIPMode.md generated Normal file
View file

@ -0,0 +1,14 @@
# openapi.model.CLIPMode
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View file

@ -0,0 +1,18 @@
# openapi.model.ClassificationConfig
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**enabled** | **bool** | |
**minScore** | **int** | |
**modelName** | **String** | |
**modelType** | [**ModelType**](ModelType.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

14
mobile/openapi/doc/ModelType.md generated Normal file
View file

@ -0,0 +1,14 @@
# openapi.model.ModelType
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

19
mobile/openapi/doc/RecognitionConfig.md generated Normal file
View file

@ -0,0 +1,19 @@
# openapi.model.RecognitionConfig
## Load the model package
```dart
import 'package:openapi/api.dart';
```
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
**enabled** | **bool** | |
**maxDistance** | **int** | |
**minScore** | **int** | |
**modelName** | **String** | |
**modelType** | [**ModelType**](ModelType.md) | | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View file

@ -8,10 +8,10 @@ import 'package:openapi/api.dart';
## Properties ## Properties
Name | Type | Description | Notes Name | Type | Description | Notes
------------ | ------------- | ------------- | ------------- ------------ | ------------- | ------------- | -------------
**clipEncodeEnabled** | **bool** | | **classification** | [**ClassificationConfig**](ClassificationConfig.md) | |
**clip** | [**CLIPConfig**](CLIPConfig.md) | |
**enabled** | **bool** | | **enabled** | **bool** | |
**facialRecognitionEnabled** | **bool** | | **facialRecognition** | [**RecognitionConfig**](RecognitionConfig.md) | |
**tagImageEnabled** | **bool** | |
**url** | **String** | | **url** | **String** | |
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View file

@ -71,11 +71,14 @@ part 'model/audit_deletes_response_dto.dart';
part 'model/auth_device_response_dto.dart'; part 'model/auth_device_response_dto.dart';
part 'model/bulk_id_response_dto.dart'; part 'model/bulk_id_response_dto.dart';
part 'model/bulk_ids_dto.dart'; part 'model/bulk_ids_dto.dart';
part 'model/clip_config.dart';
part 'model/clip_mode.dart';
part 'model/change_password_dto.dart'; part 'model/change_password_dto.dart';
part 'model/check_duplicate_asset_dto.dart'; part 'model/check_duplicate_asset_dto.dart';
part 'model/check_duplicate_asset_response_dto.dart'; part 'model/check_duplicate_asset_response_dto.dart';
part 'model/check_existing_assets_dto.dart'; part 'model/check_existing_assets_dto.dart';
part 'model/check_existing_assets_response_dto.dart'; part 'model/check_existing_assets_response_dto.dart';
part 'model/classification_config.dart';
part 'model/create_album_dto.dart'; part 'model/create_album_dto.dart';
part 'model/create_profile_image_response_dto.dart'; part 'model/create_profile_image_response_dto.dart';
part 'model/create_tag_dto.dart'; part 'model/create_tag_dto.dart';
@ -103,6 +106,7 @@ part 'model/logout_response_dto.dart';
part 'model/map_marker_response_dto.dart'; part 'model/map_marker_response_dto.dart';
part 'model/memory_lane_response_dto.dart'; part 'model/memory_lane_response_dto.dart';
part 'model/merge_person_dto.dart'; part 'model/merge_person_dto.dart';
part 'model/model_type.dart';
part 'model/o_auth_callback_dto.dart'; part 'model/o_auth_callback_dto.dart';
part 'model/o_auth_config_dto.dart'; part 'model/o_auth_config_dto.dart';
part 'model/o_auth_config_response_dto.dart'; part 'model/o_auth_config_response_dto.dart';
@ -112,6 +116,7 @@ part 'model/people_update_item.dart';
part 'model/person_response_dto.dart'; part 'model/person_response_dto.dart';
part 'model/person_update_dto.dart'; part 'model/person_update_dto.dart';
part 'model/queue_status_dto.dart'; part 'model/queue_status_dto.dart';
part 'model/recognition_config.dart';
part 'model/search_album_response_dto.dart'; part 'model/search_album_response_dto.dart';
part 'model/search_asset_dto.dart'; part 'model/search_asset_dto.dart';
part 'model/search_asset_response_dto.dart'; part 'model/search_asset_response_dto.dart';

View file

@ -235,6 +235,10 @@ class ApiClient {
return BulkIdResponseDto.fromJson(value); return BulkIdResponseDto.fromJson(value);
case 'BulkIdsDto': case 'BulkIdsDto':
return BulkIdsDto.fromJson(value); return BulkIdsDto.fromJson(value);
case 'CLIPConfig':
return CLIPConfig.fromJson(value);
case 'CLIPMode':
return CLIPModeTypeTransformer().decode(value);
case 'ChangePasswordDto': case 'ChangePasswordDto':
return ChangePasswordDto.fromJson(value); return ChangePasswordDto.fromJson(value);
case 'CheckDuplicateAssetDto': case 'CheckDuplicateAssetDto':
@ -245,6 +249,8 @@ class ApiClient {
return CheckExistingAssetsDto.fromJson(value); return CheckExistingAssetsDto.fromJson(value);
case 'CheckExistingAssetsResponseDto': case 'CheckExistingAssetsResponseDto':
return CheckExistingAssetsResponseDto.fromJson(value); return CheckExistingAssetsResponseDto.fromJson(value);
case 'ClassificationConfig':
return ClassificationConfig.fromJson(value);
case 'CreateAlbumDto': case 'CreateAlbumDto':
return CreateAlbumDto.fromJson(value); return CreateAlbumDto.fromJson(value);
case 'CreateProfileImageResponseDto': case 'CreateProfileImageResponseDto':
@ -299,6 +305,8 @@ class ApiClient {
return MemoryLaneResponseDto.fromJson(value); return MemoryLaneResponseDto.fromJson(value);
case 'MergePersonDto': case 'MergePersonDto':
return MergePersonDto.fromJson(value); return MergePersonDto.fromJson(value);
case 'ModelType':
return ModelTypeTypeTransformer().decode(value);
case 'OAuthCallbackDto': case 'OAuthCallbackDto':
return OAuthCallbackDto.fromJson(value); return OAuthCallbackDto.fromJson(value);
case 'OAuthConfigDto': case 'OAuthConfigDto':
@ -317,6 +325,8 @@ class ApiClient {
return PersonUpdateDto.fromJson(value); return PersonUpdateDto.fromJson(value);
case 'QueueStatusDto': case 'QueueStatusDto':
return QueueStatusDto.fromJson(value); return QueueStatusDto.fromJson(value);
case 'RecognitionConfig':
return RecognitionConfig.fromJson(value);
case 'SearchAlbumResponseDto': case 'SearchAlbumResponseDto':
return SearchAlbumResponseDto.fromJson(value); return SearchAlbumResponseDto.fromJson(value);
case 'SearchAssetDto': case 'SearchAssetDto':

View file

@ -64,6 +64,9 @@ String parameterToString(dynamic value) {
if (value is AudioCodec) { if (value is AudioCodec) {
return AudioCodecTypeTransformer().encode(value).toString(); return AudioCodecTypeTransformer().encode(value).toString();
} }
if (value is CLIPMode) {
return CLIPModeTypeTransformer().encode(value).toString();
}
if (value is DeleteAssetStatus) { if (value is DeleteAssetStatus) {
return DeleteAssetStatusTypeTransformer().encode(value).toString(); return DeleteAssetStatusTypeTransformer().encode(value).toString();
} }
@ -76,6 +79,9 @@ String parameterToString(dynamic value) {
if (value is JobName) { if (value is JobName) {
return JobNameTypeTransformer().encode(value).toString(); return JobNameTypeTransformer().encode(value).toString();
} }
if (value is ModelType) {
return ModelTypeTypeTransformer().encode(value).toString();
}
if (value is SharedLinkType) { if (value is SharedLinkType) {
return SharedLinkTypeTypeTransformer().encode(value).toString(); return SharedLinkTypeTypeTransformer().encode(value).toString();
} }

View file

@ -0,0 +1,131 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class ClassificationConfig {
/// Returns a new [ClassificationConfig] instance.
ClassificationConfig({
required this.enabled,
required this.minScore,
required this.modelName,
this.modelType,
});
bool enabled;
int minScore;
String modelName;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
ModelType? modelType;
@override
bool operator ==(Object other) => identical(this, other) || other is ClassificationConfig &&
other.enabled == enabled &&
other.minScore == minScore &&
other.modelName == modelName &&
other.modelType == modelType;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(enabled.hashCode) +
(minScore.hashCode) +
(modelName.hashCode) +
(modelType == null ? 0 : modelType!.hashCode);
@override
String toString() => 'ClassificationConfig[enabled=$enabled, minScore=$minScore, modelName=$modelName, modelType=$modelType]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'enabled'] = this.enabled;
json[r'minScore'] = this.minScore;
json[r'modelName'] = this.modelName;
if (this.modelType != null) {
json[r'modelType'] = this.modelType;
} else {
// json[r'modelType'] = null;
}
return json;
}
/// Returns a new [ClassificationConfig] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static ClassificationConfig? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return ClassificationConfig(
enabled: mapValueOfType<bool>(json, r'enabled')!,
minScore: mapValueOfType<int>(json, r'minScore')!,
modelName: mapValueOfType<String>(json, r'modelName')!,
modelType: ModelType.fromJson(json[r'modelType']),
);
}
return null;
}
static List<ClassificationConfig> listFromJson(dynamic json, {bool growable = false,}) {
final result = <ClassificationConfig>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = ClassificationConfig.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, ClassificationConfig> mapFromJson(dynamic json) {
final map = <String, ClassificationConfig>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = ClassificationConfig.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of ClassificationConfig-objects as value to a dart map
static Map<String, List<ClassificationConfig>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<ClassificationConfig>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = ClassificationConfig.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'enabled',
'minScore',
'modelName',
};
}

140
mobile/openapi/lib/model/clip_config.dart generated Normal file
View file

@ -0,0 +1,140 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class CLIPConfig {
/// Returns a new [CLIPConfig] instance.
CLIPConfig({
required this.enabled,
this.mode,
required this.modelName,
this.modelType,
});
bool enabled;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
CLIPMode? mode;
String modelName;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
ModelType? modelType;
@override
bool operator ==(Object other) => identical(this, other) || other is CLIPConfig &&
other.enabled == enabled &&
other.mode == mode &&
other.modelName == modelName &&
other.modelType == modelType;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(enabled.hashCode) +
(mode == null ? 0 : mode!.hashCode) +
(modelName.hashCode) +
(modelType == null ? 0 : modelType!.hashCode);
@override
String toString() => 'CLIPConfig[enabled=$enabled, mode=$mode, modelName=$modelName, modelType=$modelType]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'enabled'] = this.enabled;
if (this.mode != null) {
json[r'mode'] = this.mode;
} else {
// json[r'mode'] = null;
}
json[r'modelName'] = this.modelName;
if (this.modelType != null) {
json[r'modelType'] = this.modelType;
} else {
// json[r'modelType'] = null;
}
return json;
}
/// Returns a new [CLIPConfig] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static CLIPConfig? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return CLIPConfig(
enabled: mapValueOfType<bool>(json, r'enabled')!,
mode: CLIPMode.fromJson(json[r'mode']),
modelName: mapValueOfType<String>(json, r'modelName')!,
modelType: ModelType.fromJson(json[r'modelType']),
);
}
return null;
}
static List<CLIPConfig> listFromJson(dynamic json, {bool growable = false,}) {
final result = <CLIPConfig>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = CLIPConfig.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, CLIPConfig> mapFromJson(dynamic json) {
final map = <String, CLIPConfig>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = CLIPConfig.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of CLIPConfig-objects as value to a dart map
static Map<String, List<CLIPConfig>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<CLIPConfig>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = CLIPConfig.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'enabled',
'modelName',
};
}

85
mobile/openapi/lib/model/clip_mode.dart generated Normal file
View file

@ -0,0 +1,85 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class CLIPMode {
/// Instantiate a new enum with the provided [value].
const CLIPMode._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const vision = CLIPMode._(r'vision');
static const text = CLIPMode._(r'text');
/// List of all possible values in this [enum][CLIPMode].
static const values = <CLIPMode>[
vision,
text,
];
static CLIPMode? fromJson(dynamic value) => CLIPModeTypeTransformer().decode(value);
static List<CLIPMode>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <CLIPMode>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = CLIPMode.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [CLIPMode] to String,
/// and [decode] dynamic data back to [CLIPMode].
class CLIPModeTypeTransformer {
factory CLIPModeTypeTransformer() => _instance ??= const CLIPModeTypeTransformer._();
const CLIPModeTypeTransformer._();
String encode(CLIPMode data) => data.value;
/// Decodes a [dynamic value][data] to a CLIPMode.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
CLIPMode? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'vision': return CLIPMode.vision;
case r'text': return CLIPMode.text;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [CLIPModeTypeTransformer] instance.
static CLIPModeTypeTransformer? _instance;
}

88
mobile/openapi/lib/model/model_type.dart generated Normal file
View file

@ -0,0 +1,88 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class ModelType {
/// Instantiate a new enum with the provided [value].
const ModelType._(this.value);
/// The underlying value of this enum member.
final String value;
@override
String toString() => value;
String toJson() => value;
static const imageClassification = ModelType._(r'image-classification');
static const facialRecognition = ModelType._(r'facial-recognition');
static const clip = ModelType._(r'clip');
/// List of all possible values in this [enum][ModelType].
static const values = <ModelType>[
imageClassification,
facialRecognition,
clip,
];
static ModelType? fromJson(dynamic value) => ModelTypeTypeTransformer().decode(value);
static List<ModelType>? listFromJson(dynamic json, {bool growable = false,}) {
final result = <ModelType>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = ModelType.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
}
/// Transformation class that can [encode] an instance of [ModelType] to String,
/// and [decode] dynamic data back to [ModelType].
class ModelTypeTypeTransformer {
factory ModelTypeTypeTransformer() => _instance ??= const ModelTypeTypeTransformer._();
const ModelTypeTypeTransformer._();
String encode(ModelType data) => data.value;
/// Decodes a [dynamic value][data] to a ModelType.
///
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
///
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
/// and users are still using an old app with the old code.
ModelType? decode(dynamic data, {bool allowNull = true}) {
if (data != null) {
switch (data) {
case r'image-classification': return ModelType.imageClassification;
case r'facial-recognition': return ModelType.facialRecognition;
case r'clip': return ModelType.clip;
default:
if (!allowNull) {
throw ArgumentError('Unknown enum value to decode: $data');
}
}
}
return null;
}
/// Singleton [ModelTypeTypeTransformer] instance.
static ModelTypeTypeTransformer? _instance;
}

View file

@ -0,0 +1,139 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
part of openapi.api;
class RecognitionConfig {
/// Returns a new [RecognitionConfig] instance.
RecognitionConfig({
required this.enabled,
required this.maxDistance,
required this.minScore,
required this.modelName,
this.modelType,
});
bool enabled;
int maxDistance;
int minScore;
String modelName;
///
/// Please note: This property should have been non-nullable! Since the specification file
/// does not include a default value (using the "default:" property), however, the generated
/// source code must fall back to having a nullable type.
/// Consider adding a "default:" property in the specification file to hide this note.
///
ModelType? modelType;
@override
bool operator ==(Object other) => identical(this, other) || other is RecognitionConfig &&
other.enabled == enabled &&
other.maxDistance == maxDistance &&
other.minScore == minScore &&
other.modelName == modelName &&
other.modelType == modelType;
@override
int get hashCode =>
// ignore: unnecessary_parenthesis
(enabled.hashCode) +
(maxDistance.hashCode) +
(minScore.hashCode) +
(modelName.hashCode) +
(modelType == null ? 0 : modelType!.hashCode);
@override
String toString() => 'RecognitionConfig[enabled=$enabled, maxDistance=$maxDistance, minScore=$minScore, modelName=$modelName, modelType=$modelType]';
Map<String, dynamic> toJson() {
final json = <String, dynamic>{};
json[r'enabled'] = this.enabled;
json[r'maxDistance'] = this.maxDistance;
json[r'minScore'] = this.minScore;
json[r'modelName'] = this.modelName;
if (this.modelType != null) {
json[r'modelType'] = this.modelType;
} else {
// json[r'modelType'] = null;
}
return json;
}
/// Returns a new [RecognitionConfig] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static RecognitionConfig? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
return RecognitionConfig(
enabled: mapValueOfType<bool>(json, r'enabled')!,
maxDistance: mapValueOfType<int>(json, r'maxDistance')!,
minScore: mapValueOfType<int>(json, r'minScore')!,
modelName: mapValueOfType<String>(json, r'modelName')!,
modelType: ModelType.fromJson(json[r'modelType']),
);
}
return null;
}
static List<RecognitionConfig> listFromJson(dynamic json, {bool growable = false,}) {
final result = <RecognitionConfig>[];
if (json is List && json.isNotEmpty) {
for (final row in json) {
final value = RecognitionConfig.fromJson(row);
if (value != null) {
result.add(value);
}
}
}
return result.toList(growable: growable);
}
static Map<String, RecognitionConfig> mapFromJson(dynamic json) {
final map = <String, RecognitionConfig>{};
if (json is Map && json.isNotEmpty) {
json = json.cast<String, dynamic>(); // ignore: parameter_assignments
for (final entry in json.entries) {
final value = RecognitionConfig.fromJson(entry.value);
if (value != null) {
map[entry.key] = value;
}
}
}
return map;
}
// maps a json object with a list of RecognitionConfig-objects as value to a dart map
static Map<String, List<RecognitionConfig>> mapListFromJson(dynamic json, {bool growable = false,}) {
final map = <String, List<RecognitionConfig>>{};
if (json is Map && json.isNotEmpty) {
// ignore: parameter_assignments
json = json.cast<String, dynamic>();
for (final entry in json.entries) {
map[entry.key] = RecognitionConfig.listFromJson(entry.value, growable: growable,);
}
}
return map;
}
/// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{
'enabled',
'maxDistance',
'minScore',
'modelName',
};
}

View file

@ -13,49 +13,49 @@ part of openapi.api;
class SystemConfigMachineLearningDto { class SystemConfigMachineLearningDto {
/// Returns a new [SystemConfigMachineLearningDto] instance. /// Returns a new [SystemConfigMachineLearningDto] instance.
SystemConfigMachineLearningDto({ SystemConfigMachineLearningDto({
required this.clipEncodeEnabled, required this.classification,
required this.clip,
required this.enabled, required this.enabled,
required this.facialRecognitionEnabled, required this.facialRecognition,
required this.tagImageEnabled,
required this.url, required this.url,
}); });
bool clipEncodeEnabled; ClassificationConfig classification;
CLIPConfig clip;
bool enabled; bool enabled;
bool facialRecognitionEnabled; RecognitionConfig facialRecognition;
bool tagImageEnabled;
String url; String url;
@override @override
bool operator ==(Object other) => identical(this, other) || other is SystemConfigMachineLearningDto && bool operator ==(Object other) => identical(this, other) || other is SystemConfigMachineLearningDto &&
other.clipEncodeEnabled == clipEncodeEnabled && other.classification == classification &&
other.clip == clip &&
other.enabled == enabled && other.enabled == enabled &&
other.facialRecognitionEnabled == facialRecognitionEnabled && other.facialRecognition == facialRecognition &&
other.tagImageEnabled == tagImageEnabled &&
other.url == url; other.url == url;
@override @override
int get hashCode => int get hashCode =>
// ignore: unnecessary_parenthesis // ignore: unnecessary_parenthesis
(clipEncodeEnabled.hashCode) + (classification.hashCode) +
(clip.hashCode) +
(enabled.hashCode) + (enabled.hashCode) +
(facialRecognitionEnabled.hashCode) + (facialRecognition.hashCode) +
(tagImageEnabled.hashCode) +
(url.hashCode); (url.hashCode);
@override @override
String toString() => 'SystemConfigMachineLearningDto[clipEncodeEnabled=$clipEncodeEnabled, enabled=$enabled, facialRecognitionEnabled=$facialRecognitionEnabled, tagImageEnabled=$tagImageEnabled, url=$url]'; String toString() => 'SystemConfigMachineLearningDto[classification=$classification, clip=$clip, enabled=$enabled, facialRecognition=$facialRecognition, url=$url]';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
final json = <String, dynamic>{}; final json = <String, dynamic>{};
json[r'clipEncodeEnabled'] = this.clipEncodeEnabled; json[r'classification'] = this.classification;
json[r'clip'] = this.clip;
json[r'enabled'] = this.enabled; json[r'enabled'] = this.enabled;
json[r'facialRecognitionEnabled'] = this.facialRecognitionEnabled; json[r'facialRecognition'] = this.facialRecognition;
json[r'tagImageEnabled'] = this.tagImageEnabled;
json[r'url'] = this.url; json[r'url'] = this.url;
return json; return json;
} }
@ -68,10 +68,10 @@ class SystemConfigMachineLearningDto {
final json = value.cast<String, dynamic>(); final json = value.cast<String, dynamic>();
return SystemConfigMachineLearningDto( return SystemConfigMachineLearningDto(
clipEncodeEnabled: mapValueOfType<bool>(json, r'clipEncodeEnabled')!, classification: ClassificationConfig.fromJson(json[r'classification'])!,
clip: CLIPConfig.fromJson(json[r'clip'])!,
enabled: mapValueOfType<bool>(json, r'enabled')!, enabled: mapValueOfType<bool>(json, r'enabled')!,
facialRecognitionEnabled: mapValueOfType<bool>(json, r'facialRecognitionEnabled')!, facialRecognition: RecognitionConfig.fromJson(json[r'facialRecognition'])!,
tagImageEnabled: mapValueOfType<bool>(json, r'tagImageEnabled')!,
url: mapValueOfType<String>(json, r'url')!, url: mapValueOfType<String>(json, r'url')!,
); );
} }
@ -120,10 +120,10 @@ class SystemConfigMachineLearningDto {
/// The list of required keys that must be present in a JSON. /// The list of required keys that must be present in a JSON.
static const requiredKeys = <String>{ static const requiredKeys = <String>{
'clipEncodeEnabled', 'classification',
'clip',
'enabled', 'enabled',
'facialRecognitionEnabled', 'facialRecognition',
'tagImageEnabled',
'url', 'url',
}; };
} }

View file

@ -0,0 +1,42 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for ClassificationConfig
void main() {
// final instance = ClassificationConfig();
group('test ClassificationConfig', () {
// bool enabled
test('to test the property `enabled`', () async {
// TODO
});
// int minScore
test('to test the property `minScore`', () async {
// TODO
});
// String modelName
test('to test the property `modelName`', () async {
// TODO
});
// ModelType modelType
test('to test the property `modelType`', () async {
// TODO
});
});
}

View file

@ -0,0 +1,42 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for CLIPConfig
void main() {
// final instance = CLIPConfig();
group('test CLIPConfig', () {
// bool enabled
test('to test the property `enabled`', () async {
// TODO
});
// CLIPMode mode
test('to test the property `mode`', () async {
// TODO
});
// String modelName
test('to test the property `modelName`', () async {
// TODO
});
// ModelType modelType
test('to test the property `modelType`', () async {
// TODO
});
});
}

21
mobile/openapi/test/clip_mode_test.dart generated Normal file
View file

@ -0,0 +1,21 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for CLIPMode
void main() {
group('test CLIPMode', () {
});
}

21
mobile/openapi/test/model_type_test.dart generated Normal file
View file

@ -0,0 +1,21 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for ModelType
void main() {
group('test ModelType', () {
});
}

View file

@ -0,0 +1,47 @@
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// @dart=2.12
// ignore_for_file: unused_element, unused_import
// ignore_for_file: always_put_required_named_parameters_first
// ignore_for_file: constant_identifier_names
// ignore_for_file: lines_longer_than_80_chars
import 'package:openapi/api.dart';
import 'package:test/test.dart';
// tests for RecognitionConfig
void main() {
// final instance = RecognitionConfig();
group('test RecognitionConfig', () {
// bool enabled
test('to test the property `enabled`', () async {
// TODO
});
// int maxDistance
test('to test the property `maxDistance`', () async {
// TODO
});
// int minScore
test('to test the property `minScore`', () async {
// TODO
});
// String modelName
test('to test the property `modelName`', () async {
// TODO
});
// ModelType modelType
test('to test the property `modelType`', () async {
// TODO
});
});
}

View file

@ -16,8 +16,13 @@ void main() {
// final instance = SystemConfigMachineLearningDto(); // final instance = SystemConfigMachineLearningDto();
group('test SystemConfigMachineLearningDto', () { group('test SystemConfigMachineLearningDto', () {
// bool clipEncodeEnabled // ClassificationConfig classification
test('to test the property `clipEncodeEnabled`', () async { test('to test the property `classification`', () async {
// TODO
});
// CLIPConfig clip
test('to test the property `clip`', () async {
// TODO // TODO
}); });
@ -26,13 +31,8 @@ void main() {
// TODO // TODO
}); });
// bool facialRecognitionEnabled // RecognitionConfig facialRecognition
test('to test the property `facialRecognitionEnabled`', () async { test('to test the property `facialRecognition`', () async {
// TODO
});
// bool tagImageEnabled
test('to test the property `tagImageEnabled`', () async {
// TODO // TODO
}); });

6
package-lock.json generated Normal file
View file

@ -0,0 +1,6 @@
{
"name": "immich",
"lockfileVersion": 2,
"requires": true,
"packages": {}
}

View file

@ -5354,6 +5354,34 @@
], ],
"type": "object" "type": "object"
}, },
"CLIPConfig": {
"properties": {
"enabled": {
"type": "boolean"
},
"mode": {
"$ref": "#/components/schemas/CLIPMode"
},
"modelName": {
"type": "string"
},
"modelType": {
"$ref": "#/components/schemas/ModelType"
}
},
"required": [
"enabled",
"modelName"
],
"type": "object"
},
"CLIPMode": {
"enum": [
"vision",
"text"
],
"type": "string"
},
"ChangePasswordDto": { "ChangePasswordDto": {
"properties": { "properties": {
"newPassword": { "newPassword": {
@ -5432,6 +5460,28 @@
], ],
"type": "object" "type": "object"
}, },
"ClassificationConfig": {
"properties": {
"enabled": {
"type": "boolean"
},
"minScore": {
"type": "integer"
},
"modelName": {
"type": "string"
},
"modelType": {
"$ref": "#/components/schemas/ModelType"
}
},
"required": [
"minScore",
"enabled",
"modelName"
],
"type": "object"
},
"CreateAlbumDto": { "CreateAlbumDto": {
"properties": { "properties": {
"albumName": { "albumName": {
@ -6144,6 +6194,14 @@
], ],
"type": "object" "type": "object"
}, },
"ModelType": {
"enum": [
"image-classification",
"facial-recognition",
"clip"
],
"type": "string"
},
"OAuthCallbackDto": { "OAuthCallbackDto": {
"properties": { "properties": {
"url": { "url": {
@ -6323,6 +6381,32 @@
], ],
"type": "object" "type": "object"
}, },
"RecognitionConfig": {
"properties": {
"enabled": {
"type": "boolean"
},
"maxDistance": {
"type": "integer"
},
"minScore": {
"type": "integer"
},
"modelName": {
"type": "string"
},
"modelType": {
"$ref": "#/components/schemas/ModelType"
}
},
"required": [
"minScore",
"maxDistance",
"enabled",
"modelName"
],
"type": "object"
},
"SearchAlbumResponseDto": { "SearchAlbumResponseDto": {
"properties": { "properties": {
"count": { "count": {
@ -6968,17 +7052,17 @@
}, },
"SystemConfigMachineLearningDto": { "SystemConfigMachineLearningDto": {
"properties": { "properties": {
"clipEncodeEnabled": { "classification": {
"type": "boolean" "$ref": "#/components/schemas/ClassificationConfig"
},
"clip": {
"$ref": "#/components/schemas/CLIPConfig"
}, },
"enabled": { "enabled": {
"type": "boolean" "type": "boolean"
}, },
"facialRecognitionEnabled": { "facialRecognition": {
"type": "boolean" "$ref": "#/components/schemas/RecognitionConfig"
},
"tagImageEnabled": {
"type": "boolean"
}, },
"url": { "url": {
"type": "string" "type": "string"
@ -6987,9 +7071,9 @@
"required": [ "required": [
"enabled", "enabled",
"url", "url",
"clipEncodeEnabled", "classification",
"facialRecognitionEnabled", "clip",
"tagImageEnabled" "facialRecognition"
], ],
"type": "object" "type": "object"
}, },

11589
server/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -39,89 +39,90 @@
"api:generate": "node ./bin/sync-spec-version.js && bash ./bin/generate-open-api.sh" "api:generate": "node ./bin/sync-spec-version.js && bash ./bin/generate-open-api.sh"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.22.11",
"@nestjs/bullmq": "^1.1.0", "@nestjs/bullmq": "^10.0.1",
"@nestjs/common": "^9.2.1", "@nestjs/common": "^10.2.2",
"@nestjs/config": "^2.2.0", "@nestjs/config": "^3.0.0",
"@nestjs/core": "^9.2.1", "@nestjs/core": "^10.2.2",
"@nestjs/platform-express": "^9.2.1", "@nestjs/platform-express": "^10.2.2",
"@nestjs/platform-socket.io": "^9.2.1", "@nestjs/platform-socket.io": "^10.2.2",
"@nestjs/schedule": "^2.1.0", "@nestjs/schedule": "^3.0.3",
"@nestjs/swagger": "^6.1.4", "@nestjs/swagger": "^7.1.8",
"@nestjs/typeorm": "^9.0.1", "@nestjs/typeorm": "^10.0.0",
"@nestjs/websockets": "^9.2.1", "@nestjs/websockets": "^10.2.2",
"@socket.io/redis-adapter": "^8.0.1", "@socket.io/redis-adapter": "^8.2.1",
"archiver": "^5.3.1", "archiver": "^6.0.0",
"axios": "^0.26.0", "axios": "^1.5.0",
"bcrypt": "^5.0.1", "bcrypt": "^5.1.1",
"bullmq": "^3.14.1", "bullmq": "^4.8.0",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.0", "class-validator": "^0.14.0",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"exiftool-vendored": "^22.0.0", "exiftool-vendored": "^22.0.0",
"exiftool-vendored.pl": "^12.54.0", "exiftool-vendored.pl": "^12.62.0",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.2",
"handlebars": "^4.7.7", "handlebars": "^4.7.8",
"i18n-iso-countries": "^7.5.0", "i18n-iso-countries": "^7.6.0",
"immich": "^0.41.0", "immich": "^0.41.0",
"ioredis": "^5.3.1", "ioredis": "^5.3.2",
"joi": "^17.5.0", "joi": "^17.10.0",
"local-reverse-geocoder": "0.12.5", "local-reverse-geocoder": "0.16.5",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"luxon": "^3.0.3", "luxon": "^3.4.2",
"mv": "^2.1.1", "mv": "^2.1.1",
"nest-commander": "^3.3.0", "nest-commander": "^3.11.1",
"openid-client": "^5.2.1", "openid-client": "^5.4.3",
"pg": "^8.8.0", "pg": "^8.11.3",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"rxjs": "^7.2.0", "rxjs": "^7.8.1",
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"sharp": "^0.31.3", "sharp": "^0.31.3",
"thumbhash": "^0.1.1", "thumbhash": "^0.1.1",
"typeorm": "^0.3.11", "typeorm": "^0.3.17",
"typesense": "^1.5.3", "typesense": "^1.7.1",
"ua-parser-js": "^1.0.35" "ua-parser-js": "^1.0.35"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "^9.1.8", "@nestjs/cli": "^10.1.16",
"@nestjs/schematics": "^9.0.4", "@nestjs/schematics": "^10.0.2",
"@nestjs/testing": "^9.2.1", "@nestjs/testing": "^10.2.2",
"@openapitools/openapi-generator-cli": "2.5.2", "@openapitools/openapi-generator-cli": "2.7.0",
"@types/archiver": "^5.3.1", "@testcontainers/postgresql": "^10.2.1",
"@types/archiver": "^5.3.2",
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/cookie-parser": "^1.4.3", "@types/cookie-parser": "^1.4.3",
"@types/cron": "^2.0.0", "@types/cron": "^2.0.1",
"@types/express": "^4.17.13", "@types/express": "^4.17.17",
"@types/fluent-ffmpeg": "^2.1.20", "@types/fluent-ffmpeg": "^2.1.21",
"@types/imagemin": "^8.0.0", "@types/imagemin": "^8.0.1",
"@types/jest": "27.0.2", "@types/jest": "29.5.4",
"@types/jest-when": "^3.5.2", "@types/jest-when": "^3.5.2",
"@types/lodash": "^4.14.178", "@types/lodash": "^4.14.197",
"@types/multer": "^1.4.7", "@types/multer": "^1.4.7",
"@types/mv": "^2.1.2", "@types/mv": "^2.1.2",
"@types/node": "^18.0.0", "@types/node": "^20.5.7",
"@types/sharp": "^0.30.2", "@types/sharp": "^0.31.1",
"@types/supertest": "^2.0.11", "@types/supertest": "^2.0.12",
"@types/ua-parser-js": "^0.7.36", "@types/ua-parser-js": "^0.7.36",
"@typescript-eslint/eslint-plugin": "^5.48.1", "@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^5.48.1", "@typescript-eslint/parser": "^6.4.1",
"dotenv": "^14.2.0", "dotenv": "^16.3.1",
"eslint": "^8.31.0", "eslint": "^8.48.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^4.0.0", "eslint-plugin-prettier": "^5.0.0",
"jest": "^27.2.5", "jest": "^29.6.4",
"jest-when": "^3.5.2", "jest-when": "^3.6.0",
"prettier": "^2.3.2", "prettier": "^3.0.2",
"prettier-plugin-organize-imports": "^3.2.2", "prettier-plugin-organize-imports": "^3.2.3",
"rimraf": "^3.0.2", "rimraf": "^5.0.1",
"source-map-support": "^0.5.20", "source-map-support": "^0.5.21",
"supertest": "^6.1.3", "supertest": "^6.3.3",
"testcontainers": "^9.9.1", "testcontainers": "^10.2.1",
"ts-jest": "^27.0.3", "ts-jest": "^29.1.1",
"ts-loader": "^9.2.3", "ts-loader": "^9.4.4",
"ts-node": "^10.0.0", "ts-node": "^10.9.1",
"tsconfig-paths": "^3.10.1", "tsconfig-paths": "^4.2.0",
"typescript": "^4.9.4" "typescript": "^5.2.2"
}, },
"jest": { "jest": {
"clearMocks": true, "clearMocks": true,

View file

@ -6,7 +6,10 @@ import { Command, CommandRunner, InquirerService, Question, QuestionSet } from '
description: 'Reset the admin password', description: 'Reset the admin password',
}) })
export class ResetAdminPasswordCommand extends CommandRunner { export class ResetAdminPasswordCommand extends CommandRunner {
constructor(private userService: UserService, private readonly inquirer: InquirerService) { constructor(
private userService: UserService,
private readonly inquirer: InquirerService,
) {
super(); super();
} }

View file

@ -99,8 +99,8 @@ export class AlbumService {
ownerId: authUser.id, ownerId: authUser.id,
albumName: dto.albumName, albumName: dto.albumName,
description: dto.description, description: dto.description,
sharedUsers: dto.sharedWithUserIds?.map((value) => ({ id: value } as UserEntity)) ?? [], sharedUsers: dto.sharedWithUserIds?.map((value) => ({ id: value }) as UserEntity) ?? [],
assets: (dto.assetIds || []).map((id) => ({ id } as AssetEntity)), assets: (dto.assetIds || []).map((id) => ({ id }) as AssetEntity),
albumThumbnailAssetId: dto.assetIds?.[0] || null, albumThumbnailAssetId: dto.assetIds?.[0] || null,
}); });

View file

@ -92,7 +92,7 @@ const sidecar: Record<string, string[]> = {
const isType = (filename: string, r: Record<string, string[]>) => extname(filename).toLowerCase() in r; const isType = (filename: string, r: Record<string, string[]>) => extname(filename).toLowerCase() in r;
const lookup = (filename: string) => const lookup = (filename: string) =>
({ ...image, ...video, ...sidecar }[extname(filename).toLowerCase()]?.[0] ?? 'application/octet-stream'); ({ ...image, ...video, ...sidecar })[extname(filename).toLowerCase()]?.[0] ?? 'application/octet-stream';
export const mimeTypes = { export const mimeTypes = {
image, image,

View file

@ -115,6 +115,7 @@ describe(FacialRecognitionService.name, () => {
personMock = newPersonRepositoryMock(); personMock = newPersonRepositoryMock();
searchMock = newSearchRepositoryMock(); searchMock = newSearchRepositoryMock();
storageMock = newStorageRepositoryMock(); storageMock = newStorageRepositoryMock();
configMock = newSystemConfigRepositoryMock();
mediaMock.crop.mockResolvedValue(croppedFace); mediaMock.crop.mockResolvedValue(croppedFace);
@ -179,9 +180,18 @@ describe(FacialRecognitionService.name, () => {
machineLearningMock.detectFaces.mockResolvedValue([]); machineLearningMock.detectFaces.mockResolvedValue([]);
assetMock.getByIds.mockResolvedValue([assetStub.image]); assetMock.getByIds.mockResolvedValue([assetStub.image]);
await sut.handleRecognizeFaces({ id: assetStub.image.id }); await sut.handleRecognizeFaces({ id: assetStub.image.id });
expect(machineLearningMock.detectFaces).toHaveBeenCalledWith('http://immich-machine-learning:3003', { expect(machineLearningMock.detectFaces).toHaveBeenCalledWith(
imagePath: assetStub.image.resizePath, 'http://immich-machine-learning:3003',
}); {
imagePath: assetStub.image.resizePath,
},
{
enabled: true,
maxDistance: 0.6,
minScore: 0.7,
modelName: 'buffalo_l',
},
);
expect(faceMock.create).not.toHaveBeenCalled(); expect(faceMock.create).not.toHaveBeenCalled();
expect(jobMock.queue).not.toHaveBeenCalled(); expect(jobMock.queue).not.toHaveBeenCalled();
}); });

View file

@ -32,7 +32,7 @@ export class FacialRecognitionService {
async handleQueueRecognizeFaces({ force }: IBaseJob) { async handleQueueRecognizeFaces({ force }: IBaseJob) {
const { machineLearning } = await this.configCore.getConfig(); const { machineLearning } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.facialRecognitionEnabled) { if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) {
return true; return true;
} }
@ -59,7 +59,7 @@ export class FacialRecognitionService {
async handleRecognizeFaces({ id }: IEntityJob) { async handleRecognizeFaces({ id }: IEntityJob) {
const { machineLearning } = await this.configCore.getConfig(); const { machineLearning } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.facialRecognitionEnabled) { if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) {
return true; return true;
} }
@ -68,7 +68,11 @@ export class FacialRecognitionService {
return false; return false;
} }
const faces = await this.machineLearning.detectFaces(machineLearning.url, { imagePath: asset.resizePath }); const faces = await this.machineLearning.detectFaces(
machineLearning.url,
{ imagePath: asset.resizePath },
machineLearning.facialRecognition,
);
this.logger.debug(`${faces.length} faces detected in ${asset.resizePath}`); this.logger.debug(`${faces.length} faces detected in ${asset.resizePath}`);
this.logger.verbose(faces.map((face) => ({ ...face, embedding: `float[${face.embedding.length}]` }))); this.logger.verbose(faces.map((face) => ({ ...face, embedding: `float[${face.embedding.length}]` })));
@ -80,7 +84,7 @@ export class FacialRecognitionService {
// try to find a matching face and link to the associated person // try to find a matching face and link to the associated person
// The closer to 0, the better the match. Range is from 0 to 2 // The closer to 0, the better the match. Range is from 0 to 2
if (faceSearchResult.total && faceSearchResult.distances[0] < 0.6) { if (faceSearchResult.total && faceSearchResult.distances[0] <= machineLearning.facialRecognition.maxDistance) {
this.logger.verbose(`Match face with distance ${faceSearchResult.distances[0]}`); this.logger.verbose(`Match face with distance ${faceSearchResult.distances[0]}`);
personId = faceSearchResult.items[0].personId; personId = faceSearchResult.items[0].personId;
} }
@ -115,7 +119,7 @@ export class FacialRecognitionService {
async handleGenerateFaceThumbnail(data: IFaceThumbnailJob) { async handleGenerateFaceThumbnail(data: IFaceThumbnailJob) {
const { machineLearning } = await this.configCore.getConfig(); const { machineLearning } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.facialRecognitionEnabled) { if (!machineLearning.enabled || !machineLearning.facialRecognition.enabled) {
return true; return true;
} }

View file

@ -8,6 +8,7 @@ export interface ResizeOptions {
} }
export interface VideoStreamInfo { export interface VideoStreamInfo {
index: number;
height: number; height: number;
width: number; width: number;
rotation: number; rotation: number;
@ -18,8 +19,10 @@ export interface VideoStreamInfo {
} }
export interface AudioStreamInfo { export interface AudioStreamInfo {
index: number;
codecName?: string; codecName?: string;
codecType?: string; codecType?: string;
frameCount: number;
} }
export interface VideoFormat { export interface VideoFormat {
@ -55,7 +58,7 @@ export interface BitrateDistribution {
} }
export interface VideoCodecSWConfig { export interface VideoCodecSWConfig {
getOptions(stream: VideoStreamInfo): TranscodeOptions; getOptions(videoStream: VideoStreamInfo, audioStream: AudioStreamInfo): TranscodeOptions;
} }
export interface VideoCodecHWConfig extends VideoCodecSWConfig { export interface VideoCodecHWConfig extends VideoCodecSWConfig {

View file

@ -311,8 +311,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -350,8 +350,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -374,8 +374,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -401,8 +401,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -426,8 +426,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -451,8 +451,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -476,8 +476,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -525,8 +525,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -555,8 +555,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -582,8 +582,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -611,8 +611,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec vp9', '-c:v:0 vp9',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -642,8 +642,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec vp9', '-c:v:0 vp9',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -672,8 +672,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec vp9', '-c:v:0 vp9',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -701,8 +701,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec vp9', '-c:v:0 vp9',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -729,8 +729,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -757,8 +757,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -785,8 +785,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec hevc', '-c:v:0 hevc',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -816,8 +816,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec hevc', '-c:v:0 hevc',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -876,7 +876,6 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'],
outputOptions: [ outputOptions: [
`-vcodec h264_nvenc`,
'-tune hq', '-tune hq',
'-qmin 0', '-qmin 0',
'-g 250', '-g 250',
@ -886,7 +885,8 @@ describe(MediaService.name, () => {
'-rc-lookahead 20', '-rc-lookahead 20',
'-i_qfactor 0.75', '-i_qfactor 0.75',
'-b_qfactor 1.1', '-b_qfactor 1.1',
'-acodec aac', `-c:v:0 h264_nvenc`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -916,7 +916,6 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'],
outputOptions: [ outputOptions: [
`-vcodec h264_nvenc`,
'-tune hq', '-tune hq',
'-qmin 0', '-qmin 0',
'-g 250', '-g 250',
@ -926,7 +925,8 @@ describe(MediaService.name, () => {
'-rc-lookahead 20', '-rc-lookahead 20',
'-i_qfactor 0.75', '-i_qfactor 0.75',
'-b_qfactor 1.1', '-b_qfactor 1.1',
'-acodec aac', `-c:v:0 h264_nvenc`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -952,7 +952,6 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'],
outputOptions: [ outputOptions: [
`-vcodec h264_nvenc`,
'-tune hq', '-tune hq',
'-qmin 0', '-qmin 0',
'-g 250', '-g 250',
@ -962,7 +961,8 @@ describe(MediaService.name, () => {
'-rc-lookahead 20', '-rc-lookahead 20',
'-i_qfactor 0.75', '-i_qfactor 0.75',
'-b_qfactor 1.1', '-b_qfactor 1.1',
'-acodec aac', `-c:v:0 h264_nvenc`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -989,7 +989,6 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'],
outputOptions: [ outputOptions: [
`-vcodec h264_nvenc`,
'-tune hq', '-tune hq',
'-qmin 0', '-qmin 0',
'-g 250', '-g 250',
@ -999,7 +998,8 @@ describe(MediaService.name, () => {
'-rc-lookahead 20', '-rc-lookahead 20',
'-i_qfactor 0.75', '-i_qfactor 0.75',
'-b_qfactor 1.1', '-b_qfactor 1.1',
'-acodec aac', `-c:v:0 h264_nvenc`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1022,7 +1022,6 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'], inputOptions: ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'],
outputOptions: [ outputOptions: [
`-vcodec h264_nvenc`,
'-tune hq', '-tune hq',
'-qmin 0', '-qmin 0',
'-g 250', '-g 250',
@ -1032,7 +1031,8 @@ describe(MediaService.name, () => {
'-rc-lookahead 20', '-rc-lookahead 20',
'-i_qfactor 0.75', '-i_qfactor 0.75',
'-b_qfactor 1.1', '-b_qfactor 1.1',
'-acodec aac', `-c:v:0 h264_nvenc`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1060,12 +1060,12 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'], inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'],
outputOptions: [ outputOptions: [
`-vcodec h264_qsv`,
'-g 256', '-g 256',
'-extbrc 1', '-extbrc 1',
'-refs 5', '-refs 5',
'-bf 7', '-bf 7',
'-acodec aac', `-c:v:0 h264_qsv`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1095,12 +1095,12 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'], inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'],
outputOptions: [ outputOptions: [
`-vcodec h264_qsv`,
'-g 256', '-g 256',
'-extbrc 1', '-extbrc 1',
'-refs 5', '-refs 5',
'-bf 7', '-bf 7',
'-acodec aac', `-c:v:0 h264_qsv`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1127,12 +1127,12 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'], inputOptions: ['-init_hw_device qsv=hw', '-filter_hw_device hw'],
outputOptions: [ outputOptions: [
`-vcodec vp9_qsv`,
'-g 256', '-g 256',
'-extbrc 1', '-extbrc 1',
'-refs 5', '-refs 5',
'-bf 7', '-bf 7',
'-acodec aac', `-c:v:0 vp9_qsv`,
'-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-low_power 1', '-low_power 1',
@ -1170,8 +1170,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'], inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'],
outputOptions: [ outputOptions: [
`-vcodec h264_vaapi`, `-c:v:0 h264_vaapi`,
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1199,8 +1199,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'], inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'],
outputOptions: [ outputOptions: [
`-vcodec h264_vaapi`, `-c:v:0 h264_vaapi`,
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1230,8 +1230,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'], inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD128', '-filter_hw_device accel'],
outputOptions: [ outputOptions: [
`-vcodec h264_vaapi`, `-c:v:0 h264_vaapi`,
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1257,8 +1257,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/card1', '-filter_hw_device accel'], inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/card1', '-filter_hw_device accel'],
outputOptions: [ outputOptions: [
`-vcodec h264_vaapi`, `-c:v:0 h264_vaapi`,
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1280,8 +1280,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD129', '-filter_hw_device accel'], inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD129', '-filter_hw_device accel'],
outputOptions: [ outputOptions: [
`-vcodec h264_vaapi`, `-c:v:0 h264_vaapi`,
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1310,8 +1310,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1345,8 +1345,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1370,8 +1370,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',
@ -1395,8 +1395,8 @@ describe(MediaService.name, () => {
{ {
inputOptions: [], inputOptions: [],
outputOptions: [ outputOptions: [
'-vcodec h264', '-c:v:0 h264',
'-acodec aac', '-c:a:0 aac',
'-movflags faststart', '-movflags faststart',
'-fps_mode passthrough', '-fps_mode passthrough',
'-v verbose', '-v verbose',

View file

@ -73,15 +73,16 @@ export class MediaService {
this.logger.log(`Successfully generated image thumbnail ${asset.id}`); this.logger.log(`Successfully generated image thumbnail ${asset.id}`);
break; break;
case AssetType.VIDEO: case AssetType.VIDEO:
const { videoStreams } = await this.mediaRepository.probe(asset.originalPath); const { audioStreams, videoStreams } = await this.mediaRepository.probe(asset.originalPath);
const mainVideoStream = this.getMainVideoStream(videoStreams); const mainVideoStream = this.getMainStream(videoStreams);
if (!mainVideoStream) { if (!mainVideoStream) {
this.logger.error(`Could not extract thumbnail for asset ${asset.id}: no video streams found`); this.logger.error(`Could not extract thumbnail for asset ${asset.id}: no video streams found`);
return false; return false;
} }
const mainAudioStream = this.getMainStream(audioStreams);
const { ffmpeg } = await this.configCore.getConfig(); const { ffmpeg } = await this.configCore.getConfig();
const config = { ...ffmpeg, targetResolution: thumbnail.jpegSize.toString(), twoPass: false }; const config = { ...ffmpeg, targetResolution: thumbnail.jpegSize.toString(), twoPass: false };
const options = new ThumbnailConfig(config).getOptions(mainVideoStream); const options = new ThumbnailConfig(config).getOptions(mainVideoStream, mainAudioStream);
await this.mediaRepository.transcode(asset.originalPath, jpegThumbnailPath, options); await this.mediaRepository.transcode(asset.originalPath, jpegThumbnailPath, options);
this.logger.log(`Successfully generated video thumbnail ${asset.id}`); this.logger.log(`Successfully generated video thumbnail ${asset.id}`);
break; break;
@ -149,8 +150,8 @@ export class MediaService {
this.storageRepository.mkdirSync(outputFolder); this.storageRepository.mkdirSync(outputFolder);
const { videoStreams, audioStreams, format } = await this.mediaRepository.probe(input); const { videoStreams, audioStreams, format } = await this.mediaRepository.probe(input);
const mainVideoStream = this.getMainVideoStream(videoStreams); const mainVideoStream = this.getMainStream(videoStreams);
const mainAudioStream = this.getMainAudioStream(audioStreams); const mainAudioStream = this.getMainStream(audioStreams);
const containerExtension = format.formatName; const containerExtension = format.formatName;
if (!mainVideoStream || !containerExtension) { if (!mainVideoStream || !containerExtension) {
return false; return false;
@ -165,7 +166,7 @@ export class MediaService {
let transcodeOptions; let transcodeOptions;
try { try {
transcodeOptions = await this.getCodecConfig(config).then((c) => c.getOptions(mainVideoStream)); transcodeOptions = await this.getCodecConfig(config).then((c) => c.getOptions(mainVideoStream, mainAudioStream));
} catch (err) { } catch (err) {
this.logger.error(`An error occurred while configuring transcoding options: ${err}`); this.logger.error(`An error occurred while configuring transcoding options: ${err}`);
return false; return false;
@ -176,13 +177,13 @@ export class MediaService {
await this.mediaRepository.transcode(input, output, transcodeOptions); await this.mediaRepository.transcode(input, output, transcodeOptions);
} catch (err) { } catch (err) {
this.logger.error(err); this.logger.error(err);
if (config.accel && config.accel !== TranscodeHWAccel.DISABLED) { if (config.accel !== TranscodeHWAccel.DISABLED) {
this.logger.error( this.logger.error(
`Error occurred during transcoding. Retrying with ${config.accel.toUpperCase()} acceleration disabled.`, `Error occurred during transcoding. Retrying with ${config.accel.toUpperCase()} acceleration disabled.`,
); );
} }
config.accel = TranscodeHWAccel.DISABLED; config.accel = TranscodeHWAccel.DISABLED;
transcodeOptions = await this.getCodecConfig(config).then((c) => c.getOptions(mainVideoStream)); transcodeOptions = await this.getCodecConfig(config).then((c) => c.getOptions(mainVideoStream, mainAudioStream));
await this.mediaRepository.transcode(input, output, transcodeOptions); await this.mediaRepository.transcode(input, output, transcodeOptions);
} }
@ -193,14 +194,10 @@ export class MediaService {
return true; return true;
} }
private getMainVideoStream(streams: VideoStreamInfo[]): VideoStreamInfo | null { private getMainStream<T extends VideoStreamInfo | AudioStreamInfo>(streams: T[]): T {
return streams.sort((stream1, stream2) => stream2.frameCount - stream1.frameCount)[0]; return streams.sort((stream1, stream2) => stream2.frameCount - stream1.frameCount)[0];
} }
private getMainAudioStream(streams: AudioStreamInfo[]): AudioStreamInfo | null {
return streams[0];
}
private isTranscodeRequired( private isTranscodeRequired(
asset: AssetEntity, asset: AssetEntity,
videoStream: VideoStreamInfo, videoStream: VideoStreamInfo,

View file

@ -1,6 +1,7 @@
import { ToneMapping, TranscodeHWAccel, VideoCodec } from '@app/infra/entities'; import { ToneMapping, TranscodeHWAccel, VideoCodec } from '@app/infra/entities';
import { SystemConfigFFmpegDto } from '../system-config/dto'; import { SystemConfigFFmpegDto } from '../system-config/dto';
import { import {
AudioStreamInfo,
BitrateDistribution, BitrateDistribution,
TranscodeOptions, TranscodeOptions,
VideoCodecHWConfig, VideoCodecHWConfig,
@ -10,13 +11,13 @@ import {
class BaseConfig implements VideoCodecSWConfig { class BaseConfig implements VideoCodecSWConfig {
constructor(protected config: SystemConfigFFmpegDto) {} constructor(protected config: SystemConfigFFmpegDto) {}
getOptions(stream: VideoStreamInfo) { getOptions(videoStream: VideoStreamInfo, audioStream: AudioStreamInfo) {
const options = { const options = {
inputOptions: this.getBaseInputOptions(), inputOptions: this.getBaseInputOptions(),
outputOptions: this.getBaseOutputOptions().concat('-v verbose'), outputOptions: this.getBaseOutputOptions(videoStream, audioStream).concat('-v verbose'),
twoPass: this.eligibleForTwoPass(), twoPass: this.eligibleForTwoPass(),
} as TranscodeOptions; } as TranscodeOptions;
const filters = this.getFilterOptions(stream); const filters = this.getFilterOptions(videoStream);
if (filters.length > 0) { if (filters.length > 0) {
options.outputOptions.push(`-vf ${filters.join(',')}`); options.outputOptions.push(`-vf ${filters.join(',')}`);
} }
@ -31,9 +32,10 @@ class BaseConfig implements VideoCodecSWConfig {
return []; return [];
} }
getBaseOutputOptions() { getBaseOutputOptions(videoStream: VideoStreamInfo, audioStream: AudioStreamInfo) {
return [ return [
`-acodec ${this.config.targetAudioCodec}`, `-c:v:${videoStream.index} ${this.getVideoCodec()}`,
`-c:a:${audioStream.index} ${this.getAudioCodec()}`,
// Makes a second pass moving the moov atom to the // Makes a second pass moving the moov atom to the
// beginning of the file for improved playback speed. // beginning of the file for improved playback speed.
'-movflags faststart', '-movflags faststart',
@ -41,13 +43,13 @@ class BaseConfig implements VideoCodecSWConfig {
]; ];
} }
getFilterOptions(stream: VideoStreamInfo) { getFilterOptions(videoStream: VideoStreamInfo) {
const options = []; const options = [];
if (this.shouldScale(stream)) { if (this.shouldScale(videoStream)) {
options.push(`scale=${this.getScaling(stream)}`); options.push(`scale=${this.getScaling(videoStream)}`);
} }
if (this.shouldToneMap(stream)) { if (this.shouldToneMap(videoStream)) {
options.push(...this.getToneMapping()); options.push(...this.getToneMapping());
} }
options.push('format=yuv420p'); options.push('format=yuv420p');
@ -103,34 +105,34 @@ class BaseConfig implements VideoCodecSWConfig {
return { max, target, min, unit } as BitrateDistribution; return { max, target, min, unit } as BitrateDistribution;
} }
getTargetResolution(stream: VideoStreamInfo) { getTargetResolution(videoStream: VideoStreamInfo) {
if (this.config.targetResolution === 'original') { if (this.config.targetResolution === 'original') {
return Math.min(stream.height, stream.width); return Math.min(videoStream.height, videoStream.width);
} }
return Number.parseInt(this.config.targetResolution); return Number.parseInt(this.config.targetResolution);
} }
shouldScale(stream: VideoStreamInfo) { shouldScale(videoStream: VideoStreamInfo) {
return Math.min(stream.height, stream.width) > this.getTargetResolution(stream); return Math.min(videoStream.height, videoStream.width) > this.getTargetResolution(videoStream);
} }
shouldToneMap(stream: VideoStreamInfo) { shouldToneMap(videoStream: VideoStreamInfo) {
return stream.isHDR && this.config.tonemap !== ToneMapping.DISABLED; return videoStream.isHDR && this.config.tonemap !== ToneMapping.DISABLED;
} }
getScaling(stream: VideoStreamInfo) { getScaling(videoStream: VideoStreamInfo) {
const targetResolution = this.getTargetResolution(stream); const targetResolution = this.getTargetResolution(videoStream);
const mult = this.config.accel === TranscodeHWAccel.QSV ? 1 : 2; // QSV doesn't support scaling numbers below -1 const mult = this.config.accel === TranscodeHWAccel.QSV ? 1 : 2; // QSV doesn't support scaling numbers below -1
return this.isVideoVertical(stream) ? `${targetResolution}:-${mult}` : `-${mult}:${targetResolution}`; return this.isVideoVertical(videoStream) ? `${targetResolution}:-${mult}` : `-${mult}:${targetResolution}`;
} }
isVideoRotated(stream: VideoStreamInfo) { isVideoRotated(videoStream: VideoStreamInfo) {
return Math.abs(stream.rotation) === 90; return Math.abs(videoStream.rotation) === 90;
} }
isVideoVertical(stream: VideoStreamInfo) { isVideoVertical(videoStream: VideoStreamInfo) {
return stream.height > stream.width || this.isVideoRotated(stream); return videoStream.height > videoStream.width || this.isVideoRotated(videoStream);
} }
isBitrateConstrained() { isBitrateConstrained() {
@ -171,12 +173,23 @@ class BaseConfig implements VideoCodecSWConfig {
`zscale=p=${colors.primaries}:t=${colors.transfer}:m=${colors.matrix}:range=pc`, `zscale=p=${colors.primaries}:t=${colors.transfer}:m=${colors.matrix}:range=pc`,
]; ];
} }
getAudioCodec(): string {
return this.config.targetAudioCodec;
}
getVideoCodec(): string {
return this.config.targetVideoCodec;
}
} }
export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig { export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig {
protected devices: string[]; protected devices: string[];
constructor(protected config: SystemConfigFFmpegDto, devices: string[] = []) { constructor(
protected config: SystemConfigFFmpegDto,
devices: string[] = [],
) {
super(config); super(config);
this.devices = this.validateDevices(devices); this.devices = this.validateDevices(devices);
} }
@ -199,6 +212,10 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig {
return -a.localeCompare(b); return -a.localeCompare(b);
}); });
} }
getVideoCodec(): string {
return `${this.config.targetVideoCodec}_${this.config.accel}`;
}
} }
export class ThumbnailConfig extends BaseConfig { export class ThumbnailConfig extends BaseConfig {
@ -214,9 +231,9 @@ export class ThumbnailConfig extends BaseConfig {
return []; return [];
} }
getScaling(stream: VideoStreamInfo) { getScaling(videoStream: VideoStreamInfo) {
let options = super.getScaling(stream); let options = super.getScaling(videoStream);
if (!this.shouldToneMap(stream)) { if (!this.shouldToneMap(videoStream)) {
options += ':out_color_matrix=bt601:out_range=pc'; options += ':out_color_matrix=bt601:out_range=pc';
} }
return options; return options;
@ -233,10 +250,6 @@ export class ThumbnailConfig extends BaseConfig {
} }
export class H264Config extends BaseConfig { export class H264Config extends BaseConfig {
getBaseOutputOptions() {
return [`-vcodec ${this.config.targetVideoCodec}`, ...super.getBaseOutputOptions()];
}
getThreadOptions() { getThreadOptions() {
if (this.config.threads <= 0) { if (this.config.threads <= 0) {
return []; return [];
@ -250,10 +263,6 @@ export class H264Config extends BaseConfig {
} }
export class HEVCConfig extends BaseConfig { export class HEVCConfig extends BaseConfig {
getBaseOutputOptions() {
return [`-vcodec ${this.config.targetVideoCodec}`, ...super.getBaseOutputOptions()];
}
getThreadOptions() { getThreadOptions() {
if (this.config.threads <= 0) { if (this.config.threads <= 0) {
return []; return [];
@ -267,10 +276,6 @@ export class HEVCConfig extends BaseConfig {
} }
export class VP9Config extends BaseConfig { export class VP9Config extends BaseConfig {
getBaseOutputOptions() {
return [`-vcodec ${this.config.targetVideoCodec}`, ...super.getBaseOutputOptions()];
}
getPresetOptions() { getPresetOptions() {
const speed = Math.min(this.getPresetIndex(), 5); // values over 5 require realtime mode, which is its own can of worms since it overrides -crf and -threads const speed = Math.min(this.getPresetIndex(), 5); // values over 5 require realtime mode, which is its own can of worms since it overrides -crf and -threads
if (speed >= 0) { if (speed >= 0) {
@ -306,9 +311,8 @@ export class NVENCConfig extends BaseHWConfig {
return ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda']; return ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'];
} }
getBaseOutputOptions() { getBaseOutputOptions(videoStream: VideoStreamInfo, audioStream: AudioStreamInfo) {
return [ return [
`-vcodec ${this.config.targetVideoCodec}_nvenc`,
// below settings recommended from https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/ffmpeg-with-nvidia-gpu/index.html#command-line-for-latency-tolerant-high-quality-transcoding // below settings recommended from https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/ffmpeg-with-nvidia-gpu/index.html#command-line-for-latency-tolerant-high-quality-transcoding
'-tune hq', '-tune hq',
'-qmin 0', '-qmin 0',
@ -319,15 +323,15 @@ export class NVENCConfig extends BaseHWConfig {
'-rc-lookahead 20', '-rc-lookahead 20',
'-i_qfactor 0.75', '-i_qfactor 0.75',
'-b_qfactor 1.1', '-b_qfactor 1.1',
...super.getBaseOutputOptions(), ...super.getBaseOutputOptions(videoStream, audioStream),
]; ];
} }
getFilterOptions(stream: VideoStreamInfo) { getFilterOptions(videoStream: VideoStreamInfo) {
const options = this.shouldToneMap(stream) ? this.getToneMapping() : []; const options = this.shouldToneMap(videoStream) ? this.getToneMapping() : [];
options.push('format=nv12', 'hwupload_cuda'); options.push('format=nv12', 'hwupload_cuda');
if (this.shouldScale(stream)) { if (this.shouldScale(videoStream)) {
options.push(`scale_cuda=${this.getScaling(stream)}`); options.push(`scale_cuda=${this.getScaling(videoStream)}`);
} }
return options; return options;
@ -375,15 +379,14 @@ export class QSVConfig extends BaseHWConfig {
return ['-init_hw_device qsv=hw', '-filter_hw_device hw']; return ['-init_hw_device qsv=hw', '-filter_hw_device hw'];
} }
getBaseOutputOptions() { getBaseOutputOptions(videoStream: VideoStreamInfo, audioStream: AudioStreamInfo) {
// recommended from https://github.com/intel/media-delivery/blob/master/doc/benchmarks/intel-iris-xe-max-graphics/intel-iris-xe-max-graphics.md // recommended from https://github.com/intel/media-delivery/blob/master/doc/benchmarks/intel-iris-xe-max-graphics/intel-iris-xe-max-graphics.md
const options = [ const options = [
`-vcodec ${this.config.targetVideoCodec}_qsv`,
'-g 256', '-g 256',
'-extbrc 1', '-extbrc 1',
'-refs 5', '-refs 5',
'-bf 7', '-bf 7',
...super.getBaseOutputOptions(), ...super.getBaseOutputOptions(videoStream, audioStream),
]; ];
// VP9 requires enabling low power mode https://git.ffmpeg.org/gitweb/ffmpeg.git/commit/33583803e107b6d532def0f9d949364b01b6ad5a // VP9 requires enabling low power mode https://git.ffmpeg.org/gitweb/ffmpeg.git/commit/33583803e107b6d532def0f9d949364b01b6ad5a
if (this.config.targetVideoCodec === VideoCodec.VP9) { if (this.config.targetVideoCodec === VideoCodec.VP9) {
@ -392,11 +395,11 @@ export class QSVConfig extends BaseHWConfig {
return options; return options;
} }
getFilterOptions(stream: VideoStreamInfo) { getFilterOptions(videoStream: VideoStreamInfo) {
const options = this.shouldToneMap(stream) ? this.getToneMapping() : []; const options = this.shouldToneMap(videoStream) ? this.getToneMapping() : [];
options.push('format=nv12', 'hwupload=extra_hw_frames=64'); options.push('format=nv12', 'hwupload=extra_hw_frames=64');
if (this.shouldScale(stream)) { if (this.shouldScale(videoStream)) {
options.push(`scale_qsv=${this.getScaling(stream)}`); options.push(`scale_qsv=${this.getScaling(videoStream)}`);
} }
return options; return options;
} }
@ -434,15 +437,11 @@ export class VAAPIConfig extends BaseHWConfig {
return [`-init_hw_device vaapi=accel:/dev/dri/${this.devices[0]}`, '-filter_hw_device accel']; return [`-init_hw_device vaapi=accel:/dev/dri/${this.devices[0]}`, '-filter_hw_device accel'];
} }
getBaseOutputOptions() { getFilterOptions(videoStream: VideoStreamInfo) {
return [`-vcodec ${this.config.targetVideoCodec}_vaapi`, ...super.getBaseOutputOptions()]; const options = this.shouldToneMap(videoStream) ? this.getToneMapping() : [];
}
getFilterOptions(stream: VideoStreamInfo) {
const options = this.shouldToneMap(stream) ? this.getToneMapping() : [];
options.push('format=nv12', 'hwupload'); options.push('format=nv12', 'hwupload');
if (this.shouldScale(stream)) { if (this.shouldScale(videoStream)) {
options.push(`scale_vaapi=${this.getScaling(stream)}`); options.push(`scale_vaapi=${this.getScaling(videoStream)}`);
} }
return options; return options;

View file

@ -86,6 +86,7 @@ export interface ISearchRepository {
deleteAssets(ids: string[]): Promise<void>; deleteAssets(ids: string[]): Promise<void>;
deleteFaces(ids: string[]): Promise<void>; deleteFaces(ids: string[]): Promise<void>;
deleteAllFaces(): Promise<number>; deleteAllFaces(): Promise<number>;
updateCLIPField(num_dim: number): Promise<void>;
searchAlbums(query: string, filters: SearchFilter): Promise<SearchResult<AlbumEntity>>; searchAlbums(query: string, filters: SearchFilter): Promise<SearchResult<AlbumEntity>>;
searchAssets(query: string, filters: SearchFilter): Promise<SearchResult<AssetEntity>>; searchAssets(query: string, filters: SearchFilter): Promise<SearchResult<AssetEntity>>;

View file

@ -30,7 +30,7 @@ interface SyncQueue {
export class SearchService { export class SearchService {
private logger = new Logger(SearchService.name); private logger = new Logger(SearchService.name);
private enabled = false; private enabled = false;
private timer: NodeJS.Timer | null = null; private timer: NodeJS.Timeout | null = null;
private configCore: SystemConfigCore; private configCore: SystemConfigCore;
private albumQueue: SyncQueue = { private albumQueue: SyncQueue = {
@ -121,15 +121,18 @@ export class SearchService {
await this.configCore.requireFeature(FeatureFlag.SEARCH); await this.configCore.requireFeature(FeatureFlag.SEARCH);
const query = dto.q || dto.query || '*'; const query = dto.q || dto.query || '*';
const hasClip = machineLearning.enabled && machineLearning.clipEncodeEnabled; const hasClip = machineLearning.enabled && machineLearning.clip.enabled;
const strategy = dto.clip && hasClip ? SearchStrategy.CLIP : SearchStrategy.TEXT; const strategy = dto.clip && hasClip ? SearchStrategy.CLIP : SearchStrategy.TEXT;
const filters = { userId: authUser.id, ...dto }; const filters = { userId: authUser.id, ...dto };
let assets: SearchResult<AssetEntity>; let assets: SearchResult<AssetEntity>;
switch (strategy) { switch (strategy) {
case SearchStrategy.CLIP: case SearchStrategy.CLIP:
const clip = await this.machineLearning.encodeText(machineLearning.url, query); const {
assets = await this.searchRepository.vectorSearch(clip, filters); machineLearning: { clip },
} = await this.configCore.getConfig();
const embedding = await this.machineLearning.encodeText(machineLearning.url, { text: query }, clip);
assets = await this.searchRepository.vectorSearch(embedding, filters);
break; break;
case SearchStrategy.TEXT: case SearchStrategy.TEXT:
default: default:

View file

@ -65,7 +65,7 @@ export class SharedLinkService {
userId: authUser.id, userId: authUser.id,
type: dto.type, type: dto.type,
albumId: dto.albumId || null, albumId: dto.albumId || null,
assets: (dto.assetIds || []).map((id) => ({ id } as AssetEntity)), assets: (dto.assetIds || []).map((id) => ({ id }) as AssetEntity),
description: dto.description || null, description: dto.description || null,
expiresAt: dto.expiresAt || null, expiresAt: dto.expiresAt || null,
allowUpload: dto.allowUpload ?? true, allowUpload: dto.allowUpload ?? true,

View file

@ -0,0 +1 @@
export * from './model-config.dto';

View file

@ -0,0 +1,50 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import { IsBoolean, IsEnum, IsNotEmpty, IsNumber, IsOptional, IsString, Max, Min } from 'class-validator';
import { CLIPMode, ModelType } from '../machine-learning.interface';
export class ModelConfig {
@IsBoolean()
enabled!: boolean;
@IsString()
@IsNotEmpty()
modelName!: string;
@IsEnum(ModelType)
@IsOptional()
@ApiProperty({ enumName: 'ModelType', enum: ModelType })
modelType?: ModelType;
}
export class ClassificationConfig extends ModelConfig {
@IsNumber()
@Min(0)
@Max(1)
@Type(() => Number)
@ApiProperty({ type: 'integer' })
minScore!: number;
}
export class CLIPConfig extends ModelConfig {
@IsEnum(CLIPMode)
@IsOptional()
@ApiProperty({ enumName: 'CLIPMode', enum: CLIPMode })
mode?: CLIPMode;
}
export class RecognitionConfig extends ModelConfig {
@IsNumber()
@Min(0)
@Max(1)
@Type(() => Number)
@ApiProperty({ type: 'integer' })
minScore!: number;
@IsNumber()
@Min(0)
@Max(2)
@Type(() => Number)
@ApiProperty({ type: 'integer' })
maxDistance!: number;
}

View file

@ -1,3 +1,4 @@
export * from './dto';
export * from './machine-learning.interface'; export * from './machine-learning.interface';
export * from './smart-info.repository'; export * from './smart-info.repository';
export * from './smart-info.service'; export * from './smart-info.service';

View file

@ -1,9 +1,15 @@
import { ClassificationConfig, CLIPConfig, RecognitionConfig } from './dto';
export const IMachineLearningRepository = 'IMachineLearningRepository'; export const IMachineLearningRepository = 'IMachineLearningRepository';
export interface MachineLearningInput { export interface VisionModelInput {
imagePath: string; imagePath: string;
} }
export interface TextModelInput {
text: string;
}
export interface BoundingBox { export interface BoundingBox {
x1: number; x1: number;
y1: number; y1: number;
@ -19,9 +25,20 @@ export interface DetectFaceResult {
embedding: number[]; embedding: number[];
} }
export interface IMachineLearningRepository { export enum ModelType {
classifyImage(url: string, input: MachineLearningInput): Promise<string[]>; IMAGE_CLASSIFICATION = 'image-classification',
encodeImage(url: string, input: MachineLearningInput): Promise<number[]>; FACIAL_RECOGNITION = 'facial-recognition',
encodeText(url: string, input: string): Promise<number[]>; CLIP = 'clip',
detectFaces(url: string, input: MachineLearningInput): Promise<DetectFaceResult[]>; }
export enum CLIPMode {
VISION = 'vision',
TEXT = 'text',
}
export interface IMachineLearningRepository {
classifyImage(url: string, input: VisionModelInput, config: ClassificationConfig): Promise<string[]>;
encodeImage(url: string, input: VisionModelInput, config: CLIPConfig): Promise<number[]>;
encodeText(url: string, input: TextModelInput, config: CLIPConfig): Promise<number[]>;
detectFaces(url: string, input: VisionModelInput, config: RecognitionConfig): Promise<DetectFaceResult[]>;
} }

View file

@ -84,9 +84,13 @@ describe(SmartInfoService.name, () => {
await sut.handleClassifyImage({ id: asset.id }); await sut.handleClassifyImage({ id: asset.id });
expect(machineMock.classifyImage).toHaveBeenCalledWith('http://immich-machine-learning:3003', { expect(machineMock.classifyImage).toHaveBeenCalledWith(
imagePath: 'path/to/resize.ext', 'http://immich-machine-learning:3003',
}); {
imagePath: 'path/to/resize.ext',
},
{ enabled: true, minScore: 0.9, modelName: 'microsoft/resnet-50' },
);
expect(smartMock.upsert).toHaveBeenCalledWith({ expect(smartMock.upsert).toHaveBeenCalledWith({
assetId: 'asset-1', assetId: 'asset-1',
tags: ['tag1', 'tag2', 'tag3'], tags: ['tag1', 'tag2', 'tag3'],
@ -141,13 +145,16 @@ describe(SmartInfoService.name, () => {
}); });
it('should save the returned objects', async () => { it('should save the returned objects', async () => {
smartMock.upsert.mockResolvedValue();
machineMock.encodeImage.mockResolvedValue([0.01, 0.02, 0.03]); machineMock.encodeImage.mockResolvedValue([0.01, 0.02, 0.03]);
await sut.handleEncodeClip({ id: asset.id }); await sut.handleEncodeClip({ id: asset.id });
expect(machineMock.encodeImage).toHaveBeenCalledWith('http://immich-machine-learning:3003', { expect(machineMock.encodeImage).toHaveBeenCalledWith(
imagePath: 'path/to/resize.ext', 'http://immich-machine-learning:3003',
}); { imagePath: 'path/to/resize.ext' },
{ enabled: true, modelName: 'ViT-B-32::openai' },
);
expect(smartMock.upsert).toHaveBeenCalledWith({ expect(smartMock.upsert).toHaveBeenCalledWith({
assetId: 'asset-1', assetId: 'asset-1',
clipEmbedding: [0.01, 0.02, 0.03], clipEmbedding: [0.01, 0.02, 0.03],

View file

@ -22,7 +22,7 @@ export class SmartInfoService {
async handleQueueObjectTagging({ force }: IBaseJob) { async handleQueueObjectTagging({ force }: IBaseJob) {
const { machineLearning } = await this.configCore.getConfig(); const { machineLearning } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.tagImageEnabled) { if (!machineLearning.enabled || !machineLearning.classification.enabled) {
return true; return true;
} }
@ -43,7 +43,7 @@ export class SmartInfoService {
async handleClassifyImage({ id }: IEntityJob) { async handleClassifyImage({ id }: IEntityJob) {
const { machineLearning } = await this.configCore.getConfig(); const { machineLearning } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.tagImageEnabled) { if (!machineLearning.enabled || !machineLearning.classification.enabled) {
return true; return true;
} }
@ -52,7 +52,11 @@ export class SmartInfoService {
return false; return false;
} }
const tags = await this.machineLearning.classifyImage(machineLearning.url, { imagePath: asset.resizePath }); const tags = await this.machineLearning.classifyImage(
machineLearning.url,
{ imagePath: asset.resizePath },
machineLearning.classification,
);
await this.repository.upsert({ assetId: asset.id, tags }); await this.repository.upsert({ assetId: asset.id, tags });
return true; return true;
@ -60,7 +64,7 @@ export class SmartInfoService {
async handleQueueEncodeClip({ force }: IBaseJob) { async handleQueueEncodeClip({ force }: IBaseJob) {
const { machineLearning } = await this.configCore.getConfig(); const { machineLearning } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.clipEncodeEnabled) { if (!machineLearning.enabled || !machineLearning.clip.enabled) {
return true; return true;
} }
@ -81,7 +85,7 @@ export class SmartInfoService {
async handleEncodeClip({ id }: IEntityJob) { async handleEncodeClip({ id }: IEntityJob) {
const { machineLearning } = await this.configCore.getConfig(); const { machineLearning } = await this.configCore.getConfig();
if (!machineLearning.enabled || !machineLearning.clipEncodeEnabled) { if (!machineLearning.enabled || !machineLearning.clip.enabled) {
return true; return true;
} }
@ -90,7 +94,12 @@ export class SmartInfoService {
return false; return false;
} }
const clipEmbedding = await this.machineLearning.encodeImage(machineLearning.url, { imagePath: asset.resizePath }); const clipEmbedding = await this.machineLearning.encodeImage(
machineLearning.url,
{ imagePath: asset.resizePath },
machineLearning.clip,
);
await this.repository.upsert({ assetId: asset.id, clipEmbedding: clipEmbedding }); await this.repository.upsert({ assetId: asset.id, clipEmbedding: clipEmbedding });
return true; return true;

View file

@ -1,4 +1,6 @@
import { IsBoolean, IsUrl, ValidateIf } from 'class-validator'; import { ClassificationConfig, CLIPConfig, RecognitionConfig } from '@app/domain';
import { Type } from 'class-transformer';
import { IsBoolean, IsObject, IsUrl, ValidateIf, ValidateNested } from 'class-validator';
export class SystemConfigMachineLearningDto { export class SystemConfigMachineLearningDto {
@IsBoolean() @IsBoolean()
@ -8,12 +10,18 @@ export class SystemConfigMachineLearningDto {
@ValidateIf((dto) => dto.enabled) @ValidateIf((dto) => dto.enabled)
url!: string; url!: string;
@IsBoolean() @Type(() => ClassificationConfig)
clipEncodeEnabled!: boolean; @ValidateNested()
@IsObject()
classification!: ClassificationConfig;
@IsBoolean() @Type(() => CLIPConfig)
facialRecognitionEnabled!: boolean; @ValidateNested()
@IsObject()
clip!: CLIPConfig;
@IsBoolean() @Type(() => RecognitionConfig)
tagImageEnabled!: boolean; @ValidateNested()
@IsObject()
facialRecognition!: RecognitionConfig;
} }

View file

@ -47,12 +47,25 @@ export const defaults = Object.freeze<SystemConfig>({
[QueueName.THUMBNAIL_GENERATION]: { concurrency: 5 }, [QueueName.THUMBNAIL_GENERATION]: { concurrency: 5 },
[QueueName.VIDEO_CONVERSION]: { concurrency: 1 }, [QueueName.VIDEO_CONVERSION]: { concurrency: 1 },
}, },
machineLearning: { machineLearning: {
enabled: process.env.IMMICH_MACHINE_LEARNING_ENABLED !== 'false', enabled: process.env.IMMICH_MACHINE_LEARNING_ENABLED !== 'false',
url: process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003', url: process.env.IMMICH_MACHINE_LEARNING_URL || 'http://immich-machine-learning:3003',
facialRecognitionEnabled: true, classification: {
tagImageEnabled: true, enabled: true,
clipEncodeEnabled: true, modelName: 'microsoft/resnet-50',
minScore: 0.9,
},
clip: {
enabled: true,
modelName: 'ViT-B-32::openai',
},
facialRecognition: {
enabled: true,
modelName: 'buffalo_l',
minScore: 0.7,
maxDistance: 0.6,
},
}, },
oauth: { oauth: {
enabled: false, enabled: false,
@ -143,9 +156,9 @@ export class SystemConfigCore {
const mlEnabled = config.machineLearning.enabled; const mlEnabled = config.machineLearning.enabled;
return { return {
[FeatureFlag.CLIP_ENCODE]: mlEnabled && config.machineLearning.clipEncodeEnabled, [FeatureFlag.CLIP_ENCODE]: mlEnabled && config.machineLearning.clip.enabled,
[FeatureFlag.FACIAL_RECOGNITION]: mlEnabled && config.machineLearning.facialRecognitionEnabled, [FeatureFlag.FACIAL_RECOGNITION]: mlEnabled && config.machineLearning.facialRecognition.enabled,
[FeatureFlag.TAG_IMAGE]: mlEnabled && config.machineLearning.tagImageEnabled, [FeatureFlag.TAG_IMAGE]: mlEnabled && config.machineLearning.classification.enabled,
[FeatureFlag.SIDECAR]: true, [FeatureFlag.SIDECAR]: true,
[FeatureFlag.SEARCH]: process.env.TYPESENSE_ENABLED !== 'false', [FeatureFlag.SEARCH]: process.env.TYPESENSE_ENABLED !== 'false',
@ -230,7 +243,7 @@ export class SystemConfigCore {
_.set(config, key, value); _.set(config, key, value);
} }
return _.defaultsDeep(config, defaults) as SystemConfig; return plainToClass(SystemConfigDto, _.defaultsDeep(config, defaults));
} }
private async loadFromFile(filepath: string, force = false) { private async loadFromFile(filepath: string, force = false) {

View file

@ -49,9 +49,21 @@ const updatedConfig = Object.freeze<SystemConfig>({
machineLearning: { machineLearning: {
enabled: true, enabled: true,
url: 'http://immich-machine-learning:3003', url: 'http://immich-machine-learning:3003',
facialRecognitionEnabled: true, classification: {
tagImageEnabled: true, enabled: true,
clipEncodeEnabled: true, modelName: 'microsoft/resnet-50',
minScore: 0.9,
},
clip: {
enabled: true,
modelName: 'ViT-B-32::openai',
},
facialRecognition: {
enabled: true,
modelName: 'buffalo_l',
minScore: 0.7,
maxDistance: 0.6,
},
}, },
oauth: { oauth: {
autoLaunch: true, autoLaunch: true,

View file

@ -16,7 +16,10 @@ import { IUserRepository, UserListFilter } from './user.repository';
const SALT_ROUNDS = 10; const SALT_ROUNDS = 10;
export class UserCore { export class UserCore {
constructor(private userRepository: IUserRepository, private cryptoRepository: ICryptoRepository) {} constructor(
private userRepository: IUserRepository,
private cryptoRepository: ICryptoRepository,
) {}
async updateUser(authUser: AuthUserDto, id: string, dto: Partial<UserEntity>): Promise<UserEntity> { async updateUser(authUser: AuthUserDto, id: string, dto: Partial<UserEntity>): Promise<UserEntity> {
if (!authUser.isAdmin && authUser.id !== id) { if (!authUser.isAdmin && authUser.id !== id) {

View file

@ -5,7 +5,10 @@ import { IAssetRepository } from './asset-repository';
import { CreateAssetDto, ImportAssetDto } from './dto/create-asset.dto'; import { CreateAssetDto, ImportAssetDto } from './dto/create-asset.dto';
export class AssetCore { export class AssetCore {
constructor(private repository: IAssetRepository, private jobRepository: IJobRepository) {} constructor(
private repository: IAssetRepository,
private jobRepository: IJobRepository,
) {}
async create( async create(
authUser: AuthUserDto, authUser: AuthUserDto,

View file

@ -80,7 +80,10 @@ export interface AuthRequest extends Request {
export class AppGuard implements CanActivate { export class AppGuard implements CanActivate {
private logger = new Logger(AppGuard.name); private logger = new Logger(AppGuard.name);
constructor(private reflector: Reflector, private authService: AuthService) {} constructor(
private reflector: Reflector,
private authService: AuthService,
) {}
async canActivate(context: ExecutionContext): Promise<boolean> { async canActivate(context: ExecutionContext): Promise<boolean> {
const targets = [context.getHandler(), context.getClass()]; const targets = [context.getHandler(), context.getClass()];

View file

@ -60,7 +60,10 @@ export class FileUploadInterceptor implements NestInterceptor {
}; };
private defaultStorage: StorageEngine; private defaultStorage: StorageEngine;
constructor(private reflect: Reflector, private assetService: AssetService) { constructor(
private reflect: Reflector,
private assetService: AssetService,
) {
this.defaultStorage = diskStorage({ this.defaultStorage = diskStorage({
filename: this.filename.bind(this), filename: this.filename.bind(this),
destination: this.destination.bind(this), destination: this.destination.bind(this),

View file

@ -1,4 +1,4 @@
import { QueueName } from '@app/domain/job/job.constants'; import { QueueName } from '@app/domain';
import { Column, Entity, PrimaryColumn } from 'typeorm'; import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity('system_config') @Entity('system_config')
@ -39,9 +39,18 @@ export enum SystemConfigKey {
MACHINE_LEARNING_ENABLED = 'machineLearning.enabled', MACHINE_LEARNING_ENABLED = 'machineLearning.enabled',
MACHINE_LEARNING_URL = 'machineLearning.url', MACHINE_LEARNING_URL = 'machineLearning.url',
MACHINE_LEARNING_FACIAL_RECOGNITION_ENABLED = 'machineLearning.facialRecognitionEnabled',
MACHINE_LEARNING_TAG_IMAGE_ENABLED = 'machineLearning.tagImageEnabled', MACHINE_LEARNING_CLASSIFICATION_ENABLED = 'machineLearning.classification.enabled',
MACHINE_LEARNING_CLIP_ENCODE_ENABLED = 'machineLearning.clipEncodeEnabled', MACHINE_LEARNING_CLASSIFICATION_MODEL_NAME = 'machineLearning.classification.modelName',
MACHINE_LEARNING_CLASSIFICATION_MIN_SCORE = 'machineLearning.classification.minScore',
MACHINE_LEARNING_CLIP_ENABLED = 'machineLearning.clip.enabled',
MACHINE_LEARNING_CLIP_MODEL_NAME = 'machineLearning.clip.modelName',
MACHINE_LEARNING_FACIAL_RECOGNITION_ENABLED = 'machineLearning.facialRecognition.enabled',
MACHINE_LEARNING_FACIAL_RECOGNITION_MODEL_NAME = 'machineLearning.facialRecognition.modelName',
MACHINE_LEARNING_FACIAL_RECOGNITION_MIN_SCORE = 'machineLearning.facialRecognition.minScore',
MACHINE_LEARNING_FACIAL_RECOGNITION_MAX_DISTANCE = 'machineLearning.facialRecognition.maxDistance',
OAUTH_ENABLED = 'oauth.enabled', OAUTH_ENABLED = 'oauth.enabled',
OAUTH_ISSUER_URL = 'oauth.issuerUrl', OAUTH_ISSUER_URL = 'oauth.issuerUrl',
@ -114,9 +123,21 @@ export interface SystemConfig {
machineLearning: { machineLearning: {
enabled: boolean; enabled: boolean;
url: string; url: string;
clipEncodeEnabled: boolean; classification: {
facialRecognitionEnabled: boolean; enabled: boolean;
tagImageEnabled: boolean; modelName: string;
minScore: number;
};
clip: {
enabled: boolean;
modelName: string;
};
facialRecognition: {
enabled: boolean;
modelName: string;
minScore: number;
maxDistance: number;
};
}; };
oauth: { oauth: {
enabled: boolean; enabled: boolean;

View file

@ -0,0 +1,25 @@
import { MigrationInterface, QueryRunner } from "typeorm"
export class RenameMLEnableFlags1693236627291 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
UPDATE system_config SET key = CASE
WHEN key = 'ffmpeg.classificationEnabled' THEN 'ffmpeg.classification.enabled'
WHEN key = 'ffmpeg.clipEnabled' THEN 'ffmpeg.clip.enabled'
WHEN key = 'ffmpeg.facialRecognitionEnabled' THEN 'ffmpeg.facialRecognition.enabled'
ELSE key
END
`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`
UPDATE system_config SET key = CASE
WHEN key = 'ffmpeg.classification.enabled' THEN 'ffmpeg.classificationEnabled'
WHEN key = 'ffmpeg.clip.enabled' THEN 'ffmpeg.clipEnabled'
WHEN key = 'ffmpeg.facialRecognition.enabled' THEN 'ffmpeg.facialRecognitionEnabled'
ELSE key
END
`);
}
}

View file

@ -1,29 +1,65 @@
import { DetectFaceResult, IMachineLearningRepository, MachineLearningInput } from '@app/domain'; import {
ClassificationConfig,
CLIPConfig,
CLIPMode,
DetectFaceResult,
IMachineLearningRepository,
ModelConfig,
ModelType,
RecognitionConfig,
TextModelInput,
VisionModelInput,
} from '@app/domain';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import axios from 'axios'; import { readFile } from 'fs/promises';
import { createReadStream } from 'fs';
const client = axios.create();
@Injectable() @Injectable()
export class MachineLearningRepository implements IMachineLearningRepository { export class MachineLearningRepository implements IMachineLearningRepository {
private post<T>(input: MachineLearningInput, endpoint: string): Promise<T> { private async post<T>(url: string, input: TextModelInput | VisionModelInput, config: ModelConfig): Promise<T> {
return client.post<T>(endpoint, createReadStream(input.imagePath)).then((res) => res.data); const formData = await this.getFormData(input, config);
const res = await fetch(`${url}/predict`, { method: 'POST', body: formData });
return res.json();
} }
classifyImage(url: string, input: MachineLearningInput): Promise<string[]> { classifyImage(url: string, input: VisionModelInput, config: ClassificationConfig): Promise<string[]> {
return this.post<string[]>(input, `${url}/image-classifier/tag-image`); return this.post<string[]>(url, input, { ...config, modelType: ModelType.IMAGE_CLASSIFICATION });
} }
detectFaces(url: string, input: MachineLearningInput): Promise<DetectFaceResult[]> { detectFaces(url: string, input: VisionModelInput, config: RecognitionConfig): Promise<DetectFaceResult[]> {
return this.post<DetectFaceResult[]>(input, `${url}/facial-recognition/detect-faces`); return this.post<DetectFaceResult[]>(url, input, { ...config, modelType: ModelType.FACIAL_RECOGNITION });
} }
encodeImage(url: string, input: MachineLearningInput): Promise<number[]> { encodeImage(url: string, input: VisionModelInput, config: CLIPConfig): Promise<number[]> {
return this.post<number[]>(input, `${url}/sentence-transformer/encode-image`); return this.post<number[]>(url, input, {
...config,
modelType: ModelType.CLIP,
mode: CLIPMode.VISION,
} as CLIPConfig);
} }
encodeText(url: string, input: string): Promise<number[]> { encodeText(url: string, input: TextModelInput, config: CLIPConfig): Promise<number[]> {
return client.post<number[]>(`${url}/sentence-transformer/encode-text`, { text: input }).then((res) => res.data); return this.post<number[]>(url, input, { ...config, modelType: ModelType.CLIP, mode: CLIPMode.TEXT } as CLIPConfig);
}
async getFormData(input: TextModelInput | VisionModelInput, config: ModelConfig): Promise<FormData> {
const formData = new FormData();
const { modelName, modelType, ...options } = config;
formData.append('modelName', modelName);
if (modelType) {
formData.append('modelType', modelType);
}
if (options) {
formData.append('options', JSON.stringify(options));
}
if ('imagePath' in input) {
formData.append('image', new Blob([await readFile(input.imagePath)]));
} else if ('text' in input) {
formData.append('text', input.text);
} else {
throw new Error('Invalid input');
}
return formData;
} }
} }

View file

@ -42,6 +42,7 @@ export class MediaRepository implements IMediaRepository {
videoStreams: results.streams videoStreams: results.streams
.filter((stream) => stream.codec_type === 'video') .filter((stream) => stream.codec_type === 'video')
.map((stream) => ({ .map((stream) => ({
index: stream.index,
height: stream.height || 0, height: stream.height || 0,
width: stream.width || 0, width: stream.width || 0,
codecName: stream.codec_name === 'h265' ? 'hevc' : stream.codec_name, codecName: stream.codec_name === 'h265' ? 'hevc' : stream.codec_name,
@ -53,8 +54,10 @@ export class MediaRepository implements IMediaRepository {
audioStreams: results.streams audioStreams: results.streams
.filter((stream) => stream.codec_type === 'audio') .filter((stream) => stream.codec_type === 'audio')
.map((stream) => ({ .map((stream) => ({
index: stream.index,
codecType: stream.codec_type, codecType: stream.codec_type,
codecName: stream.codec_name, codecName: stream.codec_name,
frameCount: Number.parseInt(stream.nb_frames ?? '0'),
})), })),
}; };
} }

View file

@ -52,6 +52,8 @@ export class TypesenseRepository implements ISearchRepository {
private logger = new Logger(TypesenseRepository.name); private logger = new Logger(TypesenseRepository.name);
private _client: Client | null = null; private _client: Client | null = null;
private _updateCLIPLock = false;
private get client(): Client { private get client(): Client {
if (!this._client) { if (!this._client) {
throw new Error('Typesense client not available (no apiKey was provided)'); throw new Error('Typesense client not available (no apiKey was provided)');
@ -141,7 +143,7 @@ export class TypesenseRepository implements ISearchRepository {
await this.updateAlias(collection); await this.updateAlias(collection);
} }
} catch (error: any) { } catch (error: any) {
this.handleError(error); await this.handleError(error);
} }
} }
@ -221,6 +223,30 @@ export class TypesenseRepository implements ISearchRepository {
return records.num_deleted; return records.num_deleted;
} }
async deleteAllAssets(): Promise<number> {
const records = await this.client.collections(assetSchema.name).documents().delete({ filter_by: 'ownerId:!=null' });
return records.num_deleted;
}
async updateCLIPField(num_dim: number): Promise<void> {
const clipField = assetSchema.fields?.find((field) => field.name === 'smartInfo.clipEmbedding');
if (clipField && !this._updateCLIPLock) {
try {
this._updateCLIPLock = true;
clipField.num_dim = num_dim;
await this.deleteAllAssets();
await this.client
.collections(assetSchema.name)
.update({ fields: [{ name: 'smartInfo.clipEmbedding', drop: true } as any, clipField] });
this.logger.log(`Successfully updated CLIP dimensions to ${num_dim}`);
} catch (err: any) {
this.logger.error(`Error while updating CLIP field: ${err.message}`);
} finally {
this._updateCLIPLock = false;
}
}
}
async delete(collection: SearchCollection, ids: string[]): Promise<void> { async delete(collection: SearchCollection, ids: string[]): Promise<void> {
await this.client await this.client
.collections(schemaMap[collection].name) .collections(schemaMap[collection].name)
@ -326,21 +352,34 @@ export class TypesenseRepository implements ISearchRepository {
} as SearchResult<T>; } as SearchResult<T>;
} }
private handleError(error: any) { private async handleError(error: any) {
this.logger.error('Unable to index documents'); this.logger.error('Unable to index documents');
const results = error.importResults || []; const results = error.importResults || [];
let dimsChanged = false;
for (const result of results) { for (const result of results) {
try { try {
result.document = JSON.parse(result.document); result.document = JSON.parse(result.document);
if (result.error.includes('Field `smartInfo.clipEmbedding` must have')) {
dimsChanged = true;
this.logger.warn(
`CLIP embedding dimensions have changed, now ${result.document.smartInfo.clipEmbedding.length} dims. Updating schema...`,
);
await this.updateCLIPField(result.document.smartInfo.clipEmbedding.length);
break;
}
if (result.document?.smartInfo?.clipEmbedding) { if (result.document?.smartInfo?.clipEmbedding) {
result.document.smartInfo.clipEmbedding = '<truncated>'; result.document.smartInfo.clipEmbedding = '<truncated>';
} }
} catch {} } catch (err: any) {
this.logger.error(`Error while updating CLIP field: ${(err.message, err.stack)}`);
}
} }
this.logger.verbose(JSON.stringify(results, null, 2)); if (!dimsChanged) {
this.logger.log(JSON.stringify(results, null, 2));
}
} }
private async updateAlias(collection: SearchCollection) { private async updateAlias(collection: SearchCollection) {
const schema = schemaMap[collection]; const schema = schemaMap[collection];
const alias = await this.client const alias = await this.client

View file

@ -1,5 +1,5 @@
import { GenericContainer, PostgreSqlContainer } from 'testcontainers'; import { PostgreSqlContainer } from '@testcontainers/postgresql';
import { GenericContainer } from 'testcontainers';
export default async () => { export default async () => {
process.env.NODE_ENV = 'development'; process.env.NODE_ENV = 'development';
process.env.TYPESENSE_API_KEY = 'abc123'; process.env.TYPESENSE_API_KEY = 'abc123';

View file

@ -7,10 +7,21 @@ const probeStubDefaultFormat: VideoFormat = {
}; };
const probeStubDefaultVideoStream: VideoStreamInfo[] = [ const probeStubDefaultVideoStream: VideoStreamInfo[] = [
{ height: 1080, width: 1920, codecName: 'hevc', codecType: 'video', frameCount: 100, rotation: 0, isHDR: false }, {
index: 0,
height: 1080,
width: 1920,
codecName: 'hevc',
codecType: 'video',
frameCount: 100,
rotation: 0,
isHDR: false,
},
]; ];
const probeStubDefaultAudioStream: AudioStreamInfo[] = [{ codecName: 'aac', codecType: 'audio' }]; const probeStubDefaultAudioStream: AudioStreamInfo[] = [
{ index: 0, codecName: 'aac', codecType: 'audio', frameCount: 100 },
];
const probeStubDefault: VideoInfo = { const probeStubDefault: VideoInfo = {
format: probeStubDefaultFormat, format: probeStubDefaultFormat,
@ -25,6 +36,7 @@ export const probeStub = {
...probeStubDefault, ...probeStubDefault,
videoStreams: [ videoStreams: [
{ {
index: 0,
height: 1080, height: 1080,
width: 400, width: 400,
codecName: 'hevc', codecName: 'hevc',
@ -34,6 +46,7 @@ export const probeStub = {
isHDR: false, isHDR: false,
}, },
{ {
index: 1,
height: 1080, height: 1080,
width: 400, width: 400,
codecName: 'h7000', codecName: 'h7000',
@ -48,6 +61,7 @@ export const probeStub = {
...probeStubDefault, ...probeStubDefault,
videoStreams: [ videoStreams: [
{ {
index: 0,
height: 0, height: 0,
width: 400, width: 400,
codecName: 'hevc', codecName: 'hevc',
@ -62,6 +76,7 @@ export const probeStub = {
...probeStubDefault, ...probeStubDefault,
videoStreams: [ videoStreams: [
{ {
index: 0,
height: 2160, height: 2160,
width: 3840, width: 3840,
codecName: 'h264', codecName: 'h264',
@ -76,6 +91,7 @@ export const probeStub = {
...probeStubDefault, ...probeStubDefault,
videoStreams: [ videoStreams: [
{ {
index: 0,
height: 480, height: 480,
width: 480, width: 480,
codecName: 'h264', codecName: 'h264',
@ -90,6 +106,7 @@ export const probeStub = {
...probeStubDefault, ...probeStubDefault,
videoStreams: [ videoStreams: [
{ {
index: 0,
height: 2160, height: 2160,
width: 3840, width: 3840,
codecName: 'h264', codecName: 'h264',
@ -102,7 +119,7 @@ export const probeStub = {
}), }),
audioStreamMp3: Object.freeze<VideoInfo>({ audioStreamMp3: Object.freeze<VideoInfo>({
...probeStubDefault, ...probeStubDefault,
audioStreams: [{ codecType: 'audio', codecName: 'aac' }], audioStreams: [{ index: 0, codecType: 'audio', codecName: 'aac', frameCount: 100 }],
}), }),
matroskaContainer: Object.freeze<VideoInfo>({ matroskaContainer: Object.freeze<VideoInfo>({
...probeStubDefault, ...probeStubDefault,

View file

@ -11,6 +11,7 @@ export const newSearchRepositoryMock = (): jest.Mocked<ISearchRepository> => {
deleteAssets: jest.fn(), deleteAssets: jest.fn(),
deleteFaces: jest.fn(), deleteFaces: jest.fn(),
deleteAllFaces: jest.fn(), deleteAllFaces: jest.fn(),
updateCLIPField: jest.fn(),
searchAssets: jest.fn(), searchAssets: jest.fn(),
searchAlbums: jest.fn(), searchAlbums: jest.fn(),
vectorSearch: jest.fn(), vectorSearch: jest.fn(),

View file

@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"module": "commonjs", "module": "Node16",
"strict": true, "strict": true,
"declaration": true, "declaration": true,
"removeComments": true, "removeComments": true,
@ -17,15 +17,35 @@
"esModuleInterop": true, "esModuleInterop": true,
"baseUrl": "./", "baseUrl": "./",
"paths": { "paths": {
"@test": ["test"], "@test": [
"@test/*": ["test/*"], "test"
"@app/immich": ["src/immich"], ],
"@app/immich/*": ["src/immich/*"], "@test/*": [
"@app/infra": ["src/infra"], "test/*"
"@app/infra/*": ["src/infra/*"], ],
"@app/domain": ["src/domain"], "@app/immich": [
"@app/domain/*": ["src/domain/*"] "src/immich"
],
"@app/immich/*": [
"src/immich/*"
],
"@app/infra": [
"src/infra"
],
"@app/infra/*": [
"src/infra/*"
],
"@app/domain": [
"src/domain"
],
"@app/domain/*": [
"src/domain/*"
]
} }
}, },
"exclude": ["dist", "node_modules", "upload"] "exclude": [
} "dist",
"node_modules",
"upload"
]
}

View file

@ -862,6 +862,53 @@ export interface BulkIdsDto {
*/ */
'ids': Array<string>; 'ids': Array<string>;
} }
/**
*
* @export
* @interface CLIPConfig
*/
export interface CLIPConfig {
/**
*
* @type {boolean}
* @memberof CLIPConfig
*/
'enabled': boolean;
/**
*
* @type {CLIPMode}
* @memberof CLIPConfig
*/
'mode'?: CLIPMode;
/**
*
* @type {string}
* @memberof CLIPConfig
*/
'modelName': string;
/**
*
* @type {ModelType}
* @memberof CLIPConfig
*/
'modelType'?: ModelType;
}
/**
*
* @export
* @enum {string}
*/
export const CLIPMode = {
Vision: 'vision',
Text: 'text'
} as const;
export type CLIPMode = typeof CLIPMode[keyof typeof CLIPMode];
/** /**
* *
* @export * @export
@ -951,6 +998,39 @@ export interface CheckExistingAssetsResponseDto {
*/ */
'existingIds': Array<string>; 'existingIds': Array<string>;
} }
/**
*
* @export
* @interface ClassificationConfig
*/
export interface ClassificationConfig {
/**
*
* @type {boolean}
* @memberof ClassificationConfig
*/
'enabled': boolean;
/**
*
* @type {number}
* @memberof ClassificationConfig
*/
'minScore': number;
/**
*
* @type {string}
* @memberof ClassificationConfig
*/
'modelName': string;
/**
*
* @type {ModelType}
* @memberof ClassificationConfig
*/
'modelType'?: ModelType;
}
/** /**
* *
* @export * @export
@ -1766,6 +1846,21 @@ export interface MergePersonDto {
*/ */
'ids': Array<string>; 'ids': Array<string>;
} }
/**
*
* @export
* @enum {string}
*/
export const ModelType = {
ImageClassification: 'image-classification',
FacialRecognition: 'facial-recognition',
Clip: 'clip'
} as const;
export type ModelType = typeof ModelType[keyof typeof ModelType];
/** /**
* *
* @export * @export
@ -1991,6 +2086,45 @@ export interface QueueStatusDto {
*/ */
'isPaused': boolean; 'isPaused': boolean;
} }
/**
*
* @export
* @interface RecognitionConfig
*/
export interface RecognitionConfig {
/**
*
* @type {boolean}
* @memberof RecognitionConfig
*/
'enabled': boolean;
/**
*
* @type {number}
* @memberof RecognitionConfig
*/
'maxDistance': number;
/**
*
* @type {number}
* @memberof RecognitionConfig
*/
'minScore': number;
/**
*
* @type {string}
* @memberof RecognitionConfig
*/
'modelName': string;
/**
*
* @type {ModelType}
* @memberof RecognitionConfig
*/
'modelType'?: ModelType;
}
/** /**
* *
* @export * @export
@ -2803,10 +2937,16 @@ export interface SystemConfigJobDto {
export interface SystemConfigMachineLearningDto { export interface SystemConfigMachineLearningDto {
/** /**
* *
* @type {boolean} * @type {ClassificationConfig}
* @memberof SystemConfigMachineLearningDto * @memberof SystemConfigMachineLearningDto
*/ */
'clipEncodeEnabled': boolean; 'classification': ClassificationConfig;
/**
*
* @type {CLIPConfig}
* @memberof SystemConfigMachineLearningDto
*/
'clip': CLIPConfig;
/** /**
* *
* @type {boolean} * @type {boolean}
@ -2815,16 +2955,10 @@ export interface SystemConfigMachineLearningDto {
'enabled': boolean; 'enabled': boolean;
/** /**
* *
* @type {boolean} * @type {RecognitionConfig}
* @memberof SystemConfigMachineLearningDto * @memberof SystemConfigMachineLearningDto
*/ */
'facialRecognitionEnabled': boolean; 'facialRecognition': RecognitionConfig;
/**
*
* @type {boolean}
* @memberof SystemConfigMachineLearningDto
*/
'tagImageEnabled': boolean;
/** /**
* *
* @type {string} * @type {string}

View file

@ -10,6 +10,8 @@
import SettingSwitch from '../setting-switch.svelte'; import SettingSwitch from '../setting-switch.svelte';
import type { SystemConfigMachineLearningDto } from '@api'; import type { SystemConfigMachineLearningDto } from '@api';
import { createEventDispatcher } from 'svelte'; import { createEventDispatcher } from 'svelte';
import SettingAccordion from '../setting-accordion.svelte';
import SettingSelect from '../setting-select.svelte';
export let disabled = false; export let disabled = false;
@ -28,62 +30,157 @@
async function resetToDefault() { async function resetToDefault() {
machineLearningConfig = { ...machineLearningDefault }; machineLearningConfig = { ...machineLearningDefault };
notificationController.show({ message: 'Reset settings to defaults', type: NotificationType.Info });
notificationController.show({
message: 'Reset storage template to default',
type: NotificationType.Info,
});
} }
</script> </script>
<div class="mt-2"> <div class="mt-2">
<div in:fade={{ duration: 500 }}> <div in:fade={{ duration: 500 }}>
<form autocomplete="off" on:submit|preventDefault class="mx-4 flex flex-col gap-4 py-4"> <form autocomplete="off" on:submit|preventDefault class="mx-4 mt-4">
<SettingSwitch <div class="flex flex-col gap-4">
title="Enabled" <SettingSwitch
subtitle="Use machine learning features" title="ENABLED"
{disabled} subtitle="If disabled, all ML features will be disabled regardless of the below settings."
bind:checked={machineLearningConfig.enabled} {disabled}
/> bind:checked={machineLearningConfig.enabled}
/>
<hr /> <hr />
<SettingInputField <SettingInputField
inputType={SettingInputFieldType.TEXT} inputType={SettingInputFieldType.TEXT}
label="URL" label="URL"
desc="URL of machine learning server" desc="URL of the machine learning server"
bind:value={machineLearningConfig.url} bind:value={machineLearningConfig.url}
required={true} required={true}
disabled={disabled || !machineLearningConfig.enabled} disabled={disabled || !machineLearningConfig.enabled}
isEdited={!(machineLearningConfig.url === machineLearningConfig.url)} isEdited={machineLearningConfig.url !== savedConfig.url}
/> />
</div>
<SettingSwitch <SettingAccordion title="Image Tagging" subtitle="Tag and classify images with object labels">
title="SMART SEARCH" <div class="ml-4 mt-4 flex flex-col gap-4">
subtitle="Extract CLIP embeddings for smart search" <SettingSwitch
bind:checked={machineLearningConfig.clipEncodeEnabled} title="ENABLED"
disabled={disabled || !machineLearningConfig.enabled} subtitle="If disabled, images will not be tagged. This affects the Things section in the Explore page as well as 'm:' searches."
/> bind:checked={machineLearningConfig.classification.enabled}
disabled={disabled || !machineLearningConfig.enabled}
/>
<SettingSwitch <hr />
title="FACIAL RECOGNITION"
subtitle="Recognize and group faces in photos"
disabled={disabled || !machineLearningConfig.enabled}
bind:checked={machineLearningConfig.facialRecognitionEnabled}
/>
<SettingSwitch <SettingInputField
title="IMAGE TAGGING" inputType={SettingInputFieldType.TEXT}
subtitle="Tag and classify images" label="IMAGE CLASSIFICATION MODEL"
disabled={disabled || !machineLearningConfig.enabled} bind:value={machineLearningConfig.classification.modelName}
bind:checked={machineLearningConfig.tagImageEnabled} required={true}
/> disabled={disabled || !machineLearningConfig.enabled || !machineLearningConfig.classification.enabled}
isEdited={machineLearningConfig.classification.modelName !== savedConfig.classification.modelName}
>
<p slot="desc" class="immich-form-label pb-2 text-sm">
The name of an image classification model listed <a
href="https://huggingface.co/models?pipeline_tag=image-classification&sort=trending"><u>here</u></a
>. It must be tagged with the 'Image Classification' task and must support ONNX conversion.
</p>
</SettingInputField>
<SettingInputField
inputType={SettingInputFieldType.NUMBER}
label="IMAGE CLASSIFICATION THRESHOLD"
desc="Minimum confidence score to add a particular object tag. Lower values will add more tags to images, but may result in more false positives. Will not have any effect until the Tag Objects job is re-run."
bind:value={machineLearningConfig.classification.minScore}
step="0.1"
min="0"
max="1"
disabled={disabled || !machineLearningConfig.enabled || !machineLearningConfig.classification.enabled}
isEdited={machineLearningConfig.classification.minScore !== savedConfig.classification.minScore}
/>
</div>
</SettingAccordion>
<SettingAccordion title="Smart Search" subtitle="Search for images semantically using CLIP embeddings">
<div class="ml-4 mt-4 flex flex-col gap-4">
<SettingSwitch
title="ENABLED"
subtitle="If disabled, images will not be encoded for smart search."
bind:checked={machineLearningConfig.clip.enabled}
disabled={disabled || !machineLearningConfig.enabled}
/>
<hr />
<SettingInputField
inputType={SettingInputFieldType.TEXT}
label="CLIP MODEL"
bind:value={machineLearningConfig.clip.modelName}
required={true}
disabled={disabled || !machineLearningConfig.enabled || !machineLearningConfig.clip.enabled}
isEdited={machineLearningConfig.clip.modelName !== savedConfig.clip.modelName}
>
<p slot="desc" class="immich-form-label pb-2 text-sm">
The name of a CLIP model listed <a
href="https://clip-as-service.jina.ai/user-guides/benchmark/#size-and-efficiency"><u>here</u></a
>. Note that you must re-run the 'Encode CLIP' job for all images upon changing a model.
</p>
</SettingInputField>
</div>
</SettingAccordion>
<SettingAccordion title="Facial Recognition" subtitle="Detect, recognize and group faces in images">
<div class="ml-4 mt-4 flex flex-col gap-4">
<SettingSwitch
title="ENABLED"
subtitle="If disabled, images will not be encoded for facial recognition and will not populate the People section in the Explore page."
bind:checked={machineLearningConfig.facialRecognition.enabled}
disabled={disabled || !machineLearningConfig.enabled}
/>
<hr />
<SettingSelect
label="FACIAL RECOGNITION MODEL"
desc="Smaller models are faster and use less memory, but perform worse. Note that you must re-run the Recognize Faces job for all images upon changing a model."
name="facial-recognition-model"
bind:value={machineLearningConfig.facialRecognition.modelName}
options={[
{ value: 'buffalo_l', text: 'buffalo_l' },
{ value: 'buffalo_s', text: 'buffalo_s' },
]}
disabled={disabled || !machineLearningConfig.enabled || !machineLearningConfig.facialRecognition.enabled}
isEdited={machineLearningConfig.facialRecognition.modelName !== savedConfig.facialRecognition.modelName}
/>
<SettingInputField
inputType={SettingInputFieldType.NUMBER}
label="MIN DETECTION SCORE"
desc="Minimum confidence score for a face to be detected from 0-1. Lower values will detect more faces but may result in false positives."
bind:value={machineLearningConfig.facialRecognition.minScore}
step="0.1"
min="0"
max="1"
disabled={disabled || !machineLearningConfig.enabled || !machineLearningConfig.facialRecognition.enabled}
isEdited={machineLearningConfig.facialRecognition.minScore !== savedConfig.facialRecognition.minScore}
/>
<SettingInputField
inputType={SettingInputFieldType.NUMBER}
label="MAX RECOGNITION DISTANCE"
desc="Maximum distance between two faces to be considered the same person, ranging from 0-2. Lowering this can prevent labeling two people as the same person, while raising it can prevent labeling the same person as two different people. Note that it is easier to merge two people than to split one person in two, so err on the side of a lower threshold when possible."
bind:value={machineLearningConfig.facialRecognition.maxDistance}
step="0.1"
min="0"
max="2"
disabled={disabled || !machineLearningConfig.enabled || !machineLearningConfig.facialRecognition.enabled}
isEdited={machineLearningConfig.facialRecognition.maxDistance !== savedConfig.facialRecognition.maxDistance}
/>
</div>
</SettingAccordion>
<SettingButtonsRow <SettingButtonsRow
on:reset={reset} on:reset={reset}
on:save={() => dispatch('save', machineLearningConfig)} on:save={() => dispatch('save', machineLearningConfig)}
on:reset-to-default={resetToDefault} on:reset-to-default={resetToDefault}
showResetToDefault={!isEqual(machineLearningConfig, machineLearningDefault)} showResetToDefault={!isEqual(savedConfig, machineLearningConfig)}
{disabled} {disabled}
/> />
</form> </form>

View file

@ -13,6 +13,9 @@
export let inputType: SettingInputFieldType; export let inputType: SettingInputFieldType;
export let value: string | number; export let value: string | number;
export let min = Number.MIN_VALUE.toString();
export let max = Number.MAX_VALUE.toString();
export let step = '1';
export let label = ''; export let label = '';
export let desc = ''; export let desc = '';
export let required = false; export let required = false;
@ -48,6 +51,8 @@
<p class="immich-form-label pb-2 text-sm" id="{label}-desc"> <p class="immich-form-label pb-2 text-sm" id="{label}-desc">
{desc} {desc}
</p> </p>
{:else}
<slot name="desc" />
{/if} {/if}
<input <input
@ -57,6 +62,9 @@
id={label} id={label}
name={label} name={label}
type={inputType} type={inputType}
{min}
{max}
{step}
{required} {required}
{value} {value}
on:input={handleInput} on:input={handleInput}

View file

@ -207,14 +207,16 @@
</div> </div>
{/if} {/if}
{#if asset.exifInfo?.fNumber} {#if asset.exifInfo?.make || asset.exifInfo?.model || asset.exifInfo?.fNumber}
<div class="flex gap-4 py-4"> <div class="flex gap-4 py-4">
<div><CameraIris size="24" /></div> <div><CameraIris size="24" /></div>
<div> <div>
<p>{asset.exifInfo.make || ''} {asset.exifInfo.model || ''}</p> <p>{asset.exifInfo.make || ''} {asset.exifInfo.model || ''}</p>
<div class="flex gap-2 text-sm"> <div class="flex gap-2 text-sm">
<p>{`ƒ/${asset.exifInfo.fNumber.toLocaleString($locale)}` || ''}</p> {#if asset.exifInfo?.fNumber}
<p>{`ƒ/${asset.exifInfo.fNumber.toLocaleString($locale)}` || ''}</p>
{/if}
{#if asset.exifInfo.exposureTime} {#if asset.exifInfo.exposureTime}
<p>{`${asset.exifInfo.exposureTime}`}</p> <p>{`${asset.exifInfo.exposureTime}`}</p>
@ -226,7 +228,7 @@
{#if asset.exifInfo.iso} {#if asset.exifInfo.iso}
<p> <p>
{`ISO${asset.exifInfo.iso}`} {`ISO ${asset.exifInfo.iso}`}
</p> </p>
{/if} {/if}
</div> </div>