From 77ddef7eb44e2c7fc0010c9f5bab2c628ca333f5 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 22 Aug 2025 11:57:02 +0000 Subject: [PATCH 001/104] =?UTF-8?q?=E2=9E=95=20build(deps):=20Add=20langex?= =?UTF-8?q?tract=20for=20text=20entity=20extraction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + uv.lock | 62 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index bcde82d2..8d0770f3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,6 +91,7 @@ dependencies = [ "pymupdf4llm>=0.0.17", "pypandoc>=1.15", "python-docx>=1.2.0", + "langextract==1.0.8", ] [project.urls] diff --git a/uv.lock b/uv.lock index b73fc4a6..f660b00d 100644 --- a/uv.lock +++ b/uv.lock @@ -238,7 +238,7 @@ wheels = [ [[package]] name = "aymurai" -version = "1.1.11" +version = "1.1.12.dev0+g695a15fa1.d20250822" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -252,6 +252,7 @@ dependencies = [ { name = "gdown" }, { name = "jiwer" }, { name = "joblib" }, + { name = "langextract" }, { name = "more-itertools" }, { name = "numpy" }, { name = "odfpy" }, @@ -306,6 +307,7 @@ requires-dist = [ { name = "gdown", specifier = "==4.6.0" }, { name = "jiwer", specifier = "==3.0.5" }, { name = "joblib", specifier = ">=1.4.2" }, + { name = "langextract", specifier = "==1.0.8" }, { name = "more-itertools", specifier = ">=10.5.0" }, { name = "numpy", specifier = "<2.0.0" }, { name = "odfpy", specifier = ">=1.4.1" }, @@ -1023,6 +1025,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b1/0e/0636cc1448a7abc444fb1b3a63655e294e0d2d49092dc3de05241be6d43c/google_auth_oauthlib-0.4.6-py2.py3-none-any.whl", hash = "sha256:3f2a6e802eebbb6fb736a370fbf3b055edcb6b52878bf2f26330b5e041316c73", size = 18306 }, ] +[[package]] +name = "google-genai" +version = "1.31.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "google-auth" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "tenacity" }, + { name = "typing-extensions" }, + { name = "websockets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/1b/da30fa6e2966942d7028a58eb7aa7d04544dcc3aa66194365b2e0adac570/google_genai-1.31.0.tar.gz", hash = "sha256:8572b47aa684357c3e5e10d290ec772c65414114939e3ad2955203e27cd2fcbc", size = 233482 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/27/1525bc9cbec58660f0842ebcbfe910a1dde908c2672373804879666e0bb8/google_genai-1.31.0-py3-none-any.whl", hash = "sha256:5c6959bcf862714e8ed0922db3aaf41885bacf6318751b3421bf1e459f78892f", size = 231876 }, +] + [[package]] name = "google-pasta" version = "0.2.0" @@ -1651,6 +1672,32 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474 } +[[package]] +name = "langextract" +version = "1.0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "aiohttp" }, + { name = "async-timeout" }, + { name = "exceptiongroup" }, + { name = "google-genai" }, + { name = "ml-collections" }, + { name = "more-itertools" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2e/d8/95666e87f02f3c83420ed030f14085c9c6acd986da336b514443dee6d649/langextract-1.0.8.tar.gz", hash = "sha256:dc4c65058969486faf119d2c0cd82a12ccdff1d9785212b96fd67c52cbbe74c7", size = 78418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/70/f5eba44ee7a8c8fe651b14585618a4ca600dd41a6fdc156b4377f4f53bb1/langextract-1.0.8-py3-none-any.whl", hash = "sha256:17b5985154ec1d58f5dd8fe4d6135d0cd4b4d650a075f8cf36eca705e2459263", size = 84987 }, +] + [[package]] name = "libclang" version = "18.1.1" @@ -1823,6 +1870,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b4/b3/743ffc3f59da380da504d84ccd1faf9a857a1445991ff19bf2ec754163c2/mistune-3.1.0-py3-none-any.whl", hash = "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1", size = 53694 }, ] +[[package]] +name = "ml-collections" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, +] + [[package]] name = "more-itertools" version = "10.5.0" From 0bbf0d2c63096877458cfecaf68140c097c35468 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 22 Aug 2025 11:58:50 +0000 Subject: [PATCH 002/104] =?UTF-8?q?=F0=9F=9A=A7=20wip:=20Add=20langextract?= =?UTF-8?q?=20entity=20extraction=20experiment=20notebook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anonymization/05-langextract.ipynb | 239 ++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 notebooks/experiments/anonymization/05-langextract.ipynb diff --git a/notebooks/experiments/anonymization/05-langextract.ipynb b/notebooks/experiments/anonymization/05-langextract.ipynb new file mode 100644 index 00000000..0f7ab234 --- /dev/null +++ b/notebooks/experiments/anonymization/05-langextract.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "7052227b", + "metadata": {}, + "outputs": [], + "source": [ + "import langextract as lx\n", + "from rich.pretty import pprint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01ef2998", + "metadata": {}, + "outputs": [], + "source": [ + "# 1. Define the prompt and extraction rules\n", + "prompt = \"\"\"\n", + " Sos un asistente especializado en el análisis de documentos judiciales.\n", + " Tu tarea es identificar y extraer menciones de información sensible para su posterior anonimización.\n", + " Debés detectar fragmentos textuales que correspondan a cualquiera de las siguientes entidades:\n", + "\n", + " - \"BANCO\": Nombre de una entidad bancaria, pública o privada.\n", + " - \"CBU\": Código Bancario Uniforme (22 dígitos) de una cuenta.\n", + " - \"CORREO_ELECTRONICO\": Dirección de correo electrónico.\n", + " - \"CUIJ\": Código Único de Identificación Jurídica de causas judiciales.\n", + " - \"CUIT_CUIL\": Número de CUIT o CUIL de una persona física o jurídica.\n", + " - \"DIRECCION\": Dirección postal específica (calle, número, etc.).\n", + " - \"DNI\": Número de Documento Nacional de Identidad u otro documento identificatorio.\n", + " - \"EDAD\": Edad explícita de una persona.\n", + " - \"ESTUDIOS\": Nivel o institución educativa que permita identificar a la persona (ej. \"primario incompleto\", \"secundario completo\", \"Licenciado en…\").\n", + " - \"FECHA\": Fecha completa o parcial (día, mes y/o año).\n", + " - \"LINK\": Enlace o URL a una página web.\n", + " - \"LOC\": Localización geográfica específica (ciudad, barrio, comisaría, etc.).\n", + " - \"MARCA_AUTOMOVIL\": Marca de un vehículo (ej. Toyota, Ford).\n", + " - \"NACIONALIDAD\": Nacionalidad de una persona (ej. \"argentino\", \"brasileña\").\n", + " - \"NUM_ACTUACION\": Número identificatorio de una actuación administrativa o contravencional.\n", + " - \"NUM_CAJA_AHORRO\": Número completo de una caja de ahorro o cuenta bancaria.\n", + " - \"NUM_EXPEDIENTE\": Número de expediente judicial o administrativo.\n", + " - \"NUM_MATRICULA\": Número de matrícula profesional o académica.\n", + " - \"PATENTE_DOMINIO\": Patente o dominio de un vehículo.\n", + " - \"PER\": Nombre y apellido(s) de una persona física. Los nombres inicializados y los apodos también cuentan como información sensible a anonimizar.\n", + " - \"TELEFONO\": Número telefónico (fijo o celular).\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96f85b5f", + "metadata": {}, + "outputs": [], + "source": [ + "# 2. Provide a high-quality example to guide the model\n", + "examples = [\n", + " lx.data.ExampleData(\n", + " text=\"El 5 de mayo de 2023 el señor Fiscal indicó que realizó distintas medidas de prueba y que del resultado surge que tanto la investigada como el menor Juan Pérez se domicilian en la calle Sarmiento 1234, de la localidad de Moreno, por lo que solicitó que se declare la incompetencia en razón del territorio y se envíe el caso al Juzgado de Garantías que corresponda del Departamento Judicial de Moreno, con jurisdicción en el partido de Moreno.\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"FECHA\", extraction_text=\"5 de mayo de 2023\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Juan Pérez\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"DIRECCION\", extraction_text=\"Sarmiento 1234\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"LOC\", extraction_text=\"Moreno\"\n", + " ),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"JUZGADO DE 1RA INSTANCIA EN LO PENAL CONTRAVENCIONAL Y DE FALTAS N°10 SECRETARIA N°19\\nCarlos Gómez sobre 84 - HOMICIDIO CULPOSO Y OTROS\\nNúmero: 52345/2022\\nCUIJ: 12-34567890-1\\nActuación Nro: 2022-009876\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Carlos Gómez\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"NUM_EXPEDIENTE\", extraction_text=\"52345/2022\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"CUIJ\", extraction_text=\"12-34567890-1\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"NUM_ACTUACION\", extraction_text=\"2022-009876\"\n", + " ),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"Acusado: Miguel Torres, DNI 30123456, nacido el 14/02/1990, de 34 años de edad, de nacionalidad paraguaya, género varón cis, con estudios secundarios completos, hizo hasta 3er año porque fue padre joven, con último domicilio en Av. Corrientes 3456, de esta ciudad, donde vive con su hermana y su cuñado Jorge Pérez. Tiene dos hijos a su cargo, de 5 y 8 años. Su hijo de 8 vive con él, su hija de 5 vive con su madre, Laura Fernández.\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Miguel Torres\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"DNI\", extraction_text=\"30123456\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"FECHA\", extraction_text=\"14/02/1990\"\n", + " ),\n", + " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"34\"),\n", + " lx.data.Extraction(\n", + " extraction_class=\"NACIONALIDAD\", extraction_text=\"paraguaya\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"ESTUDIOS\",\n", + " extraction_text=\"estudios secundarios completos\",\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"DIRECCION\",\n", + " extraction_text=\"Av. Corrientes 3456\",\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Jorge Pérez\"\n", + " ),\n", + " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"5\"),\n", + " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"8\"),\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Laura Fernández\"\n", + " ),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"El testigo Juan López dejó asentado su número de contacto: 11-2345-6789. Indicó que la médica Dra. Ana García, MN 12345, asistió al lugar donde se hallaba un vehículo Volkswagen, patente AB123CD.\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Juan López\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"TELEFONO\", extraction_text=\"11-2345-6789\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Ana García\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"NUM_MATRICULA\", extraction_text=\"12345\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"MARCA_AUTOMOVIL\",\n", + " extraction_text=\"Volkswagen\",\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"PATENTE_DOMINIO\", extraction_text=\"AB123CD\"\n", + " ),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"Se identificó una transferencia bancaria con los siguientes datos: CUIT 20-12345678-3, CBU 2850590940090412345671, Caja de Ahorro N° 12345678, Banco Nación.\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"CUIT_CUIL\", extraction_text=\"20-12345678-3\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"CBU\",\n", + " extraction_text=\"2850590940090412345671\",\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"NUM_CAJA_AHORRO\", extraction_text=\"12345678\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"BANCO\", extraction_text=\"Banco Nación\"\n", + " ),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"Para mayor información, comunicarse a fiscalia.central@justicia.gob.ar o visitar el sitio https://justicia.gob.ar/actuaciones.\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"CORREO_ELECTRONICO\",\n", + " extraction_text=\"fiscalia.central@justicia.gob.ar\",\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"LINK\",\n", + " extraction_text=\"https://justicia.gob.ar/actuaciones\",\n", + " ),\n", + " ],\n", + " ),\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a34c40a8", + "metadata": {}, + "outputs": [], + "source": [ + "text = \"La Fiscalía determinó que el objeto de este caso es investigar el hecho que tuvo lugar el día 12 de marzo de 2023 a las 8:50 horas aproximadamente, ocasión en que Carlos Gómez y María Rodriguez estafaron a Juan Pérez por un monto total de pesos treinta y tres mil novecientos sesenta ($33.960).\"\n", + "\n", + "# Run the extraction\n", + "result = lx.extract(\n", + " text_or_documents=text,\n", + " prompt_description=prompt,\n", + " examples=examples,\n", + " model_id=\"llama3.2:3b\",\n", + " model_url=\"http://localhost:11434\",\n", + " fence_output=False,\n", + " use_schema_constraints=False,\n", + ")\n", + "\n", + "pprint(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb47da66", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.18)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From c2bc1f2fbfc8406a9ee6206b604e8386d0143189 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 10 Nov 2025 17:00:19 +0000 Subject: [PATCH 003/104] =?UTF-8?q?=E2=9C=A8=20feat:=20Enhance=20entity=20?= =?UTF-8?q?models=20with=20relation=20handling=20and=20canonical=20represe?= =?UTF-8?q?ntation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/meta/entities.py | 94 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/aymurai/meta/entities.py b/aymurai/meta/entities.py index d16c0b68..64170307 100644 --- a/aymurai/meta/entities.py +++ b/aymurai/meta/entities.py @@ -1,4 +1,10 @@ -from pydantic import BaseModel, Field +from __future__ import annotations + +import json +from typing import Any +from uuid import NAMESPACE_URL, UUID, uuid5 + +from pydantic import BaseModel, Field, model_validator class EntityAttributes(BaseModel): @@ -26,6 +32,9 @@ class EntityAttributes(BaseModel): description="Method used on the prediction label", ) aymurai_score: float | None = Field(None, description="Score for prediction") + canonical_entity_id: UUID | None = Field( + None, description="Reference to the canonical entity ID" + ) class Entity(BaseModel): @@ -38,3 +47,86 @@ class Entity(BaseModel): context_pre: str = "" context_post: str = "" attrs: EntityAttributes | None = None + + +class EntityRelation(BaseModel): + """Semantic relation between canonical entities.""" + + relation_id: UUID | None = Field( + None, description="Unique identifier of the relation" + ) + relation_type: str = Field( + description="Type of relation (e.g. identifies, resides_in)" + ) + subject_entity_id: UUID = Field( + description="Identifier of the subject entity participating in the relation" + ) + object_entity_id: UUID = Field( + description="Identifier of the object entity participating in the relation" + ) + attributes: dict[str, Any] = Field( + default_factory=dict, + description="Additional attributes captured for the relation", + ) + + @model_validator(mode="after") + def assign_relation_id(self) -> EntityRelation: + """Populate relation_id deterministically when not provided.""" + + if self.relation_id is not None: + return self + + payload = { + "relation_type": self.relation_type, + "subject_entity_id": str(self.subject_entity_id), + "object_entity_id": str(self.object_entity_id), + "attributes": self.attributes, + } + seed = json.dumps(payload, sort_keys=True, separators=(",", ":")) + object.__setattr__(self, "relation_id", uuid5(NAMESPACE_URL, seed)) + + return self + + +class CanonicalEntity(BaseModel): + """Canonical representation of an entity cluster.""" + + entity_id: UUID | None = Field( + None, description="Unique identifier for the canonical entity" + ) + aymurai_label: str = Field(title="AymurAI label") + canonical_text: str = Field(description="Preferred textual form for the entity") + aliases: list[str] = Field( + default_factory=list, + description="Alternative surface forms observed for the entity", + ) + attributes: dict[str, Any] = Field( + default_factory=dict, description="Additional metadata for the entity" + ) + relations: list[EntityRelation] = Field( + default_factory=list, + description="References to relations involving this entity", + ) + + @model_validator(mode="after") + def validate_entity_id(self) -> CanonicalEntity: + """ + Ensure the canonical entity has an entity_id; if missing, create a surrogate UUID and set it. + + Returns: + CanonicalEntity: the validated model instance (self). + """ + # If entity_id is already set, nothing to do. + if self.entity_id is not None: + return self + + payload = { + "aymurai_label": self.aymurai_label, + "canonical_text": self.canonical_text, + "aliases": sorted(self.aliases), + "attributes": self.attributes, + } + seed = json.dumps(payload, sort_keys=True, separators=(",", ":")) + object.__setattr__(self, "entity_id", uuid5(NAMESPACE_URL, seed)) + + return self From d19bb79879d08efaee2581be766fe517ca0b176a Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 10 Nov 2025 21:22:38 +0000 Subject: [PATCH 004/104] =?UTF-8?q?=E2=9C=A8=20feat:=20Add=20JSON=20serial?= =?UTF-8?q?ization=20support=20and=20enhance=20utility=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/utils/json_data.py | 77 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 3 deletions(-) diff --git a/aymurai/utils/json_data.py b/aymurai/utils/json_data.py index a28db543..ad43164e 100644 --- a/aymurai/utils/json_data.py +++ b/aymurai/utils/json_data.py @@ -1,20 +1,80 @@ import json +from datetime import date, datetime from itertools import groupby -from typing import Union, Iterable, Iterator +from typing import Any, Iterable, Iterator -def save_json(json_data: Union[dict, list[dict]], file_path: str): +def json_serial(obj: Any) -> str: + """ + JSON serializer for objects not serializable by default JSON encoder. + + Args: + obj: The object to serialize. This function currently supports + datetime.date and datetime.datetime objects. + + Returns: + str: The ISO 8601 formatted string representation of the date or datetime object. + + Raises: + TypeError: If the object is not of type datetime.date or datetime.datetime. + """ # noqa: E501 + if isinstance(obj, (datetime, date)): + return obj.isoformat() + raise TypeError("Type %s not serializable" % type(obj)) + + +def get_pretty(obj: dict | list[Any]) -> str: + """ + Returns a pretty json string. + + Args: + obj (Union[dict, list[Any]]): the object to be converted to json. + + Returns: + str: the pretty json string. + """ + pretty_json_str = json.dumps(obj, indent=4, ensure_ascii=False, default=json_serial) + return pretty_json_str + + +def save_json(json_data: dict | list[dict], file_path: str) -> None: + """ + + Saves a JSON object to a file. + + Args: + json_data (dict | list[dict]): The JSON data to be saved. + file_path (str): The path to the file where the JSON data will be saved. + """ with open(file_path, "w") as f: f.write(json.dumps(json_data, indent=4, ensure_ascii=False)) -def load_json(json_file_path: str) -> Union[dict, list[dict]]: +def load_json(json_file_path: str) -> dict | list[dict]: + """ + Loads a JSON object from a file. + + Args: + json_file_path (str): The path to the JSON file. + + Returns: + dict | list[dict]: The loaded JSON object. + """ with open(json_file_path, "r") as f: content = json.loads(f.read()) return content def get_unique(json_list: list[dict]) -> Iterator[dict]: + """ + Get unique json objects from a list of json objects. + + Args: + json_list (list[dict]): The list of JSON objects. + + Returns: + Iterator[dict]: An iterator of unique JSON objects. + """ unique = set(map(json.dumps, json_list)) unique = map(json.loads, unique) return unique @@ -23,7 +83,18 @@ def get_unique(json_list: list[dict]) -> Iterator[dict]: def group_by_key( json_iter: Iterable[dict], group_key: str, sort_key: str = "" ) -> Iterator[list[dict]]: + """ + Groups a list of JSON objects by a specified key. + + Args: + json_iter (Iterable[dict]): An iterable of JSON objects to be grouped. + group_key (str): The key to group the JSON objects by. + sort_key (str, optional): An optional key to sort the JSON objects before grouping. + Defaults to "". + Returns: + Iterator[list[dict]]: An iterator of lists of JSON objects grouped by the specified key. + """ if sort_key: json_iter = sorted(json_iter, key=lambda x: x[sort_key]) From 1c0edb5dbfb9ecf0e79893f9d6ba0f1014e708aa Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 10 Nov 2025 21:30:01 +0000 Subject: [PATCH 005/104] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Upgrade=20ML=20dep?= =?UTF-8?q?endencies=20and=20refresh=20uv.lock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 9 +- uv.lock | 464 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 445 insertions(+), 28 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 20a4419b..5e2711b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,10 +76,10 @@ dependencies = [ "cachetools>=5.5.0", "diskcache>=5.6.3", "scipy<1.14.1", - "torch==1.12.1", # for decision model - "torchtext==0.13.1", # for decision model + "torch==2.9.0", + "torchtext==0.18.0", "pytorch-lightning==1.8.3.post1", - "tensorflow_text==2.10.0", # last version compatible with Windows + "tensorflow_text==2.10.0", # last version compatible with Windows "psutil==6.1.0", "sqlmodel==0.0.22", "alembic>=1.13.3", @@ -91,6 +91,7 @@ dependencies = [ "pypandoc>=1.15", "python-docx>=1.2.0", "langextract==1.0.8", + "ollama==0.6.0", ] [project.urls] @@ -114,6 +115,7 @@ dev = [ "nbstripout>=0.8.0", "jupyter>=1.1.1", "pip>=24.3.1", + "streamlit>=1.21.0", ] [tool.setuptools.packages.find] @@ -128,6 +130,7 @@ aymurai-api = "aymurai.api.main:main" [tool.setuptools_scm] version_file = "aymurai/version.py" +local_scheme = "no-local-version" [tool.pylint.messages_control] diff --git a/uv.lock b/uv.lock index adad5a1f..d7646eee 100644 --- a/uv.lock +++ b/uv.lock @@ -96,6 +96,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/7e/ac0991d1745f7d755fc1cd381b3990a45b404b4d008fc75e2a983516fbfe/alembic-1.14.1-py3-none-any.whl", hash = "sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5", size = 233565 }, ] +[[package]] +name = "altair" +version = "4.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "entrypoints" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/bf/781b607da4c1a2a7211cd570bd7e22e0accd4deaf1074c32ac7344a09339/altair-4.2.2.tar.gz", hash = "sha256:39399a267c49b30d102c10411e67ab26374156a84b1aeb9fcd15140429ba49c5", size = 740430 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/62/47452306e84d4d2e67f9c559380aeb230f5e6ca84fafb428dd36b96a99ba/altair-4.2.2-py3-none-any.whl", hash = "sha256:8b45ebeaf8557f2d760c5c77b79f02ae12aee7c46c27c06014febab6f849bc87", size = 813630 }, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -238,7 +255,7 @@ wheels = [ [[package]] name = "aymurai" -version = "1.1.12" +version = "1.1.13.dev5" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -256,6 +273,7 @@ dependencies = [ { name = "more-itertools" }, { name = "numpy" }, { name = "odfpy" }, + { name = "ollama" }, { name = "psutil" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -291,6 +309,7 @@ dev = [ { name = "pre-commit" }, { name = "rich" }, { name = "seaborn" }, + { name = "streamlit" }, ] [package.metadata] @@ -310,6 +329,7 @@ requires-dist = [ { name = "more-itertools", specifier = ">=10.5.0" }, { name = "numpy", specifier = "<2.0.0" }, { name = "odfpy", specifier = ">=1.4.1" }, + { name = "ollama", specifier = "==0.6.0" }, { name = "psutil", specifier = "==6.1.0" }, { name = "pydantic", specifier = ">=2.10.4" }, { name = "pydantic-settings", specifier = ">=2.7.0" }, @@ -328,8 +348,8 @@ requires-dist = [ { name = "tensorflow-hub", specifier = ">=0.16.1" }, { name = "tensorflow-text", specifier = "==2.10.0" }, { name = "textract", specifier = "==1.6.5" }, - { name = "torch", specifier = "==1.12.1" }, - { name = "torchtext", specifier = "==0.13.1" }, + { name = "torch", specifier = "==2.9.0" }, + { name = "torchtext", specifier = "==0.18.0" }, { name = "unidecode", specifier = "==1.3.8" }, { name = "uvicorn", specifier = ">=0.34.0" }, { name = "xmltodict", specifier = "==0.14.2" }, @@ -345,6 +365,7 @@ dev = [ { name = "pre-commit", specifier = ">=4.0.1" }, { name = "rich", specifier = ">=13.9.4" }, { name = "seaborn", specifier = ">=0.13.2" }, + { name = "streamlit", specifier = ">=1.21.0" }, ] [[package]] @@ -401,6 +422,15 @@ css = [ { name = "tinycss2" }, ] +[[package]] +name = "blinker" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, +] + [[package]] name = "boto3" version = "1.36.6" @@ -733,6 +763,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] +[[package]] +name = "entrypoints" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/8d/a7121ffe5f402dc015277d2d31eb82d2187334503a011c18f2e78ecbb9b2/entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4", size = 13974 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/a8/365059bbcd4572cbc41de17fd5b682be5868b218c3c5479071865cab9078/entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f", size = 5294 }, +] + [[package]] name = "exceptiongroup" version = "1.2.2" @@ -996,6 +1035,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/54/0bbe240c6f59ac9209c2356dc65abd209963851569494376a077e55ef98d/gdown-4.6.0-py3-none-any.whl", hash = "sha256:e75c5aa8be8ea1cac642d4793f884339d887ab5e07aaa57fafa16c8a56a0cde5", size = 14400 }, ] +[[package]] +name = "gitdb" +version = "4.0.12" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "smmap" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794 }, +] + +[[package]] +name = "gitpython" +version = "3.1.45" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "gitdb" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9a/c8/dd58967d119baab745caec2f9d853297cec1989ec1d63f677d3880632b88/gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c", size = 215076 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168 }, +] + [[package]] name = "google-auth" version = "2.38.0" @@ -1204,6 +1267,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dc/39/e1c2c2c6e2356ab6ea81fcfc0a74b044b311d6a91a45300811d9a6077ef7/IMAPClient-2.1.0-py2.py3-none-any.whl", hash = "sha256:3eeb97b9aa8faab0caa5024d74bfde59408fbd542781246f6960873c7bf0dd01", size = 73972 }, ] +[[package]] +name = "importlib-metadata" +version = "8.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656 }, +] + [[package]] name = "intervaltree" version = "3.1.0" @@ -1903,6 +1978,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/95/6a/e3691bcc47485f38b09853207c928130571821d187cf174eed5418d45e82/mpld3-0.5.10-py3-none-any.whl", hash = "sha256:80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1", size = 202561 }, ] +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, +] + [[package]] name = "multidict" version = "6.1.0" @@ -2022,6 +2106,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, ] +[[package]] +name = "networkx" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -2075,6 +2168,155 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, ] +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, + { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, + { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, + { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.3.20" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/9d/3dd98852568fb845ec1f7902c90a22b240fe1cbabda411ccedf2fd737b7b/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0", size = 124484616 }, + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145 }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, +] + [[package]] name = "oauthlib" version = "3.2.2" @@ -2102,6 +2344,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/17/d3/b64c356a907242d719fc668b71befd73324e47ab46c8ebbbede252c154b2/olefile-0.47-py2.py3-none-any.whl", hash = "sha256:543c7da2a7adadf21214938bb79c83ea12b473a4b6ee4ad4bf854e7715e13d1f", size = 114565 }, ] +[[package]] +name = "ollama" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d6/47/f9ee32467fe92744474a8c72e138113f3b529fc266eea76abfdec9a33f3b/ollama-0.6.0.tar.gz", hash = "sha256:da2b2d846b5944cfbcee1ca1e6ee0585f6c9d45a2fe9467cbcd096a37383da2f", size = 50811 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/c1/edc9f41b425ca40b26b7c104c5f6841a4537bb2552bfa6ca66e81405bb95/ollama-0.6.0-py3-none-any.whl", hash = "sha256:534511b3ccea2dff419ae06c3b58d7f217c55be7897c8ce5868dfb6b219cf7a0", size = 14130 }, +] + [[package]] name = "opt-einsum" version = "3.4.0" @@ -2131,23 +2386,21 @@ wheels = [ [[package]] name = "pandas" -version = "2.2.3" +version = "1.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, { name = "pytz" }, - { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9c/d6/9f8431bacc2e19dca897724cd097b1bb224a6ad5433784a44b587c7c13af/pandas-2.2.3.tar.gz", hash = "sha256:4f18ba62b61d7e192368b84517265a99b4d7ee8912f8708660fb4a366cc82667", size = 4399213 } +sdist = { url = "https://files.pythonhosted.org/packages/74/ee/146cab1ff6d575b54ace8a6a5994048380dc94879b0125b25e62edcb9e52/pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1", size = 5203060 } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/70/c853aec59839bceed032d52010ff5f1b8d87dc3114b762e4ba2727661a3b/pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5", size = 12580827 }, - { url = "https://files.pythonhosted.org/packages/99/f2/c4527768739ffa4469b2b4fff05aa3768a478aed89a2f271a79a40eee984/pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348", size = 11303897 }, - { url = "https://files.pythonhosted.org/packages/ed/12/86c1747ea27989d7a4064f806ce2bae2c6d575b950be087837bdfcabacc9/pandas-2.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d9c45366def9a3dd85a6454c0e7908f2b3b8e9c138f5dc38fed7ce720d8453ed", size = 66480908 }, - { url = "https://files.pythonhosted.org/packages/44/50/7db2cd5e6373ae796f0ddad3675268c8d59fb6076e66f0c339d61cea886b/pandas-2.2.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86976a1c5b25ae3f8ccae3a5306e443569ee3c3faf444dfd0f41cda24667ad57", size = 13064210 }, - { url = "https://files.pythonhosted.org/packages/61/61/a89015a6d5536cb0d6c3ba02cebed51a95538cf83472975275e28ebf7d0c/pandas-2.2.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b8661b0238a69d7aafe156b7fa86c44b881387509653fdf857bebc5e4008ad42", size = 16754292 }, - { url = "https://files.pythonhosted.org/packages/ce/0d/4cc7b69ce37fac07645a94e1d4b0880b15999494372c1523508511b09e40/pandas-2.2.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:37e0aced3e8f539eccf2e099f65cdb9c8aa85109b0be6e93e2baff94264bdc6f", size = 14416379 }, - { url = "https://files.pythonhosted.org/packages/31/9e/6ebb433de864a6cd45716af52a4d7a8c3c9aaf3a98368e61db9e69e69a9c/pandas-2.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:56534ce0746a58afaf7942ba4863e0ef81c9c50d3f0ae93e9497d6a41a057645", size = 11598471 }, + { url = "https://files.pythonhosted.org/packages/a9/cd/34f6b0780301be81be804d7aa71d571457369e6131e2b330af2b0fed1aad/pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406", size = 18619230 }, + { url = "https://files.pythonhosted.org/packages/5f/34/b7858bb7d6d6bf4d9df1dde777a11fcf3ff370e1d1b3956e3d0fcca8322c/pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572", size = 11982991 }, + { url = "https://files.pythonhosted.org/packages/b8/6c/005bd604994f7cbede4d7bf030614ef49a2213f76bc3d738ecf5b0dcc810/pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996", size = 10927131 }, + { url = "https://files.pythonhosted.org/packages/27/c7/35b81ce5f680f2dac55eac14d103245cd8cf656ae4a2ff3be2e69fd1d330/pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354", size = 11368188 }, + { url = "https://files.pythonhosted.org/packages/49/e2/79e46612dc25ebc7603dc11c560baa7266c90f9e48537ecf1a02a0dd6bff/pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23", size = 12062104 }, + { url = "https://files.pythonhosted.org/packages/d9/cd/f27c2992cbe05a3e39937f73a4be635a9ec149ec3ca4467d8cf039718994/pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328", size = 10362473 }, ] [[package]] @@ -2495,6 +2748,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b4/46/93416fdae86d40879714f72956ac14df9c7b76f7d41a4d68aa9f71a0028b/pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd", size = 29718 }, ] +[[package]] +name = "pydeck" +version = "0.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, +] + [[package]] name = "pygments" version = "2.19.1" @@ -2504,6 +2770,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, ] +[[package]] +name = "pympler" +version = "1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/37/c384631908029676d8e7213dd956bb686af303a80db7afbc9be36bc49495/pympler-1.1.tar.gz", hash = "sha256:1eaa867cb8992c218430f1708fdaccda53df064144d1c5656b1e6f1ee6000424", size = 179954 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl", hash = "sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506", size = 165766 }, +] + [[package]] name = "pymupdf" version = "1.25.2" @@ -3084,6 +3362,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/73/fb/00a976f728d0d1fecfe898238ce23f502a721c0ac0ecfedb80e0d88c64e9/six-1.12.0-py2.py3-none-any.whl", hash = "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", size = 10586 }, ] +[[package]] +name = "smmap" +version = "5.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303 }, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -3185,6 +3472,52 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/61/f2b52e107b1fc8944b33ef56bf6ac4ebbe16d91b94d2b87ce013bf63fb84/starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d", size = 71507 }, ] +[[package]] +name = "streamlit" +version = "1.21.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "altair" }, + { name = "blinker" }, + { name = "cachetools" }, + { name = "click" }, + { name = "gitpython" }, + { name = "importlib-metadata" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pillow" }, + { name = "protobuf" }, + { name = "pyarrow" }, + { name = "pydeck" }, + { name = "pympler" }, + { name = "python-dateutil" }, + { name = "requests" }, + { name = "rich" }, + { name = "toml" }, + { name = "tornado" }, + { name = "typing-extensions" }, + { name = "tzlocal" }, + { name = "validators" }, + { name = "watchdog", marker = "platform_system != 'Darwin'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/95/89b0f5f51cd006ffb6cc216393793d05029c47e97f140a9bff02f8c291a8/streamlit-1.21.0.tar.gz", hash = "sha256:c72d9639508679c5e411d1f886d213777759501d01975285c049dc30db463c1a", size = 9345809 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/fa/5b010610aa136c44a20de6ed9ec0b36867daf7322d0e3c8e626a99fab11a/streamlit-1.21.0-py2.py3-none-any.whl", hash = "sha256:05862598952a9126e16652caa5bc88eeeea7b2773af252e2daccf1c84ceaaef4", size = 9665093 }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, +] + [[package]] name = "tabulate" version = "0.9.0" @@ -3471,6 +3804,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/69/d21eb253fa91622da25585d362a874fa4710be600f0ea9446d8d0217cec1/tokenizers-0.21.0-cp39-abi3-win_amd64.whl", hash = "sha256:87841da5a25a3a5f70c102de371db120f41873b854ba65e52bccd57df5a3780c", size = 2389192 }, ] +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, +] + [[package]] name = "tomli" version = "2.2.1" @@ -3480,19 +3822,48 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, ] +[[package]] +name = "toolz" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/d6/114b492226588d6ff54579d95847662fc69196bdeec318eb45393b24c192/toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b", size = 52613 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8", size = 58093 }, +] + [[package]] name = "torch" -version = "1.12.1" +version = "2.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/74/7342c7f21449557a8263c925071a55081edd7e9b641404cfe31d6fb71d3b/torch-1.12.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:9c038662db894a23e49e385df13d47b2a777ffd56d9bcd5b832593fab0a7e286", size = 776338835 }, - { url = "https://files.pythonhosted.org/packages/36/b0/4857929aa28dfe26f7de909ebf002b60499edcd7566441a7433df865f9ba/torch-1.12.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:4e1b9c14cf13fd2ab8d769529050629a0e68a6fc5cb8e84b4a3cc1dd8c4fe541", size = 55712361 }, - { url = "https://files.pythonhosted.org/packages/b9/25/fc2111599a038aa6c1c618a7dc9246aabc95f899008949ade31213255a0c/torch-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:e9c8f4a311ac29fc7e8e955cfb7733deb5dbe1bdaabf5d4af2765695824b7e0d", size = 162235663 }, - { url = "https://files.pythonhosted.org/packages/37/72/ef80d39a371a9b4a8aadfb22b141972cc67a7075dae69a9d5b8116505ec0/torch-1.12.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:976c3f997cea38ee91a0dd3c3a42322785414748d1761ef926b789dfa97c6134", size = 133811424 }, - { url = "https://files.pythonhosted.org/packages/2f/17/8b557dde1cdb5fbe82f90a3f192046c8e508f106456e12f17c87543e6a42/torch-1.12.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:68104e4715a55c4bb29a85c6a8d57d820e0757da363be1ba680fa8cc5be17b52", size = 49099890 }, + { url = "https://files.pythonhosted.org/packages/bb/86/245c240d2138c17ed572c943c289056c2721abab70810d772c6bf5495b28/torch-2.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:030bbfe367379ae6a4ae4042b6c44da25383343b8b3c68abaa9c7231efbaf2dd", size = 104213554 }, + { url = "https://files.pythonhosted.org/packages/58/1d/fd1e88ae0948825efcab7dd66d12bec23f05d4d38ed81573c8d453c14c06/torch-2.9.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:51cb63902182a78e90886e8068befd8ea102af4b00e420263591a3d70c7d3c6c", size = 899795167 }, + { url = "https://files.pythonhosted.org/packages/63/5a/496197b45c14982bef4e079b24c61dc108e3ab0d0cc9718dba9f54f45a46/torch-2.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:3f6aad4d2f0ee2248bac25339d74858ff846c3969b27d14ac235821f055af83d", size = 109310314 }, + { url = "https://files.pythonhosted.org/packages/58/b0/2b4e647b0fc706e88eb6c253d05511865578f5f67b55fad639bf3272a4a1/torch-2.9.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:413e1654c9203733138858780e184d9fc59442f0b3b209e16f39354eb893db9b", size = 74452019 }, ] [[package]] @@ -3511,7 +3882,7 @@ wheels = [ [[package]] name = "torchtext" -version = "0.13.1" +version = "0.18.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, @@ -3520,11 +3891,9 @@ dependencies = [ { name = "tqdm" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/10/6f/673e3533a296f135fecfccdf2519ecfba7e16971dca5c3bc7a8cc9cfd064/torchtext-0.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aa59df8f9542674311fc23aca147a34256c936c25840c4b6ee3fee47d511ad17", size = 1775853 }, - { url = "https://files.pythonhosted.org/packages/2f/bd/5f27d604d3dc6421b3c0bd24c28f73eecb091fce9dbdcbe7af314f252cee/torchtext-0.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:492a22727181edf5a33fa18587f3430ffbb366c2ea835e0f4f8a08be8d9e859c", size = 1966034 }, - { url = "https://files.pythonhosted.org/packages/48/4e/56352383c30b75becd5faaff8d404eb86f3a2282d72ae52aaad705bf22bf/torchtext-0.13.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:f56359165eb00ea2ff998b67727f87e7fa32665c1a46610c9b5a2d5d581095e5", size = 1910382 }, - { url = "https://files.pythonhosted.org/packages/3f/fd/e3eef8b5d691cdeb42506fc9fec2a64ab1549039cdf9e7545a171e4a694e/torchtext-0.13.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:b5bf4f9da5326b6e74318b4a5035abfaf166b3abd822565be685f44947adb8d3", size = 1832850 }, - { url = "https://files.pythonhosted.org/packages/b8/9d/7f9b786637d664579b66ae7c6742d662a91b8e6a9f55a34e22c20883d801/torchtext-0.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f8c1b426bda2f22e5bfd118c779c12f8612ed1077e5e3a491242bb4ab7ac4d3", size = 2239348 }, + { url = "https://files.pythonhosted.org/packages/cc/94/1e805ef3ec6541de75e8a86c32e00be471d98cdcef5035ad26457bc388cf/torchtext-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5826d5bbfe84a3c533e7e97659f72dbff73e1614c00c06709607d17c8446e09c", size = 2137942 }, + { url = "https://files.pythonhosted.org/packages/d7/4f/9953b4d4b79917e03c393484ea8ce8f46a4cc1745f272cc371550fb7fc05/torchtext-0.18.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:3dc446f74aaa9aebab045fbefd102752675258e72ba447982c65e010e1cfd29a", size = 2021446 }, + { url = "https://files.pythonhosted.org/packages/b2/3d/6f18d551b00bf8babaa3a569d5fd62cba2bd7bbdeaf82167a959352ba56b/torchtext-0.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:d4bfe9cb7b08cf7ff3473309d9f24ed243c3a847bfbb2c932925551bf7a05892", size = 1949005 }, ] [[package]] @@ -3611,6 +3980,15 @@ torch = [ { name = "torch" }, ] +[[package]] +name = "triton" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/22/507b6f58a35e05e84381630b2dc2a3cee1a7a2a7eaf4cba857c638a18a24/triton-3.5.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f90de6a6566bb619b4c0adc9855729e1b1b5e26533fca1bf6206e96b6d277a3", size = 159827599 }, + { url = "https://files.pythonhosted.org/packages/0b/eb/09e31d107a5d00eb281aa7e6635ca463e9bca86515944e399480eadb71f8/triton-3.5.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5d3b3d480debf24eaa739623c9a42446b0b77f95593d30eb1f64cd2278cc1f0", size = 170333110 }, +] + [[package]] name = "typer" version = "0.15.1" @@ -3731,6 +4109,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523 }, ] +[[package]] +name = "validators" +version = "0.35.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/66/a435d9ae49850b2f071f7ebd8119dd4e84872b01630d6736761e6e7fd847/validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a", size = 73399 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/6e/3e955517e22cbdd565f2f8b2e73d52528b14b8bcfdb04f62466b071de847/validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd", size = 44712 }, +] + [[package]] name = "virtualenv" version = "20.29.1" @@ -3745,6 +4132,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/89/9b/599bcfc7064fbe5740919e78c5df18e5dceb0887e676256a1061bb5ae232/virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779", size = 4282379 }, ] +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, +] + [[package]] name = "watchfiles" version = "1.0.4" @@ -3977,3 +4382,12 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fd/b7/2e9a5b18eb0fe24c3a0e8bae994e812ed9852ab4fd067c0107fadde0d5f0/yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", size = 90484 }, { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 }, ] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, +] From fe35a4edbe2a7fa9de3ce9c37e9b34fc05df1562 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 10 Nov 2025 21:35:28 +0000 Subject: [PATCH 006/104] =?UTF-8?q?=F0=9F=9A=A7=20=20wip:=20Update=20extra?= =?UTF-8?q?ction=20examples=20in=20langextract=20notebook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anonymization/05-langextract.ipynb | 125 +++++++++++++----- 1 file changed, 95 insertions(+), 30 deletions(-) diff --git a/notebooks/experiments/anonymization/05-langextract.ipynb b/notebooks/experiments/anonymization/05-langextract.ipynb index 0f7ab234..c7035718 100644 --- a/notebooks/experiments/anonymization/05-langextract.ipynb +++ b/notebooks/experiments/anonymization/05-langextract.ipynb @@ -63,23 +63,17 @@ " lx.data.Extraction(\n", " extraction_class=\"FECHA\", extraction_text=\"5 de mayo de 2023\"\n", " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Juan Pérez\"\n", - " ),\n", + " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Juan Pérez\"),\n", " lx.data.Extraction(\n", " extraction_class=\"DIRECCION\", extraction_text=\"Sarmiento 1234\"\n", " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"LOC\", extraction_text=\"Moreno\"\n", - " ),\n", + " lx.data.Extraction(extraction_class=\"LOC\", extraction_text=\"Moreno\"),\n", " ],\n", " ),\n", " lx.data.ExampleData(\n", " text=\"JUZGADO DE 1RA INSTANCIA EN LO PENAL CONTRAVENCIONAL Y DE FALTAS N°10 SECRETARIA N°19\\nCarlos Gómez sobre 84 - HOMICIDIO CULPOSO Y OTROS\\nNúmero: 52345/2022\\nCUIJ: 12-34567890-1\\nActuación Nro: 2022-009876\",\n", " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Carlos Gómez\"\n", - " ),\n", + " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Carlos Gómez\"),\n", " lx.data.Extraction(\n", " extraction_class=\"NUM_EXPEDIENTE\", extraction_text=\"52345/2022\"\n", " ),\n", @@ -94,15 +88,9 @@ " lx.data.ExampleData(\n", " text=\"Acusado: Miguel Torres, DNI 30123456, nacido el 14/02/1990, de 34 años de edad, de nacionalidad paraguaya, género varón cis, con estudios secundarios completos, hizo hasta 3er año porque fue padre joven, con último domicilio en Av. Corrientes 3456, de esta ciudad, donde vive con su hermana y su cuñado Jorge Pérez. Tiene dos hijos a su cargo, de 5 y 8 años. Su hijo de 8 vive con él, su hija de 5 vive con su madre, Laura Fernández.\",\n", " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Miguel Torres\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"DNI\", extraction_text=\"30123456\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"FECHA\", extraction_text=\"14/02/1990\"\n", - " ),\n", + " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Miguel Torres\"),\n", + " lx.data.Extraction(extraction_class=\"DNI\", extraction_text=\"30123456\"),\n", + " lx.data.Extraction(extraction_class=\"FECHA\", extraction_text=\"14/02/1990\"),\n", " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"34\"),\n", " lx.data.Extraction(\n", " extraction_class=\"NACIONALIDAD\", extraction_text=\"paraguaya\"\n", @@ -115,9 +103,7 @@ " extraction_class=\"DIRECCION\",\n", " extraction_text=\"Av. Corrientes 3456\",\n", " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Jorge Pérez\"\n", - " ),\n", + " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Jorge Pérez\"),\n", " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"5\"),\n", " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"8\"),\n", " lx.data.Extraction(\n", @@ -128,15 +114,11 @@ " lx.data.ExampleData(\n", " text=\"El testigo Juan López dejó asentado su número de contacto: 11-2345-6789. Indicó que la médica Dra. Ana García, MN 12345, asistió al lugar donde se hallaba un vehículo Volkswagen, patente AB123CD.\",\n", " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Juan López\"\n", - " ),\n", + " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Juan López\"),\n", " lx.data.Extraction(\n", " extraction_class=\"TELEFONO\", extraction_text=\"11-2345-6789\"\n", " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Ana García\"\n", - " ),\n", + " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Ana García\"),\n", " lx.data.Extraction(\n", " extraction_class=\"NUM_MATRICULA\", extraction_text=\"12345\"\n", " ),\n", @@ -180,9 +162,90 @@ " ),\n", " ],\n", " ),\n", + " lx.data.ExampleData(\n", + " text=\"En la Ciudad Autónoma de Buenos Aires, el día 5 de mayo de 2023, el Sr. Fiscal hace saber que Juan Pérez se domicilia en la calle Sarmiento 1234, localidad de Moreno.\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"FECHA\", extraction_text=\"5 de mayo de 2023\"\n", + " ),\n", + " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Juan Pérez\"),\n", + " lx.data.Extraction(\n", + " extraction_class=\"DIRECCION\", extraction_text=\"Sarmiento 1234\"\n", + " ),\n", + " lx.data.Extraction(extraction_class=\"LOC\", extraction_text=\"Moreno\"),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"Por otra parte, la División Investigaciones Judiciales de la Policía Federal Argentina informó que no se dio intervención a ninguna otra Fiscalía u otro Juzgado por la sustracción del vehículo Volkswagen Voyage, dominio KXY-876\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"PATENTE_DOMINIO\", extraction_text=\"KXY-876\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"MARCA_AUTOMOVIL\",\n", + " extraction_text=\"Volkswagen Voyage\",\n", + " ),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"A su vez, requirió informes al Banco BBVA Francés, respecto de las cuentas bancarias de la denunciante, Carla Alejandra Garcia, D.N.I. 36.998.621 identificadas como Caja de ahorro en pesos argentinos número 117-59824/6 con CBU 0180132640000004685591 y Caja de ahorro en dólares número 119-619018/2 con CBU 0170115544000062081822.\",\n", + " extractions=[\n", + " lx.data.Extraction(\n", + " extraction_class=\"PER\", extraction_text=\"Carla Alejandra Garcia\"\n", + " ),\n", + " lx.data.Extraction(extraction_class=\"DNI\", extraction_text=\"36.998.621\"),\n", + " lx.data.Extraction(\n", + " extraction_class=\"NUM_CAJA_AHORRO\", extraction_text=\"117-59824/6\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"CBU\", extraction_text=\"0180132640000004685591\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"NUM_CAJA_AHORRO\", extraction_text=\"119-619018/2\"\n", + " ),\n", + " lx.data.Extraction(\n", + " extraction_class=\"CBU\", extraction_text=\"0170115544000062081822\"\n", + " ),\n", + " ],\n", + " ),\n", + " lx.data.ExampleData(\n", + " text=\"VISTOS: Que a fin de ordenar la marcha del proceso, se fija audiencia preliminar. No se consignan números de expediente, CUIJ ni domicilios en el presente proveído.\",\n", + " extractions=[], # ejemplo negativo: desalienta devolver clases ausentes\n", + " ),\n", "]" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb82c82d", + "metadata": {}, + "outputs": [], + "source": [ + "len(examples)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c52e56f4", + "metadata": {}, + "outputs": [], + "source": [ + "iter_examples = iter(examples)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68945d23", + "metadata": {}, + "outputs": [], + "source": [ + "example = next(iter_examples)\n", + "pprint(example)" + ] + }, { "cell_type": "code", "execution_count": null, @@ -190,6 +253,7 @@ "metadata": {}, "outputs": [], "source": [ + "# Sample text to extract from\n", "text = \"La Fiscalía determinó que el objeto de este caso es investigar el hecho que tuvo lugar el día 12 de marzo de 2023 a las 8:50 horas aproximadamente, ocasión en que Carlos Gómez y María Rodriguez estafaron a Juan Pérez por un monto total de pesos treinta y tres mil novecientos sesenta ($33.960).\"\n", "\n", "# Run the extraction\n", @@ -197,8 +261,9 @@ " text_or_documents=text,\n", " prompt_description=prompt,\n", " examples=examples,\n", - " model_id=\"llama3.2:3b\",\n", + " model_id=\"llama3.1:8b\",\n", " model_url=\"http://localhost:11434\",\n", + " max_char_buffer=16_384,\n", " fence_output=False,\n", " use_schema_constraints=False,\n", ")\n", @@ -209,7 +274,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fb47da66", + "id": "82279f15", "metadata": {}, "outputs": [], "source": [] @@ -217,7 +282,7 @@ ], "metadata": { "kernelspec": { - "display_name": "aymurai (3.10.18)", + "display_name": "aymurai", "language": "python", "name": "python3" }, From 3d3d2300a5f2e1b06d5284507d16d87e02815fb7 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 14 Nov 2025 19:10:28 +0000 Subject: [PATCH 007/104] =?UTF-8?q?=F0=9F=93=9D=20=20Add=20entity=20disamb?= =?UTF-8?q?iguation=20notebook=20for=20canonical=20entity=20extraction?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01-entity-disambiguation.ipynb | 550 ++++++++++++++++++ 1 file changed, 550 insertions(+) create mode 100644 notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb diff --git a/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb new file mode 100644 index 00000000..99477159 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb @@ -0,0 +1,550 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "c8fc128c", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8eeefe8b", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import mimetypes\n", + "import os\n", + "import re\n", + "import time\n", + "from pathlib import Path\n", + "from typing import Iterable\n", + "\n", + "import ollama\n", + "import requests\n", + "from IPython.display import Markdown\n", + "from ollama import ChatResponse\n", + "from pydantic import BaseModel\n", + "from pydantic.json_schema import JsonSchemaValue\n", + "from rich.pretty import pprint\n", + "from tqdm import tqdm\n", + "\n", + "from aymurai.meta.entities import CanonicalEntity # , EntityRelation\n", + "from aymurai.utils.json_data import get_pretty, load_json, save_json" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46b328aa", + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"OLLAMA_KEEP_ALIVE\"] = \"0\"\n", + "print(\"OLLAMA_KEEP_ALIVE set to 0. Models will unload immediately after use.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "758353c4", + "metadata": {}, + "outputs": [], + "source": [ + "DATA_DIR = \"/resources/data/restricted/summarization\"\n", + "API_URL = \"http://localhost:8899\" # Url for debugger. change it to your own" + ] + }, + { + "cell_type": "markdown", + "id": "84d11bba", + "metadata": {}, + "source": [ + "## /document-extract endpoint output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e0ec450", + "metadata": {}, + "outputs": [], + "source": [ + "BASE_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", + "ENDPOINT = f\"{BASE_URL}/misc/document-extract\"\n", + "DATA_ROOT = Path(\n", + " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef352767", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "print(f\"Discovered {len(documents)} documents.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21fd6e36", + "metadata": {}, + "outputs": [], + "source": [ + "def call_extraction_api(\n", + " session: requests.Session, file_path: Path\n", + ") -> dict[str, object]:\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " ENDPOINT,\n", + " files=files,\n", + " timeout=REQUEST_TIMEOUT_S,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload" + ] + }, + { + "cell_type": "markdown", + "id": "9254ef68", + "metadata": {}, + "source": [ + "## Inference" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a308cf90", + "metadata": {}, + "outputs": [], + "source": [ + "# Function to make inference using the API\n", + "def get_predictions(sample: str) -> dict:\n", + " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample})\n", + " response.raise_for_status()\n", + " return response.json()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ef6a0fa", + "metadata": {}, + "outputs": [], + "source": [ + "from itertools import chain\n", + "from operator import itemgetter\n", + "from typing import Any\n", + "\n", + "from more_itertools import unique_everseen\n", + "\n", + "\n", + "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", + " \"\"\"\n", + " Parse prediction labels to extract unique aymurai_label and aymurai_alt_text pairs.\n", + "\n", + " Args:\n", + " predictions (list[dict[str, Any]]): A list of prediction dictionaries.\n", + "\n", + " Returns:\n", + " list[dict[str, str]]: A list of dictionaries containing unique aymurai_label and aymurai_alt_text pairs.\n", + " \"\"\"\n", + " attrs_stream = (\n", + " label.get(\"attrs\") or {}\n", + " for label in chain.from_iterable(pred.get(\"labels\", ()) for pred in predictions)\n", + " )\n", + "\n", + " unique_pairs = unique_everseen(\n", + " (\n", + " attrs.get(\"aymurai_label\"),\n", + " attrs.get(\"aymurai_alt_text\"),\n", + " )\n", + " for attrs in attrs_stream\n", + " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", + " )\n", + "\n", + " return sorted(\n", + " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", + " key=itemgetter(\"aymurai_label\", \"text\"),\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "ccbe21f4", + "metadata": {}, + "source": [ + "## CanonicalEntity extraction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e2a8113", + "metadata": {}, + "outputs": [], + "source": [ + "# Function to get chat response from the model\n", + "def get_chat_response(\n", + " user_prompt: str,\n", + " model: str = \"gpt-oss:20b\",\n", + " system_prompt: str = \"Sos un asistente jurídico que resume sin inventar nada.\",\n", + " options: dict = {\"temperature\": 0},\n", + " format: JsonSchemaValue | None = None,\n", + ") -> ChatResponse:\n", + " \"\"\"\n", + " Get chat response from the model.\n", + "\n", + " Args:\n", + " user_prompt (str): The prompt from the user.\n", + " model (str, optional): The model to use. Defaults to \"gpt-oss:20b\".\n", + " system_prompt (str, optional): The system prompt. Defaults to \"Sos un asistente jurídico que resume sin inventar nada.\".\n", + " options (dict, optional): The options for the chat. Defaults to {\"temperature\": 0}.\n", + " format (JsonSchemaValue | None, optional): The format for the response. Defaults to None.\n", + "\n", + " Returns:\n", + " ChatResponse: The response from the chat.\n", + " \"\"\"\n", + " response = ollama.chat(\n", + " model=model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options=options,\n", + " format=format,\n", + " )\n", + "\n", + " return response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd025617", + "metadata": {}, + "outputs": [], + "source": [ + "# Sanity check\n", + "get_chat_response(\"hola, ¿cómo estás?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09631e51", + "metadata": {}, + "outputs": [], + "source": [ + "class CanonicalEntities(BaseModel):\n", + " canonical_entities: list[CanonicalEntity]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c7ec7c6", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt = \"\"\"\n", + "Eres un asistente especializado en anonimización de sentencias judiciales.\n", + "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", + "Una **entidad canónica** es la representación única de una entidad real.\n", + "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", + "\n", + "# Reglas\n", + "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", + "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", + "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", + "- Cada entidad canónica debe incluir:\n", + " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", + " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", + " - `aliases` (todas las menciones textuales relevantes).\n", + " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", + "\n", + "# Notas\n", + "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", + "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + "\n", + "# Ejemplo\n", + "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", + "A: ```json\n", + "[\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Laura Beatriz Gómez\",\n", + " \"aliases\": [\"Laura Beatriz Gómez\"],\n", + " \"attributes\": {\"role\": \"Denunciante\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"42987654\",\n", + " \"aliases\": [\"42.987.654\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DIRECCION\",\n", + " \"canonical_text\": \"calle Falsa 123\",\n", + " \"aliases\": [\"calle Falsa 123\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", + " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", + " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", + " \"attributes\": {\"role\": \"Denunciado\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"27654321\",\n", + " \"aliases\": [\"27.654.321\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"calle Real 789\",\n", + " \"aliases\": [\"calle Real 789\"]\n", + " }\n", + "]\n", + "```\n", + "\"\"\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6994e3c3", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template = \"\"\"\n", + "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", + "\n", + "# Documento\n", + "{document_text}\n", + "\n", + "# Menciones de entidades detectadas por el NER\n", + "{ner_output_json}\n", + "\n", + "# Instrucciones\n", + "1. Evalúa cada mención listada. Si representa una entidad real, inclúyela en la lista de aliases de alguna entidad canónica.\n", + "2. No omitas entidades válidas, alias con iniciales ni variantes abreviadas.\n", + "3. Solo fusiona menciones cuando exista evidencia clara de que se refieren a la misma entidad.\n", + "4. Normaliza canonical_text; mantén los alias tal como aparecen.\n", + "5. Utiliza attributes para indicar roles (p. ej. {{\"role\": \"Denunciante\"}}) o aclaraciones de desambiguación.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "349fa489", + "metadata": {}, + "outputs": [], + "source": [ + "def extract_canonical_entities(\n", + " doc_path: str, model: str = \"phi4:14b\"\n", + ") -> CanonicalEntities:\n", + " \"\"\"\n", + " Extract canonical entities from a document.\n", + "\n", + " Args:\n", + " doc_path (str): The path to the document.\n", + " model (str, optional): The model to use for extraction. Defaults to \"phi4:14b\".\n", + "\n", + " Raises:\n", + " ValueError: If the document is empty or not found.\n", + " ValueError: If the document summary is empty or not found.\n", + "\n", + " Returns:\n", + " CanonicalEntities: The extracted canonical entities.\n", + " \"\"\"\n", + " # Extract document\n", + " session = requests.Session()\n", + " document = call_extraction_api(session, Path(doc_path))\n", + " document = document.get(\"detail\", {}).get(\"document\")\n", + "\n", + " if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")\n", + "\n", + " # Get NER predictions\n", + " ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + " parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", + " ner_output_json = get_pretty(parsed_ner_labels)\n", + "\n", + " # Prepare user prompt\n", + " user_prompt = user_prompt_template.format(\n", + " document_text=\"\\n\".join(document).strip(),\n", + " ner_output_json=ner_output_json,\n", + " )\n", + "\n", + " # Get chat response\n", + " response = get_chat_response(\n", + " user_prompt=user_prompt,\n", + " model=model,\n", + " system_prompt=system_prompt,\n", + " format=CanonicalEntities.model_json_schema(),\n", + " )\n", + "\n", + " # Parse canonical entities from response\n", + " canonical_entities = [\n", + " output for output in json.loads(response.message.content)[\"canonical_entities\"]\n", + " ]\n", + "\n", + " canonical_entities = [\n", + " CanonicalEntity.model_validate(canonical_entity)\n", + " for canonical_entity in canonical_entities\n", + " ]\n", + "\n", + " return canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52c14551", + "metadata": {}, + "outputs": [], + "source": [ + "for doc_path in documents:\n", + " print(f\"Processing document: {doc_path}\")\n", + "\n", + " try:\n", + " canonical_entities = extract_canonical_entities(doc_path)\n", + " print(f\"Extracted {len(canonical_entities)} canonical entities.\")\n", + "\n", + " target_filename = re.sub(\n", + " r\"\\s+\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", + " )\n", + " target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)\n", + " save_json(\n", + " [\n", + " canonical_entity.model_dump()\n", + " | {\"entity_id\": canonical_entity.entity_id.hex}\n", + " for canonical_entity in canonical_entities\n", + " ],\n", + " f\"entities-to-review/{target_filename}-canonical-entities.json\",\n", + " )\n", + "\n", + " except Exception as e:\n", + " print(f\"Error processing document {doc_path}: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f734b642", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 444194bbfbb1534fe3c10e4239059ab199b4b5bc Mon Sep 17 00:00:00 2001 From: jansaldo Date: Tue, 18 Nov 2025 16:06:34 +0000 Subject: [PATCH 008/104] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20dependenc?= =?UTF-8?q?ies:=20langextract=20to=201.1.0=20and=20ollama=20to=200.6.1;=20?= =?UTF-8?q?add=20openai=20extra=20for=20langextract?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 4 +- uv.lock | 186 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 175 insertions(+), 15 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5e2711b4..0bd35304 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -90,8 +90,8 @@ dependencies = [ "pymupdf4llm>=0.0.17", "pypandoc>=1.15", "python-docx>=1.2.0", - "langextract==1.0.8", - "ollama==0.6.0", + "langextract[openai]==1.1.0", + "ollama==0.6.1", ] [project.urls] diff --git a/uv.lock b/uv.lock index d7646eee..7f198f0d 100644 --- a/uv.lock +++ b/uv.lock @@ -255,7 +255,7 @@ wheels = [ [[package]] name = "aymurai" -version = "1.1.13.dev5" +version = "1.1.13.dev16" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -269,7 +269,7 @@ dependencies = [ { name = "gdown" }, { name = "jiwer" }, { name = "joblib" }, - { name = "langextract" }, + { name = "langextract", extra = ["openai"] }, { name = "more-itertools" }, { name = "numpy" }, { name = "odfpy" }, @@ -325,11 +325,11 @@ requires-dist = [ { name = "gdown", specifier = "==4.6.0" }, { name = "jiwer", specifier = "==3.0.5" }, { name = "joblib", specifier = ">=1.4.2" }, - { name = "langextract", specifier = "==1.0.8" }, + { name = "langextract", extras = ["openai"], specifier = "==1.1.0" }, { name = "more-itertools", specifier = ">=10.5.0" }, { name = "numpy", specifier = "<2.0.0" }, { name = "odfpy", specifier = ">=1.4.1" }, - { name = "ollama", specifier = "==0.6.0" }, + { name = "ollama", specifier = "==0.6.1" }, { name = "psutil", specifier = "==6.1.0" }, { name = "pydantic", specifier = ">=2.10.4" }, { name = "pydantic-settings", specifier = ">=2.7.0" }, @@ -721,6 +721,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, ] +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, +] + [[package]] name = "dnspython" version = "2.7.0" @@ -1059,6 +1068,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168 }, ] +[[package]] +name = "google-api-core" +version = "2.28.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "googleapis-common-protos" }, + { name = "proto-plus" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706 }, +] + [[package]] name = "google-auth" version = "2.38.0" @@ -1086,9 +1111,55 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b1/0e/0636cc1448a7abc444fb1b3a63655e294e0d2d49092dc3de05241be6d43c/google_auth_oauthlib-0.4.6-py2.py3-none-any.whl", hash = "sha256:3f2a6e802eebbb6fb736a370fbf3b055edcb6b52878bf2f26330b5e041316c73", size = 18306 }, ] +[[package]] +name = "google-cloud-core" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469 }, +] + +[[package]] +name = "google-cloud-storage" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-api-core" }, + { name = "google-auth" }, + { name = "google-cloud-core" }, + { name = "google-crc32c" }, + { name = "google-resumable-media" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/cd/7e112cf025b2b591067b599e4bfe965df0c12b0cc0afdb5556469bff126d/google_cloud_storage-3.6.0.tar.gz", hash = "sha256:29cc6b9a6c0fc9cdad071e375d540a5a50fbc9a7fad8300fa02fb904f6fe2ca2", size = 17251072 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/ef/3b57bf617ee0c79450c1ff211d1eb888db8fc1050ac74b3e52cc6ed86e63/google_cloud_storage-3.6.0-py3-none-any.whl", hash = "sha256:5decbdddd63b7d1fc3e266a393ad6453d2e27d172bd982b1e2f15481668db097", size = 299039 }, +] + +[[package]] +name = "google-crc32c" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/ae/87802e6d9f9d69adfaedfcfd599266bf386a54d0be058b532d04c794f76d/google_crc32c-1.7.1.tar.gz", hash = "sha256:2bff2305f98846f3e825dbeec9ee406f89da7962accdb29356e4eadc251bd472", size = 14495 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/69/b1b05cf415df0d86691d6a8b4b7e60ab3a6fb6efb783ee5cd3ed1382bfd3/google_crc32c-1.7.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:b07d48faf8292b4db7c3d64ab86f950c2e94e93a11fd47271c28ba458e4a0d76", size = 30467 }, + { url = "https://files.pythonhosted.org/packages/44/3d/92f8928ecd671bd5b071756596971c79d252d09b835cdca5a44177fa87aa/google_crc32c-1.7.1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7cc81b3a2fbd932a4313eb53cc7d9dde424088ca3a0337160f35d91826880c1d", size = 30311 }, + { url = "https://files.pythonhosted.org/packages/33/42/c2d15a73df79d45ed6b430b9e801d0bd8e28ac139a9012d7d58af50a385d/google_crc32c-1.7.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c67ca0a1f5b56162951a9dae987988679a7db682d6f97ce0f6381ebf0fbea4c", size = 37889 }, + { url = "https://files.pythonhosted.org/packages/57/ea/ac59c86a3c694afd117bb669bde32aaf17d0de4305d01d706495f09cbf19/google_crc32c-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc5319db92daa516b653600794d5b9f9439a9a121f3e162f94b0e1891c7933cb", size = 33028 }, + { url = "https://files.pythonhosted.org/packages/60/44/87e77e8476767a4a93f6cf271157c6d948eacec63688c093580af13b04be/google_crc32c-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcdf5a64adb747610140572ed18d011896e3b9ae5195f2514b7ff678c80f1603", size = 38026 }, + { url = "https://files.pythonhosted.org/packages/c8/bf/21ac7bb305cd7c1a6de9c52f71db0868e104a5b573a4977cd9d0ff830f82/google_crc32c-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:754561c6c66e89d55754106739e22fdaa93fafa8da7221b29c8b8e8270c6ec8a", size = 33476 }, + { url = "https://files.pythonhosted.org/packages/0b/43/31e57ce04530794917dfe25243860ec141de9fadf4aa9783dffe7dac7c39/google_crc32c-1.7.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8e9afc74168b0b2232fb32dd202c93e46b7d5e4bf03e66ba5dc273bb3559589", size = 28242 }, + { url = "https://files.pythonhosted.org/packages/eb/f3/8b84cd4e0ad111e63e30eb89453f8dd308e3ad36f42305cf8c202461cdf0/google_crc32c-1.7.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa8136cc14dd27f34a3221c0f16fd42d8a40e4778273e61a3c19aedaa44daf6b", size = 28049 }, +] + [[package]] name = "google-genai" -version = "1.31.0" +version = "1.51.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1100,9 +1171,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e0/1b/da30fa6e2966942d7028a58eb7aa7d04544dcc3aa66194365b2e0adac570/google_genai-1.31.0.tar.gz", hash = "sha256:8572b47aa684357c3e5e10d290ec772c65414114939e3ad2955203e27cd2fcbc", size = 233482 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/1c/29245699c7c274ed5709b33b6a5192af2d57da5da3d2f189f222d1895336/google_genai-1.51.0.tar.gz", hash = "sha256:596c1ec964b70fec17a6ccfe6ee4edede31022584e8b1d33371d93037c4001b1", size = 258060 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/27/1525bc9cbec58660f0842ebcbfe910a1dde908c2672373804879666e0bb8/google_genai-1.31.0-py3-none-any.whl", hash = "sha256:5c6959bcf862714e8ed0922db3aaf41885bacf6318751b3421bf1e459f78892f", size = 231876 }, + { url = "https://files.pythonhosted.org/packages/c6/28/0185dcda66f1994171067cfdb0e44a166450239d5b11b3a8a281dd2da459/google_genai-1.51.0-py3-none-any.whl", hash = "sha256:bfb7d0c6ba48ba9bda539f0d5e69dad827d8735a8b1e4703bafa0a2945d293e1", size = 260483 }, ] [[package]] @@ -1117,6 +1188,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a3/de/c648ef6835192e6e2cc03f40b19eeda4382c49b5bafb43d88b931c4c74ac/google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed", size = 57471 }, ] +[[package]] +name = "google-resumable-media" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-crc32c" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340 }, +] + +[[package]] +name = "googleapis-common-protos" +version = "1.63.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4f/bc/cb5c74fca58d9c37bc621642e2c2b19c004d078b472d49fb03d9fa8ffeef/googleapis-common-protos-1.63.1.tar.gz", hash = "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a", size = 121632 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/87/1608d23bb9879694579fff5dc56d60e3d48e012fd08670f140cf82f6cf26/googleapis_common_protos-1.63.1-py2.py3-none-any.whl", hash = "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877", size = 229151 }, +] + [[package]] name = "greenlet" version = "3.1.1" @@ -1386,6 +1481,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, ] +[[package]] +name = "jiter" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652 }, + { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829 }, + { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568 }, + { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052 }, + { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585 }, + { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541 }, + { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423 }, + { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958 }, + { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084 }, + { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054 }, + { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368 }, + { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847 }, + { url = "https://files.pythonhosted.org/packages/fe/54/5339ef1ecaa881c6948669956567a64d2670941925f245c434f494ffb0e5/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8", size = 311144 }, + { url = "https://files.pythonhosted.org/packages/27/74/3446c652bffbd5e81ab354e388b1b5fc1d20daac34ee0ed11ff096b1b01a/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3", size = 305877 }, + { url = "https://files.pythonhosted.org/packages/a1/f4/ed76ef9043450f57aac2d4fbeb27175aa0eb9c38f833be6ef6379b3b9a86/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e", size = 340419 }, + { url = "https://files.pythonhosted.org/packages/21/01/857d4608f5edb0664aa791a3d45702e1a5bcfff9934da74035e7b9803846/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d", size = 347212 }, + { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974 }, + { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233 }, + { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537 }, + { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110 }, +] + [[package]] name = "jiwer" version = "3.0.5" @@ -1747,13 +1870,14 @@ sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2 [[package]] name = "langextract" -version = "1.0.8" +version = "1.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "absl-py" }, { name = "aiohttp" }, { name = "async-timeout" }, { name = "exceptiongroup" }, + { name = "google-cloud-storage" }, { name = "google-genai" }, { name = "ml-collections" }, { name = "more-itertools" }, @@ -1766,9 +1890,14 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/d8/95666e87f02f3c83420ed030f14085c9c6acd986da336b514443dee6d649/langextract-1.0.8.tar.gz", hash = "sha256:dc4c65058969486faf119d2c0cd82a12ccdff1d9785212b96fd67c52cbbe74c7", size = 78418 } +sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/70/f5eba44ee7a8c8fe651b14585618a4ca600dd41a6fdc156b4377f4f53bb1/langextract-1.0.8-py3-none-any.whl", hash = "sha256:17b5985154ec1d58f5dd8fe4d6135d0cd4b4d650a075f8cf36eca705e2459263", size = 84987 }, + { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592 }, +] + +[package.optional-dependencies] +openai = [ + { name = "openai" }, ] [[package]] @@ -2346,15 +2475,34 @@ wheels = [ [[package]] name = "ollama" -version = "0.6.0" +version = "0.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/47/f9ee32467fe92744474a8c72e138113f3b529fc266eea76abfdec9a33f3b/ollama-0.6.0.tar.gz", hash = "sha256:da2b2d846b5944cfbcee1ca1e6ee0585f6c9d45a2fe9467cbcd096a37383da2f", size = 50811 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/c1/edc9f41b425ca40b26b7c104c5f6841a4537bb2552bfa6ca66e81405bb95/ollama-0.6.0-py3-none-any.whl", hash = "sha256:534511b3ccea2dff419ae06c3b58d7f217c55be7897c8ce5868dfb6b219cf7a0", size = 14130 }, + { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354 }, +] + +[[package]] +name = "openai" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d5/e4/42591e356f1d53c568418dc7e30dcda7be31dd5a4d570bca22acb0525862/openai-2.8.1.tar.gz", hash = "sha256:cb1b79eef6e809f6da326a7ef6038719e35aa944c42d081807bfa1be8060f15f", size = 602490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/4f/dbc0c124c40cb390508a82770fb9f6e3ed162560181a85089191a851c59a/openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463", size = 1022688 }, ] [[package]] @@ -2573,6 +2721,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 }, ] +[[package]] +name = "proto-plus" +version = "1.26.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163 }, +] + [[package]] name = "protobuf" version = "3.19.6" From 8b13aad4b71b0b397ab36af0e0d3be71d8f465f8 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Tue, 18 Nov 2025 16:06:51 +0000 Subject: [PATCH 009/104] =?UTF-8?q?=F0=9F=93=9D=20=20Integrate=20custom=20?= =?UTF-8?q?OpenAI=20model=20for=20extraction=20and=20remove=20failing=20em?= =?UTF-8?q?pty=20example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anonymization/05-langextract.ipynb | 63 ++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/notebooks/experiments/anonymization/05-langextract.ipynb b/notebooks/experiments/anonymization/05-langextract.ipynb index c7035718..df2b0646 100644 --- a/notebooks/experiments/anonymization/05-langextract.ipynb +++ b/notebooks/experiments/anonymization/05-langextract.ipynb @@ -208,10 +208,6 @@ " ),\n", " ],\n", " ),\n", - " lx.data.ExampleData(\n", - " text=\"VISTOS: Que a fin de ordenar la marcha del proceso, se fija audiencia preliminar. No se consignan números de expediente, CUIJ ni domicilios en el presente proveído.\",\n", - " extractions=[], # ejemplo negativo: desalienta devolver clases ausentes\n", - " ),\n", "]" ] }, @@ -274,7 +270,60 @@ { "cell_type": "code", "execution_count": null, - "id": "82279f15", + "id": "9064a3b6", + "metadata": {}, + "outputs": [], + "source": [ + "# Custom OpenAI model integration\n", + "# Support for Ollama gpt-oss:20b #116\n", + "# https://github.com/google/langextract/issues/116#issuecomment-3209618602\n", + "from langextract.providers.openai import OpenAILanguageModel\n", + "\n", + "\n", + "# Custom OpenAI model class to handle Ollama gpt-oss:20b\n", + "class CustomOpenAIModel(OpenAILanguageModel):\n", + " def _process_single_prompt(self, prompt, config):\n", + " api_params = {\n", + " \"model\": self.model_id,\n", + " \"messages\": [{\"role\": \"user\", \"content\": prompt}],\n", + " \"temperature\": 0.1,\n", + " \"max_tokens\": 2000,\n", + " }\n", + "\n", + " try:\n", + " response = self._client.chat.completions.create(**api_params)\n", + " output_text = response.choices[0].message.content\n", + " return lx.inference.ScoredOutput(score=1.0, output=output_text)\n", + "\n", + " except Exception as e:\n", + " raise lx.exceptions.InferenceRuntimeError(\n", + " f\"Custom OpenAI API error: {str(e)}\", original=e\n", + " ) from e\n", + "\n", + "\n", + "# Instantiate the custom model\n", + "custom_model = CustomOpenAIModel(\n", + " model_id=\"gpt-oss:20b\",\n", + " api_key=\"dummy\",\n", + " base_url=\"http://localhost:11434/v1\",\n", + ")\n", + "\n", + "# Run extraction with the custom model\n", + "result = lx.extract(\n", + " text_or_documents=text,\n", + " prompt_description=prompt,\n", + " examples=examples,\n", + " model=custom_model,\n", + " fence_output=False,\n", + " use_schema_constraints=False,\n", + ")\n", + "pprint(result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e905e794", "metadata": {}, "outputs": [], "source": [] @@ -282,7 +331,7 @@ ], "metadata": { "kernelspec": { - "display_name": "aymurai", + "display_name": "aymurai (3.10.19)", "language": "python", "name": "python3" }, @@ -296,7 +345,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.18" + "version": "3.10.19" } }, "nbformat": 4, From 68eae78c29fa3ef67c2893c7ad0493c24e33d53f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:06:56 -0300 Subject: [PATCH 010/104] =?UTF-8?q?=F0=9F=93=9D=20Update=20error=20message?= =?UTF-8?q?=20format=20in=20json=5Fserial=20function=20for=20better=20read?= =?UTF-8?q?ability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- aymurai/utils/json_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aymurai/utils/json_data.py b/aymurai/utils/json_data.py index ad43164e..f07e4e9f 100644 --- a/aymurai/utils/json_data.py +++ b/aymurai/utils/json_data.py @@ -20,7 +20,7 @@ def json_serial(obj: Any) -> str: """ # noqa: E501 if isinstance(obj, (datetime, date)): return obj.isoformat() - raise TypeError("Type %s not serializable" % type(obj)) + raise TypeError(f"Type {type(obj)} not serializable") def get_pretty(obj: dict | list[Any]) -> str: From 45176013d64b77d62019bbe72bbf3fa8c0613543 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:11:11 -0300 Subject: [PATCH 011/104] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Inline=20immediate?= =?UTF-8?q?=20return=20in=20get=5Fpretty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> --- aymurai/utils/json_data.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aymurai/utils/json_data.py b/aymurai/utils/json_data.py index f07e4e9f..58fbb2d4 100644 --- a/aymurai/utils/json_data.py +++ b/aymurai/utils/json_data.py @@ -33,8 +33,7 @@ def get_pretty(obj: dict | list[Any]) -> str: Returns: str: the pretty json string. """ - pretty_json_str = json.dumps(obj, indent=4, ensure_ascii=False, default=json_serial) - return pretty_json_str + return json.dumps(obj, indent=4, ensure_ascii=False, default=json_serial) def save_json(json_data: dict | list[dict], file_path: str) -> None: From e96d8e41ef871736f290bb6c8e9c00e5e29e5a34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Tue, 18 Nov 2025 14:14:09 -0300 Subject: [PATCH 012/104] =?UTF-8?q?=F0=9F=90=9B=20Fix:=20Use=20json=5Fseri?= =?UTF-8?q?al=20in=20save=5Fjson?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- aymurai/utils/json_data.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aymurai/utils/json_data.py b/aymurai/utils/json_data.py index 58fbb2d4..c8122114 100644 --- a/aymurai/utils/json_data.py +++ b/aymurai/utils/json_data.py @@ -46,7 +46,7 @@ def save_json(json_data: dict | list[dict], file_path: str) -> None: file_path (str): The path to the file where the JSON data will be saved. """ with open(file_path, "w") as f: - f.write(json.dumps(json_data, indent=4, ensure_ascii=False)) + f.write(json.dumps(json_data, indent=4, ensure_ascii=False, default=json_serial)) def load_json(json_file_path: str) -> dict | list[dict]: From c45a86348a89f6011756cc6316c04630b1318669 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Tue, 18 Nov 2025 17:17:46 +0000 Subject: [PATCH 013/104] =?UTF-8?q?=F0=9F=8E=A8=20Format=20json.dumps=20ca?= =?UTF-8?q?ll=20in=20save=5Fjson=20for=20improved=20readability?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/utils/json_data.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/aymurai/utils/json_data.py b/aymurai/utils/json_data.py index c8122114..7fda48d0 100644 --- a/aymurai/utils/json_data.py +++ b/aymurai/utils/json_data.py @@ -46,7 +46,9 @@ def save_json(json_data: dict | list[dict], file_path: str) -> None: file_path (str): The path to the file where the JSON data will be saved. """ with open(file_path, "w") as f: - f.write(json.dumps(json_data, indent=4, ensure_ascii=False, default=json_serial)) + f.write( + json.dumps(json_data, indent=4, ensure_ascii=False, default=json_serial) + ) def load_json(json_file_path: str) -> dict | list[dict]: From 401a08b2ebaa0b2e40a34590b4976f9da5c70150 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:57:56 -0300 Subject: [PATCH 014/104] Feature/ollama service (#59) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Add GPU-enabled Ollama service to compose stack * 🔧 Add Make targets for managing Ollama service and models * 🔧 Add launch configuration and task for starting Ollama service --- .vscode/launch.json | 3 ++- .vscode/tasks.json | 19 +++++++++++++++++++ Makefile | 34 ++++++++++++++++++++++++++++++++++ docker-compose.yml | 23 +++++++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 00fd92d6..d6348f6f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,7 +19,8 @@ ], "subProcess": false, "envFile": "${workspaceFolder}/.env", - "python": "${workspaceFolder}/.venv/bin/python" + "python": "${workspaceFolder}/.venv/bin/python", + "preLaunchTask": "Start Ollama service" }, ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..6283a7ed --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,19 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Start Ollama service", + "type": "shell", + "command": "make", + "args": [ + "ollama-up" + ], + "options": { + "cwd": "${workspaceFolder}" + }, + "problemMatcher": [] + } + ] +} \ No newline at end of file diff --git a/Makefile b/Makefile index 64e27084..2f8a00e5 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,40 @@ api-full-run: api-full-pull: docker compose pull aymurai-api-full +ollama-up: + docker compose up -d --no-recreate ollama + +ollama-stop: + docker compose stop ollama + +ollama-restart: + docker compose restart ollama + +ollama-pull: +ifndef MODEL + $(error MODEL variable is required, e.g. make ollama-pull MODEL=llama3) +endif + docker compose up -d --no-recreate ollama + docker compose exec ollama ollama pull $(MODEL) + +ollama-run: +ifndef MODEL + $(error MODEL variable is required, e.g. make ollama-run MODEL=llama3) +endif + docker compose up -d --no-recreate ollama + docker compose exec -it ollama ollama run $(MODEL) + +ollama-list: + docker compose up -d --no-recreate ollama + docker compose exec ollama ollama list + +ollama-rm: +ifndef MODEL + $(error MODEL variable is required, e.g. make ollama-rm MODEL=llama3) +endif + docker compose up -d --no-recreate ollama + docker compose exec ollama ollama rm $(MODEL) + stress-test: locust -f locustfile.py --host http://localhost:8899 diff --git a/docker-compose.yml b/docker-compose.yml index 3ce7c536..b9f2ab12 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,6 +3,8 @@ services: image: ghcr.io/aymurai/api:latest ports: - "8899:8899" + depends_on: + - ollama build: context: . dockerfile: ./docker/api/Dockerfile @@ -17,6 +19,8 @@ services: image: ghcr.io/aymurai/api:full ports: - "8899:8899" + depends_on: + - ollama build: context: . dockerfile: ./docker/api/Dockerfile @@ -27,3 +31,22 @@ services: limits: memory: 4g cpus: "4.0" + + ollama: + image: ollama/ollama + container_name: ollama + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + ports: + - "11434:11434" + volumes: + - ollama:/root/.ollama + restart: always + +volumes: + ollama: From 29d83280f3c56cd5a551339a93f79899fe2a145d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Thu, 20 Nov 2025 20:13:47 -0300 Subject: [PATCH 015/104] Feature/llm providers (#60) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Add GPU-enabled Ollama service to compose stack * 🔧 Add Make targets for managing Ollama service and models * 🔧 Add launch configuration and task for starting Ollama service * ✨ Implement LLM providers module with Ollama adapter and shared abstractions * ✅ Add unit tests for LLM providers including DummyProvider and OllamaLLMProvider * 📝 Document Ollama provider usage via notebook demo * 🐛 Fix tokenizer encoding by removing unnecessary special tokens flag * ♻️ Refactor chunk handling in LLMProvider to use _append_chunk method for consistency and improved readability * ✨ Enhance Ollama provider docs and DRY response building for sync/async calls * ♻️ Refactor OllamaLLMProvider to reuse AsyncClient instance for improved efficiency * 📝 Add async examples to OllamaLLMProvider notebook * ✅ Add async coverage for OllamaLLMProvider and tighten chunking tests * ♻️ Refactor OllamaLLMProvider to remove async client caching and streamline client instantiation --- aymurai/llm_providers/__init__.py | 9 + aymurai/llm_providers/ollama_provider.py | 254 +++++++++++++++++ aymurai/llm_providers/provider.py | 256 ++++++++++++++++++ .../llm-providers/01-ollama-provider.ipynb | 200 ++++++++++++++ test/llm_providers/__init__.py | 0 test/llm_providers/test_providers.py | 148 ++++++++++ 6 files changed, 867 insertions(+) create mode 100644 aymurai/llm_providers/__init__.py create mode 100644 aymurai/llm_providers/ollama_provider.py create mode 100644 aymurai/llm_providers/provider.py create mode 100644 notebooks/experiments/llm-providers/01-ollama-provider.ipynb create mode 100644 test/llm_providers/__init__.py create mode 100644 test/llm_providers/test_providers.py diff --git a/aymurai/llm_providers/__init__.py b/aymurai/llm_providers/__init__.py new file mode 100644 index 00000000..c63aaaac --- /dev/null +++ b/aymurai/llm_providers/__init__.py @@ -0,0 +1,9 @@ +from aymurai.llm_providers.ollama_provider import OllamaLLMProvider +from aymurai.llm_providers.provider import DocumentChunk, LLMProvider, LLMResponse + +__all__ = [ + "DocumentChunk", + "LLMProvider", + "LLMResponse", + "OllamaLLMProvider", +] diff --git a/aymurai/llm_providers/ollama_provider.py b/aymurai/llm_providers/ollama_provider.py new file mode 100644 index 00000000..b3e9ef80 --- /dev/null +++ b/aymurai/llm_providers/ollama_provider.py @@ -0,0 +1,254 @@ +from __future__ import annotations + +from typing import Any, AsyncIterator, Iterator + +import ollama +from ollama import AsyncClient + +from aymurai.llm_providers.provider import LLMProvider, LLMResponse + + +class OllamaLLMProvider(LLMProvider): + """Adapter that wraps `ollama.chat` preserving the common interface.""" + + def __init__( + self, + model: str, + *, + system_prompt: str | None = None, + keep_alive: int | str | None = None, + **kwargs, + ) -> None: + super().__init__(model=model, **kwargs) + self.system_prompt = system_prompt + self.keep_alive = keep_alive + + def generate( + self, + prompt: str | None = None, + *, + messages: list[dict[str, str]] | None = None, + **kwargs, + ) -> LLMResponse: + """ + Generate text using the configured Ollama model. + + Args: + prompt (str | None, optional): Optional single prompt string to be transformed into a chat message. Defaults to None. + messages (list[dict[str, str]] | None, optional): Optional list of pre-formatted chat messages to send. Defaults to None. + + Returns: + LLMResponse: Response containing the generated text, metadata about the request, and the raw payload. + """ + # Build the message payload + payload = self._build_messages(prompt=prompt, messages=messages) + + # Call ollama.chat + response = ollama.chat( + model=self.model_name, + messages=payload, + keep_alive=self.keep_alive, + **kwargs, + ) + + return self._build_llm_response( + response, + extra_metadata={ + "eval_count": response.get("eval_count"), + "eval_duration": response.get("eval_duration"), + }, + ) + + async def async_generate( + self, + prompt: str | None = None, + *, + messages: list[dict[str, str]] | None = None, + **kwargs, + ) -> LLMResponse: + """ + Asynchronously generate text using the configured Ollama model. + + Args: + prompt (str | None): Optional single prompt string to be transformed into a chat message. Defaults to None. + messages (list[dict[str, str]] | None): Optional list of pre-formatted chat messages to send. Defaults to None. + **kwargs: Additional keyword arguments forwarded to the Ollama AsyncClient chat endpoint. + + Returns: + LLMResponse: Response containing the generated text, metadata about the request, and the raw payload. + """ + # Build the message payload + payload = self._build_messages(prompt=prompt, messages=messages) + + # Call ollama.chat asynchronously + client = self._get_async_client() + response = await client.chat( + model=self.model_name, + messages=payload, + keep_alive=self.keep_alive, + **kwargs, + ) + + return self._build_llm_response( + response, + extra_metadata={ + "eval_count": response.get("eval_count"), + "eval_duration": response.get("eval_duration"), + }, + ) + + def stream( + self, + prompt: str | None = None, + *, + messages: list[dict[str, str]] | None = None, + **kwargs, + ) -> Iterator[LLMResponse]: + """ + Stream the response from the model using the provided prompt or messages. + + Args: + prompt (str | None, optional): Optional single prompt string to be transformed into a chat message. Defaults to None. + messages (list[dict[str, str]] | None, optional): Optional list of pre-formatted chat messages to send. Defaults to None. + + Yields: + Iterator[LLMResponse]: Response chunks containing generated text, metadata, and raw payloads. + """ + # Build the message payload + payload = self._build_messages(prompt=prompt, messages=messages) + + # Call ollama.chat with streaming enabled + stream_kwargs = {**kwargs, "stream": True} + + # Iterate over the streamed responses + for chunk in ollama.chat( + model=self.model_name, + messages=payload, + keep_alive=self.keep_alive, + **stream_kwargs, + ): + yield self._build_stream_response(chunk) + + async def async_stream( + self, + prompt: str | None = None, + *, + messages: list[dict[str, str]] | None = None, + **kwargs, + ) -> AsyncIterator[LLMResponse]: + """ + Asynchronously stream the response from the model using the provided prompt or messages. + + Args: + prompt (str | None, optional): Optional single prompt string to be transformed into a chat message. Defaults to None. + messages (list[dict[str, str]] | None, optional): Optional list of pre-formatted chat messages to send. Defaults to None. + + Yields: + AsyncIterator[LLMResponse]: Asynchronous iterator yielding response chunks containing generated text, metadata, and raw payloads. + """ + # Build the message payload + payload = self._build_messages(prompt=prompt, messages=messages) + + # Call ollama.chat with streaming enabled + stream_kwargs = {**kwargs, "stream": True} + + # Iterate over the streamed responses asynchronously + client = self._get_async_client() + stream = await client.chat( + model=self.model_name, + messages=payload, + keep_alive=self.keep_alive, + **stream_kwargs, + ) + async for chunk in stream: + yield self._build_stream_response(chunk) + + def _build_messages( + self, + *, + prompt: str | None, + messages: list[dict[str, str]] | None = None, + ) -> list[dict[str, str]]: + """ + Build the message payload for `ollama.chat`. + + Args: + prompt (str | None): The user prompt to be sent to the model. + messages (list[dict[str, str]] | None, optional): A list of message dictionaries to be sent to the model. + Defaults to None. + + Raises: + ValueError: If neither prompt nor messages are provided. + + Returns: + list[dict[str, str]]: The message payload to be sent to `ollama.chat`. + """ + if messages is not None: + return list(messages) + + if prompt is None: + raise ValueError("Either prompt or messages must be provided.") + + payload = [] + + if self.system_prompt: + payload.append({"role": "system", "content": self.system_prompt}) + + payload.append({"role": "user", "content": prompt}) + + return payload + + def _get_async_client(self) -> AsyncClient: + """ + Create a fresh AsyncClient instance. + + Returns: + AsyncClient: A new AsyncClient instance for making asynchronous requests. + """ + return AsyncClient() + + def _build_llm_response( + self, response: dict[str, Any], *, extra_metadata: dict[str, Any] | None = None + ) -> LLMResponse: + """ + Build an LLMResponse with consistent metadata from the response payload. + + Args: + response (dict[str, Any]): The response payload from the Ollama model. + extra_metadata (dict[str, Any] | None, optional): Additional metadata to include in the response. Defaults to None. + + Returns: + LLMResponse: The constructed LLMResponse object containing text, metadata, and raw response. + """ + # Extract the generated text + text = response.get("message", {}).get("content", "") + + # Build metadata + metadata = { + "model": self.model_name, + "provider": "ollama", + } + + # Include any extra metadata + if extra_metadata: + metadata.update(extra_metadata) + + return LLMResponse(text=text, metadata=metadata, raw=response) + + def _build_stream_response(self, chunk: dict[str, Any]) -> LLMResponse: + """ + Build stream responses with consistent metadata from chunk payloads. + + Args: + chunk (dict[str, Any]): The chunk payload from the Ollama model. + + Returns: + LLMResponse: The constructed LLMResponse object containing text, metadata, and raw chunk. + """ + return self._build_llm_response( + chunk, + extra_metadata={"done": chunk.get("done")}, + ) + + +__all__ = ["OllamaLLMProvider"] diff --git a/aymurai/llm_providers/provider.py b/aymurai/llm_providers/provider.py new file mode 100644 index 00000000..89e3750d --- /dev/null +++ b/aymurai/llm_providers/provider.py @@ -0,0 +1,256 @@ +from __future__ import annotations + +import abc +from typing import Any, Sequence + +from pydantic import BaseModel, Field + + +class LLMResponse(BaseModel): + """Standard response wrapper for any LLM provider.""" + + text: str + metadata: dict[str, Any] = Field(default_factory=dict) + raw: Any | None = None + + +class DocumentChunk(BaseModel): + """Represents a chunked portion of a larger document.""" + + text: str + token_count: int + index: int + + +TokenizerType = Any + + +class LLMProvider(abc.ABC): + """Base class with shared utilities for concrete LLM providers.""" + + def __init__( + self, + model: str, + *, + tokenizer: TokenizerType | None = None, + max_context_tokens: int | None = None, + chunk_overlap: int = 0, + ) -> None: + self.model_name = model + self._tokenizer = tokenizer + self.max_context_tokens = max_context_tokens + self.chunk_overlap = max(chunk_overlap, 0) + + @abc.abstractmethod + def generate(self, prompt: str, **kwargs) -> LLMResponse: + """ + Generate a response from the model using the provided prompt. + + Args: + prompt (str): The input prompt to generate a response for. + **kwargs: Additional provider-specific parameters. + + Returns: + LLMResponse: The generated response wrapped in an LLMResponse object. + """ + pass + + @abc.abstractmethod + def stream(self, prompt: str, **kwargs): + """ + Stream the response from the model using the provided prompt. + + Args: + prompt (str): The input prompt to generate a response for. + **kwargs: Additional provider-specific parameters. + + Raises: + NotImplementedError: If the provider does not support streaming. + """ + raise NotImplementedError("This provider does not support streaming.") + + def count_tokens(self, text: str) -> int: + """ + Count the number of tokens in the given text. + + Args: + text (str): The input text to count tokens for. + + Returns: + int: The number of tokens in the input text. + """ + tokens = self._tokenize(text) + return len(tokens) + + def chunk_text( + self, + text: str, + *, + max_tokens: int | None = None, + overlap: int | None = None, + ) -> list[DocumentChunk]: + """ + Chunk text ensuring every piece respects the token budget. + + Args: + text (str): The input text to chunk. + max_tokens (int | None): Optional maximum tokens per chunk. + overlap (int | None): Optional token overlap between chunks. + + Returns: + list[DocumentChunk]: A list of document chunks. + """ + cleaned_text = text.strip() + if not cleaned_text: + return [] + + limit = max_tokens or self.max_context_tokens + if limit is None: + total_tokens = self.count_tokens(cleaned_text) + return [DocumentChunk(text=cleaned_text, token_count=total_tokens, index=0)] + + words = cleaned_text.split() + if not words: + return [] + + chunks = [] + overlap_tokens = overlap if overlap is not None else self.chunk_overlap + current_words = [] + current_tokens = 0 + + for word in words: + if not current_words: + current_words = [word] + current_tokens = self.count_tokens(" ".join(current_words)) + if current_tokens > limit: + self._append_chunk( + chunks=chunks, + text=current_words[0], + token_count=current_tokens, + ) + current_words = [] + current_tokens = 0 + continue + + tentative_words = current_words + [word] + tentative_text = " ".join(tentative_words) + tentative_tokens = self.count_tokens(tentative_text) + + if tentative_tokens <= limit: + current_words = tentative_words + current_tokens = tentative_tokens + continue + + chunk_text = " ".join(current_words) + self._append_chunk( + chunks=chunks, + text=chunk_text, + token_count=current_tokens, + ) + + carry_over = self._overlap_tail(current_words, overlap_tokens) + current_words = carry_over + [word] + current_tokens = self.count_tokens(" ".join(current_words)) + + if current_tokens > limit: + chunk_text = " ".join(current_words) + self._append_chunk( + chunks=chunks, + text=chunk_text, + token_count=current_tokens, + ) + current_words = [] + current_tokens = 0 + + if current_words: + chunk_text = " ".join(current_words) + self._append_chunk( + chunks=chunks, + text=chunk_text, + token_count=current_tokens, + fallback_count=True, + ) + + return chunks + + def _tokenize(self, text: str) -> Sequence[Any]: + """ + Tokenize text using the configured tokenizer or fallback to whitespace. + + Args: + text (str): The input text to tokenize. + + Returns: + Sequence[Any]: The sequence of tokens. + """ + if self._tokenizer is None: + return text.split() + + tokenizer = self._tokenizer + if hasattr(tokenizer, "encode"): + return tokenizer.encode(text) + + if callable(tokenizer): + tokens = tokenizer(text) + if isinstance(tokens, dict): + return tokens.get("input_ids", []) + return tokens + + return text.split() + + def _overlap_tail(self, words: list[str], overlap_tokens: int) -> list[str]: + """ + Get the tail overlap of words based on the token budget. + + Args: + words (list[str]): The list of words to consider for overlap. + overlap_tokens (int): The token budget for the overlap. Must be non-negative. + + Returns: + list[str]: The list of words representing the tail overlap. + """ + assert overlap_tokens >= 0, "`overlap_tokens` must be non-negative." + + if not words or overlap_tokens == 0: + return [] + + tail = [] + + for word in reversed(words): + tail.insert(0, word) + token_budget = self.count_tokens(" ".join(tail)) + if token_budget >= overlap_tokens: + break + + return tail + + def _append_chunk( + self, + *, + chunks: list[DocumentChunk], + text: str, + token_count: int, + fallback_count: bool = False, + ) -> None: + """ + Append a chunk with consistent indexing, optionally recomputing token count if missing. + + Args: + chunks (list[DocumentChunk]): Accumulated chunk list. + text (str): Chunk text. + token_count (int): Token count for the chunk. + fallback_count (bool): Recompute token count when provided count is falsy. Defaults to False. + """ + count = token_count or ( + self.count_tokens(text) if fallback_count else token_count + ) + chunks.append( + DocumentChunk( + text=text, + token_count=count, + index=len(chunks), + ) + ) + + +__all__ = ["DocumentChunk", "LLMProvider", "LLMResponse"] diff --git a/notebooks/experiments/llm-providers/01-ollama-provider.ipynb b/notebooks/experiments/llm-providers/01-ollama-provider.ipynb new file mode 100644 index 00000000..216292c4 --- /dev/null +++ b/notebooks/experiments/llm-providers/01-ollama-provider.ipynb @@ -0,0 +1,200 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "dcfd3a57", + "metadata": {}, + "source": [ + "# `OllamaLLMProvider`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9890c8fb", + "metadata": {}, + "outputs": [], + "source": [ + "import asyncio\n", + "\n", + "from rich.pretty import pprint\n", + "\n", + "from aymurai.llm_providers import OllamaLLMProvider" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85317574", + "metadata": {}, + "outputs": [], + "source": [ + "MODEL_NAME = \"llama3.2:3b\"\n", + "SYSTEM_PROMPT = \"Eres un asistente legal especializado en anonimización y desambiguación de entidades.\"\n", + "\n", + "provider = OllamaLLMProvider(model=MODEL_NAME, system_prompt=SYSTEM_PROMPT)\n", + "provider" + ] + }, + { + "cell_type": "markdown", + "id": "94e43f16", + "metadata": {}, + "source": [ + "## Chunking" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53afac4f", + "metadata": {}, + "outputs": [], + "source": [ + "sample_text = (\n", + " \"La jueza fijó audiencia para la próxima semana y solicitó a las partes presentar \"\n", + " \"documentación adicional relacionada con la causa. El objetivo es determinar si existieron \"\n", + " \"violaciones al protocolo vigente y establecer medidas de protección para las víctimas.\"\n", + ")\n", + "\n", + "chunks = provider.chunk_text(sample_text, max_tokens=10, overlap=0)\n", + "for chunk in chunks:\n", + " print(f\"Chunk {chunk.index}: {chunk.token_count} tokens\")\n", + " pprint(chunk)" + ] + }, + { + "cell_type": "markdown", + "id": "1aa4d182", + "metadata": {}, + "source": [ + "## Generation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1ce3b9b", + "metadata": {}, + "outputs": [], + "source": [ + "prompt = (\n", + " \"Resume en español el siguiente extracto de un expediente judicial y menciona los actores involucrados:\"\n", + " + sample_text\n", + ")\n", + "\n", + "try:\n", + " summary_response = provider.generate(prompt)\n", + " print(summary_response.text)\n", + " pprint(summary_response.metadata)\n", + "\n", + "except Exception as exc:\n", + " print(\"No se pudo contactar a Ollama:\", exc)" + ] + }, + { + "cell_type": "markdown", + "id": "da8f9c60", + "metadata": {}, + "source": [ + "## Streaming" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ac718bd", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " stream_prompt = \"Explica en detalle el procedimiento legal descrito.\"\n", + " pieces = []\n", + " for event in provider.stream(stream_prompt):\n", + " print(event.text, end=\"\", flush=True)\n", + " pieces.append(event.text)\n", + " print()\n", + " full_text = \"\".join(pieces)\n", + "\n", + "except Exception as exc:\n", + " print(\"La transmisión no está disponible:\", exc)" + ] + }, + { + "cell_type": "markdown", + "id": "async-section", + "metadata": {}, + "source": [ + "## Async calls" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "async-demo", + "metadata": {}, + "outputs": [], + "source": [ + "async def demo_async_generate():\n", + " try:\n", + " result = await provider.async_generate(\"Di un resumen breve del texto\")\n", + " print(result.text)\n", + " except Exception as exc:\n", + " print(\"No se pudo contactar a Ollama (async):\", exc)\n", + "\n", + "\n", + "await demo_async_generate()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72c5c551", + "metadata": {}, + "outputs": [], + "source": [ + "async def demo_async_stream():\n", + " try:\n", + " parts = []\n", + " async for event in provider.async_stream(\"Explica el caso con más detalle\"):\n", + " print(event.text, end=\"\", flush=True)\n", + " parts.append(event.text)\n", + " print()\n", + " except Exception as exc:\n", + " print(\"La transmisión async no está disponible:\", exc)\n", + "\n", + "\n", + "await demo_async_stream()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "67ede506", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/test/llm_providers/__init__.py b/test/llm_providers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/test/llm_providers/test_providers.py b/test/llm_providers/test_providers.py new file mode 100644 index 00000000..9fbc64ae --- /dev/null +++ b/test/llm_providers/test_providers.py @@ -0,0 +1,148 @@ +import unittest +from unittest.mock import AsyncMock, MagicMock, patch + +from aymurai.llm_providers import LLMProvider, LLMResponse, OllamaLLMProvider + + +class DummyProvider(LLMProvider): + def __init__(self, **kwargs): + super().__init__(model="dummy", **kwargs) + self.last_prompt = None + + def generate(self, prompt: str, **kwargs) -> LLMResponse: + self.last_prompt = prompt + return LLMResponse(text=f"echo::{prompt}") + + def stream(self, prompt, **kwargs): + return super().stream(prompt, **kwargs) + + +class FakeTokenizer: + def encode(self, text, add_special_tokens: bool = False): + return text.split() + + +class BaseProviderTests(unittest.TestCase): + def test_chunk_text_respects_token_limit(self): + provider = DummyProvider(max_context_tokens=4, chunk_overlap=1) + text = "uno dos tres cuatro cinco seis" + chunks = provider.chunk_text(text) + self.assertGreater(len(chunks), 1) + for i, chunk in enumerate(chunks): + self.assertEqual(chunk.index, i) + self.assertLessEqual(chunk.token_count, 4) + + def test_chunk_text_overlap_applied(self): + provider = DummyProvider(max_context_tokens=3, chunk_overlap=1) + text = "one two three four" + chunks = provider.chunk_text(text) + self.assertEqual([c.index for c in chunks], [0, 1]) + self.assertTrue(chunks[0].text.split()[-1] in chunks[1].text.split()) + + def test_chunk_text_fallback_count(self): + provider = DummyProvider(max_context_tokens=1) + provider._tokenizer = type("EmptyTok", (), {"encode": lambda self, t: []})() + chunks = provider.chunk_text("hello") + self.assertEqual(len(chunks), 1) + self.assertEqual(chunks[0].token_count, 0) + + +class OllamaProviderTests(unittest.TestCase): + def test_generate_builds_messages(self): + provider = OllamaLLMProvider(model="llama3", system_prompt="Sistema") + fake_response = {"message": {"content": "respuesta"}, "eval_count": 10} + with patch("aymurai.llm_providers.ollama_provider.ollama.chat") as mock_chat: + mock_chat.return_value = fake_response + response = provider.generate("Hola") + + self.assertEqual(response.text, "respuesta") + args, kwargs = mock_chat.call_args + self.assertEqual(kwargs["model"], "llama3") + self.assertEqual(kwargs["messages"][0]["role"], "system") + self.assertEqual(response.metadata.get("model"), "llama3") + self.assertEqual(response.metadata.get("provider"), "ollama") + self.assertIn("eval_count", response.metadata) + self.assertIn("eval_duration", response.metadata) + + def test_generate_forwards_keep_alive(self): + provider = OllamaLLMProvider(model="llama3", keep_alive=30) + fake_response = {"message": {"content": "ok"}} + with patch("aymurai.llm_providers.ollama_provider.ollama.chat") as mock_chat: + mock_chat.return_value = fake_response + _ = provider.generate("Hola") + _, kwargs = mock_chat.call_args + self.assertEqual(kwargs["keep_alive"], 30) + + def test_stream_yields_chunks(self): + provider = OllamaLLMProvider(model="llama3") + fake_chunks = iter( + [ + {"message": {"content": "Hola"}, "done": False}, + {"message": {"content": " Mundo"}, "done": True}, + ] + ) + with patch("aymurai.llm_providers.ollama_provider.ollama.chat") as mock_chat: + mock_chat.return_value = fake_chunks + pieces = list(provider.stream("Hola")) + + self.assertEqual([piece.text for piece in pieces], ["Hola", " Mundo"]) + _, kwargs = mock_chat.call_args + self.assertTrue(kwargs["stream"]) + self.assertEqual(pieces[-1].text, " Mundo") + self.assertTrue(pieces[-1].metadata.get("done")) + + def test_generate_raises_without_prompt_or_messages(self): + provider = OllamaLLMProvider(model="llama3") + with self.assertRaises(ValueError): + provider.generate(prompt=None, messages=None) + + +class AsyncOllamaProviderTests(unittest.IsolatedAsyncioTestCase): + async def test_async_generate_builds_messages(self): + provider = OllamaLLMProvider(model="llama3", system_prompt="Sistema") + fake_response = {"message": {"content": "respuesta"}, "eval_count": 10} + mock_client = MagicMock() + mock_client.chat = AsyncMock(return_value=fake_response) + + with patch( + "aymurai.llm_providers.ollama_provider.AsyncClient", + return_value=mock_client, + ): + response = await provider.async_generate("Hola") + + self.assertEqual(response.text, "respuesta") + mock_client.chat.assert_awaited_once() + _, kwargs = mock_client.chat.call_args + self.assertEqual(kwargs["model"], "llama3") + self.assertEqual(kwargs["messages"][0]["role"], "system") + self.assertEqual(response.metadata.get("model"), "llama3") + self.assertEqual(response.metadata.get("provider"), "ollama") + self.assertIn("eval_count", response.metadata) + + async def test_async_stream_yields_chunks(self): + provider = OllamaLLMProvider(model="llama3") + + async def fake_gen(): + yield {"message": {"content": "Hola"}, "done": False} + yield {"message": {"content": " Mundo"}, "done": True} + + mock_client = MagicMock() + mock_client.chat = AsyncMock(return_value=fake_gen()) + + with patch( + "aymurai.llm_providers.ollama_provider.AsyncClient", + return_value=mock_client, + ): + pieces = [] + last_chunk = None + async for chunk in provider.async_stream("Hola"): + pieces.append(chunk.text) + last_chunk = chunk + + self.assertEqual(pieces, ["Hola", " Mundo"]) + mock_client.chat.assert_awaited() + self.assertTrue(last_chunk.metadata.get("done")) + + +if __name__ == "__main__": + unittest.main() From d80f74bc4264f51017a7ebe240ceef4abe567824 Mon Sep 17 00:00:00 2001 From: Paolo Donizetti Date: Wed, 26 Nov 2025 16:18:01 -0300 Subject: [PATCH 016/104] Feature/disambiguation metric v2 (#62) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update .gitignore to exclude entity disambiguation experiment directories and modify Jupyter notebook execution counts and output handling * Refactor Makefile for improved service management and update .gitignore to exclude specific experiment directories. Add new Jupyter notebooks for entity disambiguation metrics and documentation. * Adjust example data for consistency in entity representation. * Refactor entity disambiguation notebooks to standardize attribute naming and improve metric evaluation. Update role attribute from 'rol' to 'role' for consistency across examples and documentation. Adjust evaluation function to return both score and metrics. * Add evaluation metrics for entity disambiguation - Introduced new metrics module for evaluating entity disambiguation performance, including functions for alias normalization, Jaccard similarity, and greedy matching. - Implemented main evaluation function to compute scores and metrics from gold and predicted entities. - Added Jupyter notebooks for practical examples and evaluation results, including normalized and non-normalized text evaluations. - Updated documentation to reflect changes in function signatures and outputs. * 🔧 Expand Makefile: add API management targets (api-run, api-stop, api-logs, api-full-run) for smoother service control * ♻️ Refactor metrics.py: clarify docstrings, align type hints, and polish logging * ✏️ Fix role attribute reference in evaluation metric documentation for consistency * 🔧 Add CanonicalEntities class to represent a collection of canonical entities * 📝 Update entity disambiguation notebooks: clean up imports, adjust paths, and streamline API calls for improved clarity and functionality --------- Co-authored-by: padonizetti Co-authored-by: jansaldo --- Makefile | 19 +- aymurai/evaluation/__init__.py | 0 aymurai/evaluation/metrics.py | 366 +++++++++++++ aymurai/meta/entities.py | 6 + .../01-entity-disambiguation.ipynb | 130 ++--- .../02-disambiguation-metric.ipynb | 431 +++++++++++++++ .../03-disambiguation-evaluation.ipynb | 110 ++++ .../Desarrollo metrica.md | 500 ++++++++++++++++++ 8 files changed, 1472 insertions(+), 90 deletions(-) create mode 100644 aymurai/evaluation/__init__.py create mode 100644 aymurai/evaluation/metrics.py create mode 100644 notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb create mode 100644 notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb create mode 100644 notebooks/experiments/entity-disambiguation/Desarrollo metrica.md diff --git a/Makefile b/Makefile index 2f8a00e5..14e1d527 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,19 @@ include .env export $(shell sed 's/=.*//' .env) include .env.common export $(shell sed 's/=.*//' .env.common) +OLLAMA_CONTAINER := $(shell docker ps -q -f name=^ollama$$) api-build: docker compose build aymurai-api api-run: docker compose run --service-ports aymurai-api +api-up: + docker compose up -d aymurai-api +api-stop: + docker compose stop aymurai-api +api-logs: + docker compose logs -f aymurai-api api-pull: docker compose pull aymurai-api @@ -15,6 +22,12 @@ api-full-build: docker compose build aymurai-api-full api-full-run: docker compose run --service-ports aymurai-api-full +api-full-up: + docker compose up -d aymurai-api-full +api-full-stop: + docker compose stop aymurai-api-full +api-full-logs: + docker compose logs -f aymurai-api-full api-full-pull: docker compose pull aymurai-api-full @@ -31,8 +44,10 @@ ollama-pull: ifndef MODEL $(error MODEL variable is required, e.g. make ollama-pull MODEL=llama3) endif - docker compose up -d --no-recreate ollama - docker compose exec ollama ollama pull $(MODEL) +ifndef OLLAMA_CONTAINER + $(error Ollama container 'ollama' is not running. Start it first with 'make ollama-up') +endif + docker exec ollama ollama pull $(MODEL) ollama-run: ifndef MODEL diff --git a/aymurai/evaluation/__init__.py b/aymurai/evaluation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aymurai/evaluation/metrics.py b/aymurai/evaluation/metrics.py new file mode 100644 index 00000000..30bceca5 --- /dev/null +++ b/aymurai/evaluation/metrics.py @@ -0,0 +1,366 @@ +from __future__ import annotations + +import json +import unicodedata +from pathlib import Path +from typing import Any + +from aymurai.logger import get_logger +from aymurai.utils.json_data import load_json + +logger = get_logger(__name__) + + +def normalize_text(text: str) -> str: + """ + Normalize text by lowercasing, stripping, and removing accents. + + Args: + text (str): Input text. + + Returns: + str: Normalized text. + """ + if not text: + return "" + + # Lowercase and strip + text = text.strip().lower() + + # Remove accents + text = unicodedata.normalize("NFD", text) + text = "".join(ch for ch in text if unicodedata.category(ch) != "Mn") + + return text + + +def get_alias_set(entity: dict[str, Any], normalize: bool = True) -> set[str]: + """ + Returns the set of normalized aliases for an entity, ensuring that the + canonical_text is included as an alias. + + Args: + entity (dict[str, Any]): A dictionary containing entity information with + optional 'aliases' (list of strings) and 'canonical_text' (string) keys. + normalize (bool, optional): If True, normalizes the alias texts using + normalize_text function. Defaults to True. + Returns: + set[str]: A set of alias strings (normalized if normalize=True) including + both explicit aliases and the canonical text. + """ + aliases = set() + + # Get aliases from the entity + for alias in entity.get("aliases", []): + text = normalize_text(alias) if normalize else alias + if text: + aliases.add(text) + + # Get canonical text from the entity + canonical = ( + normalize_text(entity.get("canonical_text", "")) + if normalize + else entity.get("canonical_text", "") + ) + if canonical: + aliases.add(canonical) + + return aliases + + +def alias_jaccard(aliases_gold: set[str], aliases_pred: set[str]) -> float: + """ + Jaccard similarity between two sets of aliases. + + Args: + aliases_gold (set[str]): Set of gold aliases. + aliases_pred (set[str]): Set of predicted aliases. + + Returns: + float: Jaccard similarity score. + """ + # If both sets are empty, define similarity as 1.0 + if not aliases_gold and not aliases_pred: + return 1.0 + + # Calculate Jaccard similarity + union = aliases_gold | aliases_pred + inter = aliases_gold & aliases_pred + + return len(inter) / len(union) + + +def greedy_matching( + sim_matrix: list[list[float]], sim_threshold: float +) -> list[tuple[int, int, float]]: + """ + Perform greedy maximum matching based on similarity scores. + + Args: + sim_matrix (list[list[float]]): Similarity matrix where sim_matrix[i][j] + represents the similarity between the gold entity i and predicted + entity j. + sim_threshold (float): Minimum similarity required to consider a match + between two entities. + + Returns: + list[tuple[int, int, float]]: Tuples containing the matched gold index, + predicted index, and their similarity score. + """ + matches: list[tuple[int, int, float]] = [] + num_gold = len(sim_matrix) + num_pred = len(sim_matrix[0]) if num_gold > 0 else 0 + + # Build the list of candidate matches above the threshold + candidates: list[tuple[float, int, int]] = [] + for i in range(num_gold): + for j in range(num_pred): + sim = sim_matrix[i][j] + if sim >= sim_threshold: + candidates.append((sim, i, j)) + + # Sort descending by similarity so higher matches are selected first + candidates.sort(reverse=True, key=lambda x: x[0]) + + used_gold = set() + used_pred = set() + + for sim, i, j in candidates: + if i in used_gold or j in used_pred: + continue + used_gold.add(i) + used_pred.add(j) + matches.append((i, j, sim)) + + return matches + + +def compute_metrics_components( + gold_entities: list[dict[str, Any]], + pred_entities: list[dict[str, Any]], + sim_threshold: float = 0.3, + normalize: bool = True, +) -> dict[str, float]: + """ + Compute each component of the disambiguation metric. + + The metric includes entity-level F1, macro average alias F1, and accuracy + for labels and roles on matched entities. + + Args: + gold_entities (list[dict[str, Any]]): Ground-truth entities. + pred_entities (list[dict[str, Any]]): Predicted entities. + sim_threshold (float): Minimum alias similarity to consider entities a match. + Defaults to 0.3. + normalize (bool): If True normalizes aliases before comparison. + Defaults to True. + + Returns: + dict[str, float]: Mapping with the keys F1_ent, AliasF1_macro, Acc_label, and Acc_role. + """ + + # Handle the trivial case where both sets are empty + if not gold_entities and not pred_entities: + return { + "F1_ent": 1.0, + "AliasF1_macro": 1.0, + "Acc_label": 1.0, + "Acc_role": 1.0, + } + + # Preprocess aliases, labels and roles + gold_aliases = [get_alias_set(e, normalize=normalize) for e in gold_entities] + pred_aliases = [get_alias_set(e, normalize=normalize) for e in pred_entities] + + gold_labels = [e.get("aymurai_label") for e in gold_entities] + pred_labels = [e.get("aymurai_label") for e in pred_entities] + + gold_roles = [e.get("attributes", {}).get("role") for e in gold_entities] + pred_roles = [e.get("attributes", {}).get("role") for e in pred_entities] + + num_gold = len(gold_entities) + num_pred = len(pred_entities) + + # Build the alias similarity matrix + sim_matrix = [] + for i in range(num_gold): + row = [] + for j in range(num_pred): + sim = alias_jaccard(gold_aliases[i], pred_aliases[j]) + row.append(sim) + sim_matrix.append(row) + + # Perform greedy matching + matches = greedy_matching(sim_matrix, sim_threshold=sim_threshold) + + TP = len(matches) + FN = num_gold - TP + FP = num_pred - TP + + # Entity-level precision/recall/F1 + if TP + FP > 0: + P_ent = TP / (TP + FP) + else: + P_ent = 0.0 + + if TP + FN > 0: + R_ent = TP / (TP + FN) + else: + R_ent = 0.0 + + if P_ent + R_ent > 0: + F1_ent = 2 * P_ent * R_ent / (P_ent + R_ent) + else: + F1_ent = 0.0 + + # Alias-level F1 macro + if TP > 0: + alias_f1_sum = 0.0 + label_correct = 0 + role_correct = 0 + + for i, j, _sim in matches: + A_g = gold_aliases[i] + A_p = pred_aliases[j] + + inter = len(A_g & A_p) + P_alias = inter / len(A_p) if len(A_p) > 0 else 0.0 + R_alias = inter / len(A_g) if len(A_g) > 0 else 0.0 + if P_alias + R_alias > 0: + F1_alias = 2 * P_alias * R_alias / (P_alias + R_alias) + else: + F1_alias = 0.0 + + alias_f1_sum += F1_alias + + # Label accuracy on matched entities + if gold_labels[i] == pred_labels[j]: + label_correct += 1 + + # Role accuracy on matched entities + if gold_roles[i] == pred_roles[j]: + role_correct += 1 + + AliasF1_macro = alias_f1_sum / TP + Acc_label = label_correct / TP + Acc_role = role_correct / TP + else: + AliasF1_macro = 0.0 + Acc_label = 0.0 + Acc_role = 0.0 + + return { + "F1_ent": F1_ent, + "AliasF1_macro": AliasF1_macro, + "Acc_label": Acc_label, + "Acc_role": Acc_role, + } + + +def evaluate_disambiguation( + gold_json: Any, + pred_json: Any, + w_ent: float = 0.4, + w_alias: float = 0.35, + w_label: float = 0.2, + w_role: float = 0.05, + sim_threshold: float = 0.3, + normalize: bool = True, +) -> tuple[float, dict[str, float]]: + """ + Evaluate disambiguation predictions against ground truth entities. + + Args: + gold_json (Any): Ground-truth entities as a parsed list or JSON string. + pred_json (Any): Predicted entities as a parsed list or JSON string. + w_ent (float): Weight assigned to entity-level F1. Defaults to 0.4. + w_alias (float): Weight assigned to alias macro F1. Defaults to 0.35. + w_label (float): Weight assigned to label accuracy. Defaults to 0.2. + w_role (float): Weight assigned to role accuracy. Defaults to 0.05. + sim_threshold (float): Minimum alias similarity to consider entities a match. + Defaults to 0.3. + normalize (bool): If True normalizes aliases before comparison. + Defaults to True. + + Returns: + tuple[float, dict[str, float]]: Overall disambiguation score and detailed metrics components. + """ + + # Parse JSON strings if necessary + if isinstance(gold_json, str): + gold_entities = json.loads(gold_json) + else: + gold_entities = gold_json + + if isinstance(pred_json, str): + pred_entities = json.loads(pred_json) + else: + pred_entities = pred_json + + metrics = compute_metrics_components( + gold_entities, pred_entities, sim_threshold=sim_threshold, normalize=normalize + ) + + score = ( + w_ent * metrics["F1_ent"] + + w_alias * metrics["AliasF1_macro"] + + w_label * metrics["Acc_label"] + + w_role * metrics["Acc_role"] + ) + + return score, metrics + + +def evaluate_prediction_directories( + test_dir: Path, + preds_dir: Path, + *, + sim_threshold: float = 0.3, + normalize: bool = True, +) -> tuple[list[tuple[str, float, dict[str, float]]], float]: + """ + Evaluate predictions stored on disk against the gold standard set. + + Args: + test_dir (Path): Directory containing gold json files. + preds_dir (Path): Directory containing predicted json files. + sim_threshold (float): Minimum alias similarity to consider entities a match. + Defaults to 0.3. + normalize (bool): If True normalizes aliases before comparison. + Defaults to True. + + Returns: + tuple[list[tuple[str, float, dict[str, float]]], float]: Detailed results + per document and the average score across all evaluated documents. + """ + test_dir = Path(test_dir) + preds_dir = Path(preds_dir) + + results = [] + + for test_path in sorted(test_dir.glob("*.json")): + prefix = test_path.name[: -len(".json")] + pred_path = preds_dir / f"{prefix}.json" + + if not pred_path.exists(): + logger.warning(f"Prediction for {test_path.name} was not found; skipping.") + continue + + gold_data = load_json(test_path) + pred_data = load_json(pred_path) + + score, metrics = evaluate_disambiguation( + gold_data, + pred_data, + sim_threshold=sim_threshold, + normalize=normalize, + ) + results.append((prefix, score, metrics)) + + average_score = ( + sum(score for _, score, _ in results) / len(results) + if results + else float("nan") + ) + + return results, average_score diff --git a/aymurai/meta/entities.py b/aymurai/meta/entities.py index 64170307..08eca7ae 100644 --- a/aymurai/meta/entities.py +++ b/aymurai/meta/entities.py @@ -130,3 +130,9 @@ def validate_entity_id(self) -> CanonicalEntity: object.__setattr__(self, "entity_id", uuid5(NAMESPACE_URL, seed)) return self + + +class CanonicalEntities(BaseModel): + """Collection of canonical entities.""" + + canonical_entities: list[CanonicalEntity] diff --git a/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb index 99477159..65318651 100644 --- a/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb +++ b/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb @@ -30,39 +30,12 @@ "from pathlib import Path\n", "from typing import Iterable\n", "\n", - "import ollama\n", "import requests\n", - "from IPython.display import Markdown\n", - "from ollama import ChatResponse\n", - "from pydantic import BaseModel\n", - "from pydantic.json_schema import JsonSchemaValue\n", - "from rich.pretty import pprint\n", "from tqdm import tqdm\n", "\n", - "from aymurai.meta.entities import CanonicalEntity # , EntityRelation\n", - "from aymurai.utils.json_data import get_pretty, load_json, save_json" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "46b328aa", - "metadata": {}, - "outputs": [], - "source": [ - "os.environ[\"OLLAMA_KEEP_ALIVE\"] = \"0\"\n", - "print(\"OLLAMA_KEEP_ALIVE set to 0. Models will unload immediately after use.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "758353c4", - "metadata": {}, - "outputs": [], - "source": [ - "DATA_DIR = \"/resources/data/restricted/summarization\"\n", - "API_URL = \"http://localhost:8899\" # Url for debugger. change it to your own" + "from aymurai.llm_providers import OllamaLLMProvider\n", + "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", + "from aymurai.utils.json_data import get_pretty, save_json" ] }, { @@ -80,10 +53,10 @@ "metadata": {}, "outputs": [], "source": [ - "BASE_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", - "ENDPOINT = f\"{BASE_URL}/misc/document-extract\"\n", + "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", + "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", "DATA_ROOT = Path(\n", - " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", + " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/disambiguation-eval\")\n", ")\n", "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", @@ -253,47 +226,6 @@ "## CanonicalEntity extraction" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "0e2a8113", - "metadata": {}, - "outputs": [], - "source": [ - "# Function to get chat response from the model\n", - "def get_chat_response(\n", - " user_prompt: str,\n", - " model: str = \"gpt-oss:20b\",\n", - " system_prompt: str = \"Sos un asistente jurídico que resume sin inventar nada.\",\n", - " options: dict = {\"temperature\": 0},\n", - " format: JsonSchemaValue | None = None,\n", - ") -> ChatResponse:\n", - " \"\"\"\n", - " Get chat response from the model.\n", - "\n", - " Args:\n", - " user_prompt (str): The prompt from the user.\n", - " model (str, optional): The model to use. Defaults to \"gpt-oss:20b\".\n", - " system_prompt (str, optional): The system prompt. Defaults to \"Sos un asistente jurídico que resume sin inventar nada.\".\n", - " options (dict, optional): The options for the chat. Defaults to {\"temperature\": 0}.\n", - " format (JsonSchemaValue | None, optional): The format for the response. Defaults to None.\n", - "\n", - " Returns:\n", - " ChatResponse: The response from the chat.\n", - " \"\"\"\n", - " response = ollama.chat(\n", - " model=model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options=options,\n", - " format=format,\n", - " )\n", - "\n", - " return response" - ] - }, { "cell_type": "code", "execution_count": null, @@ -301,19 +233,24 @@ "metadata": {}, "outputs": [], "source": [ - "# Sanity check\n", - "get_chat_response(\"hola, ¿cómo estás?\")" + "# Available models\n", + "# model = \"gpt-oss:20b\"\n", + "# model = \"llama3\"\n", + "# model = \"phi4:14b\"\n", + "# model = \"llama3.1:8b\"\n", + "model = \"gemma3:270m\"" ] }, { "cell_type": "code", "execution_count": null, - "id": "09631e51", + "id": "25284997", "metadata": {}, "outputs": [], "source": [ - "class CanonicalEntities(BaseModel):\n", - " canonical_entities: list[CanonicalEntity]" + "# Sanity check\n", + "provider = OllamaLLMProvider(model=model)\n", + "provider.generate(\"hola, ¿cómo estás?\")" ] }, { @@ -465,17 +402,20 @@ " ner_output_json=ner_output_json,\n", " )\n", "\n", - " # Get chat response\n", - " response = get_chat_response(\n", - " user_prompt=user_prompt,\n", - " model=model,\n", - " system_prompt=system_prompt,\n", + " # Get canonical entities from the model\n", + " provider = OllamaLLMProvider(model=model)\n", + " response = provider.generate(\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options={\"temperature\": 0},\n", " format=CanonicalEntities.model_json_schema(),\n", " )\n", "\n", " # Parse canonical entities from response\n", " canonical_entities = [\n", - " output for output in json.loads(response.message.content)[\"canonical_entities\"]\n", + " output for output in json.loads(response.text)[\"canonical_entities\"]\n", " ]\n", "\n", " canonical_entities = [\n", @@ -493,24 +433,38 @@ "metadata": {}, "outputs": [], "source": [ + "output_root = Path(DATA_ROOT) / \"preds\"\n", + "output_root.mkdir(parents=True, exist_ok=True)\n", + "\n", + "prompt_version = \"1\"\n", + "\n", + "timestamp = time.strftime(\"%y%m%d_%H%M\")\n", + "base_dir_name = f\"preds-{model}-pv{prompt_version}-{timestamp}\"\n", + "output_dir = output_root / base_dir_name\n", + "\n", + "output_dir.mkdir(parents=True, exist_ok=False)\n", + "print(f\"Saving canonical entities to {output_dir}\")\n", + "\n", "for doc_path in documents:\n", " print(f\"Processing document: {doc_path}\")\n", "\n", " try:\n", - " canonical_entities = extract_canonical_entities(doc_path)\n", + " canonical_entities = extract_canonical_entities(doc_path, model=model)\n", " print(f\"Extracted {len(canonical_entities)} canonical entities.\")\n", "\n", " target_filename = re.sub(\n", - " r\"\\s+\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", " )\n", " target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)\n", + " target_path = output_dir / f\"{target_filename}.json\"\n", + "\n", " save_json(\n", " [\n", " canonical_entity.model_dump()\n", " | {\"entity_id\": canonical_entity.entity_id.hex}\n", " for canonical_entity in canonical_entities\n", " ],\n", - " f\"entities-to-review/{target_filename}-canonical-entities.json\",\n", + " str(target_path),\n", " )\n", "\n", " except Exception as e:\n", diff --git a/notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb b/notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb new file mode 100644 index 00000000..ebe84474 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb @@ -0,0 +1,431 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "10301fb9", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import unicodedata\n", + "from pathlib import Path\n", + "from typing import Any, Dict, Iterable, List, Optional, Set, Tuple\n", + "\n", + "from IPython.display import Markdown\n", + "from ollama import ChatResponse\n", + "from pydantic import BaseModel\n", + "from pydantic.json_schema import JsonSchemaValue\n", + "from rich.pretty import pprint\n", + "from tqdm import tqdm\n", + "\n", + "from aymurai.meta.entities import CanonicalEntity # , EntityRelation\n", + "from aymurai.utils.json_data import get_pretty, load_json, save_json" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "93f3977b", + "metadata": {}, + "outputs": [], + "source": [ + "def normalize_text(text: str) -> str:\n", + " \"\"\"\n", + " Normaliza un alias:\n", + " - pasa a minúsculas\n", + " - elimina espacios extra\n", + " - quita tildes/acentos\n", + " \"\"\"\n", + " if text is None:\n", + " return \"\"\n", + " text = text.strip().lower()\n", + " # eliminar acentos\n", + " text = unicodedata.normalize(\"NFD\", text)\n", + " text = \"\".join(ch for ch in text if unicodedata.category(ch) != \"Mn\")\n", + " return text" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfaeeada", + "metadata": {}, + "outputs": [], + "source": [ + "def get_alias_set(entity: Dict[str, Any]) -> Set[str]:\n", + " \"\"\"\n", + " Devuelve el conjunto de aliases normalizados para una entidad,\n", + " asegurándose de incluir el canonical_text como alias.\n", + " \"\"\"\n", + " aliases = set()\n", + " # aliases explícitos\n", + " for a in entity.get(\"aliases\", []):\n", + " norm = normalize_text(a)\n", + " if norm:\n", + " aliases.add(norm)\n", + " # incluir canonical_text\n", + " canonical = normalize_text(entity.get(\"canonical_text\", \"\"))\n", + " if canonical:\n", + " aliases.add(canonical)\n", + " return aliases" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "789f9be0", + "metadata": {}, + "outputs": [], + "source": [ + "def alias_jaccard(aliases_gold: Set[str], aliases_pred: Set[str]) -> float:\n", + " \"\"\"\n", + " Similaridad Jaccard entre conjuntos de aliases.\n", + " \"\"\"\n", + " if not aliases_gold and not aliases_pred:\n", + " return 1.0\n", + " union = aliases_gold | aliases_pred\n", + " if not union:\n", + " return 0.0\n", + " inter = aliases_gold & aliases_pred\n", + " return len(inter) / len(union)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b551edbc", + "metadata": {}, + "outputs": [], + "source": [ + "def greedy_matching(\n", + " sim_matrix: List[List[float]], sim_threshold: float\n", + ") -> List[Tuple[int, int, float]]:\n", + " \"\"\"\n", + " Emparejamiento greedy máximo por similitud:\n", + " - sim_matrix[i][j] = similitud entre entidad gold i y pred j\n", + " - sim_threshold: mínimo para considerar un match\n", + "\n", + " Devuelve una lista de tuplas (i_gold, j_pred, sim).\n", + " \"\"\"\n", + " matches: List[Tuple[int, int, float]] = []\n", + " num_gold = len(sim_matrix)\n", + " num_pred = len(sim_matrix[0]) if num_gold > 0 else 0\n", + "\n", + " # Generar la lista de candidatos (i, j, sim) por encima del umbral\n", + " candidates: List[Tuple[float, int, int]] = []\n", + " for i in range(num_gold):\n", + " for j in range(num_pred):\n", + " sim = sim_matrix[i][j]\n", + " if sim >= sim_threshold:\n", + " candidates.append((sim, i, j))\n", + "\n", + " # Ordenar descendente por similitud\n", + " candidates.sort(reverse=True, key=lambda x: x[0])\n", + "\n", + " used_gold = set()\n", + " used_pred = set()\n", + "\n", + " for sim, i, j in candidates:\n", + " if i in used_gold or j in used_pred:\n", + " continue\n", + " used_gold.add(i)\n", + " used_pred.add(j)\n", + " matches.append((i, j, sim))\n", + "\n", + " return matches\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b59d4083", + "metadata": {}, + "outputs": [], + "source": [ + "def compute_metrics_components(\n", + " gold_entities: List[Dict[str, Any]],\n", + " pred_entities: List[Dict[str, Any]],\n", + " sim_threshold: float = 0.3,\n", + ") -> Dict[str, float]:\n", + " \"\"\"\n", + " Calcula los componentes de la métrica:\n", + " - F1_ent: F1 de entidades (detección de entidades canónicas)\n", + " - AliasF1_macro: F1 macro promedio sobre aliases por entidad emparejada\n", + " - Acc_label: accuracy de labels en entidades emparejadas\n", + " - Acc_role: accuracy de roles en entidades emparejadas\n", + " \"\"\"\n", + "\n", + " # Caso trivial: sin entidades en ambos\n", + " if not gold_entities and not pred_entities:\n", + " return {\n", + " \"F1_ent\": 1.0,\n", + " \"AliasF1_macro\": 1.0,\n", + " \"Acc_label\": 1.0,\n", + " \"Acc_role\": 1.0,\n", + " }\n", + "\n", + " # Preprocesar aliases, labels y roles\n", + " gold_aliases = [get_alias_set(e) for e in gold_entities]\n", + " pred_aliases = [get_alias_set(e) for e in pred_entities]\n", + "\n", + " gold_labels = [e.get(\"aymurai_label\") for e in gold_entities]\n", + " pred_labels = [e.get(\"aymurai_label\") for e in pred_entities]\n", + "\n", + " gold_roles = [e.get(\"attributes\", {}).get(\"role\") for e in gold_entities]\n", + " pred_roles = [e.get(\"attributes\", {}).get(\"role\") for e in pred_entities]\n", + "\n", + " num_gold = len(gold_entities)\n", + " num_pred = len(pred_entities)\n", + "\n", + " # Matriz de similitud de aliases\n", + " sim_matrix: List[List[float]] = []\n", + " for i in range(num_gold):\n", + " row = []\n", + " for j in range(num_pred):\n", + " sim = alias_jaccard(gold_aliases[i], pred_aliases[j])\n", + " row.append(sim)\n", + " sim_matrix.append(row)\n", + "\n", + " # Matching greedy\n", + " matches = greedy_matching(sim_matrix, sim_threshold=sim_threshold)\n", + "\n", + " TP = len(matches)\n", + " FN = num_gold - TP\n", + " FP = num_pred - TP\n", + "\n", + " # Entidad-level precision/recall/F1\n", + " if TP + FP > 0:\n", + " P_ent = TP / (TP + FP)\n", + " else:\n", + " P_ent = 0.0\n", + "\n", + " if TP + FN > 0:\n", + " R_ent = TP / (TP + FN)\n", + " else:\n", + " R_ent = 0.0\n", + "\n", + " if P_ent + R_ent > 0:\n", + " F1_ent = 2 * P_ent * R_ent / (P_ent + R_ent)\n", + " else:\n", + " F1_ent = 0.0\n", + "\n", + " # Alias-level F1 macro\n", + " if TP > 0:\n", + " alias_f1_sum = 0.0\n", + " label_correct = 0\n", + " role_correct = 0\n", + "\n", + " for i, j, _sim in matches:\n", + " A_g = gold_aliases[i]\n", + " A_p = pred_aliases[j]\n", + "\n", + " inter = len(A_g & A_p)\n", + " P_alias = inter / len(A_p) if len(A_p) > 0 else 0.0\n", + " R_alias = inter / len(A_g) if len(A_g) > 0 else 0.0\n", + " if P_alias + R_alias > 0:\n", + " F1_alias = 2 * P_alias * R_alias / (P_alias + R_alias)\n", + " else:\n", + " F1_alias = 0.0\n", + "\n", + " alias_f1_sum += F1_alias\n", + "\n", + " # label\n", + " if gold_labels[i] == pred_labels[j]:\n", + " label_correct += 1\n", + "\n", + " # rol\n", + " if gold_roles[i] == pred_roles[j]:\n", + " role_correct += 1\n", + "\n", + " AliasF1_macro = alias_f1_sum / TP\n", + " Acc_label = label_correct / TP\n", + " Acc_role = role_correct / TP\n", + " else:\n", + " AliasF1_macro = 0.0\n", + " Acc_label = 0.0\n", + " Acc_role = 0.0\n", + "\n", + " return {\n", + " \"F1_ent\": F1_ent,\n", + " \"AliasF1_macro\": AliasF1_macro,\n", + " \"Acc_label\": Acc_label,\n", + " \"Acc_role\": Acc_role,\n", + " }\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14cab697", + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate_disambiguation(\n", + " gold_json: Any,\n", + " pred_json: Any,\n", + " w_ent: float = 0.4,\n", + " w_alias: float = 0.35,\n", + " w_label: float = 0.2,\n", + " w_role: float = 0.05,\n", + " sim_threshold: float = 0.3,\n", + ") -> Tuple[float, Dict[str, float]]:\n", + " \"\"\"\n", + " Función principal pedida:\n", + " - gold_json: JSON ground truth (lista de entidades o string JSON)\n", + " - pred_json: JSON predicho (lista de entidades o string JSON)\n", + " - w_ent, w_alias, w_label, w_role: pesos de cada componente\n", + " - sim_threshold: umbral mínimo de similitud de aliases para emparejar entidades\n", + "\n", + " Devuelve una tupla (Score_global, métricas_componentes) donde:\n", + " - Score_global es un escalar entre 0 y 1.\n", + " - métricas_componentes es un dict con los valores individuales de cada métrica.\n", + " \"\"\"\n", + "\n", + " # Si vienen como string, parsear JSON\n", + " if isinstance(gold_json, str):\n", + " gold_entities = json.loads(gold_json)\n", + " else:\n", + " gold_entities = gold_json\n", + "\n", + " if isinstance(pred_json, str):\n", + " pred_entities = json.loads(pred_json)\n", + " else:\n", + " pred_entities = pred_json\n", + "\n", + " metrics = compute_metrics_components(\n", + " gold_entities,\n", + " pred_entities,\n", + " sim_threshold=sim_threshold,\n", + " )\n", + "\n", + " score = (\n", + " w_ent * metrics[\"F1_ent\"]\n", + " + w_alias * metrics[\"AliasF1_macro\"]\n", + " + w_label * metrics[\"Acc_label\"]\n", + " + w_role * metrics[\"Acc_role\"]\n", + " )\n", + "\n", + " return score, metrics\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12f75b12", + "metadata": {}, + "outputs": [], + "source": [ + "# Ejemplo de JSON gold y pred\n", + "gold = [\n", + " {\n", + " \"entity_id\": \"GT_1\",\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"Juan Pérez\",\n", + " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\"],\n", + " \"attributes\": {\"role\": \"imputado\"},\n", + " \"relations\": [],\n", + " }\n", + "]\n", + "\n", + "pred = [\n", + " {\n", + " \"entity_id\": \"P_1\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Juan Pérez\",\n", + " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\"],\n", + " \"attributes\": {\"role\": \"imputado\"},\n", + " \"relations\": [],\n", + " }\n", + "]\n", + "\n", + "\n", + "score, metrics = evaluate_disambiguation(gold, pred)\n", + "print(\"Metrics vector:\", metrics)\n", + "print(\"Score global:\", score)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d1a279b", + "metadata": {}, + "outputs": [], + "source": [ + "# Ejemplo de JSON gold y pred\n", + "gold = [\n", + " {\n", + " \"entity_id\": \"GT_1\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Juan Pérez\",\n", + " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\"],\n", + " \"attributes\": {\"role\": \"imputado\"},\n", + " \"relations\": [],\n", + " },\n", + " {\n", + " \"entity_id\": \"GT_2\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"María Gómez\",\n", + " \"aliases\": [\"María\", \"Sra. Gómez\"],\n", + " \"attributes\": {\"role\": \"imputado\"},\n", + " \"relations\": [],\n", + " },\n", + "]\n", + "\n", + "pred = [\n", + " {\n", + " \"entity_id\": \"P_1\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Juan Pérez\",\n", + " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\", \"Pérez Juan\"],\n", + " \"attributes\": {\"role\": \"imputado\"},\n", + " \"relations\": [],\n", + " },\n", + " {\n", + " \"entity_id\": \"GT_2\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"María Gómez\",\n", + " \"aliases\": [\"María\", \"Sra. Gómez\"],\n", + " \"attributes\": {\"role\": \"imputado\"},\n", + " \"relations\": [],\n", + " },\n", + "]\n", + "\n", + "score, metrics = evaluate_disambiguation(gold, pred)\n", + "print(\"Metrics vector:\", metrics)\n", + "print(\"Score global:\", score)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb0c3ddf", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb b/notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb new file mode 100644 index 00000000..05c54a17 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb @@ -0,0 +1,110 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "164a8904", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "from pathlib import Path\n", + "\n", + "from aymurai.evaluation.metrics import evaluate_prediction_directories\n", + "\n", + "project_root = Path.cwd().parents[2]\n", + "if str(project_root) not in sys.path:\n", + " sys.path.insert(0, str(project_root))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72f996d1", + "metadata": {}, + "outputs": [], + "source": [ + "# Ajusta estas rutas antes de ejecutar\n", + "TEST_DIR = Path(\"/resources/data/restricted/disambiguation-eval/test\")\n", + "PREDS_DIR = Path(\n", + " \"/resources/data/restricted/disambiguation-eval/preds/preds_phi4:14b_pv1_251125_1716\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7b456c9", + "metadata": {}, + "outputs": [], + "source": [ + "# Normalizando los textos\n", + "results, average = evaluate_prediction_directories(TEST_DIR, PREDS_DIR)\n", + "\n", + "if not results:\n", + " print(\"No se encontraron pares test/pred que evaluar.\")\n", + "else:\n", + " for doc_id, score, metrics in results:\n", + " print(f\"Documento: {doc_id}\")\n", + " print(f\" Score global: {score:.4f}\")\n", + " for metric_name, value in metrics.items():\n", + " print(f\" {metric_name}: {value:.4f}\")\n", + " print()\n", + "\n", + " print(f\"Promedio Score_global: {average:.4f}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80f08e1d", + "metadata": {}, + "outputs": [], + "source": [ + "# Sin Normalizar los textos\n", + "results, average = evaluate_prediction_directories(TEST_DIR, PREDS_DIR, normalize=False)\n", + "\n", + "if not results:\n", + " print(\"No se encontraron pares test/pred que evaluar.\")\n", + "else:\n", + " for doc_id, score, metrics in results:\n", + " print(f\"Documento: {doc_id}\")\n", + " print(f\" Score global: {score:.4f}\")\n", + " for metric_name, value in metrics.items():\n", + " print(f\" {metric_name}: {value:.4f}\")\n", + " print()\n", + "\n", + " print(f\"Promedio Score_global: {average:.4f}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8fd5e8b7", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md b/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md new file mode 100644 index 00000000..5f02a5f2 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md @@ -0,0 +1,500 @@ +# Métrica de evaluación para el desambiguador de entidades + +Este documento describe la métrica con la que evaluamos el módulo de **desambiguación de entidades canónicas** en documentos judiciales. La métrica es independiente del NER (que se evalúa por separado con F1 por clase) y se centra en medir la calidad de la resolución de entidades. + +La métrica: + +- recibe dos JSON: + - `gold_json`: referencia (ground truth), + - `pred_json`: salida del desambiguador; +- calcula cuatro componentes complementarios: +- $F1_{\text{ent}}$: calidad en la **detección de entidades canónicas**, +- $\text{AliasF1}_{\text{macro}}$: calidad en la **agrupación de aliases**, +- $Acc_{\text{label}}$: exactitud del **label** (`aymurai_label`), +- $Acc_{\text{rol}}$: exactitud del **rol** (`attributes["role"]`); +- devuelve un escalar final como combinación ponderada: + +$$ +\text{Score}_{\text{global}} = +w_{\text{ent}} \cdot F1_{\text{ent}} + +w_{\text{alias}} \cdot \text{AliasF1}_{\text{macro}} + +w_{\text{label}} \cdot Acc_{\text{label}} + +w_{\text{rol}} \cdot Acc_{\text{rol}}. +$$ + +Valores por defecto de los pesos: + +- $w_{\text{ent}} = 0.40$ +- $w_{\text{alias}} = 0.35$ +- $w_{\text{label}} = 0.20$ +- $w_{\text{rol}} = 0.05$ + +--- + +## 1. Modelo de datos y notación + +Tanto `gold_json` como `pred_json` se modelan como una **lista de entidades canónicas**. Cada entidad sigue la estructura: + +```json +{ + "entity_id": "", + "aymurai_label": "", + "canonical_text": "", + "aliases": [], + "attributes": {}, + "relations": [] +} +``` + +Denotamos: + +- Conjunto de entidades gold (referencia): $G = \{ g_1, g_2, \dots, g_N \}$ +- Conjunto de entidades predichas: $P = \{ p_1, p_2, \dots, p_M \}$ + +Para cada entidad $e \in G \cup P$: + +- $\text{label}(e)$ es su `aymurai_label`. +- $\text{aliases}(e)$ es el conjunto de aliases (incluyendo `canonical_text`). +- $\text{rol}(e)$ es `attributes["role"]` si existe (en caso contrario es `None`). + +La métrica está inspirada en trabajos de **entity resolution** y **coreference**, donde interesa comparar la formación de clusters más que strings exactos. + +--- + +## 2. Preprocesamiento: normalización y conjuntos de aliases + +Cada alias se normaliza para mitigar variaciones de formato. Se procesa tanto la lista `aliases` como `canonical_text`, y se construye un conjunto de strings normalizados que representa a la entidad. + +### 2.1. Normalización de texto + +Sea una función $\text{norm}(\cdot)$ que: + +1. convierte a minúsculas, +2. aplica `strip()` para remover espacios extras, +3. elimina tildes y acentos utilizando normalización Unicode. + +```python +import unicodedata + +def normalize_text(text: str) -> str: + if text is None: + return "" + text = text.strip().lower() + text = unicodedata.normalize("NFD", text) + text = "".join(ch for ch in text if unicodedata.category(ch) != "Mn") + return text +``` + +### 2.2. Construcción del conjunto de aliases + +Para cada entidad $e$: + +$$ +\text{aliases}(e) = \{ \text{norm}(a) \mid a \in e.\text{aliases} \} \cup \{ \text{norm}(e.\text{canonical\_text}) \}. +$$ + +```python +from typing import Any, Dict, Set + +def get_alias_set(entity: Dict[str, Any]) -> Set[str]: + aliases = { + normalize_text(a) + for a in entity.get("aliases", []) + if normalize_text(a) + } + canonical = normalize_text(entity.get("canonical_text", "")) + if canonical: + aliases.add(canonical) + return aliases +``` + +--- + +## 3. Similitud entre entidades: Jaccard sobre aliases + +Para medir qué tan similares son dos entidades, usamos la similitud de **Jaccard** sobre sus conjuntos de aliases: + +$$ +\text{sim}(g_i, p_j) = +\frac{\lvert \text{aliases}(g_i) \cap \text{aliases}(p_j) \rvert} + {\lvert \text{aliases}(g_i) \cup \text{aliases}(p_j) \rvert}. +$$ + +- Valor 1: conjuntos idénticos. +- Valor 0: conjuntos disjuntos. +- Valores intermedios: superposición parcial. + +```python +from typing import Set + +def alias_jaccard(aliases_gold: Set[str], aliases_pred: Set[str]) -> float: + if not aliases_gold and not aliases_pred: + return 1.0 + union = aliases_gold | aliases_pred + if not union: + return 0.0 + inter = aliases_gold & aliases_pred + return len(inter) / len(union) +``` + +Construimos una **matriz de similitud** $S \in \mathbb{R}^{N \times M}$ donde $S_{ij} = \text{sim}(g_i, p_j)$. + +--- + +## 4. Emparejamiento de entidades (matching gold–pred) + +### 4.1. Problema + +Necesitamos decidir qué entidad predicha corresponde a cada entidad gold. Esto es un matching bipartito: + +- Si el modelo divide una entidad real en dos, solo una predicha debería emparejarse con la gold; la otra contará como falso positivo. +- Si el modelo fusiona dos entidades distintas, solo una gold se emparejará; la otra será falso negativo. + +### 4.2. Umbral de similitud + +Se define un umbral $\tau$ (por defecto $\tau = 0.3$): + +- Si $S_{ij} < \tau$, se rechaza el match. +- Si $S_{ij} \ge \tau$, el par se considera candidato. + +### 4.3. Algoritmo greedy de emparejamiento + +Usamos un matching greedy ordenado por similitud (alternativa simple al algoritmo Húngaro): + +```python +from typing import List, Tuple + +def greedy_matching( + sim_matrix: List[List[float]], + sim_threshold: float +) -> List[Tuple[int, int, float]]: + matches: List[Tuple[int, int, float]] = [] + num_gold = len(sim_matrix) + num_pred = len(sim_matrix[0]) if num_gold > 0 else 0 + + candidates = [] + for i in range(num_gold): + for j in range(num_pred): + sim = sim_matrix[i][j] + if sim >= sim_threshold: + candidates.append((sim, i, j)) + + candidates.sort(reverse=True, key=lambda x: x[0]) + + used_gold, used_pred = set(), set() + for sim, i, j in candidates: + if i in used_gold or j in used_pred: + continue + used_gold.add(i) + used_pred.add(j) + matches.append((i, j, sim)) + + return matches +``` + +El resultado es una lista de triples $(i, j, \text{sim})$ con las parejas aceptadas. + +--- + +## 5. Métrica de entidades: $F1_{\text{ent}}$ + +Sean: + +- $\text{TP}$: número de pares emparejados. +- $\text{FN} = N - \text{TP}$: entidades gold sin match (perdidas). +- $\text{FP} = M - \text{TP}$: entidades pred sin match (inventadas o splits innecesarios). + +```math +P_{\text{ent}} = \frac{\text{TP}}{\text{TP} + \text{FP}}, \qquad +R_{\text{ent}} = \frac{\text{TP}}{\text{TP} + \text{FN}} +``` + +```math +F1_{\text{ent}} = +\begin{cases} +\dfrac{2 P_{\text{ent}} R_{\text{ent}}}{P_{\text{ent}} + R_{\text{ent}}}, & \text{si } P_{\text{ent}} + R_{\text{ent}} > 0 \\ +0, & \text{en otro caso} +\end{cases} +``` + +Interpretación: penaliza entidades faltantes, inventadas y los splits/merges incorrectos. + +--- + +## 6. Métrica de aliases: $\text{AliasF1}_{\text{macro}}$ + +Para cada par emparejado $(g_i, p_j)$: + +```math +A_g = \text{aliases}(g_i), \quad +A_p = \text{aliases}(p_j), \quad +I = |A_g \cap A_p| +``` + +```math +P_{\text{alias}}^{(i)} = \frac{I}{|A_p|}, \qquad +R_{\text{alias}}^{(i)} = \frac{I}{|A_g|} +``` + +```math +F1_{\text{alias}}^{(i)} = +\begin{cases} +\dfrac{2 P_{\text{alias}}^{(i)} R_{\text{alias}}^{(i)}} + {P_{\text{alias}}^{(i)} + R_{\text{alias}}^{(i)}}, & +\text{si } P_{\text{alias}}^{(i)} + R_{\text{alias}}^{(i)} > 0 \\ +0, & \text{en otro caso} +\end{cases} +``` + +Promediamos macro sobre los matches: + +```math +\text{AliasF1}_\text{macro} = +\frac{1}{\text{TP}} \sum_{(i,j) \in M_{\text{match}}} F1_{\text{alias}}^{(i)} +``` + +- Falta de aliases relevantes → baja el recall. +- Aliases incorrectos → baja la precision. +- Splits se reflejan en menor $F1_{\text{alias}}$. + +```python +alias_f1_sum = 0.0 +for i, j, _ in matches: + A_g = gold_aliases[i] + A_p = pred_aliases[j] + inter = len(A_g & A_p) + + P_alias = inter / len(A_p) if A_p else 0.0 + R_alias = inter / len(A_g) if A_g else 0.0 + if P_alias + R_alias > 0: + F1_alias = 2 * P_alias * R_alias / (P_alias + R_alias) + else: + F1_alias = 0.0 + + alias_f1_sum += F1_alias + +AliasF1_macro = alias_f1_sum / TP if TP > 0 else 0.0 +``` + +--- + +## 7. Exactitud de label y rol + +Para cada match \((g_i, p_j)\): + +```math +\text{correctLabel}^{(i)} = +\begin{cases} +1, & \text{si } \text{label}(g_i) = \text{label}(p_j) \\ +0, & \text{en otro caso} +\end{cases} +``` + +```math +\text{correctRol}^{(i)} = +\begin{cases} +1, & \text{si } \text{rol}(g_i) = \text{rol}(p_j) \\ +0, & \text{en otro caso} +\end{cases} +``` + +```math +Acc_{\text{label}} = +\frac{1}{\text{TP}} \sum_{(i,j) \in M_{\text{match}}} \text{correctLabel}^{(i)}, \quad +Acc_{\text{rol}} = +\frac{1}{\text{TP}} \sum_{(i,j) \in M_{\text{match}}} \text{correctRol}^{(i)}. +``` + +```python +label_correct = 0 +role_correct = 0 + +for i, j, _ in matches: + if gold_labels[i] == pred_labels[j]: + label_correct += 1 + if gold_roles[i] == pred_roles[j]: + role_correct += 1 + +Acc_label = label_correct / TP if TP > 0 else 0.0 +Acc_role = role_correct / TP if TP > 0 else 0.0 +``` + +Separar la calidad de la clusterización (aliases) de la del rotulado alinea la métrica con enfoques **entity-centric** en la literatura. + +--- + +## 8. Función `compute_metrics_components` + +Integra todos los pasos anteriores y devuelve un diccionario con los cuatro componentes: + +```python +from typing import Any, Dict, List + +def compute_metrics_components( + gold_entities: List[Dict[str, Any]], + pred_entities: List[Dict[str, Any]], + sim_threshold: float = 0.3, +) -> Dict[str, float]: + if not gold_entities and not pred_entities: + return { + "F1_ent": 1.0, + "AliasF1_macro": 1.0, + "Acc_label": 1.0, + "Acc_role": 1.0, + } + + gold_aliases = [get_alias_set(e) for e in gold_entities] + pred_aliases = [get_alias_set(e) for e in pred_entities] + + gold_labels = [e.get("aymurai_label") for e in gold_entities] + pred_labels = [e.get("aymurai_label") for e in pred_entities] + + gold_roles = [e.get("attributes", {}).get("rol") for e in gold_entities] + pred_roles = [e.get("attributes", {}).get("rol") for e in pred_entities] + + sim_matrix = [ + [alias_jaccard(g_gold, g_pred) for g_pred in pred_aliases] + for g_gold in gold_aliases + ] + + matches = greedy_matching(sim_matrix, sim_threshold=sim_threshold) + + TP = len(matches) + FN = len(gold_entities) - TP + FP = len(pred_entities) - TP + + P_ent = TP / (TP + FP) if TP + FP > 0 else 0.0 + R_ent = TP / (TP + FN) if TP + FN > 0 else 0.0 + F1_ent = 2 * P_ent * R_ent / (P_ent + R_ent) if P_ent + R_ent > 0 else 0.0 + + alias_f1_sum = 0.0 + label_correct = 0 + role_correct = 0 + + for i, j, _ in matches: + A_g = gold_aliases[i] + A_p = pred_aliases[j] + inter = len(A_g & A_p) + + P_alias = inter / len(A_p) if A_p else 0.0 + R_alias = inter / len(A_g) if A_g else 0.0 + if P_alias + R_alias > 0: + F1_alias = 2 * P_alias * R_alias / (P_alias + R_alias) + else: + F1_alias = 0.0 + alias_f1_sum += F1_alias + + if gold_labels[i] == pred_labels[j]: + label_correct += 1 + if gold_roles[i] == pred_roles[j]: + role_correct += 1 + + AliasF1_macro = alias_f1_sum / TP if TP > 0 else 0.0 + Acc_label = label_correct / TP if TP > 0 else 0.0 + Acc_role = role_correct / TP if TP > 0 else 0.0 + + return { + "F1_ent": F1_ent, + "AliasF1_macro": AliasF1_macro, + "Acc_label": Acc_label, + "Acc_role": Acc_role, + } +``` + +--- + +## 9. Métrica escalar final: `evaluate_disambiguation` + +Función de alto nivel que combina los componentes con los pesos: + +```python +import json +from typing import Any + +def evaluate_disambiguation( + gold_json: Any, + pred_json: Any, + w_ent: float = 0.4, + w_alias: float = 0.35, + w_label: float = 0.2, + w_role: float = 0.05, + sim_threshold: float = 0.3, +) -> Tuple[float, Dict[str, float]]: + if isinstance(gold_json, str): + gold_entities = json.loads(gold_json) + else: + gold_entities = gold_json + + if isinstance(pred_json, str): + pred_entities = json.loads(pred_json) + else: + pred_entities = pred_json + + metrics = compute_metrics_components( + gold_entities, + pred_entities, + sim_threshold=sim_threshold, + ) + + return ( + w_ent * metrics["F1_ent"] + + w_alias * metrics["AliasF1_macro"] + + w_label * metrics["Acc_label"] + + w_role * metrics["Acc_role"] + ) +``` + +### Justificación de los pesos por defecto + +- **$w_{\text{ent}} = 0.40$**: prioriza detectar todas las entidades canónicas sin inventarlas. +- **$w_{\text{alias}} = 0.35$**: agrupar aliases es crucial para preservar el anonimato. +- **$w_{\text{label}} = 0.20$**: el tipo de entidad importa, pero es secundario frente a la detección. +- **$w_{\text{rol}} = 0.05$**: el rol agrega contexto, pero tiene menor peso. + +Los pesos pueden ajustarse según las necesidades del proyecto. + +--- + +## 10. Ejemplo de uso + +```python +gold = [ + { + "entity_id": "GT_1", + "aymurai_label": "PER", + "canonical_text": "Juan Pérez", + "aliases": ["Juan Pérez", "Pérez, Juan"], + "attributes": {"role": "imputado"}, + "relations": [] + } +] + +pred = [ + { + "entity_id": "P_1", + "aymurai_label": "PER", + "canonical_text": "juan perez", + "aliases": ["juan perez", "perez juan"], + "attributes": {"role": "imputado"}, + "relations": [] + } +] + +score, components = evaluate_disambiguation(gold, pred) +print("Score global:", score) +print(components) +``` + +--- + +## 11. Referencias y relación con la literatura + +- Moosavi, N. S., & Strube, M. (2016). *Which coreference evaluation metric do you trust? A proposal for a link-based entity aware metric*. ACL. +- Menestrina, D., Whang, S. E., & Garcia-Molina, H. (2010). *Evaluating entity resolution results*. PVLDB. +- Binette, O., et al. (2024). *Comprehensive evaluation frameworks for entity resolution*. + +La métrica propuesta toma conceptos de la evaluación de coreference y entity resolution y los adapta a nuestro contexto judicial: + +- priorizando no perder entidades sensibles, +- evitando crear entidades inexistentes, +- y reforzando que los aliases de una misma persona no se mezclen con los de otra. From 3f040317ae661c0ad7384853fc068a4f57e413a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Wed, 26 Nov 2025 17:15:20 -0300 Subject: [PATCH 017/104] Feature/summarization (#61) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ feat: Add Streamlit app for document summarization experiments * Add statistical analysis notebook for summarization performance evaluation( Visualized gaps in performance between CPU and CUDA models, llm alucinations) * 🎨 Quantitative and qualitative analysis of summaries: descriptive analysis by features, model comparison, gap analusis (CPU-CUDA), Garbage detection/outliers, analysis by document, visuailzations. * 🔒️ clear all outputs * 🎨 Improve Summary Analysis per document: cuda vs llama (same model), gemma vs llama (cuda), same document phi3 vs. phi4. Token per second gap. * ✨ Add YAML utility functions for loading and saving data * Merge dev into main for v1.1.12 (#57) * Update README.md * 🐛 bugfix: Fix XML special character escaping in DocAnonymizer * ➕ build(deps): Add python-docx package * ✨ feat: Add watermark and hyperlink functionality to document anonymization * ✨ feat: Install Archivo font in Dockerfile * 🎨 refactor: Improve Dockerfile structure and comments for clarity * ⏪ revert: Remove Archivo font installation from Dockerfile * 🔖 feat: Update aymurai package version to 1.1.11 in uv.lock * 🐛 Improve get_extension logic to fix document extraction issues on Windows and remove python-magic dependency * 🔧 Update Dockerfile to use 'bullseye' variant for Python images for improved compatibility * 🔧 Update Makefile targets for improved Docker workflow * 🔖 feat: Bump aymurai package version to 1.1.12 * ♻️ Harden get_extension with header scans and zip safeguards * 🔧 Extend document extraction timeout to 30s * 🔧 Refactor Docker workflow to build and push images using docker/build-push-action * 🔧 Fix workflow step order to correctly extract tag name before building Docker images * 🔧 Remove tag extraction step and use github.ref_name directly for Docker image builds * ⏪ Revert Docker workflow to extract tag name and use it for image versioning * Update .github/workflows/build-docker-image.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * ✏️ Remove incomplete comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: jed Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * ✨ Add GPU-enabled Ollama service to compose stack * 🔧 Add Make targets for managing Ollama service and models * 🔧 Add launch configuration and task for starting Ollama service * 🔧 Add system prompts for document summarization * 📝 Add summarization benchmark notebook * 🚚 Move statistical analysis notebook to summarization folder * ✨ Implement LLM providers module with Ollama adapter and shared abstractions * ✅ Add unit tests for LLM providers including DummyProvider and OllamaLLMProvider * 📝 Document Ollama provider usage via notebook demo * 🐛 Fix tokenizer encoding by removing unnecessary special tokens flag * ♻️ Refactor chunk handling in LLMProvider to use _append_chunk method for consistency and improved readability * ✨ Enhance Ollama provider docs and DRY response building for sync/async calls * ♻️ Refactor OllamaLLMProvider to reuse AsyncClient instance for improved efficiency * 📝 Add async examples to OllamaLLMProvider notebook * ✅ Add async coverage for OllamaLLMProvider and tighten chunking tests * ➕ Add tiktoken dependency to pyproject.toml and update version in uv.lock * 🔧 Enhance summarization prompts with additional information extraction and entity identification details * ✨ Add LLM summarization router * 📝 Add notebook for the summarization endpoint * ✏️ Fix formatting of keys in summarization defaults for consistency * ➕ Add dspy dependency and update related packages in project configuration * 🚧 WIP: Add prompt optimization notebook for summarization experiments --------- Co-authored-by: Sofi Co-authored-by: jed Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- aymurai/api/core.py | 8 + aymurai/api/endpoints/routers/llm/__init__.py | 1 + .../endpoints/routers/llm/summarization.py | 580 ++++++ aymurai/utils/yaml_data.py | 28 + .../01-summarization-benchmark.ipynb | 735 ++++++++ .../02-statistical-analysis.ipynb | 1651 +++++++++++++++++ .../03-summarization-endpoint.ipynb | 170 ++ .../04-dspy-prompt-optimization.ipynb | 955 ++++++++++ pyproject.toml | 2 + resources/llm/summarization.yml | 71 + summarization_app/app.py | 759 ++++++++ summarization_app/run_streamlit_app.sh | 10 + uv.lock | 208 ++- 13 files changed, 5177 insertions(+), 1 deletion(-) create mode 100644 aymurai/api/endpoints/routers/llm/__init__.py create mode 100644 aymurai/api/endpoints/routers/llm/summarization.py create mode 100644 aymurai/utils/yaml_data.py create mode 100644 notebooks/experiments/summarization/01-summarization-benchmark.ipynb create mode 100644 notebooks/experiments/summarization/02-statistical-analysis.ipynb create mode 100644 notebooks/experiments/summarization/03-summarization-endpoint.ipynb create mode 100644 notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb create mode 100755 resources/llm/summarization.yml create mode 100755 summarization_app/app.py create mode 100755 summarization_app/run_streamlit_app.sh diff --git a/aymurai/api/core.py b/aymurai/api/core.py index c9223455..fe955b4b 100644 --- a/aymurai/api/core.py +++ b/aymurai/api/core.py @@ -3,6 +3,7 @@ from .endpoints.routers.anonymizer import anonymizer from .endpoints.routers.anonymizer import database as anonymizer_database from .endpoints.routers.datapublic import datapublic +from .endpoints.routers.llm import summarization from .endpoints.routers.misc import convert, document_extract from .endpoints.routers.server import stats @@ -36,6 +37,13 @@ tags=["datapublic/model"], ) +# LLM +router.include_router( + summarization.router, + prefix="/llm", + tags=["llm/summarization"], +) + # Misc router.include_router(document_extract.router, tags=["document"], deprecated=True) diff --git a/aymurai/api/endpoints/routers/llm/__init__.py b/aymurai/api/endpoints/routers/llm/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/aymurai/api/endpoints/routers/llm/__init__.py @@ -0,0 +1 @@ + diff --git a/aymurai/api/endpoints/routers/llm/summarization.py b/aymurai/api/endpoints/routers/llm/summarization.py new file mode 100644 index 00000000..6e40bc02 --- /dev/null +++ b/aymurai/api/endpoints/routers/llm/summarization.py @@ -0,0 +1,580 @@ +from __future__ import annotations + +import json +from pathlib import Path +from typing import Any, AsyncIterator + +import tiktoken +from fastapi import APIRouter, HTTPException +from fastapi.responses import StreamingResponse +from pydantic import BaseModel, ConfigDict, Field + +from aymurai.llm_providers import OllamaLLMProvider +from aymurai.logger import get_logger +from aymurai.settings import settings +from aymurai.utils.yaml_data import load_yaml + +logger = get_logger(__name__) + +router = APIRouter() + +DEFAULT_MODEL = "gpt-oss:20b" +DEFAULT_OPTIONS = {"num_ctx": 16_384, "num_predict": 4096} +DEFAULT_TOKENIZER = "o200k_harmony" +PROMPT_TEMPLATE_PATH = Path(settings.RESOURCES_BASEPATH) / "llm" / "summarization.yml" + + +def _load_prompt_defaults(path: Path) -> tuple[str, str]: + """ + Load default placeholders from the YAML template, + ensuring both required fields are present. + + Args: + path: Path to the summarization YAML file. + + Returns: + tuple[str, str]: Defaults for `information_to_extract` and `entities_to_identify`. + + Raises: + FileNotFoundError: If the YAML file cannot be located. + RuntimeError: If the defaults block is missing or incomplete. + """ + content = load_yaml(str(path)) + defaults = content.get("defaults", {}) + info = (defaults.get("information_to_extract") or "").strip() + entities = (defaults.get("entities_to_identify") or "").strip() + if not info or not entities: + raise RuntimeError("summarization defaults missing in YAML") + return info, entities + + +DEFAULT_INFORMATION_TO_EXTRACT, DEFAULT_ENTITIES_TO_IDENTIFY = _load_prompt_defaults( + PROMPT_TEMPLATE_PATH +) + + +class SummarizationRequest(BaseModel): + model_config = ConfigDict( + json_schema_extra={ + "example": { + "text": "Texto de entrada a resumir.", + "model": DEFAULT_MODEL, + "tokenizer": DEFAULT_TOKENIZER, + "options": DEFAULT_OPTIONS, + } + } + ) + + text: str = Field(..., description="Raw document to summarize.") + model: str = Field( + default=DEFAULT_MODEL, + description="Model name for Ollama. Defaults to gpt-oss:20b.", + ) + tokenizer: str | None = Field( + default=DEFAULT_TOKENIZER, + description="Tokenizer name (tiktoken). Falls back to whitespace if unavailable.", + ) + system_prompt: str | None = Field( + default=None, + description="Optional system prompt override. Defaults to the template in /resources/llm/summarization.yml.", + ) + information_to_extract: str | None = Field( + default=DEFAULT_INFORMATION_TO_EXTRACT, + description="Template variable information_to_extract.", + ) + entities_to_identify: str | None = Field( + default=DEFAULT_ENTITIES_TO_IDENTIFY, + description="Template variable entities_to_identify.", + ) + options: dict[str, Any] = Field( + default_factory=lambda: DEFAULT_OPTIONS.copy(), + description="Ollama chat options. Defaults to num_ctx=16_384 and num_predict=4096.", + ) + + +class SummarizationStep(BaseModel): + chunk_index: int + input_tokens: int + source: str + + +class SummarizationResponse(BaseModel): + summary: str + model: str + system_prompt: str + options: dict[str, Any] + chunks_used: int + steps: list[SummarizationStep] + + +def _load_template_prompt( + *, + information_to_extract: str | None, + entities_to_identify: str | None, +) -> str: + """ + Load and format the summarization prompt template. + + Args: + information_to_extract: Template placeholder describing what to extract. + entities_to_identify: Template placeholder listing entities to detect. + + Returns: + str: Formatted system prompt for summarization. + + Raises: + HTTPException: If the template file is missing or cannot be parsed. + """ + path = PROMPT_TEMPLATE_PATH + try: + content = load_yaml(str(path)) + template = content["system-prompts"]["template"] + + except FileNotFoundError as exc: + logger.exception(f"Summarization prompt template not found at {path}") + raise HTTPException( + status_code=500, + detail="Summarization prompt template not found.", + ) from exc + except Exception as exc: + logger.exception("Error loading summarization prompt template.") + raise HTTPException( + status_code=500, + detail="Unable to load summarization prompt template.", + ) from exc + + info = information_to_extract or DEFAULT_INFORMATION_TO_EXTRACT + entities = entities_to_identify or DEFAULT_ENTITIES_TO_IDENTIFY + + return template.format( + information_to_extract=info, + entities_to_identify=entities, + ) + + +def _load_tokenizer(tokenizer_name: str | None) -> tiktoken.Encoding | None: + """ + Load a tiktoken tokenizer by name. + + Args: + tokenizer_name (str | None): Name of the tokenizer to load. + + Returns: + tiktoken.Encoding | None: The loaded tokenizer encoding or None if unavailable. + """ + if not tokenizer_name: + return None + + try: + return tiktoken.get_encoding(tokenizer_name) + + except Exception: + logger.warning( + f"Tokenizer {tokenizer_name} is not available. Falling back to whitespace." + ) + return None + + +def _count_tokens(text: str, tokenizer: Any) -> int: + """ + Count the number of tokens in the given text using the provided tokenizer. + + Args: + text (str): The input text to count tokens for. + tokenizer (Any): The tokenizer to use for counting tokens. + + Returns: + int: The number of tokens in the input text. + """ + if tokenizer is None: + return len(text.split()) + try: + return len(tokenizer.encode(text)) + except Exception: + return len(text.split()) + + +def _build_provider( + model_name: str, + *, + tokenizer_name: str | None, + system_prompt: str, + context_limit: int, +) -> OllamaLLMProvider: + """ + Build an Ollama provider, adjusting available context for the system prompt. + + Args: + model_name: Name of the model to use. + tokenizer_name: Tokenizer name to attempt loading. + system_prompt: System prompt to set and budget for. + context_limit: Maximum number of context tokens. + + Returns: + OllamaLLMProvider: Configured OllamaLLMProvider instance. + """ + encoding = _load_tokenizer(tokenizer_name) + available_context = max(context_limit - _count_tokens(system_prompt, encoding), 1) + + return OllamaLLMProvider( + model=model_name, + tokenizer=encoding, + system_prompt=system_prompt, + max_context_tokens=available_context, + ) + + +async def _summarize_once( + provider: OllamaLLMProvider, + *, + text: str, + options: dict[str, Any], +) -> str: + """ + Run a single summarization call on the provider. + + Args: + provider: Initialized OllamaLLMProvider instance. + text: Chunk or combined text to summarize. + options: Provider options forwarded to the model. + + Returns: + str: The model's text output for the given input. + """ + response = await provider.async_generate(prompt=text, options=options) + return response.text + + +async def _rolling_summarize( + provider: OllamaLLMProvider, + *, + text: str, + options: dict[str, Any], +) -> tuple[str, list[SummarizationStep], int]: + """ + Summarize potentially long text by chunking and rolling summaries forward. + + Args: + provider: Initialized OllamaLLMProvider instance. + text: Full document text to summarize. + options: Provider options forwarded to the model. + + Returns: + tuple[str, list[SummarizationStep], int]: A tuple of (final_summary, steps_metadata, chunk_count). + """ + chunks = provider.chunk_text(text, max_tokens=provider.max_context_tokens) + if not chunks: + return "", [], 0 + + steps = [] + summary = await _summarize_once(provider, text=chunks[0].text, options=options) + steps.append( + SummarizationStep( + chunk_index=chunks[0].index, + input_tokens=chunks[0].token_count, + source="chunk", + ) + ) + + for chunk in chunks[1:]: + combined_text = f"{summary}\n\n{chunk.text}" + combined_tokens = provider.count_tokens(combined_text) + + if ( + provider.max_context_tokens + and combined_tokens > provider.max_context_tokens + ): + chunk_summary = await _summarize_once( + provider, + text=chunk.text, + options=options, + ) + steps.append( + SummarizationStep( + chunk_index=chunk.index, + input_tokens=chunk.token_count, + source="chunk", + ) + ) + combined_text = f"{summary}\n\n{chunk_summary}" + combined_tokens = provider.count_tokens(combined_text) + + if ( + provider.max_context_tokens + and combined_tokens > provider.max_context_tokens + ): + trimmed_parts = [] + for part in provider.chunk_text( + combined_text, max_tokens=provider.max_context_tokens + ): + tentative = " ".join(trimmed_parts + [part.text]) + if ( + provider.max_context_tokens + and provider.count_tokens(tentative) + > provider.max_context_tokens + ): + break + trimmed_parts.append(part.text) + combined_text = " ".join(trimmed_parts) + combined_tokens = provider.count_tokens(combined_text) + + summary = await _summarize_once( + provider, + text=combined_text, + options=options, + ) + steps.append( + SummarizationStep( + chunk_index=chunk.index, + input_tokens=combined_tokens, + source="summary+chunk", + ) + ) + + return summary, steps, len(chunks) + + +def _build_sse_message(payload: dict[str, Any]) -> str: + """ + Format a payload as an SSE data message. + + Args: + payload: Dictionary to serialize into the SSE data field. + + Returns: + str: Serialized SSE message string. + """ + return f"data: {json.dumps(payload)}\n\n" + + +def _trim_to_context(provider: OllamaLLMProvider, text: str) -> str: + """ + Trim combined text to respect the provider's context window. + + Args: + provider: Provider with a configured max_context_tokens. + text: Concatenated summary and chunk text. + + Returns: + str: Text trimmed to fit within the context limit. + """ + if not provider.max_context_tokens: + return text + + trimmed_parts: list[str] = [] + for part in provider.chunk_text(text, max_tokens=provider.max_context_tokens): + tentative = " ".join(trimmed_parts + [part.text]) + if ( + provider.max_context_tokens + and provider.count_tokens(tentative) > provider.max_context_tokens + ): + break + trimmed_parts.append(part.text) + + return " ".join(trimmed_parts) + + +@router.post("/summarize", response_model=SummarizationResponse) +async def summarize_document(payload: SummarizationRequest) -> SummarizationResponse: + """ + Summarize a document using a local Ollama model. + + The endpoint chunks inputs above the context limit and performs a rolling + summarization that keeps the interim summary in context for subsequent chunks. + """ + if not payload.text.strip(): + raise HTTPException(status_code=400, detail="Input text cannot be empty.") + + system_prompt = payload.system_prompt or _load_template_prompt( + information_to_extract=payload.information_to_extract, + entities_to_identify=payload.entities_to_identify, + ) + model_name = payload.model or DEFAULT_MODEL + options = {**DEFAULT_OPTIONS, **(payload.options or {})} + + try: + context_limit = int(options.get("num_ctx", DEFAULT_OPTIONS["num_ctx"])) + + except (TypeError, ValueError) as exc: + raise HTTPException( + status_code=400, + detail="num_ctx option must be an integer.", + ) from exc + + if context_limit <= 0: + raise HTTPException(status_code=400, detail="num_ctx must be greater than 0.") + + provider = _build_provider( + model_name, + tokenizer_name=payload.tokenizer, + system_prompt=system_prompt, + context_limit=context_limit, + ) + + summary, steps, chunk_count = await _rolling_summarize( + provider, + text=payload.text, + options=options, + ) + + return SummarizationResponse( + summary=summary, + model=provider.model_name, + system_prompt=system_prompt, + options=options, + chunks_used=chunk_count or 1, + steps=steps, + ) + + +@router.post("/summarize/stream") +async def stream_summarize_document( + payload: SummarizationRequest, +) -> StreamingResponse: + """ + Stream a document summary using server-sent events (text/event-stream). + + Emits: + - data: {"type": "meta", ...} + - data: {"type": "token", "chunk_index": int, "source": str, "text": str} + - data: {"type": "summary", "summary": str, "chunks_used": int, "steps": [...], "model": str} + """ + if not payload.text.strip(): + raise HTTPException(status_code=400, detail="Input text cannot be empty.") + + system_prompt = payload.system_prompt or _load_template_prompt( + information_to_extract=payload.information_to_extract, + entities_to_identify=payload.entities_to_identify, + ) + model_name = payload.model or DEFAULT_MODEL + options = {**DEFAULT_OPTIONS, **(payload.options or {})} + + try: + context_limit = int(options.get("num_ctx", DEFAULT_OPTIONS["num_ctx"])) + + except (TypeError, ValueError) as exc: + raise HTTPException( + status_code=400, + detail="num_ctx option must be an integer.", + ) from exc + + if context_limit <= 0: + raise HTTPException(status_code=400, detail="num_ctx must be greater than 0.") + + provider = _build_provider( + model_name, + tokenizer_name=payload.tokenizer, + system_prompt=system_prompt, + context_limit=context_limit, + ) + + async def event_stream() -> AsyncIterator[str]: + yield _build_sse_message( + { + "type": "meta", + "model": provider.model_name, + "system_prompt": system_prompt, + "options": options, + } + ) + + chunks = provider.chunk_text( + payload.text, + max_tokens=provider.max_context_tokens, + ) + + if not chunks: + yield _build_sse_message( + { + "type": "summary", + "summary": "", + "chunks_used": 0, + "steps": [], + "model": provider.model_name, + } + ) + return + + steps: list[dict[str, Any]] = [] + summary = "" + + for chunk in chunks: + source = "chunk" if not summary else "summary+chunk" + combined_text = f"{summary}\n\n{chunk.text}" if summary else chunk.text + combined_tokens = provider.count_tokens(combined_text) + + if ( + provider.max_context_tokens + and combined_tokens > provider.max_context_tokens + and summary + ): + # Summarize the current chunk alone when the combined context would overflow. + chunk_summary = "" + async for resp in provider.async_stream( + prompt=chunk.text, + options=options, + ): + token = resp.text + if not token: + continue + chunk_summary += token + yield _build_sse_message( + { + "type": "token", + "chunk_index": chunk.index, + "source": "chunk", + "text": token, + } + ) + + steps.append( + { + "chunk_index": chunk.index, + "input_tokens": chunk.token_count, + "source": "chunk", + } + ) + + combined_text = f"{summary}\n\n{chunk_summary}" + combined_text = _trim_to_context(provider, combined_text) + source = "summary+chunk" + combined_tokens = provider.count_tokens(combined_text) + + updated_summary = "" + async for resp in provider.async_stream( + prompt=combined_text, + options=options, + ): + token = resp.text + if not token: + continue + updated_summary += token + yield _build_sse_message( + { + "type": "token", + "chunk_index": chunk.index, + "source": source, + "text": token, + } + ) + + steps.append( + { + "chunk_index": chunk.index, + "input_tokens": combined_tokens, + "source": source, + } + ) + summary = updated_summary + + yield _build_sse_message( + { + "type": "summary", + "summary": summary, + "chunks_used": len(chunks), + "steps": steps, + "model": provider.model_name, + } + ) + + return StreamingResponse(event_stream(), media_type="text/event-stream") diff --git a/aymurai/utils/yaml_data.py b/aymurai/utils/yaml_data.py new file mode 100644 index 00000000..97d30fbb --- /dev/null +++ b/aymurai/utils/yaml_data.py @@ -0,0 +1,28 @@ +import yaml + + +def load_yaml(file_path: str) -> dict: + """ + Loads a yaml file and returns its content as a dictionary. + + Args: + file_path (str): The path to the yaml file. + + Returns: + dict: The yaml file content. + """ + with open(file_path, "r") as f: + content = yaml.safe_load(f) + return content + + +def save_yaml(dict_data: dict, file_path: str) -> None: + """ + Saves a dictionary as a yaml file. + + Args: + dict_data (dict): The dictionary to be saved. + file_path (str): The path to the file where the yaml will be saved. + """ + with open(file_path, "w") as f: + f.write(yaml.dump(dict_data)) diff --git a/notebooks/experiments/summarization/01-summarization-benchmark.ipynb b/notebooks/experiments/summarization/01-summarization-benchmark.ipynb new file mode 100644 index 00000000..1178ac62 --- /dev/null +++ b/notebooks/experiments/summarization/01-summarization-benchmark.ipynb @@ -0,0 +1,735 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "f900ed31", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "%load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03359440", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import mimetypes\n", + "import os\n", + "import time\n", + "from pathlib import Path\n", + "from typing import Iterable\n", + "\n", + "import ollama\n", + "import requests\n", + "from IPython.display import Markdown\n", + "from ollama import ChatResponse\n", + "from tqdm import tqdm\n", + "\n", + "from aymurai.utils.json_data import load_json, save_json\n", + "from aymurai.utils.yaml_data import load_yaml" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6297e02c", + "metadata": {}, + "outputs": [], + "source": [ + "os.environ[\"OLLAMA_KEEP_ALIVE\"] = \"0\"\n", + "print(\"OLLAMA_KEEP_ALIVE set to 0. Models will unload immediately after use.\")" + ] + }, + { + "cell_type": "markdown", + "id": "1d59c9c9", + "metadata": {}, + "source": [ + "## Documents" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28110bf0", + "metadata": {}, + "outputs": [], + "source": [ + "BASE_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", + "ENDPOINT = f\"{BASE_URL}/misc/document-extract\"\n", + "DATA_ROOT = Path(\n", + " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3fb80b7", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "print(f\"Discovered {len(documents)} documents.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aebe1738", + "metadata": {}, + "outputs": [], + "source": [ + "def call_extraction_api(\n", + " session: requests.Session, file_path: Path\n", + ") -> dict[str, object]:\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " ENDPOINT,\n", + " files=files,\n", + " timeout=REQUEST_TIMEOUT_S,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f04a9d2", + "metadata": {}, + "outputs": [], + "source": [ + "doc_path = documents[0]\n", + "extracted_document = call_extraction_api(requests.Session(), doc_path)[\"detail\"]\n", + "document = \"\\n\".join(extracted_document[\"document\"])\n", + "print(document)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb930b69", + "metadata": {}, + "outputs": [], + "source": [ + "extracted_documents = []\n", + "\n", + "for doc_path in tqdm(documents):\n", + " session = requests.Session()\n", + " extracted_document = call_extraction_api(session, doc_path)\n", + " extracted_documents.append(\n", + " {\n", + " \"doc_path\": os.path.basename(doc_path),\n", + " **extracted_document,\n", + " }\n", + " )\n", + " session.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce7ea84c", + "metadata": {}, + "outputs": [], + "source": [ + "len(extracted_documents)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a4fee57", + "metadata": {}, + "outputs": [], + "source": [ + "extracted_documents[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a11c0245", + "metadata": {}, + "outputs": [], + "source": [ + "# Filter out empty extracted documents\n", + "extracted_documents = [\n", + " doc for doc in extracted_documents if len(doc[\"detail\"][\"document\"])\n", + "]\n", + "len(extracted_documents)" + ] + }, + { + "cell_type": "markdown", + "id": "e509e467", + "metadata": {}, + "source": [ + "## LLMs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00604dcd", + "metadata": {}, + "outputs": [], + "source": [ + "MODELS = [\n", + " # Llama\n", + " \"llama3.1:8b\",\n", + " \"llama3.2:3b\",\n", + " # Gemma\n", + " \"gemma3:4b\",\n", + " \"gemma3n:e4b\",\n", + " \"gemma3:12b\",\n", + " # Qwen\n", + " \"qwen3:8b\",\n", + " \"qwen3:14b\",\n", + " # Phi\n", + " \"phi3:3.8b\",\n", + " \"phi4:14b\",\n", + " # DeepSeek\n", + " \"deepseek-r1:8b\",\n", + " \"deepseek-r1:14b\",\n", + " # GPT\n", + " \"gpt-oss:20b\",\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "7669a65c", + "metadata": {}, + "source": [ + "### System Prompts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1adce13", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompts = load_yaml(\"/resources/llm/summarization.yml\")[\"system-prompts\"]\n", + "system_prompts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4dfe7899", + "metadata": {}, + "outputs": [], + "source": [ + "# Function to get chat response from the model\n", + "def get_chat_response(\n", + " system_prompt: str,\n", + " user_prompt: str,\n", + " model: str = \"llama3.2:3b\",\n", + " options: dict = {\"num_ctx\": 16_384, \"num_predict\": 4096},\n", + ") -> ChatResponse:\n", + " \"\"\"\n", + " Get chat response from the model.\n", + "\n", + " Args:\n", + " system_prompt (str): The system prompt.\n", + " user_prompt (str): The prompt from the user.\n", + " model (str, optional): The model to use. Defaults to \"llama3.2:3b\".\n", + " options (dict, optional): The options for the chat.\n", + " Defaults to {\"num_ctx\": 16_384, \"num_predict\": 4096}.\n", + "\n", + " Returns:\n", + " ChatResponse: The response from the chat.\n", + " \"\"\"\n", + " response = ollama.chat(\n", + " model=model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options=options,\n", + " )\n", + "\n", + " return response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c8016bd", + "metadata": {}, + "outputs": [], + "source": [ + "iter_documents = iter(extracted_documents)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8677785", + "metadata": {}, + "outputs": [], + "source": [ + "document = next(iter_documents)\n", + "document = \"\\n\".join(document[\"detail\"][\"document\"])\n", + "print(document)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "034bd672", + "metadata": {}, + "outputs": [], + "source": [ + "# Define system prompt and get chat response\n", + "system_prompt = system_prompts[\"baseline\"]\n", + "\n", + "# Get chat response\n", + "chat_response = get_chat_response(system_prompt, document)\n", + "print(chat_response.message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "918dc835", + "metadata": {}, + "outputs": [], + "source": [ + "# Define system prompt and get chat response\n", + "system_prompt = system_prompts[\"task-specific\"]\n", + "\n", + "# Get chat response\n", + "chat_response = get_chat_response(system_prompt, document)\n", + "print(chat_response.message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f4b55f3", + "metadata": {}, + "outputs": [], + "source": [ + "# Define prompt parameters\n", + "INFORMATION = \"\"\"\n", + " - Hechos relevantes (qué ocurrió).\n", + " - Actores clave (quiénes están involucrados).\n", + " * Denunciante(s).\n", + " * Denunciado(s).\n", + " * Testigo(s).\n", + " * Juez(es).\n", + " * Abogado(s).\n", + " * Fiscal(es).\n", + " * Perito(s).\n", + " * Otros (especificar).\n", + " - Cronología (cuándo ocurrieron los hechos y eventos procesales importantes).\n", + " - Lugar(es) (dónde ocurrieron los hechos y eventos procesales importantes).\n", + " - Fundamentos (normas legales, precedentes judiciales, doctrinas aplicadas).\n", + " - Decisión (resultado/medida adoptada).\n", + "\"\"\"\n", + "\n", + "ENTITIES = \"\"\"\n", + " - \"BANCO\": Nombre de una entidad bancaria, pública o privada.\n", + " - \"CBU\": Código Bancario Uniforme (22 dígitos) de una cuenta.\n", + " - \"CORREO_ELECTRONICO\": Dirección de correo electrónico.\n", + " - \"CUIJ\": Código Único de Identificación Jurídica de causas judiciales.\n", + " - \"CUIT_CUIL\": Número de CUIT o CUIL de una persona física o jurídica.\n", + " - \"DIRECCION\": Dirección específica (calle, número, intersección de calles y/o avenidas, código postal, etc.).\n", + " - \"DNI\": Número de Documento Nacional de Identidad u otro documento identificatorio.\n", + " - \"EDAD\": Edad explícita de una persona.\n", + " - \"ESTUDIOS\": Nivel o institución educativa que permita identificar a la persona (ej. \"primario incompleto\", \"secundario completo\", \"Licenciado en…\").\n", + " - \"FECHA\": Fecha completa o parcial (día, mes y/o año).\n", + " - \"LINK\": Enlace o URL a una página web.\n", + " - \"LOC\": Localización geográfica específica (país, provincia, estado, ciudad, localidad, barrio, etc.).\n", + " - \"MARCA_AUTOMOVIL\": Marca de un vehículo (ej. Toyota, Ford, Suzuki, etc.).\n", + " - \"NACIONALIDAD\": Nacionalidad de una persona (ej. \"argentino\", \"brasileña\").\n", + " - \"NUM_ACTUACION\": Número identificatorio de una actuación administrativa o contravencional.\n", + " - \"NUM_CAJA_AHORRO\": Número completo de una caja de ahorro o cuenta bancaria.\n", + " - \"NUM_EXPEDIENTE\": Número de expediente judicial o administrativo.\n", + " - \"NUM_MATRICULA\": Número de matrícula profesional o académica.\n", + " - \"PATENTE_DOMINIO\": Patente o dominio de un vehículo.\n", + " - \"PER\": Nombre y apellido(s) de una persona física. Los nombres inicializados (ej., \"M.T.G\") y los apodos (ej., \"el Gato\") también cuentan como información sensible a anonimizar.\n", + " - \"TELEFONO\": Número telefónico (fijo o celular).\n", + "\"\"\"\n", + "\n", + "\n", + "# Define system prompt\n", + "system_prompt = system_prompts[\"template\"].format(\n", + " information_to_extract=INFORMATION,\n", + " entities_to_identify=ENTITIES,\n", + ")\n", + "\n", + "print(system_prompt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3efcf14f", + "metadata": {}, + "outputs": [], + "source": [ + "# Get chat response\n", + "chat_response = get_chat_response(system_prompt, document)\n", + "Markdown(chat_response.message.content)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92f8d337", + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate_chat_response(\n", + " system_prompt: str,\n", + " user_prompt: str,\n", + " model: str = \"llama3.2:3b\",\n", + " options: dict = {\"num_ctx\": 16_384, \"num_predict\": 4096},\n", + ") -> dict:\n", + " \"\"\"\n", + " Get chat response from the model and evaluate tokens and runtime metrics.\n", + "\n", + " Args:\n", + " system_prompt (str): The system prompt.\n", + " user_prompt (str): The prompt from the user.\n", + " model (str, optional): The model to use. Defaults to \"llama3.2:3b\".\n", + " options (dict, optional): The options for the chat.\n", + " Defaults to {\"num_ctx\": 16_384, \"num_predict\": 4096}.\n", + "\n", + " Returns:\n", + " dict: A dictionary containing:\n", + " - response: The content of the response\n", + " - model: The model name\n", + " - input_tokens: Number of tokens in the prompt (prompt_eval_count)\n", + " - input_duration_ms: Time taken to process input tokens in milliseconds\n", + " - output_tokens: Number of tokens in the output (eval_count)\n", + " - output_duration_ms: Time taken to generate output tokens in milliseconds\n", + " - total_tokens: Total number of tokens processed\n", + " - total_duration_ms: Total duration of the request in milliseconds\n", + " - tokens_per_second: Rate of token generation (output tokens / output duration)\n", + " \"\"\"\n", + " start = time.time()\n", + "\n", + " # Get the chat response\n", + " response = get_chat_response(\n", + " user_prompt=user_prompt,\n", + " model=model,\n", + " system_prompt=system_prompt,\n", + " options=options,\n", + " )\n", + "\n", + " end = time.time()\n", + "\n", + " # Extract metrics\n", + " input_tokens = (\n", + " response.prompt_eval_count if hasattr(response, \"prompt_eval_count\") else None\n", + " )\n", + " output_tokens = response.eval_count if hasattr(response, \"eval_count\") else None\n", + " total_tokens = None\n", + "\n", + " # If total_tokens is still None but we have input and output tokens\n", + " if total_tokens is None and input_tokens is not None and output_tokens is not None:\n", + " total_tokens = input_tokens + output_tokens\n", + "\n", + " # Extract durations and convert nanoseconds to milliseconds\n", + " input_duration_ms = None\n", + " if hasattr(response, \"prompt_eval_duration\"):\n", + " input_duration_ms = response.prompt_eval_duration / 1_000_000 # ns to ms\n", + "\n", + " output_duration_ms = None\n", + " if hasattr(response, \"eval_duration\"):\n", + " output_duration_ms = response.eval_duration / 1_000_000 # ns to ms\n", + "\n", + " model_total_duration_ms = None\n", + " if hasattr(response, \"total_duration\"):\n", + " model_total_duration_ms = response.total_duration / 1_000_000 # ns to ms\n", + "\n", + " # Calculate the total duration from our timer (this will include network latency)\n", + " measured_duration_ms = (end - start) * 1000\n", + "\n", + " # Calculate tokens per second for generation\n", + " tokens_per_second = None\n", + " if (\n", + " output_tokens is not None\n", + " and output_duration_ms is not None\n", + " and output_duration_ms > 0\n", + " ):\n", + " tokens_per_second = output_tokens / (output_duration_ms / 1000)\n", + "\n", + " return {\n", + " \"model\": model,\n", + " \"options\": options,\n", + " \"system_prompt\": system_prompt,\n", + " \"user_prompt\": user_prompt,\n", + " \"chat_response\": response.message.content,\n", + " \"input_tokens\": input_tokens,\n", + " \"input_duration_ms\": input_duration_ms,\n", + " \"output_tokens\": output_tokens,\n", + " \"output_duration_ms\": output_duration_ms,\n", + " \"total_tokens\": total_tokens,\n", + " \"model_duration_ms\": model_total_duration_ms,\n", + " \"measured_duration_ms\": measured_duration_ms,\n", + " \"tokens_per_second\": tokens_per_second,\n", + " \"raw_response\": response.model_dump(), # Include the full response object for reference\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fce8d0f", + "metadata": {}, + "outputs": [], + "source": [ + "# Test our new evaluation function\n", + "test_result = evaluate_chat_response(\n", + " system_prompt=system_prompts[\"task-specific\"],\n", + " user_prompt=document,\n", + ")\n", + "\n", + "# Display the metrics\n", + "print(f\"Response from {test_result['model']}:\")\n", + "print(\"-\" * 50)\n", + "print(test_result[\"raw_response\"])\n", + "print(\"-\" * 50)\n", + "print(f\"Input tokens: {test_result['input_tokens']}\")\n", + "print(f\"Input processing time: {test_result['input_duration_ms']:.2f} ms\")\n", + "print(f\"Output tokens: {test_result['output_tokens']}\")\n", + "print(f\"Output generation time: {test_result['output_duration_ms']:.2f} ms\")\n", + "print(f\"Total tokens: {test_result['total_tokens']}\")\n", + "print(f\"Model reported duration: {test_result['model_duration_ms']:.2f} ms\")\n", + "print(f\"Measured duration: {test_result['measured_duration_ms']:.2f} ms\")\n", + "print(f\"Generation speed: {test_result['tokens_per_second']:.2f} tokens/second\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "68a55804", + "metadata": {}, + "outputs": [], + "source": [ + "errors = []\n", + "results = []" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "868fbd4c", + "metadata": {}, + "outputs": [], + "source": [ + "DEVICE = \"cuda\"\n", + "\n", + "results = load_json(f\"./summarization-benchmark-results-{DEVICE}.json\")\n", + "results[-1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ca81c50", + "metadata": {}, + "outputs": [], + "source": [ + "len(results)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72c190b3", + "metadata": {}, + "outputs": [], + "source": [ + "for extracted_document in tqdm(\n", + " extracted_documents, total=len(extracted_documents), desc=\"Evaluating documents\"\n", + "):\n", + " doc_path = os.path.basename(extracted_document[\"doc_path\"])\n", + " document = \"\\n\".join(extracted_document[\"detail\"][\"document\"])\n", + "\n", + " if not document.strip():\n", + " print(f\"Skipping empty document: {doc_path}\")\n", + " continue\n", + "\n", + " for model in MODELS:\n", + " for system_prompt_type in system_prompts:\n", + " print(\n", + " f\"Evaluating {doc_path} with model {model} and prompt {system_prompt_type}\"\n", + " )\n", + " if any(\n", + " r\n", + " for r in results\n", + " if r[\"doc_path\"] == doc_path\n", + " and r[\"model\"] == model\n", + " and r[\"system_prompt_type\"] == system_prompt_type\n", + " and r[\"device\"] == DEVICE\n", + " ):\n", + " print(\n", + " f\"Skipping {doc_path} with model {model} and prompt {system_prompt_type} on {DEVICE} (already evaluated)\"\n", + " )\n", + " continue\n", + "\n", + " system_prompt = system_prompts[system_prompt_type]\n", + " if system_prompt_type == \"template\":\n", + " system_prompt = system_prompts[\"template\"].format(\n", + " information_to_extract=INFORMATION,\n", + " entities_to_identify=ENTITIES,\n", + " )\n", + "\n", + " try:\n", + " result = evaluate_chat_response(\n", + " system_prompt=system_prompt,\n", + " user_prompt=document,\n", + " model=model,\n", + " )\n", + " result[\"doc_path\"] = doc_path\n", + " result[\"system_prompt_type\"] = system_prompt_type\n", + " result[\"device\"] = DEVICE\n", + " results.append(result)\n", + "\n", + " save_json(\n", + " results,\n", + " f\"./summarization-benchmark-results-{DEVICE}.json\",\n", + " )\n", + "\n", + " except Exception as e:\n", + " print(f\"Error evaluating {doc_path} with model {model}: {e}\")\n", + " errors.append(\n", + " {\n", + " \"doc_path\": doc_path,\n", + " \"model\": model,\n", + " \"system_prompt\": system_prompt,\n", + " \"device\": DEVICE,\n", + " \"error\": str(e),\n", + " }\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1359dec5", + "metadata": {}, + "outputs": [], + "source": [ + "len(errors)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "849850e9", + "metadata": {}, + "outputs": [], + "source": [ + "errors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc9c3cab", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/summarization/02-statistical-analysis.ipynb b/notebooks/experiments/summarization/02-statistical-analysis.ipynb new file mode 100644 index 00000000..aef5a7d9 --- /dev/null +++ b/notebooks/experiments/summarization/02-statistical-analysis.ipynb @@ -0,0 +1,1651 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f5458e0a", + "metadata": {}, + "source": [ + "# Summaries Analysis\n", + "\n", + "This notebook performs both **quantitative** and **qualitative** analyses of the summaries generated by the API, to build a complete picture of model summary performance.\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "481c1d32", + "metadata": {}, + "source": [ + "\n", + "\n", + "**1. Quantitative Analysis**\n", + "- Conduct a **statistical and exploratory data analysis** of the API results using Pandas and descriptive statistics. \n", + "- Explore and refine the **visualizations** to better highlight differences and distributions. \n", + "- Compare **model runtimes** (CPU vs GPU) for the same document to assess performance efficiency. \n", + "\n", + "\n", + "\n", + "**1. Qualitative Analysis**\n", + "- **Garbage Detection:** Identify low-quality or nonsensical summaries (e.g., hallucinations or “garbage” outputs). \n", + " These can often be detected as **outliers** in the quantitative performance metrics. \n", + " DeepSeek has shown clear examples of this behavior. \n", + "- **Summary Comparison:** Evaluate the **relative quality and performance** of summaries across different models, linking the findings with the quantitative metrics.\n" + ] + }, + { + "cell_type": "markdown", + "id": "69039406", + "metadata": {}, + "source": [ + "## Quantitative Analysis" + ] + }, + { + "cell_type": "markdown", + "id": "d98633a6", + "metadata": {}, + "source": [ + "#### Load data and function definitions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5be98b6f", + "metadata": {}, + "outputs": [], + "source": [ + "# Libraries imports\n", + "\n", + "import os\n", + "import json\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "import seaborn as sns" + ] + }, + { + "cell_type": "markdown", + "id": "b4b981af", + "metadata": {}, + "source": [ + "Function definitions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d58de8bc", + "metadata": {}, + "outputs": [], + "source": [ + "# Attempt to identify parameter scale (in billions) from model names\n", + "def get_model_parameter_scale(model_name):\n", + " import re\n", + "\n", + " if not model_name:\n", + " return None\n", + "\n", + " known_params = {\n", + " \"gemma3:12b\": 12,\n", + " \"gemma3:40b\": 40,\n", + " \"gemma3:20b\": 20,\n", + " \"gemma3:22b\": 22,\n", + " \"gemma3:38b\": 38,\n", + " \"llama3.1:8b\": 8,\n", + " \"llama3.2:3b\": 3,\n", + " \"llama3.2:11b\": 11,\n", + " \"deepseek-r1:1.1b\": 1.1,\n", + " \"deepseek-r1:1b\": 1,\n", + " \"phi-3:3.8b\": 3.8,\n", + " \"phi-4:14b\": 14,\n", + " \"qwen3:3.8b\": 3.8,\n", + " \"qwen3:14b\": 14,\n", + " \"qwen3:72b\": 72,\n", + " }\n", + "\n", + " model_name_lower = model_name.lower()\n", + " if model_name_lower in known_params:\n", + " return known_params[model_name_lower]\n", + "\n", + " match = re.search(r\"(\\d+(?:\\.\\d+)?)\\s*b\", model_name_lower)\n", + " if match:\n", + " try:\n", + " return float(match.group(1))\n", + " except ValueError:\n", + " return None\n", + " return None\n", + "\n", + "\n", + "def unique_vals(df, col):\n", + " print(col)\n", + " return print(f\"Total {col}: {(df[col].nunique())} \\n {(df[col].unique())} \\n\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03ae93cc", + "metadata": {}, + "outputs": [], + "source": [ + "DATA_PATH = \"/resources/data/restricted/summarization\" # Change this to your data path\n", + "cuda_summaries_file = os.path.join(\n", + " DATA_PATH, \"summarization-benchmark-results-cuda.json\"\n", + ")\n", + "cpu_summaries_file = os.path.join(DATA_PATH, \"summarization-benchmark-results-cpu.json\")\n", + "\n", + "with open(cuda_summaries_file, \"r\") as f:\n", + " cuda_summaries = json.load(f)\n", + "with open(cpu_summaries_file, \"r\") as f:\n", + " cpu_summaries = json.load(f)\n", + "\n", + "summaries = cuda_summaries + cpu_summaries\n", + "df = pd.DataFrame(summaries)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64887e36", + "metadata": {}, + "outputs": [], + "source": [ + "df.doc_path.nunique()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9eff2b81", + "metadata": {}, + "outputs": [], + "source": [ + "df.doc_path = df.doc_path.apply(lambda x: os.path.basename(x))\n", + "df.doc_path.nunique()" + ] + }, + { + "cell_type": "markdown", + "id": "9000571b", + "metadata": {}, + "source": [ + "### Descriptive analysis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4081f62e", + "metadata": {}, + "outputs": [], + "source": [ + "df.head(4)" + ] + }, + { + "cell_type": "markdown", + "id": "bdaddf02", + "metadata": {}, + "source": [ + "#### Prompts visualization/print" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3dd1c488", + "metadata": {}, + "outputs": [], + "source": [ + "import pprint\n", + "\n", + "unique = (\n", + " df[[\"system_prompt\", \"system_prompt_type\"]].drop_duplicates().reset_index(drop=True)\n", + ")\n", + "\n", + "for _, row in unique.iterrows():\n", + " print(\"Type:\", row[\"system_prompt_type\"])\n", + " print(\"Prompt:\")\n", + " pprint.pprint(row[\"system_prompt\"])\n", + " print(\"---\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7a99302", + "metadata": {}, + "outputs": [], + "source": [ + "df.info()" + ] + }, + { + "cell_type": "markdown", + "id": "9b7300d5", + "metadata": {}, + "source": [ + "#### Data engineer (ms -> mins)" + ] + }, + { + "cell_type": "markdown", + "id": "f628dc9e", + "metadata": {}, + "source": [ + "Create new columns to mins unit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ed9c4c4", + "metadata": {}, + "outputs": [], + "source": [ + "ms_cols = [c for c in df.columns if c.endswith(\"ms\")]\n", + "ms_min_cols = [[c.replace(\"ms\", \"min\"), c] for c in ms_cols]\n", + "time_cols = [c[0] for c in ms_min_cols]\n", + "\n", + "for cols in ms_min_cols:\n", + " c, ms_col = cols\n", + " df[c] = df[ms_col] / 1000 / 60\n", + "\n", + "df.head(2)\n", + "\n", + "time_cols" + ] + }, + { + "cell_type": "markdown", + "id": "4d25024d", + "metadata": {}, + "source": [ + "#### Describe columns" + ] + }, + { + "cell_type": "markdown", + "id": "33014b1c", + "metadata": {}, + "source": [ + "We describe the float type columns:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61cc141c", + "metadata": {}, + "outputs": [], + "source": [ + "desc = (\n", + " df[\n", + " [\n", + " \"input_tokens\",\n", + " \"output_tokens\",\n", + " \"total_tokens\",\n", + " \"input_duration_min\",\n", + " \"output_duration_min\",\n", + " \"model_duration_min\",\n", + " \"tokens_per_second\",\n", + " ]\n", + " ]\n", + " .describe()\n", + " .T\n", + ")\n", + "print(desc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6dbb2ba5", + "metadata": {}, + "outputs": [], + "source": [ + "840 / 60" + ] + }, + { + "cell_type": "markdown", + "id": "116603ca", + "metadata": {}, + "source": [ + "We observed that the 75% of the results have model_duration_min <= 7.7 minutes, and the is at list one outlier with model_duration_min = 840 minutes (14 hours)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bcd5ccbd", + "metadata": {}, + "outputs": [], + "source": [ + "df[df[\"model_duration_min\"] > 840]" + ] + }, + { + "cell_type": "markdown", + "id": "7945a14f", + "metadata": {}, + "source": [ + "This is an outlier due the garbage of its output:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f02adf9b", + "metadata": {}, + "outputs": [], + "source": [ + "import pprint\n", + "\n", + "df[df[\"model_duration_min\"] > 840].chat_response.iloc[0][-200:]" + ] + }, + { + "cell_type": "markdown", + "id": "1ddcf0b0", + "metadata": {}, + "source": [ + "Visualization of unique values per main columns:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0ec9e75", + "metadata": {}, + "outputs": [], + "source": [ + "for col in [\n", + " \"model\",\n", + " \"system_prompt\",\n", + " \"device\",\n", + " \"system_prompt_type\",\n", + " \"user_prompt\",\n", + " \"doc_path\",\n", + "]:\n", + " unique_vals(df, col)" + ] + }, + { + "cell_type": "markdown", + "id": "2e1f550d", + "metadata": {}, + "source": [ + "### Model comparison" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3d684ef", + "metadata": {}, + "outputs": [], + "source": [ + "df.groupby(\"model\")[\n", + " [\"tokens_per_second\", \"model_duration_min\", \"total_tokens\"]\n", + "].mean().sort_values(\"tokens_per_second\", ascending=False)\n", + "df.groupby([\"model\", \"device\"])[[\"model_duration_min\", \"tokens_per_second\"]].mean()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f749026", + "metadata": {}, + "outputs": [], + "source": [ + "# Runtime distribution\n", + "plt.figure(figsize=(8, 5), dpi=50)\n", + "sns.boxplot(data=df, x=\"model\", y=\"model_duration_min\", hue=\"device\")\n", + "plt.xticks(rotation=45)\n", + "plt.title(\"Model Duration by Device\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "86d0a9a8", + "metadata": {}, + "source": [ + "Since deepseek-r1:8b has a duration one or two orders of magnitude longer compared to other models, we removed it from the visualization to avoid scaling issues:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "646c45d5", + "metadata": {}, + "outputs": [], + "source": [ + "df_to_plot = df[df[\"model\"] != \"deepseek-r1:8b\"]\n", + "# Runtime distribution\n", + "plt.figure(figsize=(8, 5), dpi=100)\n", + "sns.boxplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"device\")\n", + "plt.xticks(rotation=45)\n", + "plt.title(\"Tokens per second by device\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ceada36", + "metadata": {}, + "outputs": [], + "source": [ + "df_to_plot = df[df[\"model\"] != \"deepseek-r1:8b\"]\n", + "# Runtime distribution\n", + "plt.figure(figsize=(8, 5), dpi=100)\n", + "sns.boxplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"system_prompt_type\")\n", + "plt.xticks(rotation=45)\n", + "plt.title(\"Model Duration by device\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30d74a25", + "metadata": {}, + "outputs": [], + "source": [ + "df_to_plot = df[df[\"model\"] != \"deepseek-r1:8b\"]\n", + "# Runtime distribution\n", + "plt.figure(figsize=(8, 5), dpi=100)\n", + "sns.boxplot(\n", + " data=df_to_plot, x=\"model\", y=\"model_duration_min\", hue=\"system_prompt_type\"\n", + ")\n", + "plt.xticks(rotation=45)\n", + "plt.title(\"Model Duration by device\")\n", + "plt.grid(True)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "3b6df54f", + "metadata": {}, + "source": [ + "It can be seen how much better cuda performs over cpu" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8fd45e41", + "metadata": {}, + "outputs": [], + "source": [ + "# Throughput\n", + "plt.figure(figsize=(8, 5), dpi=100)\n", + "sns.barplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"system_prompt_type\")\n", + "plt.xticks(rotation=45)\n", + "plt.grid(True)\n", + "plt.title(\"Throughput (tokens/sec) by Model and Prompt Type\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60c2cbb3", + "metadata": {}, + "outputs": [], + "source": [ + "# Throughput\n", + "plt.figure(figsize=(8, 5), dpi=100)\n", + "sns.barplot(\n", + " data=df_to_plot, x=\"model\", y=\"model_duration_min\", hue=\"system_prompt_type\"\n", + ")\n", + "plt.xticks(rotation=45)\n", + "plt.grid(True)\n", + "plt.ylabel(\"Model duration (min)\")\n", + "plt.title(\"Tokens per second by Model and Prompt Type\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a8c681b9", + "metadata": {}, + "outputs": [], + "source": [ + "# Token ratios\n", + "plt.figure(figsize=(8, 5), dpi=100)\n", + "df_to_plot[\"compression_ratio\"] = df_to_plot[\"output_tokens\"] / df[\"input_tokens\"]\n", + "sns.violinplot(data=df_to_plot, x=\"model\", y=\"compression_ratio\")\n", + "plt.xticks(rotation=45)\n", + "plt.grid(True)\n", + "plt.title(\"Output/Input Token Ratio (Compression Quality Proxy)\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "8bc2cfc2", + "metadata": {}, + "source": [ + "A nivel " + ] + }, + { + "cell_type": "markdown", + "id": "36a2746e", + "metadata": {}, + "source": [ + "The mean imput tokens by model are:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eb3d4078", + "metadata": {}, + "outputs": [], + "source": [ + "for filter, df_filtered in [\n", + " (\"all\", df),\n", + " (\"cuda\", df[df[\"device\"] == \"cuda\"]),\n", + " (\"cpu\", df[df[\"device\"] == \"cpu\"]),\n", + "]:\n", + " fig, axes = plt.subplots(ncols=2, figsize=(10, 5))\n", + " label = filter if filter != \"all\" else filter + \" devices\"\n", + "\n", + " sns.barplot(\n", + " data=df_filtered,\n", + " x=\"model\",\n", + " y=\"tokens_per_second\",\n", + " ax=axes[0],\n", + " order=vc.index if \"vc\" in globals() else None,\n", + " label=label,\n", + " )\n", + " axes[0].set_title(\"Generation Speed by Model\")\n", + " axes[0].set_ylabel(\"Tokens per Second\")\n", + " axes[0].tick_params(axis=\"x\", rotation=45)\n", + " axes[0].grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", + "\n", + " sns.barplot(\n", + " data=df_filtered,\n", + " x=\"model\",\n", + " y=\"measured_duration_min\",\n", + " ax=axes[1],\n", + " order=vc.index if \"vc\" in globals() else None,\n", + " label=label,\n", + " )\n", + " axes[1].set_title(\"Total Processing Time by Model\")\n", + " axes[1].set_ylabel(\"Duration (min)\")\n", + " axes[1].tick_params(axis=\"x\", rotation=45)\n", + " axes[1].grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", + "\n", + " plt.tight_layout()\n", + " plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "a7afc1f2", + "metadata": {}, + "source": [ + "### Gap Analysis (CPU - CUDA)" + ] + }, + { + "cell_type": "markdown", + "id": "ea239bb0", + "metadata": {}, + "source": [ + "#### Time Gap" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7218eea4", + "metadata": {}, + "outputs": [], + "source": [ + "# time gap between CPU and CUDA (cpu_ms - cuda_ms)\n", + "pivot = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", + "pivot.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50c879eb", + "metadata": {}, + "outputs": [], + "source": [ + "# time gap between CPU and CUDA (cpu_ms - cuda_ms)\n", + "pivot = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", + "if {\"cpu\", \"cuda\"}.issubset(pivot.columns):\n", + " # ensure no missing values and work on a copy\n", + " pivot = pivot.reindex(pivot.index).fillna(0).copy()\n", + "\n", + " # reset index so 'model' becomes a column\n", + " pivot = pivot.reset_index().rename(columns={\"index\": \"model\"})\n", + "\n", + " # ensure numeric types and compute difference (values are already in minutes)\n", + " pivot[\"cpu\"] = pd.to_numeric(pivot[\"cpu\"], errors=\"coerce\").fillna(0)\n", + " pivot[\"cuda\"] = pd.to_numeric(pivot[\"cuda\"], errors=\"coerce\").fillna(0)\n", + " pivot[\"cpu_minus_cuda_min\"] = pivot[\"cpu\"] - pivot[\"cuda\"]\n", + "\n", + " # build a 1-D list of model names ordered by the gap\n", + " order = list(pivot.sort_values(\"cpu_minus_cuda_min\", ascending=False)[\"model\"])\n", + "\n", + " plt.figure(figsize=(12, 5))\n", + " sns.barplot(data=pivot, x=\"model\", y=\"cpu_minus_cuda_min\", order=order)\n", + " plt.axhline(0, color=\"k\", linestyle=\"--\", linewidth=0.8)\n", + " plt.xticks(rotation=45)\n", + " plt.ylabel(\"CPU - CUDA duration (min)\")\n", + " plt.title(\"Time gap between CPU and CUDA by model (CPU - CUDA)\")\n", + " plt.tight_layout()\n", + " plt.show()\n", + "else:\n", + " print(\n", + " \"Not enough data to compute CPU vs CUDA gap (missing 'cpu' or 'cuda' device rows).\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "583b4638", + "metadata": {}, + "source": [ + "#### Token per second gap" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0ea8df17", + "metadata": {}, + "outputs": [], + "source": [ + "# time gap between CPU and CUDA (cpu_ms - cuda_ms)\n", + "pivot = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", + "if {\"cpu\", \"cuda\"}.issubset(pivot.columns):\n", + " # ensure no missing values and work on a copy\n", + " pivot = pivot.reindex(pivot.index).fillna(0).copy()\n", + "\n", + " # reset index so 'model' becomes a column\n", + " pivot = pivot.reset_index().rename(columns={\"index\": \"model\"})\n", + "\n", + " # ensure numeric types and compute difference (values are already in minutes)\n", + " pivot[\"cpu\"] = pd.to_numeric(pivot[\"cpu\"], errors=\"coerce\").fillna(0)\n", + " pivot[\"cuda\"] = pd.to_numeric(pivot[\"cuda\"], errors=\"coerce\").fillna(0)\n", + " pivot[\"cpu_minus_cuda_min\"] = pivot[\"cpu\"] - pivot[\"cuda\"]\n", + "\n", + " # build a 1-D list of model names ordered by the gap\n", + " order = list(pivot.sort_values(\"cpu_minus_cuda_min\", ascending=False)[\"model\"])\n", + "\n", + " plt.figure(figsize=(12, 5))\n", + " sns.barplot(data=pivot, x=\"model\", y=\"cpu_minus_cuda_min\", order=order)\n", + " plt.axhline(0, color=\"k\", linestyle=\"--\", linewidth=0.8)\n", + " plt.xticks(rotation=45)\n", + " plt.ylabel(\"CPU - CUDA tokens per second gap\")\n", + " plt.title(\"Token per second gap between CPU and CUDA by model (CPU - CUDA)\")\n", + " plt.tight_layout()\n", + " plt.show()\n", + "else:\n", + " print(\n", + " \"Not enough data to compute CPU vs CUDA gap (missing 'cpu' or 'cuda' device rows).\"\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bebfb4d2", + "metadata": {}, + "outputs": [], + "source": [ + "df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "797cfad4", + "metadata": {}, + "outputs": [], + "source": [ + "pivot_token = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", + "pivot_dur = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", + "\n", + "# prepare a list of models to keep consistent ordering (try to reuse vc order if present)\n", + "models = list(vc.index) if \"vc\" in globals() else sorted(df[\"model\"].unique())\n", + "\n", + "\n", + "# build a safe summary even if one device is missing\n", + "def safe_gap(pivot, models):\n", + " # ensure index contains all models and missing values filled with 0\n", + " p = (\n", + " pivot.reindex(models)\n", + " .fillna(0)\n", + " .copy()\n", + " .reset_index()\n", + " .rename(columns={\"index\": \"model\"})\n", + " )\n", + " # coerce numeric and add cpu/cuda columns if missing\n", + " p[\"cpu\"] = pd.to_numeric(p.get(\"cpu\", 0), errors=\"coerce\").fillna(0)\n", + " p[\"cuda\"] = pd.to_numeric(p.get(\"cuda\", 0), errors=\"coerce\").fillna(0)\n", + " return p\n", + "\n", + "\n", + "p_token = safe_gap(pivot_token, models)\n", + "p_dur = safe_gap(pivot_dur, models)\n", + "\n", + "model_summary = pd.DataFrame(\n", + " {\n", + " \"model\": p_token[\"model\"],\n", + " \"gap_input_tokens\": p_token[\"cpu\"] - p_token[\"cuda\"],\n", + " # convert minutes gap to seconds\n", + " \"gap_total_duration_min\": (p_dur[\"cpu\"] - p_dur[\"cuda\"]),\n", + " }\n", + ")\n", + "\n", + "# bubble size: proportional to number of samples per model (scaled for plotting)\n", + "counts = df.groupby(\"model\").size().reindex(model_summary[\"model\"]).fillna(1)\n", + "model_summary[\"bubble_size\"] = (counts / counts.max()) * 400 + 50\n", + "\n", + "# ensure columns have expected dtypes\n", + "model_summary[\"gap_input_tokens\"] = pd.to_numeric(\n", + " model_summary[\"gap_input_tokens\"], errors=\"coerce\"\n", + ").fillna(0)\n", + "model_summary[\"gap_total_duration_min\"] = pd.to_numeric(\n", + " model_summary[\"gap_total_duration_min\"], errors=\"coerce\"\n", + ").fillna(0)\n", + "\n", + "model_summary.head()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c00d6e92", + "metadata": {}, + "outputs": [], + "source": [ + "pivot_token = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", + "pivot_dur = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", + "\n", + "# prepare a list of models to keep consistent ordering (try to reuse vc order if present)\n", + "models = list(vc.index) if \"vc\" in globals() else sorted(df[\"model\"].unique())\n", + "\n", + "\n", + "# build a safe summary even if one device is missing\n", + "def safe_gap(pivot, models):\n", + " # ensure index contains all models and missing values filled with 0\n", + " p = (\n", + " pivot.reindex(models)\n", + " .fillna(0)\n", + " .copy()\n", + " .reset_index()\n", + " .rename(columns={\"index\": \"model\"})\n", + " )\n", + " # coerce numeric and add cpu/cuda columns if missing\n", + " p[\"cpu\"] = pd.to_numeric(p.get(\"cpu\", 0), errors=\"coerce\").fillna(0)\n", + " p[\"cuda\"] = pd.to_numeric(p.get(\"cuda\", 0), errors=\"coerce\").fillna(0)\n", + " return p\n", + "\n", + "\n", + "p_token = safe_gap(pivot_token, models)\n", + "p_dur = safe_gap(pivot_dur, models)\n", + "\n", + "model_summary = pd.DataFrame(\n", + " {\n", + " \"model\": p_token[\"model\"],\n", + " \"gap_tokens\": p_token[\"cpu\"] - p_token[\"cuda\"],\n", + " # convert minutes gap to seconds\n", + " \"gap_total_duration_min\": (p_dur[\"cpu\"] - p_dur[\"cuda\"]),\n", + " }\n", + ")\n", + "\n", + "# bubble size: proportional to number of samples per model (scaled for plotting)\n", + "counts = df.groupby(\"model\").size().reindex(model_summary[\"model\"]).fillna(1)\n", + "model_summary[\"bubble_size\"] = (counts / counts.max()) * 400 + 50\n", + "\n", + "# ensure columns have expected dtypes\n", + "model_summary[\"gap_tokens\"] = pd.to_numeric(\n", + " model_summary[\"gap_tokens\"], errors=\"coerce\"\n", + ").fillna(0)\n", + "model_summary[\"gap_total_duration_min\"] = pd.to_numeric(\n", + " model_summary[\"gap_total_duration_min\"], errors=\"coerce\"\n", + ").fillna(0)\n", + "\n", + "model_summary.head()\n", + "\n", + "\n", + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "ax.scatter(\n", + " model_summary[\"gap_tokens\"],\n", + " model_summary[\"gap_total_duration_min\"],\n", + " # s=model_summary[\"bubble_size\"],\n", + " alpha=0.7,\n", + " color=\"#1f77b4\",\n", + " edgecolors=\"black\",\n", + ")\n", + "for _, row in model_summary.iterrows():\n", + " ax.text(\n", + " row[\"gap_tokens\"],\n", + " row[\"gap_total_duration_min\"],\n", + " row[\"model\"],\n", + " fontsize=9,\n", + " ha=\"left\",\n", + " va=\"bottom\",\n", + " alpha=0.9,\n", + " )\n", + "ax.set_ylabel(\"Average Total Duration Gap (min)\")\n", + "ax.set_xlabel(\"Average Tokens per second\")\n", + "# ax.set_ylabel(\"Average Total Duration (s)\")\n", + "ax.grid(True, linestyle=\"--\", alpha=0.6)\n", + "ax.set_title(\"CPU vs CUDA Performance Gap by Model\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8542204f", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7c42e753", + "metadata": {}, + "outputs": [], + "source": [ + "def make_summary(df):\n", + " pivot_token = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", + " pivot_dur = (\n", + " df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", + " )\n", + "\n", + " # prepare a list of models to keep consistent ordering\n", + " models = sorted(df[\"model\"].unique())\n", + "\n", + " # build a safe summary even if one device is missing\n", + " def safe_gap(pivot, models):\n", + " p = (\n", + " pivot.reindex(models)\n", + " .fillna(0)\n", + " .copy()\n", + " .reset_index()\n", + " .rename(columns={\"index\": \"model\"})\n", + " )\n", + " p[\"cpu\"] = pd.to_numeric(p.get(\"cpu\", 0), errors=\"coerce\").fillna(0)\n", + " p[\"cuda\"] = pd.to_numeric(p.get(\"cuda\", 0), errors=\"coerce\").fillna(0)\n", + " return p\n", + "\n", + " p_token = safe_gap(pivot_token, models)\n", + " p_dur = safe_gap(pivot_dur, models)\n", + "\n", + " model_summary = pd.DataFrame(\n", + " {\n", + " \"model\": p_token[\"model\"],\n", + " # CUDA - CPU gap for tokens per second\n", + " \"gap_tokens\": p_token[\"cuda\"] - p_token[\"cpu\"],\n", + " # CUDA - CPU gap for total duration (minutes)\n", + " \"gap_total_duration_min\": p_dur[\"cuda\"] - p_dur[\"cpu\"],\n", + " }\n", + " )\n", + "\n", + " # add parameter scale and bubble size\n", + " model_summary[\"param_scale\"] = model_summary[\"model\"].apply(\n", + " get_model_parameter_scale\n", + " )\n", + " model_summary[\"param_scale\"] = pd.to_numeric(\n", + " model_summary[\"param_scale\"], errors=\"coerce\"\n", + " ).fillna(0)\n", + "\n", + " # counts = df.groupby('model').size().reindex(model_summary['model']).fillna(1)\n", + " # model_summary['bubble_size'] = (counts / counts.max()) * 400 + 50\n", + "\n", + " # ensure numeric types and no NaNs\n", + " model_summary[\"gap_tokens\"] = pd.to_numeric(\n", + " model_summary[\"gap_tokens\"], errors=\"coerce\"\n", + " ).fillna(0)\n", + " model_summary[\"gap_total_duration_min\"] = pd.to_numeric(\n", + " model_summary[\"gap_total_duration_min\"], errors=\"coerce\"\n", + " ).fillna(0)\n", + "\n", + " return model_summary\n", + "\n", + "\n", + "model_summary = make_summary(df)\n", + "model_summary.head()\n", + "\n", + "model_summary.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9fef1bba", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "# generate a unique color per model\n", + "palette = sns.color_palette(n_colors=len(model_summary))\n", + "model_summary.sort_values(\"param_scale\", inplace=True)\n", + "model_colors = dict(zip(model_summary[\"model\"], palette))\n", + "\n", + "fig, ax = plt.subplots(figsize=(12, 6))\n", + "i = 1\n", + "# plot bubbles with model-specific colors\n", + "for _, row in model_summary.iterrows():\n", + " color = model_colors[row[\"model\"]]\n", + " ax.scatter(\n", + " row[\"param_scale\"], # row[\"gap_total_duration_min\"],\n", + " row[\"gap_tokens\"],\n", + " s=row[\"param_scale\"] * 100,\n", + " alpha=0.7,\n", + " color=color,\n", + " edgecolors=\"black\",\n", + " linewidth=0.7,\n", + " )\n", + " ax.text(\n", + " row[\"param_scale\"] + (0.5 * (-1) ** i), # row[\"gap_total_duration_min\"]\n", + " row[\"gap_tokens\"],\n", + " row[\"model\"],\n", + " fontsize=9,\n", + " ha=\"left\",\n", + " va=\"bottom\",\n", + " alpha=1,\n", + " fontweight=\"bold\",\n", + " color=color,\n", + " )\n", + " i += 1\n", + "\n", + " # add a label for the bubble size\n", + "\n", + "ax.set_ylabel(\"Average Tokens per Second\")\n", + "ax.set_xlabel(\"Parameter Scale (Billion Parameters)\")\n", + "ax.grid(True, linestyle=\"--\", alpha=0.6)\n", + "ax.set_title(\"CUDA - CPU Gap Token per Second by Model Parameter Scale per Model\")\n", + "\n", + "# optional legend showing color per model\n", + "handles = [\n", + " plt.Line2D(\n", + " [0],\n", + " [0],\n", + " marker=\"o\",\n", + " color=\"w\",\n", + " label=model,\n", + " markerfacecolor=color,\n", + " markersize=8,\n", + " markeredgecolor=\"black\",\n", + " )\n", + " for model, color in model_colors.items()\n", + "]\n", + "ax.legend(handles=handles, title=\"Model\", loc=\"best\")\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cdfdde71", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import seaborn as sns\n", + "\n", + "# generate a unique color per model\n", + "palette = sns.color_palette(n_colors=len(model_summary))\n", + "model_summary.sort_values(\"param_scale\", inplace=True)\n", + "model_colors = dict(zip(model_summary[\"model\"], palette))\n", + "\n", + "fig, ax = plt.subplots(figsize=(12, 6), dpi=100)\n", + "i = 1\n", + "# plot bubbles with model-specific colors\n", + "for _, row in model_summary.iterrows():\n", + " color = model_colors[row[\"model\"]]\n", + " ax.scatter(\n", + " row[\"param_scale\"], # row[\"gap_total_duration_min\"],\n", + " row[\"gap_total_duration_min\"],\n", + " s=row[\"param_scale\"] * 100,\n", + " alpha=0.7,\n", + " color=color,\n", + " edgecolors=\"black\",\n", + " linewidth=0.7,\n", + " )\n", + " ax.text(\n", + " row[\"param_scale\"] + (0.5 * (-1) ** i), # row[\"gap_total_duration_min\"]\n", + " row[\"gap_total_duration_min\"],\n", + " row[\"model\"],\n", + " fontsize=9,\n", + " ha=\"left\",\n", + " va=\"bottom\",\n", + " alpha=1,\n", + " fontweight=\"bold\",\n", + " color=color,\n", + " )\n", + " i += 1\n", + "\n", + " # add a label for the bubble size\n", + "\n", + "ax.set_ylabel(\"Average Total Duration Gap (min)\")\n", + "ax.set_xlabel(\"Parameter Scale (Billion Parameters)\")\n", + "ax.grid(True, linestyle=\"--\", alpha=0.6)\n", + "ax.set_title(\"CUDA - CPU Gap Token per Second by Model Parameter Scale per Model\")\n", + "\n", + "# optional legend showing color per model\n", + "handles = [\n", + " plt.Line2D(\n", + " [0],\n", + " [0],\n", + " marker=\"o\",\n", + " color=\"w\",\n", + " label=model,\n", + " markerfacecolor=color,\n", + " markersize=8,\n", + " markeredgecolor=\"black\",\n", + " )\n", + " for model, color in model_colors.items()\n", + "]\n", + "ax.legend(handles=handles, title=\"Model\", loc=\"best\")\n", + "\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36d4c49b", + "metadata": {}, + "outputs": [], + "source": [ + "(\n", + " df.iloc[0].output_tokens / df.iloc[0].output_duration_ms\n", + ") * 1000 # it is tokens_per_second" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8666d95d", + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.utils.json_data import load_json, save_json\n", + "\n", + "save_json(\n", + " summaries,\n", + " DATA_PATH + \"summaries.json\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eae7c0e6", + "metadata": {}, + "outputs": [], + "source": [ + "df.iloc[0].input_duration_ms + df.iloc[0].output_duration_ms # total duration in ms" + ] + }, + { + "cell_type": "markdown", + "id": "8d4847a7", + "metadata": {}, + "source": [ + "## Qualitative Analysis" + ] + }, + { + "cell_type": "markdown", + "id": "4c19dacc", + "metadata": {}, + "source": [ + "### Garbage Detection - Outliers " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bba4ac3", + "metadata": {}, + "outputs": [], + "source": [ + "df.describe()" + ] + }, + { + "cell_type": "markdown", + "id": "600d3507", + "metadata": {}, + "source": [ + "max output_tokens is 163840, same value as max input token, so, it is truncated. We will see examples" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cfce3c0", + "metadata": {}, + "outputs": [], + "source": [ + "df_truncated = df[df[\"output_tokens\"] > 16000]\n", + "print(\"Truncated summary analysis: \\ndoc paths: \\n\", df_truncated.doc_path.unique())\n", + "print(\"Models: \\n\", df_truncated.model.unique())\n", + "df_truncated.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77a9fe88", + "metadata": {}, + "outputs": [], + "source": [ + "df_truncated.groupby([\"model\", \"doc_path\", \"system_prompt_type\"]).count()" + ] + }, + { + "cell_type": "markdown", + "id": "fc67ba29", + "metadata": {}, + "source": [ + "11 of 12 outputs truncated correspond to deepseek-r1:8b model, and the other one to phi3:3.8b. We will see the hallucinations bellow" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "687db5cd", + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(figsize=(12, 6))\n", + "sns.boxplot(data=df, x=\"model\", y=\"model_duration_ms\")\n", + "plt.xticks(rotation=45)\n", + "plt.title(\"Runtime Variability Across Documents\")\n", + "plt.ylabel(\"Model Duration (ms)\")\n", + "plt.grid(True, alpha=0.4)\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fba9021e", + "metadata": {}, + "outputs": [], + "source": [ + "corr = df_to_plot[\n", + " [\n", + " \"input_tokens\",\n", + " \"output_tokens\",\n", + " \"model_duration_ms\",\n", + " \"tokens_per_second\",\n", + " \"compression_ratio\",\n", + " ]\n", + "].corr()\n", + "sns.heatmap(corr, annot=True, cmap=\"coolwarm\", center=0)\n", + "plt.title(\"Correlation Between Metrics\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95666d38", + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(figsize=(12, 6))\n", + "sns.boxplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"device\")\n", + "plt.xticks(rotation=45)\n", + "plt.title(\"Tokens per Second Variability Across Documents\")\n", + "plt.ylabel(\"Tokens per Second\")\n", + "plt.grid(True, alpha=0.4)\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dce57b6a", + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(figsize=(12, 6))\n", + "sns.boxplot(data=df_to_plot, x=\"model\", y=\"model_duration_min\")\n", + "plt.xticks(rotation=45)\n", + "plt.title(\"Runtime Variability Across Documents\")\n", + "plt.ylabel(\"Model Duration (min)\")\n", + "plt.grid(True, alpha=0.4)\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "19b0ed7e", + "metadata": {}, + "source": [ + "### Analysis by document" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a4f0af7", + "metadata": {}, + "outputs": [], + "source": [ + "df_cuda = df[df[\"device\"] == \"cuda\"]\n", + "plt.figure(figsize=(10, 6))\n", + "sns.boxplot(data=df_cuda, x=\"doc_path\", y=\"tokens_per_second\", hue=\"model\")\n", + "plt.xticks(rotation=90)\n", + "plt.title(\"Tokens per second by Document and Model - CUDA\")\n", + "plt.grid(True)\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c4f88ac", + "metadata": {}, + "outputs": [], + "source": [ + "plt.figure(figsize=(10, 6))\n", + "sns.boxplot(data=df, x=\"doc_path\", y=\"tokens_per_second\", hue=\"model\")\n", + "plt.xticks(rotation=90)\n", + "plt.title(\"Throughput by Document and Model\")\n", + "plt.tight_layout()\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc30cd3b", + "metadata": {}, + "outputs": [], + "source": [ + "order = sorted(df[\"model\"].unique())\n", + "order" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9ef6921", + "metadata": {}, + "outputs": [], + "source": [ + "i = 1\n", + "for doc in df[\"doc_path\"].unique():\n", + " df_doc = df[df[\"doc_path\"] == doc]\n", + " doc_name = doc.split(\"/\")[-1]\n", + " plt.figure(figsize=(10, 6))\n", + " sns.boxplot(\n", + " data=df_doc, x=\"model\", y=\"tokens_per_second\", hue=\"device\", order=order\n", + " )\n", + " plt.xticks(rotation=90)\n", + " plt.grid(True)\n", + " plt.title(f\"Fig. {i}: {doc_name}\")\n", + " plt.tight_layout()\n", + " i += 1\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "8977b125", + "metadata": {}, + "source": [ + "#### Summary comparison (same document)" + ] + }, + { + "cell_type": "markdown", + "id": "31ba2818", + "metadata": {}, + "source": [ + "##### cuda vs llama (same model)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c76d769", + "metadata": {}, + "outputs": [], + "source": [ + "last_N = 1000\n", + "document = \"1- FLORES ABARCA, Francisco Alexander s 149 bis J-01-00369422-0-2022-1 Sala Feria (II) nnya vict do apela pp.pdf\"\n", + "model = \"llama3.2:3b\"\n", + "devices = [\"cuda\", \"cpu\"]\n", + "df_doc = df[df[\"doc_path\"] == document]\n", + "for d in devices:\n", + " df_filtered = df_doc[\n", + " (df[\"model\"] == model)\n", + " & (df[\"device\"] == d)\n", + " & (df[\"system_prompt_type\"] == \"template\")\n", + " ]\n", + " print(\n", + " f\"--------------------- Document: {document}, device= {d}, model= {model}---------------------\"\n", + " )\n", + " text = df_filtered[\"chat_response\"].astype(str).fillna(\"\")[-last_N:].values[0]\n", + " print(text)\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "d1afcf25", + "metadata": {}, + "source": [ + " **Interpretation**\n", + "- Running the same model (Llama 3.2:3b) and same prompt/document in cuda is 5–6× faster than in cpu\n", + "- Despite the speedup, output content remains consistent, with both versions extracting similar entities and structure.\n", + "- The CUDA output finishes much faster but tends to include slightly more redundant or verbose entities (e.g., repeated names), suggesting minor decoding variability due to parallelization.\n", + "- The CPU output is slower but more stable and concise, with slightly better formatting consistency.\n", + "\n", + "This comparison confirms that CUDA significantly improves throughput without major semantic drift, though some token-level differences may appear." + ] + }, + { + "cell_type": "markdown", + "id": "699a16de", + "metadata": {}, + "source": [ + "##### gemma vs llama (cuda)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ad69da3", + "metadata": {}, + "outputs": [], + "source": [ + "last_N = 1000\n", + "document = \"aymurai - ejemplo 02.docx\"\n", + "models = [\"phi3:3.8b\", \"gemma3:12b\"]\n", + "df_doc = df[df[\"doc_path\"] == document]\n", + "for m in models:\n", + " df_filtered = df_doc[\n", + " (df[\"model\"] == m)\n", + " & (df[\"device\"] == \"cuda\")\n", + " & (df[\"system_prompt_type\"] == \"template\")\n", + " ]\n", + " print(\n", + " f\"--------------------- Document: {document}, model= {m}---------------------\"\n", + " )\n", + " text = df_filtered[\"chat_response\"].astype(str).fillna(\"\")[-last_N:].values[0]\n", + " print(text)\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "5d7a976c", + "metadata": {}, + "source": [ + "- Both models now generate coherent, well-structured summaries capturing key actors, context, and applied laws.\n", + "Phi 3:3.8b stands out for its richer narrative detail , like “Ana Carolina Rodríguez (DNI 34.112.456) y su hija menor M.F.R”\n", + "\n", + "- Gemma 3:12b produces a clearer and more factual summary, focusing on explicit information and structured entities.\n", + "- Phi offers greater completeness and contextual depth, while Gemma achieves higher precision and speed.\n", + "Overall, they show complementary strengths: Phi excels in descriptive depth, Gemma in concise factual extraction." + ] + }, + { + "cell_type": "markdown", + "id": "182387a0", + "metadata": {}, + "source": [ + "##### Same document, phi3 vs. phi4" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ea9f690", + "metadata": {}, + "outputs": [], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31fb2d90", + "metadata": {}, + "outputs": [], + "source": [ + "set(df.model)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cfece56c", + "metadata": {}, + "outputs": [], + "source": [ + "set(df.doc_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1296370", + "metadata": {}, + "outputs": [], + "source": [ + "df.columns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63a4ef9d", + "metadata": {}, + "outputs": [], + "source": [ + "last_N = 1000\n", + "document = \"aymurai - ejemplo 02.docx\"\n", + "models = [\"phi3:3.8b\", \"phi4:14b\"]\n", + "df_doc = df[df[\"doc_path\"] == document]\n", + "for m in models:\n", + " df_filtered = df_doc[\n", + " (df[\"model\"] == m)\n", + " & (df[\"device\"] == \"cuda\")\n", + " & (df[\"system_prompt_type\"] == \"template\")\n", + " ]\n", + " print(\n", + " f\"--------------------- Document: {document}, model= {m}---------------------\"\n", + " )\n", + " text = df_filtered[\"chat_response\"].astype(str).fillna(\"\")[-last_N:].values[0]\n", + " print(text)\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "e078eef3", + "metadata": {}, + "source": [ + "When comparing phi3:3.8b and phi4:14b on the same document, the improvement in phi4 is evident both in structure and content quality. \n", + "\n", + "While phi3 tends to generate verbose outputs and include unnecessary placeholders (e.g., “not mentioned in the document provided”), phi4 produces concise, relevant, and well-organized information. \n", + "\n", + "Its summaries remain focused on the extracted entities without overgenerating text, which improves readability and coherence. The token usage, shown in Fig. 4, also confirm this efficiency: phi4 requires fewer output tokens while maintaining higher generation speed and precision in content extraction." + ] + }, + { + "cell_type": "markdown", + "id": "aebe3666", + "metadata": {}, + "source": [ + "#### Tokens/sec by document: cuda and cpu" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2023483d", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "\n", + "# Compute mean and std per document/model/device\n", + "df_summary = (\n", + " df.groupby([\"doc_path\", \"model\", \"device\"])[\"tokens_per_second\"]\n", + " .agg([\"mean\", \"std\", \"count\"])\n", + " .reset_index()\n", + ")\n", + "df_summary[\"sem\"] = df_summary[\"std\"] / df_summary[\"count\"] ** 0.5 # standard error\n", + "\n", + "# Sort models for consistent order\n", + "# order = sorted(df_summary['model'].unique())\n", + "\n", + "# --- Plot for each device type ---\n", + "for device in [\"cuda\", \"cpu\"]:\n", + " df_device = df_summary[df_summary[\"device\"] == device]\n", + "\n", + " plt.figure(figsize=(10, 6))\n", + "\n", + " # Plot one line per document\n", + " for doc, df_doc in df_device.groupby(\"doc_path\"):\n", + " doc_name = doc.split(\"/\")[-1][:20]\n", + " plt.errorbar(\n", + " df_doc[\"model\"],\n", + " df_doc[\"mean\"],\n", + " yerr=df_doc[\"sem\"],\n", + " fmt=\"-o\",\n", + " capsize=3,\n", + " alpha=0.7,\n", + " label=doc_name,\n", + " )\n", + "\n", + " plt.xticks(rotation=90)\n", + " plt.xlabel(\"Model\")\n", + " plt.ylabel(\"Tokens per second (mean ± SEM)\")\n", + " plt.title(f\"Performance across documents ({device.upper()})\")\n", + " plt.grid(True, linestyle=\"--\", alpha=0.6)\n", + " plt.legend(\n", + " title=\"Document\", fontsize=\"small\", loc=\"best\"\n", + " ) # bbox_to_anchor=(1.05, 1), loc='upper left')\n", + " plt.tight_layout()\n", + " plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "id": "2fbe4fdc", + "metadata": {}, + "source": [ + "**Overall speed:**\n", + "- On CUDA, generation speed ranges from ~10 to 90 tokens/sec — up to 10× faster than CPU.\n", + "- On CPU, all models stay below 13 tokens/sec, showing clear hardware dependency.\n", + " \n", + "**Model comparison:**\n", + "- Llama 3.2:3b consistently achieves the highest speed across both devices, though its summary quality is limited.\n", + "- Phi 3/4 and DeepSeek 1.1b are among the slowest, likely due to heavier contextual reasoning or token complexity — however, DeepSeek often fails to summarize properly, repeating or looping.\n", + "- Gemma 3:12b and Gemma 3:4b show balanced performance, maintaining moderate speed and stable behavior across documents.\n", + "\n", + "**Document variability:**\n", + "- Speed variation across documents is low, indicating that model performance is robust to input differences.\n", + "- Slight dips appear for longer or denser texts, especially in CPU runs.\n", + " \n", + "**Key insight:**\n", + "- CUDA acceleration drastically improves throughput without affecting consistency across documents.\n", + "- Llama remains the best trade-off between speed and reliability, while Phi and Gemma prioritize content quality over raw speed." + ] + }, + { + "cell_type": "markdown", + "id": "0b721074", + "metadata": {}, + "source": [ + "### Output outliers/hallucinations visualizations" + ] + }, + { + "cell_type": "markdown", + "id": "c3a3c149", + "metadata": {}, + "source": [ + "We see the last 100 characters of each output that was truncated (df['output_tokens']>16000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca18869a", + "metadata": {}, + "outputs": [], + "source": [ + "N = 100\n", + "for idx, txt in enumerate(df_truncated[\"chat_response\"].astype(str).fillna(\"\")):\n", + " print(\n", + " f\"+++++++++++++ Truncated summary {idx} (model={df_truncated.iloc[idx].get('model', '')}, system_prompt_type={df_truncated.iloc[idx].get('system_prompt_type', '')}, doc_path={df_truncated.iloc[idx].get('doc_path', '')}) +++++++++++++\"\n", + " )\n", + " text = txt[-N:]\n", + " print(text)\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aed870a3", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.15" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/summarization/03-summarization-endpoint.ipynb b/notebooks/experiments/summarization/03-summarization-endpoint.ipynb new file mode 100644 index 00000000..059248c0 --- /dev/null +++ b/notebooks/experiments/summarization/03-summarization-endpoint.ipynb @@ -0,0 +1,170 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d636dee3", + "metadata": {}, + "source": [ + "# Summarization API endpoint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53cbedeb", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "\n", + "import requests\n", + "from rich.pretty import pprint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24dfb1f2", + "metadata": {}, + "outputs": [], + "source": [ + "API_BASE_URL = os.getenv(\"AYMURAI_API_BASE_URL\", \"http://localhost:8999\")\n", + "SUMMARIZE_URL = f\"{API_BASE_URL}/llm/summarize\"\n", + "print(f\"POST {SUMMARIZE_URL}\")" + ] + }, + { + "cell_type": "markdown", + "id": "2be189f4", + "metadata": {}, + "source": [ + "## Build request payload" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b547916", + "metadata": {}, + "outputs": [], + "source": [ + "sample_text = \"\"\"\n", + "La inteligencia artificial (IA) ha revolucionado numerosos campos, desde la medicina hasta la industria del entretenimiento,\n", + "y el ámbito de la justicia no es una excepción. La IA tiene el potencial de transformar la forma en que se administran los\n", + "sistemas legales, mejorando la eficiencia y la precisión en la toma de decisiones judiciales. Sin embargo, también plantea\n", + "desafíos éticos y legales significativos que deben ser abordados cuidadosamente.\n", + "\"\"\".strip()\n", + "\n", + "payload = {\n", + " \"text\": sample_text,\n", + " \"model\": \"llama3.2:3b\",\n", + " \"system_prompt\": \"Eres un asistente que resume textos de manera concisa y clara sin inventar información.\",\n", + " \"tokenizer\": None,\n", + " \"options\": {\"num_ctx\": 1024, \"num_predict\": 512, \"stream\": True},\n", + "}\n", + "\n", + "pprint(payload)\n" + ] + }, + { + "cell_type": "markdown", + "id": "aa2adc0d", + "metadata": {}, + "source": [ + "## Call the endpoint" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81d6d33f", + "metadata": {}, + "outputs": [], + "source": [ + "def call_summarize(text_payload: dict) -> dict:\n", + " response = requests.post(SUMMARIZE_URL, json=text_payload)\n", + " response.raise_for_status()\n", + " return response.json()\n", + "\n", + "\n", + "result = call_summarize(payload)\n", + "pprint({\"model\": result.get(\"model\"), \"chunks_used\": result.get(\"chunks_used\")})\n", + "print(\"Summary:\")\n", + "print(result.get(\"summary\", \"\"))\n", + "\n", + "print(\"Steps:\")\n", + "pprint(result.get(\"steps\", []))" + ] + }, + { + "cell_type": "markdown", + "id": "d3402133", + "metadata": {}, + "source": [ + "## Streamed call" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aaa18c09", + "metadata": {}, + "outputs": [], + "source": [ + "STREAM_URL = f\"{API_BASE_URL}/llm/summarize/stream\"\n", + "\n", + "\n", + "def stream_summarize(text_payload: dict) -> None:\n", + " with requests.post(STREAM_URL, json=text_payload, stream=True, timeout=120) as resp:\n", + " resp.raise_for_status()\n", + " for raw_line in resp.iter_lines():\n", + " if not raw_line:\n", + " continue\n", + " if not raw_line.startswith(b\"data: \"):\n", + " continue\n", + " event = json.loads(raw_line.split(b\"data: \", 1)[1])\n", + " if event.get(\"type\") == \"token\":\n", + " print(event.get(\"text\", \"\"), end=\"\", flush=True)\n", + " elif event.get(\"type\") == \"summary\":\n", + " print(\"\\n\\n---\\nFinal summary:\\n\")\n", + " print(event.get(\"summary\", \"\"))\n", + " print(\"\\nSteps:\", event.get(\"steps\", []))\n", + " else:\n", + " print(f\"\\n[{event.get('type')}] {event}\")\n", + "\n", + "\n", + "stream_summarize(payload)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d14bc8be", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb b/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb new file mode 100644 index 00000000..b40fb1a2 --- /dev/null +++ b/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb @@ -0,0 +1,955 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "0bf2c8f0", + "metadata": {}, + "outputs": [], + "source": [ + "# !uv add dspy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fab6180c", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c1734177", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "import dspy\n", + "\n", + "from aymurai.utils.json_data import load_json" + ] + }, + { + "cell_type": "markdown", + "id": "011093f3", + "metadata": {}, + "source": [ + "## Fetch data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2d546951", + "metadata": {}, + "outputs": [], + "source": [ + "labels_dir = \"/workspace/notebooks/experiments/entity-disambiguation/entities-reviewed\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4dd3dbc2", + "metadata": {}, + "outputs": [], + "source": [ + "filenames = os.listdir(labels_dir)\n", + "filenames[:1]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60e2e77a", + "metadata": {}, + "outputs": [], + "source": [ + "filename = filenames[0]\n", + "label_data = load_json(os.path.join(labels_dir, filename))\n", + "label_data" + ] + }, + { + "cell_type": "markdown", + "id": "43684f12", + "metadata": {}, + "source": [ + "## Documents" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2c389b4", + "metadata": {}, + "outputs": [], + "source": [ + "import mimetypes\n", + "import time\n", + "from pathlib import Path\n", + "from typing import Iterable\n", + "\n", + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ebc22f54", + "metadata": {}, + "outputs": [], + "source": [ + "BASE_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", + "ENDPOINT = f\"{BASE_URL}/misc/document-extract\"\n", + "DATA_ROOT = Path(\n", + " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78f2d559", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "print(f\"Discovered {len(documents)} documents.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04c89e3b", + "metadata": {}, + "outputs": [], + "source": [ + "def call_extraction_api(\n", + " session: requests.Session, file_path: Path\n", + ") -> dict[str, object]:\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " ENDPOINT,\n", + " files=files,\n", + " timeout=REQUEST_TIMEOUT_S,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08b9ebb8", + "metadata": {}, + "outputs": [], + "source": [ + "doc_path = Path(os.path.join(DATA_ROOT, \"aymurai - ejemplo 01.docx\"))\n", + "extracted_document = call_extraction_api(requests.Session(), doc_path)\n", + "document = \"\\n\".join(extracted_document[\"detail\"][\"document\"])\n", + "print(document)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6f722d5", + "metadata": {}, + "outputs": [], + "source": [ + "references = load_json(os.path.join(labels_dir, filename))\n", + "references" + ] + }, + { + "cell_type": "markdown", + "id": "137a89c6", + "metadata": {}, + "source": [ + "## Evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e9b03a8", + "metadata": {}, + "outputs": [], + "source": [ + "# lm = dspy.LM(\"ollama_chat/gpt-oss:20b\", api_base=\"http://localhost:11434\")\n", + "lm = dspy.LM(\"ollama_chat/qwen3:8b\", api_base=\"http://localhost:11434\")\n", + "dspy.configure(lm=lm)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81c419f3", + "metadata": {}, + "outputs": [], + "source": [ + "print(document)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9825ac86", + "metadata": {}, + "outputs": [], + "source": [ + "# qwen3:14b\n", + "summarize = dspy.ChainOfThought(\"document -> summary\")\n", + "response = summarize(document=document)\n", + "print(response.summary)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8b91d03", + "metadata": {}, + "outputs": [], + "source": [ + "summarize = dspy.ChainOfThought(\"document -> summary\")\n", + "response = summarize(document=document)\n", + "print(response.summary)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a17443d0", + "metadata": {}, + "outputs": [], + "source": [ + "print(response.reasoning)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15d30a8d", + "metadata": {}, + "outputs": [], + "source": [ + "from dataclasses import dataclass\n", + "\n", + "from rapidfuzz import fuzz\n", + "\n", + "\n", + "class AssessSummary(dspy.Signature):\n", + " \"\"\"High-precision assessment of legal summaries with strict grounding requirements.\"\"\"\n", + "\n", + " # Inputs\n", + " document = dspy.InputField(\n", + " desc=\"Verbatim source document. Treat it as the only ground truth; cite exact passages when justifying decisions.\"\n", + " )\n", + " summary = dspy.InputField(\n", + " desc=\"Candidate legal summary whose clarity, factual grounding, and entity coverage will be judged.\"\n", + " )\n", + " references = dspy.InputField(\n", + " desc=\"Ordered list of salient legal entities, citations, or parties expected to appear verbatim in the summary.\"\n", + " )\n", + "\n", + " # Outputs\n", + " language_ok: bool = dspy.OutputField(\n", + " desc=\"Return True only if the input summary is completely written in the same language as the document.\"\n", + " )\n", + " language_reason = dspy.OutputField(\n", + " desc=\"Identify any language mismatches or confirm consistent language use.\"\n", + " )\n", + " clarity_ok: bool = dspy.OutputField(\n", + " desc=\"Return True only if the summary is concise, logically ordered, and understandable without assuming missing context.\"\n", + " )\n", + " clarity_reason = dspy.OutputField(\n", + " desc=\"Briefly highlight phrasing strengths or point out specific sentences that harmed clarity.\"\n", + " )\n", + " factfulness_ok: bool = dspy.OutputField(\n", + " desc=\"Return True only if every claim is explicitly supported by the document. Any unsupported or extrapolated statement must flip this to False.\"\n", + " )\n", + " factfulness_reason = dspy.OutputField(\n", + " desc=\"Quote the exact evidence backing supported claims. Explicitly list each unsupported or hallucinated statement.\"\n", + " )\n", + " coverage_ok: bool = dspy.OutputField(\n", + " desc=\"Return True only if the summary mentions the expected references with correct attributes and relationships.\"\n", + " )\n", + " coverage_reason = dspy.OutputField(\n", + " desc=\"Explain which references were correctly included or omitted, explicitly citing the relevant summary spans.\"\n", + " )\n", + "\n", + "\n", + "@dataclass\n", + "class SummaryScore:\n", + " score: float\n", + " coverage_score: float\n", + " judgement: dspy.Prediction\n", + "\n", + "\n", + "class SummaryMetric(dspy.Module):\n", + " COVERAGE_THRESHOLD = 0.9\n", + "\n", + " def __call__(self, document, references, summary, trace=None):\n", + " coverage_score = self._coverage_score(summary, references)\n", + "\n", + " # with dspy.context(\n", + " # lm=dspy.LM(\"ollama_chat/gpt-oss:20b\", api_base=\"http://localhost:11434\")\n", + " # ):\n", + " # Run assessment model\n", + " judgement = self.predict(\n", + " document=document,\n", + " summary=summary,\n", + " references=references,\n", + " )\n", + "\n", + " if not judgement.language_ok:\n", + " return SummaryScore(\n", + " score=0.0,\n", + " coverage_score=coverage_score,\n", + " judgement=judgement,\n", + " )\n", + "\n", + " score = sum(\n", + " [\n", + " 0.2 * (judgement.clarity_ok or 0),\n", + " 0.2 * (judgement.factfulness_ok or 0),\n", + " 0.6 * (coverage_score * (judgement.coverage_ok or 0)),\n", + " ]\n", + " )\n", + "\n", + " return SummaryScore(\n", + " score=score,\n", + " coverage_score=coverage_score,\n", + " judgement=judgement,\n", + " )\n", + "\n", + " def predict(self, document, summary, references):\n", + " return dspy.Predict(AssessSummary)(\n", + " document=document,\n", + " summary=summary,\n", + " references=references,\n", + " )\n", + "\n", + " def _coverage_score(\n", + " self, summary: str, references, threshold: float | None = None\n", + " ) -> float:\n", + " \"\"\"\n", + " Calculate the coverage score of the summary against the reference entities.\n", + "\n", + " Args:\n", + " summary (str): The summary text to be evaluated for coverage.\n", + " references (list): The list of reference entities expected to be covered in the summary.\n", + " threshold (float | None): The minimum similarity threshold to consider an entity as covered.\n", + " Defaults to COVERAGE_THRESHOLD.\n", + "\n", + " Returns:\n", + " float: The coverage score representing how well the summary covers the reference entities.\n", + " \"\"\"\n", + " if not references:\n", + " return 1.0\n", + "\n", + " threshold = threshold or self.COVERAGE_THRESHOLD\n", + " summary_lower = summary.lower()\n", + " total_score, counted = 0.0, 0\n", + "\n", + " for ref in references:\n", + " aliases = list(ref.get(\"aliases\") or [])\n", + " canonical = ref.get(\"canonical_text\")\n", + " if canonical:\n", + " aliases = [canonical, *aliases]\n", + "\n", + " aliases = set(alias.strip().lower() for alias in aliases if alias)\n", + "\n", + " best = max(\n", + " fuzz.partial_ratio(alias.lower(), summary_lower) / 100.0\n", + " for alias in aliases\n", + " )\n", + " if best < threshold:\n", + " best = 0.0\n", + "\n", + " total_score += best\n", + " counted += 1\n", + "\n", + " return total_score / counted if counted else 0.0\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6607ae5", + "metadata": {}, + "outputs": [], + "source": [ + "metric = SummaryMetric()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f43d5278", + "metadata": {}, + "outputs": [], + "source": [ + "# phi3:14b\n", + "score = metric(document, references, response.summary)\n", + "score" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "636d3124", + "metadata": {}, + "outputs": [], + "source": [ + "score = metric(document, references, response.summary)\n", + "score" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2e23a09", + "metadata": {}, + "outputs": [], + "source": [ + "summarization_results = load_json(\n", + " DATA_ROOT / \"summarization-benchmark-results-cuda.json\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52a0ef90", + "metadata": {}, + "outputs": [], + "source": [ + "len(summarization_results)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "88820925", + "metadata": {}, + "outputs": [], + "source": [ + "summaries = [\n", + " doc\n", + " for doc in summarization_results\n", + " if doc[\"doc_path\"] == os.path.basename(doc_path)\n", + "]\n", + "\n", + "len(summaries)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb08ce45", + "metadata": {}, + "outputs": [], + "source": [ + "from tqdm import tqdm\n", + "\n", + "evaluation_results = []\n", + "\n", + "for summary_entry in tqdm(summaries):\n", + " summary = summary_entry[\"chat_response\"]\n", + " score = metric(document, references, summary)\n", + " evaluation_results.append(\n", + " {\n", + " \"doc_path\": summary_entry[\"doc_path\"],\n", + " \"summary\": summary,\n", + " \"score\": score,\n", + " \"metadata\": {\n", + " \"model\": summary_entry.get(\"model\"),\n", + " \"system_prompt_type\": summary_entry.get(\"system_prompt_type\"),\n", + " \"options\": summary_entry.get(\"options\"),\n", + " },\n", + " }\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "986029ec", + "metadata": {}, + "outputs": [], + "source": [ + "evaluation_results = sorted(\n", + " evaluation_results, key=lambda x: x[\"score\"].score, reverse=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7637aa56", + "metadata": {}, + "outputs": [], + "source": [ + "evaluation_results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2be4980", + "metadata": {}, + "outputs": [], + "source": [ + "# Update the score recomputation\n", + "\n", + "evaluation_results_bkp = evaluation_results.copy()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55177b67", + "metadata": {}, + "outputs": [], + "source": [ + "evaluation_results[-1][\"score\"].score = 0" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a33d896", + "metadata": {}, + "outputs": [], + "source": [ + "evaluation_results[-1][\"score\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bac3165b", + "metadata": {}, + "outputs": [], + "source": [ + "for eval_result in evaluation_results:\n", + " summary_score = eval_result[\"score\"]\n", + " judgement = summary_score.judgement\n", + "\n", + " score = sum(\n", + " [\n", + " 0.2 * (judgement.clarity_ok or 0),\n", + " 0.2 * (judgement.factfulness_ok or 0),\n", + " 0.6 * (summary_score.coverage_score or 0),\n", + " ]\n", + " )\n", + "\n", + " summary_score.score = score" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "78790a1b", + "metadata": {}, + "outputs": [], + "source": [ + "evaluation_resultsv = sorted(\n", + " evaluation_results, key=lambda x: x[\"score\"].score, reverse=True\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea3d7601", + "metadata": {}, + "outputs": [], + "source": [ + "evaluation_results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "91f48ef6", + "metadata": {}, + "outputs": [], + "source": [ + "lm.history[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ff02fd1c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "71898f8f", + "metadata": {}, + "source": [ + "---\n", + "## Optimization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "831a7eee", + "metadata": {}, + "outputs": [], + "source": [ + "labels_docs_map = {} # Fill in with appropriate mapping of labels to documents" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "69fa5ec5", + "metadata": {}, + "outputs": [], + "source": [ + "examples = []\n", + "\n", + "for filename, doc_path in labels_docs_map.items():\n", + " references = load_json(os.path.join(labels_dir, filename))\n", + " extracted_document = call_extraction_api(requests.Session(), Path(doc_path))\n", + " document = \"\\n\".join(extracted_document[\"detail\"][\"document\"])\n", + "\n", + " example = dspy.Example(\n", + " document=document,\n", + " references=references,\n", + " ).with_inputs(\"document\")\n", + " examples.append(example)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "307668d0", + "metadata": {}, + "outputs": [], + "source": [ + "examples[:2]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2403a1c", + "metadata": {}, + "outputs": [], + "source": [ + "# Split examples into simple train/dev partitions\n", + "train_examples = examples[:8]\n", + "dev_examples = examples[8:]\n", + "\n", + "print(f\"Train examples: {len(train_examples)}\")\n", + "print(f\"Dev examples: {len(dev_examples)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe1d3d92", + "metadata": {}, + "outputs": [], + "source": [ + "class CoTSummarizer(dspy.Module):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.cot = dspy.ChainOfThought(\"document -> summary\")\n", + "\n", + " def forward(self, document):\n", + " # references flows through so optimizers can use it in demos/prompts\n", + " return self.cot(document=document)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ce4e7b5", + "metadata": {}, + "outputs": [], + "source": [ + "metric_module = SummaryMetric()\n", + "\n", + "\n", + "def summary_metric(example, prediction, trace=None):\n", + " package = metric_module(\n", + " document=example.document,\n", + " references=example.references,\n", + " summary=prediction.summary,\n", + " trace=trace,\n", + " )\n", + "\n", + " if trace is not None:\n", + " return package.score >= 0.75\n", + "\n", + " return package.score" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a194d49a", + "metadata": {}, + "outputs": [], + "source": [ + "evaluate = dspy.Evaluate(\n", + " devset=examples,\n", + " metric=summary_metric,\n", + " num_threads=8,\n", + " display_progress=True,\n", + " display_table=True,\n", + ")\n", + "\n", + "evaluation = evaluate(\n", + " program=CoTSummarizer(),\n", + ")\n", + "\n", + "evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "305f5d0f", + "metadata": {}, + "outputs": [], + "source": [ + "from dspy.teleprompt import COPRO\n", + "\n", + "model_to_generate_prompts = dspy.LM(\n", + " \"ollama_chat/gpt-oss:20b\",\n", + " api_base=\"http://localhost:11434\",\n", + " drop_params=True,\n", + ")\n", + "\n", + "copro = COPRO(\n", + " prompt_model=model_to_generate_prompts,\n", + " metric=summary_metric,\n", + ")\n", + "eval_kwargs = {\"num_threads\": 16, \"display_progress\": True, \"display_table\": 0}\n", + "\n", + "copro_program = copro.compile(\n", + " student=CoTSummarizer(),\n", + " trainset=examples,\n", + " eval_kwargs=eval_kwargs,\n", + ")\n", + "\n", + "copro_program" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "126401a0", + "metadata": {}, + "outputs": [], + "source": [ + "copro_program" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4b7b2f1", + "metadata": {}, + "outputs": [], + "source": [ + "from dspy.teleprompt import COPRO\n", + "\n", + "model_to_generate_prompts = dspy.LM(\n", + " \"ollama_chat/gpt-oss:20b\",\n", + " api_base=\"http://localhost:11434\",\n", + " drop_params=True,\n", + ")\n", + "\n", + "copro = COPRO(\n", + " prompt_model=model_to_generate_prompts,\n", + " metric=summary_metric,\n", + ")\n", + "eval_kwargs = {\"num_threads\": 16, \"display_progress\": True, \"display_table\": 0}\n", + "\n", + "copro_program = copro.compile(\n", + " student=CoTSummarizer(),\n", + " trainset=examples,\n", + " eval_kwargs=eval_kwargs,\n", + ")\n", + "\n", + "copro_program" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "56912cdf", + "metadata": {}, + "outputs": [], + "source": [ + "copro_program" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d604c0e", + "metadata": {}, + "outputs": [], + "source": [ + "evaluate = dspy.Evaluate(\n", + " devset=examples,\n", + " metric=summary_metric,\n", + " num_threads=8,\n", + " display_progress=True,\n", + " display_table=True,\n", + ")\n", + "\n", + "\n", + "evaluation = evaluate(program=copro_program)\n", + "evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6224fc48", + "metadata": {}, + "outputs": [], + "source": [ + "from dspy.teleprompt import MIPROv2\n", + "\n", + "program = CoTSummarizer()\n", + "\n", + "optimizer = MIPROv2(\n", + " prompt_model=model_to_generate_prompts,\n", + " metric=summary_metric,\n", + " auto=\"medium\",\n", + ")\n", + "\n", + "# Optimize program\n", + "print(\"Optimizing program with MIPRO...\")\n", + "optimized_program = optimizer.compile(\n", + " program.deepcopy(),\n", + " trainset=train_examples,\n", + " valset=dev_examples,\n", + " max_bootstrapped_demos=4,\n", + " max_labeled_demos=0,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a262672", + "metadata": {}, + "outputs": [], + "source": [ + "bootstrapped_eval = evaluate(program=optimized_program)\n", + "bootstrapped_eval" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a9e63a6", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.18" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pyproject.toml b/pyproject.toml index 0bd35304..9c0dbf08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,7 @@ dependencies = [ "python-docx>=1.2.0", "langextract[openai]==1.1.0", "ollama==0.6.1", + "tiktoken==0.12.0", ] [project.urls] @@ -116,6 +117,7 @@ dev = [ "jupyter>=1.1.1", "pip>=24.3.1", "streamlit>=1.21.0", + "dspy>=3.0.4", ] [tool.setuptools.packages.find] diff --git a/resources/llm/summarization.yml b/resources/llm/summarization.yml new file mode 100755 index 00000000..78a502fc --- /dev/null +++ b/resources/llm/summarization.yml @@ -0,0 +1,71 @@ +system-prompts: + baseline: | + Eres un asistente especializado en resumir documentos. + Tu único objetivo es producir un resumen fiel, claro y conciso del texto que recibirás. + No añadas interpretaciones ni conclusiones no presentes en el documento. + + task-specific: | + Eres un analista legal especializado en elaborar resúmenes de resoluciones y documentos jurídicos. + Tu tarea es condensar la información esencial: hechos, cuestiones jurídicas, fundamentos y decisión. + Mantén precisión terminológica y evita inferencias no textuales. Si algún elemento no aparece en el texto, no lo inventes. + + template: | + Eres un asistente especializado en el análisis de documentos judiciales. + Debes elaborar un resumen conciso del texto recibido, priorizando la información más relevante e identificando: + + {information_to_extract} + + Además, cuando el texto lo permita, debes reconocer y listar las siguientes entidades: + + {entities_to_identify} + + # Formato de salida (Markdown) + + ## Resumen del documento + [Descripción narrativa: hechos principales, cuestiones jurídicas, fundamentos legales y decisión.] + + ## Entidades relevantes + [Listado de entidades identificadas, agrupadas por tipo y, cuando sea posible, indicando relaciones o correspondencias.] + +defaults: + information-to-extract: | + - Hechos relevantes (qué ocurrió). + - Actores clave (quiénes están involucrados). + * Denunciante(s). + * Acusado/a(s). + * Testigo/a(s). + * Juez/a(s). + * Abogado/a(s). + * Fiscal(es). + * Perito(s). + * Otros (especificar). + - Cronología (cuándo ocurrieron los hechos y eventos procesales importantes). + - Lugar(es) (dónde ocurrieron los hechos y eventos procesales importantes). + - Fundamentos (normas legales, precedentes judiciales, doctrinas aplicadas). + - Decisión (resultado/medida adoptada). + + entities-to-identify: | + - "BANCO": Nombre de una entidad bancaria, pública o privada. + - "CBU": Código Bancario Uniforme (22 dígitos) de una cuenta. + - "CORREO_ELECTRONICO": Dirección de correo electrónico. + - "CUIJ": Código Único de Identificación Jurídica de causas judiciales. + - "CUIT_CUIL": Número de CUIT o CUIL de una persona física o jurídica. + - "DIRECCION": Dirección específica (calle, número, intersección de calles y/o avenidas, código postal, etc.). + - "DNI": Número de Documento Nacional de Identidad u otro documento identificatorio. + - "EDAD": Edad explícita de una persona. + - "ESTUDIOS": Nivel o institución educativa que permita identificar a la persona (ej. "primario incompleto", "secundario completo", "Licenciado en…"). + - "FECHA": Fecha completa o parcial (día, mes y/o año). + - "IP": Dirección IP (IPv4 o IPv6). + - "LINK": Enlace o URL a una página web. + - "LOC": Localización geográfica específica (país, provincia, estado, ciudad, localidad, barrio, etc.). + - "MARCA_AUTOMOVIL": Marca de un vehículo (ej. Toyota, Ford, Suzuki, etc.). + - "NACIONALIDAD": Nacionalidad de una persona (ej. "argentino", "brasileña"). + - "NOMBRE_ARCHIVO": Nombre completo de un archivo digital (incluyendo extensión). + - "NUM_ACTUACION": Número identificatorio de una actuación administrativa o contravencional. + - "NUM_CAJA_AHORRO": Número completo de una caja de ahorro o cuenta bancaria. + - "NUM_EXPEDIENTE": Número de expediente judicial o administrativo. + - "NUM_MATRICULA": Número de matrícula profesional o académica. + - "PATENTE_DOMINIO": Patente o dominio de un vehículo. + - "PER": Nombre(s) y apellido(s) de una persona física. Los nombres inicializados (ej., "M.T.G") y los apodos (ej., "el Gato") también cuentan como información sensible a anonimizar. + - "TELEFONO": Número telefónico (fijo o celular). + - "USUARIX": Nombre de usuario o "handle" en redes sociales o plataformas digitales. diff --git a/summarization_app/app.py b/summarization_app/app.py new file mode 100755 index 00000000..e5404bc8 --- /dev/null +++ b/summarization_app/app.py @@ -0,0 +1,759 @@ +import json +import re +import textwrap +from pathlib import Path + +import matplotlib.pyplot as plt +import pandas as pd +import seaborn as sns +import streamlit as st + +# Set page configuration +st.set_page_config( + page_title="Document Summarization Experiments", + page_icon="📄", + layout="wide", +) + + +# Function to load the results +@st.cache_data +def load_data(file_path: str): + try: + with open(file_path, "r") as f: + data = json.load(f) + return data + except Exception as e: + st.error(f"Error loading data: {e}") + return [] + + +# Function to extract unique values from the dataset +def get_unique_values(data, field): + values = set() + for item in data: + if field in item: + values.add(item[field]) + return sorted(list(values)) + + +# Create a helper function to handle None values +def get_sort_key(item, field, sort_order): + value = item.get(field) + # Handle None values by putting them at the end + if value is None: + return float("inf") if sort_order == "Ascending" else float("-inf") + return value + + +# Mapping from UI names to data fields for sorting and plotting +SORT_FIELD_MAP = { + "Model": "model", + "Prompt Type": "system_prompt_type", + "Tokens per Second": "tokens_per_second", + "Duration": "measured_duration_ms", + "Input Tokens": "input_tokens", + "Output Tokens": "output_tokens", + "Device": "device", +} + + +# Attempt to identify parameter scale (in billions) from model names +def get_model_parameter_scale(model_name): + if not model_name: + return None + + known_params = { + "gemma3:12b": 12, + "gemma3:40b": 40, + "gemma3:20b": 20, + "gemma3:22b": 22, + "gemma3:38b": 38, + "llama3.1:8b": 8, + "llama3.2:3b": 3, + "llama3.2:11b": 11, + "deepseek-r1:1.1b": 1.1, + "deepseek-r1:1b": 1, + "phi-3:3.8b": 3.8, + "phi-4:14b": 14, + "qwen3:3.8b": 3.8, + "qwen3:14b": 14, + "qwen3:72b": 72, + } + + model_name_lower = model_name.lower() + if model_name_lower in known_params: + return known_params[model_name_lower] + + match = re.search(r"(\d+(?:\.\d+)?)\s*b", model_name_lower) + if match: + try: + return float(match.group(1)) + except ValueError: + return None + return None + + +# Main function +def main(): + st.title("📄 Document Summarization Experiments") + + # File selector + results_file = st.sidebar.file_uploader("Upload JSON results file", type=["json"]) + + if results_file is not None: + # Load data from uploaded file + content = results_file.getvalue().decode("utf-8") + data = json.loads(content) + else: + # Try to load from the default path + default_path = "./summarization-benchmark-results.json" + if Path(default_path).exists(): + data = load_data(default_path) + st.sidebar.success(f"Loaded data from {default_path}") + else: + st.sidebar.warning("Please upload a JSON results file") + st.stop() + + # Extract unique values for filters + models = get_unique_values(data, "model") + prompt_types = get_unique_values(data, "system_prompt_type") + doc_paths = get_unique_values(data, "doc_path") + doc_filenames = {doc_path: Path(doc_path).name for doc_path in doc_paths} + devices = get_unique_values(data, "device") + + # Create filters in the sidebar + st.sidebar.header("Filters") + + model_options = ["All"] + models + default_models = ["All"] if models else [] + selected_models = st.sidebar.multiselect( + "Select Models", options=model_options, default=default_models + ) + selected_prompt_type = st.sidebar.selectbox( + "Select Prompt Type", ["All"] + prompt_types + ) + selected_doc = st.sidebar.selectbox( + "Select Document", ["All"] + list(doc_filenames.values()) + ) + selected_device = st.sidebar.selectbox("Select Device", ["All"] + devices) + + # Add metrics display option + st.sidebar.header("Display Options") + show_metrics = st.sidebar.checkbox("Show Metrics", value=True) + show_system_prompt = st.sidebar.checkbox("Show System Prompt", value=False) + show_raw_response = st.sidebar.checkbox("Show Raw Response", value=False) + + # Sorting options + st.sidebar.header("Sorting") + sort_by = st.sidebar.selectbox( + "Sort by", + [ + "Default", + "Model", + "Prompt Type", + "Tokens per Second", + "Duration", + "Input Tokens", + "Output Tokens", + "Device", + ], + ) + sort_order = st.sidebar.radio("Sort order", ["Ascending", "Descending"]) + + # Filter data based on selections + filtered_data = data + + if "All" in selected_models: + if len(selected_models) == 1: + selected_models_filter = None + else: + selected_models_filter = { + model for model in selected_models if model != "All" + } + else: + selected_models_filter = set(selected_models) + + if selected_models_filter: + filtered_data = [ + item + for item in filtered_data + if item.get("model") in selected_models_filter + ] + + if selected_prompt_type != "All": + filtered_data = [ + item + for item in filtered_data + if item.get("system_prompt_type") == selected_prompt_type + ] + + if selected_doc != "All": + filtered_data = [ + item + for item in filtered_data + if doc_filenames.get(item.get("doc_path")) == selected_doc + ] + + if selected_device != "All": + filtered_data = [ + item for item in filtered_data if item.get("device") == selected_device + ] + + # Apply sorting + if sort_by != "Default": + field = SORT_FIELD_MAP.get(sort_by) + if field: + # Sort the filtered data + filtered_data = sorted( + filtered_data, + key=lambda item: get_sort_key(item, field, sort_order), + reverse=(sort_order == "Descending"), + ) + + # Display results count + st.write(f"Found {len(filtered_data)} result(s) out of {len(data)} total.") + + # Pagination controls + st.sidebar.header("Pagination") + items_per_page_options = [5, 10, 20, 50, 100, "All"] + + # Create session state for items per page if it doesn't exist + if "items_per_page" not in st.session_state: + st.session_state.items_per_page = 10 + + # Handle the items per page selection + selected_items = st.sidebar.selectbox( + "Results per page", + options=items_per_page_options, + index=items_per_page_options.index( + 10 if 10 in items_per_page_options else items_per_page_options[1] + ), + key="items_per_page_selector", + ) + + # Handle the "All" option + if selected_items == "All": + items_per_page = len(filtered_data) + else: + items_per_page = selected_items + + # Update session state + if st.session_state.items_per_page != items_per_page: + st.session_state.items_per_page = items_per_page + st.session_state.current_page = ( + 1 # Reset to first page when changing items per page + ) + + total_pages = max(1, (len(filtered_data) + items_per_page - 1) // items_per_page) + + # Create session state for pagination if it doesn't exist + if "current_page" not in st.session_state: + st.session_state.current_page = 1 + + # Ensure current page is valid after filtering + if st.session_state.current_page > total_pages: + st.session_state.current_page = 1 + + # Only show pagination controls if there are multiple pages + if total_pages > 1: + col_label, col_input, _ = st.columns([1, 1, 6]) + + with col_label: + st.markdown("**Page**") + st.caption(f"1 - {total_pages}") + + with col_input: + current_page = st.number_input( + "Page selector", + min_value=1, + max_value=total_pages, + value=st.session_state.current_page, + step=1, + label_visibility="collapsed", + ) + st.session_state.current_page = current_page + else: + st.session_state.current_page = 1 + + current_page = st.session_state.current_page + + # Calculate start and end indices for the current page + start_idx = (current_page - 1) * items_per_page + end_idx = min(start_idx + items_per_page, len(filtered_data)) + + # Get the subset of data for the current page + page_data = filtered_data[start_idx:end_idx] + + # Show page information + col1, col2 = st.columns([3, 1]) + with col1: + st.write( + f"Displaying results {start_idx + 1}-{end_idx} of {len(filtered_data)}" + ) + + with col2: + # If we have multiple pages, show a page indicator + if total_pages > 1: + st.write(f"Page {current_page} of {total_pages}") + + # Display the filtered results + if page_data: + for idx, result in enumerate(page_data): + device_tag = ( + f" ({result.get('device', 'N/A')})" if result.get("device") else "" + ) + title = f"{result.get('model', 'N/A')}{device_tag} - [{result.get('system_prompt_type', 'Unknown')}] - {Path(result.get('doc_path', 'N/A')).name}" + + with st.expander(title): + # Display metrics as a table in a clean format + if show_metrics: + col1, col2 = st.columns(2) + + with col1: + st.subheader("Summarization Context") + context_info = { + "Model": result.get("model", "N/A"), + "Device": result.get("device", "N/A"), + "Prompt Type": result.get("system_prompt_type", "Unknown"), + "Document": Path(result.get("doc_path", "N/A")).name, + } + st.table(pd.DataFrame([context_info])) + + with col2: + st.subheader("Performance Metrics") + metrics = { + "Input Tokens": result.get("input_tokens", "N/A"), + "Output Tokens": result.get("output_tokens", "N/A"), + "Total Tokens": result.get("total_tokens", "N/A"), + "Tokens/Second": f"{result.get('tokens_per_second', 0):.2f}", + "Duration (sec)": f"{result.get('measured_duration_ms', 0) / 1000:.2f}", + "Device": result.get("device", "N/A"), + } + st.table(pd.DataFrame([metrics])) + + if show_system_prompt: + st.subheader("System Prompt") + st.caption( + f"Prompt type: **{result.get('system_prompt_type', 'Unknown')}**" + ) + st.code( + result.get("system_prompt", "N/A"), + language="markdown", + ) + + # Display chat response as markdown + st.subheader("Response") + st.markdown(result.get("chat_response", "No response available")) + + # Optional: Display raw response as a JSON + if show_raw_response and "raw_response" in result: + st.subheader("Raw Response") + st.json(result["raw_response"]) + + # Show a summary visualization if more than one result is selected + if len(filtered_data) > 1: + st.header("Summary Visualizations") + + # Create a DataFrame for easier analysis + df = pd.DataFrame(filtered_data) + df = df.loc[:, ~pd.Index(df.columns).duplicated()] + if "model" in df.columns: + df["model"] = df["model"].apply( + lambda value: ( + value + if isinstance(value, str) + else str(value) + if value is not None + else "Unknown" + ) + ) + if "doc_path" in df.columns: + df["document_name"] = df["doc_path"].apply( + lambda p: Path(p).name if isinstance(p, str) else "Unknown" + ) + else: + df["document_name"] = "Unknown" + df["model_params_b"] = df["model"].apply(get_model_parameter_scale) + df["total_duration_sec"] = df["measured_duration_ms"] / 1000 + + # Determine ordering for models in visualizations based on sorting + if "model" in df.columns: + model_values = df["model"].dropna().unique().tolist() + else: + model_values = [] + model_order = model_values.copy() + sort_field = SORT_FIELD_MAP.get(sort_by) + ascending = sort_order == "Ascending" + + if sort_by == "Model": + model_order = sorted(model_values, reverse=not ascending) + elif ( + sort_field + and sort_field in df.columns + and pd.api.types.is_numeric_dtype(df[sort_field]) + ): + model_metric = ( + df.groupby("model")[sort_field] + .mean() + .dropna() + .sort_values(ascending=ascending) + ) + if not model_metric.empty: + model_order = model_metric.index.tolist() + # Append any models missing from the metric (e.g., all NaNs) + remaining_models = [ + model for model in model_values if model not in model_order + ] + model_order.extend(remaining_models) + + if "model" in df.columns and not df.empty: + model_summary = ( + df.groupby("model") + .agg( + avg_input_tokens=("input_tokens", "mean"), + avg_total_duration_ms=("measured_duration_ms", "mean"), + avg_tokens_per_second=("tokens_per_second", "mean"), + runs=("model", "count"), + params_b=("model_params_b", "mean"), + ) + .reset_index() + ) + model_summary["avg_total_duration_sec"] = ( + model_summary["avg_total_duration_ms"] / 1000 + ) + default_param_scale = ( + model_summary["params_b"].median() + if not model_summary["params_b"].dropna().empty + else 1.0 + ) + model_summary["params_b"].fillna(default_param_scale, inplace=True) + model_summary["bubble_size"] = model_summary["params_b"] * 60 + else: + model_summary = pd.DataFrame() + + # Set up tabs for different visualizations + tab1, tab2, tab3, tab4 = st.tabs( + [ + "Performance Metrics", + "Token Usage", + "Prompt Analysis", + "Device Performance", + ] + ) + + with tab1: + col1, col2 = st.columns(2) + + with col1: + # Generation speed by model + fig, ax = plt.subplots(figsize=(10, 6)) + sns.barplot( + data=df, + x="model", + y="tokens_per_second", + order=model_order or None, + ax=ax, + ) + plt.title("Generation Speed by Model") + plt.xticks(rotation=45, ha="right") + plt.ylabel("Tokens per Second") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + with col2: + # Total duration by model + fig, ax = plt.subplots(figsize=(10, 6)) + sns.barplot( + data=df, + x="model", + y="measured_duration_ms", + order=model_order or None, + ax=ax, + ) + plt.title("Total Processing Time by Model") + plt.xticks(rotation=45, ha="right") + plt.ylabel("Duration (ms)") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + st.subheader("Input Tokens vs Total Duration (Average)") + if not model_summary.empty: + fig, ax = plt.subplots(figsize=(12, 6)) + ax.scatter( + model_summary["avg_input_tokens"], + model_summary["avg_total_duration_sec"], + s=model_summary["bubble_size"], + alpha=0.7, + color="#1f77b4", + edgecolors="black", + ) + for _, row in model_summary.iterrows(): + ax.text( + row["avg_input_tokens"], + row["avg_total_duration_sec"], + row["model"], + fontsize=9, + ha="left", + va="bottom", + alpha=0.9, + ) + ax.set_xlabel("Average Input Tokens") + ax.set_ylabel("Average Total Duration (s)") + ax.grid(True, linestyle="--", alpha=0.6) + st.pyplot(fig) + else: + st.info("Not enough data to render the bubble chart.") + + st.subheader("Performance Distributions") + dist_col1, dist_col2 = st.columns(2) + + with dist_col1: + fig, ax = plt.subplots(figsize=(10, 6)) + sns.violinplot( + data=df, + x="model", + y="tokens_per_second", + order=model_order or None, + inner="quartile", + ax=ax, + ) + plt.xticks(rotation=45, ha="right") + plt.ylabel("Tokens per Second") + plt.title("Tokens per Second Distribution by Model") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + with dist_col2: + fig, ax = plt.subplots(figsize=(10, 6)) + sns.violinplot( + data=df, + x="model", + y="total_duration_sec", + order=model_order or None, + inner="quartile", + ax=ax, + ) + plt.xticks(rotation=45, ha="right") + plt.ylabel("Total Duration (s)") + plt.title("Total Duration Distribution by Model") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + with tab2: + col1, col2 = st.columns(2) + + with col1: + # Input vs Output tokens + df_melted = pd.melt( + df, + id_vars=["model"], + value_vars=["input_tokens", "output_tokens"], + var_name="Token Type", + value_name="Token Count", + ) + fig, ax = plt.subplots(figsize=(10, 6)) + sns.barplot( + data=df_melted, + x="model", + y="Token Count", + order=model_order or None, + hue="Token Type", + ax=ax, + ) + plt.title("Input vs Output Tokens by Model") + plt.xticks(rotation=45, ha="right") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + with col2: + # Input processing time vs Output generation time + df_melted = pd.melt( + df, + id_vars=["model"], + value_vars=["input_duration_ms", "output_duration_ms"], + var_name="Processing Stage", + value_name="Duration (ms)", + ) + fig, ax = plt.subplots(figsize=(10, 6)) + sns.barplot( + data=df_melted, + x="model", + y="Duration (ms)", + order=model_order or None, + hue="Processing Stage", + ax=ax, + ) + plt.title("Processing Time Breakdown by Model") + plt.xticks(rotation=45, ha="right") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + with tab3: + col1, col2 = st.columns(2) + + with col1: + # Prompt type distribution + fig, ax = plt.subplots(figsize=(10, 6)) + prompt_counts = ( + df["system_prompt_type"].value_counts().reset_index() + ) + prompt_counts.columns = ["prompt_type", "count"] + sns.barplot(data=prompt_counts, x="prompt_type", y="count", ax=ax) + plt.title("Prompt Type Distribution") + plt.xticks(rotation=45, ha="right") + plt.ylabel("Count") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + with col2: + # Performance by prompt type + fig, ax = plt.subplots(figsize=(10, 6)) + sns.boxplot( + data=df, + x="system_prompt_type", + y="tokens_per_second", + ax=ax, + ) + plt.title("Performance by Prompt Type") + plt.xticks(rotation=45, ha="right") + plt.ylabel("Tokens per Second") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + st.subheader("Document Coverage by Model") + doc_counts = df.assign( + document_label=df["document_name"].apply( + lambda name: ( + textwrap.shorten(name, width=55, placeholder="…") + if isinstance(name, str) + else name + ) + ), + _count=1, + ).pivot_table( + index="document_label", + columns="model", + values="_count", + aggfunc="sum", + fill_value=0, + ) + if not doc_counts.empty: + if model_order: + ordered_cols = [ + col for col in model_order if col in doc_counts.columns + ] + remaining_cols = [ + col for col in doc_counts.columns if col not in ordered_cols + ] + doc_counts = doc_counts[ordered_cols + remaining_cols] + doc_totals = doc_counts.sum(axis=1).sort_values(ascending=False) + max_docs = 25 + if len(doc_totals) > max_docs: + doc_counts = doc_counts.loc[doc_totals.index[:max_docs]] + st.caption( + f"Showing top {max_docs} documents by experiment count." + ) + fig, ax = plt.subplots(figsize=(12, max(6, 0.4 * len(doc_counts)))) + sns.heatmap( + doc_counts, + annot=True, + fmt="d", + cmap="YlGnBu", + linewidths=0.3, + linecolor="white", + cbar=True, + ax=ax, + ) + plt.xlabel("Model") + plt.ylabel("Document") + plt.xticks(rotation=45, ha="right") + plt.yticks(rotation=0) + plt.title("Experiment Coverage per Document and Model") + st.pyplot(fig) + else: + st.info( + "Document coverage heatmap is unavailable with the current selection." + ) + + with tab4: + # Device performance analysis + st.subheader("Performance by Device") + if "device" in df.columns and not df.empty: + # Performance by device (all models combined) + col1, col2 = st.columns(2) + + with col1: + fig, ax = plt.subplots(figsize=(10, 6)) + sns.boxplot(data=df, x="device", y="tokens_per_second", ax=ax) + plt.title("Tokens per Second by Device") + plt.ylabel("Tokens per Second") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + with col2: + fig, ax = plt.subplots(figsize=(10, 6)) + sns.boxplot(data=df, x="device", y="total_duration_sec", ax=ax) + plt.title("Total Duration by Device") + plt.ylabel("Duration (seconds)") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + + # Model performance by device + st.subheader("Model Performance by Device") + fig, ax = plt.subplots(figsize=(12, 8)) + sns.barplot( + data=df, + x="model", + y="tokens_per_second", + hue="device", + order=model_order or None, + ax=ax, + ) + plt.title("Tokens per Second by Model and Device") + plt.xticks(rotation=45, ha="right") + plt.ylabel("Tokens per Second") + plt.grid(axis="y", linestyle="--", alpha=0.7) + plt.legend(title="Device") + st.pyplot(fig) + + # Device usage count + st.subheader("Device Usage Distribution") + device_counts = df["device"].value_counts().reset_index() + device_counts.columns = ["device", "count"] + fig, ax = plt.subplots(figsize=(8, 5)) + sns.barplot(data=device_counts, x="device", y="count", ax=ax) + plt.title("Number of Experiments by Device") + plt.ylabel("Count") + plt.grid(axis="y", linestyle="--", alpha=0.7) + st.pyplot(fig) + else: + st.info( + "Device performance data is unavailable with the current selection." + ) + + else: + st.info("No results match the selected filters.") + + # Add footer with instructions + st.sidebar.markdown("---") + st.sidebar.markdown("### Instructions") + st.sidebar.markdown( + """ + 1. Use the filters above to narrow down results: + - Filter by model, prompt type, document, or device (CPU/CUDA) + - Use multiple selections in the Models filter + 2. Expand result items to view details + 3. Toggle display options to show/hide metrics and raw responses + 4. Explore visualization tabs: + - Performance Metrics: Compare speed and duration between models + - Token Usage: Analyze input and output token distributions + - Prompt Analysis: Review prompt type performance + - Device Performance: Compare CPU vs CUDA performance + 5. Sort results by any metric including device type + """ + ) + + +if __name__ == "__main__": + main() diff --git a/summarization_app/run_streamlit_app.sh b/summarization_app/run_streamlit_app.sh new file mode 100755 index 00000000..0e419441 --- /dev/null +++ b/summarization_app/run_streamlit_app.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Set environment variables to reduce Streamlit watching +export STREAMLIT_SERVER_WATCH_DIRS="false" +export STREAMLIT_SERVER_HEADLESS="true" +export STREAMLIT_SERVER_FILE_WATCHER_TYPE="none" + +# Run Streamlit app +echo "Starting Streamlit app..." +python -m streamlit run app.py diff --git a/uv.lock b/uv.lock index 7f198f0d..6890516d 100644 --- a/uv.lock +++ b/uv.lock @@ -244,6 +244,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, ] +[[package]] +name = "asyncer" +version = "0.0.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209 }, +] + [[package]] name = "attrs" version = "25.1.0" @@ -255,7 +267,7 @@ wheels = [ [[package]] name = "aymurai" -version = "1.1.13.dev16" +version = "1.1.13.dev63" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -292,6 +304,7 @@ dependencies = [ { name = "tensorflow-hub" }, { name = "tensorflow-text" }, { name = "textract" }, + { name = "tiktoken" }, { name = "torch" }, { name = "torchtext" }, { name = "unidecode" }, @@ -301,6 +314,7 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "dspy" }, { name = "jupyter" }, { name = "matplotlib" }, { name = "nbstripout" }, @@ -348,6 +362,7 @@ requires-dist = [ { name = "tensorflow-hub", specifier = ">=0.16.1" }, { name = "tensorflow-text", specifier = "==2.10.0" }, { name = "textract", specifier = "==1.6.5" }, + { name = "tiktoken", specifier = "==0.12.0" }, { name = "torch", specifier = "==2.9.0" }, { name = "torchtext", specifier = "==0.18.0" }, { name = "unidecode", specifier = "==1.3.8" }, @@ -357,6 +372,7 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ + { name = "dspy", specifier = ">=3.0.4" }, { name = "jupyter", specifier = ">=1.1.1" }, { name = "matplotlib", specifier = ">=3.10.0" }, { name = "nbstripout", specifier = ">=0.8.0" }, @@ -377,6 +393,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 }, ] +[[package]] +name = "backoff" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, +] + [[package]] name = "beautifulsoup4" version = "4.8.2" @@ -552,6 +577,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, ] +[[package]] +name = "cloudpickle" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228 }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -561,6 +595,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] +[[package]] +name = "colorlog" +version = "6.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743 }, +] + [[package]] name = "comm" version = "0.2.2" @@ -751,6 +797,40 @@ version = "0.8" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/7d/7d/60ee3f2b16d9bfdfa72e8599470a2c1a5b759cb113c6fe1006be28359327/docx2txt-0.8.tar.gz", hash = "sha256:2c06d98d7cfe2d3947e5760a57d924e3ff07745b379c8737723922e7009236e5", size = 2814 } +[[package]] +name = "dspy" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "asyncer" }, + { name = "backoff" }, + { name = "cachetools" }, + { name = "cloudpickle" }, + { name = "diskcache" }, + { name = "gepa" }, + { name = "joblib" }, + { name = "json-repair" }, + { name = "litellm" }, + { name = "magicattr" }, + { name = "numpy" }, + { name = "openai" }, + { name = "optuna" }, + { name = "orjson" }, + { name = "pillow" }, + { name = "pydantic" }, + { name = "regex" }, + { name = "requests" }, + { name = "rich" }, + { name = "tenacity" }, + { name = "tqdm" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/18/0042d299cd5e85fdb381568f0cfcc7769122e8f70ea0a2d33e12fd63e705/dspy-3.0.4.tar.gz", hash = "sha256:cb4529df9a91353a16144d9d94ba6ff25f36fc5adfd921f127f4c49d0e309fb8", size = 236376 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/52/56eed4828175f48f712a50a994293065afa7cc98cb112992a0b071179b6c/dspy-3.0.4-py3-none-any.whl", hash = "sha256:c0a88c7936f41f6f613ee6ca8cd92e63746ff2bd780e3896615ade7628eb6a6a", size = 285224 }, +] + [[package]] name = "ebcdic" version = "1.1.1" @@ -879,6 +959,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924 }, ] +[[package]] +name = "fastuuid" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760 }, + { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748 }, + { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537 }, + { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994 }, + { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003 }, + { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583 }, + { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955 }, + { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763 }, + { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613 }, + { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045 }, + { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122 }, +] + [[package]] name = "filelock" version = "3.17.0" @@ -1044,6 +1143,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/54/0bbe240c6f59ac9209c2356dc65abd209963851569494376a077e55ef98d/gdown-4.6.0-py3-none-any.whl", hash = "sha256:e75c5aa8be8ea1cac642d4793f884339d887ab5e07aaa57fafa16c8a56a0cde5", size = 14400 }, ] +[[package]] +name = "gepa" +version = "0.0.17" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/61/f0/fe312ed4405ddc2ca97dc1ce8915c4dd707e413503e6832910ab088fceb6/gepa-0.0.17.tar.gz", hash = "sha256:641ed46f8127618341b66ee82a87fb46a21c5d2d427a5e0b91c850a7f7f64e7f", size = 99816 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/dc/2bc81a01caa887ed58db3c725bebf1e98f37807a4d06c51ecaa85a7cabe0/gepa-0.0.17-py3-none-any.whl", hash = "sha256:0ea98f4179dbc8dd83bdf53494f302e663ee1da8300d086c4cc8ce4aefa4042c", size = 110464 }, +] + [[package]] name = "gitdb" version = "4.0.12" @@ -1540,6 +1648,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6", size = 301817 }, ] +[[package]] +name = "json-repair" +version = "0.54.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/00/46/d3a4d9a3dad39bb4a2ad16b8adb9fe2e8611b20b71197fe33daa6768e85d/json_repair-0.54.1.tar.gz", hash = "sha256:d010bc31f1fc66e7c36dc33bff5f8902674498ae5cb8e801ad455a53b455ad1d", size = 38555 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/96/c9aad7ee949cc1bf15df91f347fbc2d3bd10b30b80c7df689ce6fe9332b5/json_repair-0.54.1-py3-none-any.whl", hash = "sha256:016160c5db5d5fe443164927bb58d2dfbba5f43ad85719fa9bc51c713a443ab1", size = 29311 }, +] + [[package]] name = "json5" version = "0.10.0" @@ -1929,6 +2046,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594 }, ] +[[package]] +name = "litellm" +version = "1.80.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "click" }, + { name = "fastuuid" }, + { name = "httpx" }, + { name = "importlib-metadata" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "tiktoken" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/b8/357544534bef87dd2858432f3cbd3a0e5cc267caebca5ea86b03618786c5/litellm-1.80.5.tar.gz", hash = "sha256:922791c264845d9ed59e540c8fa74a74d237c1b209568a05ffeacd8b51770deb", size = 11885764 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/af/1d4693746ff9fbbe27a6e7d6394b801acf234e00c83f45ad1cb5bf2eaa6c/litellm-1.80.5-py3-none-any.whl", hash = "sha256:2ac5f4e88cd57ae056e00da8f872e1c2956653750929fba2fd9b007b400fdb77", size = 10671970 }, +] + [[package]] name = "lxml" version = "5.3.0" @@ -1960,6 +2100,14 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/b2/6a22fb5c0885da3b00e116aee81f0b829ec9ac8f736cd414b4a09413fc7d/lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", size = 3487557 }, ] +[[package]] +name = "magicattr" +version = "0.1.6" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/7e/76b7e0c391bee7e9273725c29c8fe41c4df62a215ce58aa8e3518baee0bb/magicattr-0.1.6-py2.py3-none-any.whl", hash = "sha256:d96b18ee45b5ee83b09c17e15d3459a64de62d538808c2f71182777dd9dbbbdf", size = 4664 }, +] + [[package]] name = "mako" version = "1.3.8" @@ -2514,6 +2662,45 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932 }, ] +[[package]] +name = "optuna" +version = "4.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alembic" }, + { name = "colorlog" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "sqlalchemy" }, + { name = "tqdm" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708 }, +] + +[[package]] +name = "orjson" +version = "3.11.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870 }, + { url = "https://files.pythonhosted.org/packages/44/1f/da46563c08bef33c41fd63c660abcd2184b4d2b950c8686317d03b9f5f0c/orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44", size = 130622 }, + { url = "https://files.pythonhosted.org/packages/02/bd/b551a05d0090eab0bf8008a13a14edc0f3c3e0236aa6f5b697760dd2817b/orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c", size = 129344 }, + { url = "https://files.pythonhosted.org/packages/87/6c/9ddd5e609f443b2548c5e7df3c44d0e86df2c68587a0e20c50018cdec535/orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23", size = 136633 }, + { url = "https://files.pythonhosted.org/packages/95/f2/9f04f2874c625a9fb60f6918c33542320661255323c272e66f7dcce14df2/orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea", size = 137695 }, + { url = "https://files.pythonhosted.org/packages/d2/c2/c7302afcbdfe8a891baae0e2cee091583a30e6fa613e8bdf33b0e9c8a8c7/orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba", size = 136879 }, + { url = "https://files.pythonhosted.org/packages/c6/3a/b31c8f0182a3e27f48e703f46e61bb769666cd0dac4700a73912d07a1417/orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff", size = 136374 }, + { url = "https://files.pythonhosted.org/packages/29/d0/fd9ab96841b090d281c46df566b7f97bc6c8cd9aff3f3ebe99755895c406/orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac", size = 140519 }, + { url = "https://files.pythonhosted.org/packages/d6/ce/36eb0f15978bb88e33a3480e1a3fb891caa0f189ba61ce7713e0ccdadabf/orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79", size = 406522 }, + { url = "https://files.pythonhosted.org/packages/85/11/e8af3161a288f5c6a00c188fc729c7ba193b0cbc07309a1a29c004347c30/orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827", size = 149790 }, + { url = "https://files.pythonhosted.org/packages/ea/96/209d52db0cf1e10ed48d8c194841e383e23c2ced5a2ee766649fe0e32d02/orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b", size = 140040 }, + { url = "https://files.pythonhosted.org/packages/ef/0e/526db1395ccb74c3d59ac1660b9a325017096dc5643086b38f27662b4add/orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3", size = 135955 }, + { url = "https://files.pythonhosted.org/packages/e6/69/18a778c9de3702b19880e73c9866b91cc85f904b885d816ba1ab318b223c/orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc", size = 131577 }, +] + [[package]] name = "overrides" version = "7.7.0" @@ -3927,6 +4114,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467", size = 18414 }, ] +[[package]] +name = "tiktoken" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991 }, + { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798 }, + { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865 }, + { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856 }, + { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308 }, + { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697 }, + { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, +] + [[package]] name = "tinycss2" version = "1.4.0" From 60bf959116d87e024760fe9ab912834dfb45f4c2 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Thu, 27 Nov 2025 14:18:46 +0000 Subject: [PATCH 018/104] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20YAML=20key=20names?= =?UTF-8?q?=20in=20prompt=20defaults=20for=20summarization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/api/endpoints/routers/llm/summarization.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aymurai/api/endpoints/routers/llm/summarization.py b/aymurai/api/endpoints/routers/llm/summarization.py index 6e40bc02..a681f594 100644 --- a/aymurai/api/endpoints/routers/llm/summarization.py +++ b/aymurai/api/endpoints/routers/llm/summarization.py @@ -41,8 +41,8 @@ def _load_prompt_defaults(path: Path) -> tuple[str, str]: """ content = load_yaml(str(path)) defaults = content.get("defaults", {}) - info = (defaults.get("information_to_extract") or "").strip() - entities = (defaults.get("entities_to_identify") or "").strip() + info = (defaults.get("information-to-extract") or "").strip() + entities = (defaults.get("entities-to-identify") or "").strip() if not info or not entities: raise RuntimeError("summarization defaults missing in YAML") return info, entities From f0420895c0f1deb17f1b158955695423a82eea52 Mon Sep 17 00:00:00 2001 From: Lio Date: Fri, 5 Dec 2025 15:51:03 -0300 Subject: [PATCH 019/104] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20Restru?= =?UTF-8?q?cture=20USEM=20module=20with=20factory=20pattern=20and=20multip?= =?UTF-8?q?l=E2=80=A6=20(#64)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Merge dev into main for v1.1.12 (#57) * Update README.md * 🐛 bugfix: Fix XML special character escaping in DocAnonymizer * ➕ build(deps): Add python-docx package * ✨ feat: Add watermark and hyperlink functionality to document anonymization * ✨ feat: Install Archivo font in Dockerfile * 🎨 refactor: Improve Dockerfile structure and comments for clarity * ⏪ revert: Remove Archivo font installation from Dockerfile * 🔖 feat: Update aymurai package version to 1.1.11 in uv.lock * 🐛 Improve get_extension logic to fix document extraction issues on Windows and remove python-magic dependency * 🔧 Update Dockerfile to use 'bullseye' variant for Python images for improved compatibility * 🔧 Update Makefile targets for improved Docker workflow * 🔖 feat: Bump aymurai package version to 1.1.12 * ♻️ Harden get_extension with header scans and zip safeguards * 🔧 Extend document extraction timeout to 30s * 🔧 Refactor Docker workflow to build and push images using docker/build-push-action * 🔧 Fix workflow step order to correctly extract tag name before building Docker images * 🔧 Remove tag extraction step and use github.ref_name directly for Docker image builds * ⏪ Revert Docker workflow to extract tag name and use it for image versioning * Update .github/workflows/build-docker-image.yml * ✏️ Remove incomplete comment --------- * ♻️ refactor: Restructure USEM module with factory pattern and multiple encoder backends - Add BaseSentenceEncoder abstract base class for encoder interface - Implement factory pattern with EncoderType enum and create_encoder function - Add sentence-transformers encoder implementations (DistilUSE, MultilingualMiniLM) - Move TensorFlow implementation to tensorflow_encoder.py - Add lazy loading for encoder implementations via __getattr__ - Add auto-detection for Apple Silicon compatibility (defaults * 🚚 Rename test sentence encoders mac notebook * 📌 Sync dependencies --------- --- aymurai/models/usem/__init__.py | 48 + aymurai/models/usem/base.py | 66 + aymurai/models/usem/core.py | 109 +- aymurai/models/usem/factory.py | 107 + .../usem/sentence_transformers_encoder.py | 124 + aymurai/models/usem/tensorflow_encoder.py | 81 + .../transforms/entity_subcategories/usem.py | 14 +- .../01-test-sentence-encoders-mac.ipynb | 346 +++ pyproject.toml | 5 +- uv.lock | 2556 ++++++++++------- 10 files changed, 2329 insertions(+), 1127 deletions(-) create mode 100644 aymurai/models/usem/base.py create mode 100644 aymurai/models/usem/factory.py create mode 100644 aymurai/models/usem/sentence_transformers_encoder.py create mode 100644 aymurai/models/usem/tensorflow_encoder.py create mode 100644 notebooks/experiments/sentence-encoders/01-test-sentence-encoders-mac.ipynb diff --git a/aymurai/models/usem/__init__.py b/aymurai/models/usem/__init__.py index e69de29b..ce72ab75 100644 --- a/aymurai/models/usem/__init__.py +++ b/aymurai/models/usem/__init__.py @@ -0,0 +1,48 @@ +"""Sentence encoder module with multiple backend implementations. + +Implementations are lazily loaded to avoid importing unavailable dependencies. +Use the factory function `create_encoder()` for automatic backend selection, +or import specific implementations directly from their modules: + + from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder + from aymurai.models.usem.sentence_transformers_encoder import DistilUSEEncoder +""" + +from aymurai.models.usem.base import BaseSentenceEncoder +from aymurai.models.usem.factory import EncoderType, create_encoder, get_encoder +from aymurai.models.usem.core import SentenceRetrieval + + +def __getattr__(name: str): + """Lazy loading of encoder implementations.""" + if name == "TensorFlowUSEEncoder" or name == "USEMQA": + from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder + return TensorFlowUSEEncoder + + if name == "DistilUSEEncoder": + from aymurai.models.usem.sentence_transformers_encoder import DistilUSEEncoder + return DistilUSEEncoder + + if name == "MultilingualMiniLMEncoder": + from aymurai.models.usem.sentence_transformers_encoder import MultilingualMiniLMEncoder + return MultilingualMiniLMEncoder + + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +__all__ = [ + # Base interface + "BaseSentenceEncoder", + # Factory + "EncoderType", + "create_encoder", + "get_encoder", + # Implementations (lazy loaded) + "TensorFlowUSEEncoder", + "DistilUSEEncoder", + "MultilingualMiniLMEncoder", + # Backwards compatibility (lazy loaded) + "USEMQA", + # Retrieval + "SentenceRetrieval", +] diff --git a/aymurai/models/usem/base.py b/aymurai/models/usem/base.py new file mode 100644 index 00000000..daf25c69 --- /dev/null +++ b/aymurai/models/usem/base.py @@ -0,0 +1,66 @@ +""" +Abstract base class for sentence encoders. +""" + +import unicodedata +from abc import ABC, abstractmethod +from typing import Iterable, Optional + +import numpy as np + + +class BaseSentenceEncoder(ABC): + """ + Abstract base class defining the interface for sentence encoders. + All encoder implementations must inherit from this class. + """ + + def normalize_text(self, text: str) -> str: + """Normalize text by lowercasing and removing non-alphanumeric characters.""" + text = text.lower() + text = "".join( + char + for char in unicodedata.normalize("NFKD", text) + if char.isalnum() or char.isspace() + ) + return text + + @abstractmethod + def encode( + self, + text_array: list[str], + encoder_type: str, + context_array: Optional[list[str]] = None, + ) -> np.ndarray: + """ + Encode a list of texts into embeddings. + + Args: + text_array: List of texts to encode. + encoder_type: Type of encoder to use ('question_encoder' or 'response_encoder'). + context_array: Optional context for response encoding. + + Returns: + numpy array of embeddings. + """ + pass + + @abstractmethod + def batch_encode( + self, + text_array: Iterable[str], + encoder_type: str, + batch_size: int = 256, + ) -> np.ndarray: + """ + Encode texts in batches. + + Args: + text_array: Iterable of texts to encode. + encoder_type: Type of encoder to use. + batch_size: Number of texts per batch. + + Returns: + numpy array of embeddings. + """ + pass diff --git a/aymurai/models/usem/core.py b/aymurai/models/usem/core.py index 4fbd6746..5a3e6e27 100644 --- a/aymurai/models/usem/core.py +++ b/aymurai/models/usem/core.py @@ -1,97 +1,48 @@ -import unicodedata -from multiprocessing import cpu_count -from typing import Iterable, Optional +"""Sentence encoder implementations and retrieval utilities.""" -import numpy as np -import tensorflow as tf -import tensorflow_hub as hub -import tensorflow_text # noqa -from more_itertools import chunked -from tqdm.auto import tqdm - -from aymurai.logger import get_logger - -logger = get_logger(__name__) - -N_JOBS = cpu_count() - - -class USEMQA: - """ - Base class for USEM (Universal Sentence Encoder Multilingual QA) - """ - - def __init__( - self, - usem_qa_url: str = "https://tfhub.dev/google/universal-sentence-encoder-multilingual-qa/3", - ): - self.embed = hub.load(usem_qa_url) - - def normalize_text(self, text: str) -> str: - text = text.lower() - text = "".join( - char - for char in unicodedata.normalize("NFKD", text) - if char.isalnum() or char.isspace() - ) - return text +from typing import TYPE_CHECKING, Optional - def encode( - self, - text_array: list[str], - encoder_type: str, - context_array: Optional[list[str]] = None, - ) -> np.ndarray: - input_array = [self.normalize_text(text) for text in text_array] - - if encoder_type == "response_encoder": - encoder_params = { - "input": tf.constant(input_array), - "context": tf.constant(context_array), - } - - if encoder_type == "question_encoder": - encoder_params = { - "input": tf.constant(input_array), - } - - encoded = self.embed.signatures[encoder_type](**encoder_params) - encoded = encoded["outputs"] - - return encoded - - def batch_encode( - self, - text_array: Iterable[str], - encoder_type: str, - batch_size: int = 256, - ) -> np.ndarray: - text_chunks = chunked(text_array, batch_size) - - encoded = [ - self.encode(text_chunk, encoder_type) - for text_chunk in tqdm( - text_chunks, - desc="creating USEM vectors...", - total=len(text_array) // batch_size, - ) - ] +import numpy as np - encoded = np.vstack(encoded) +from aymurai.models.usem.base import BaseSentenceEncoder +from aymurai.models.usem.factory import EncoderType, create_encoder - return encoded +# Type hints only - no runtime import +if TYPE_CHECKING: + from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder + from aymurai.models.usem.sentence_transformers_encoder import ( + DistilUSEEncoder, + MultilingualMiniLMEncoder, + ) class SentenceRetrieval: + """Retrieve similar sentences using sentence embeddings.""" + def __init__( self, categories: list[str], response_embeddings_path: str, + encoder: Optional[BaseSentenceEncoder] = None, + encoder_type: Optional[EncoderType] = None, ): - self.usem = USEMQA() + """ + Initialize SentenceRetrieval. + + Args: + categories: List of category labels. + response_embeddings_path: Path to pre-computed embeddings (.npy file). + encoder: Pre-configured encoder instance. If None, creates one using factory. + encoder_type: Type of encoder to create if encoder is None. + If None, reads from SENTENCE_ENCODER_TYPE env var. + """ + self.encoder = encoder if encoder is not None else create_encoder(encoder_type) self.categories = categories self.usem_vectors = self.load_usem_vectors(response_embeddings_path) + # Backwards compatibility alias + self.usem = self.encoder + def load_usem_vectors(self, file_path): usem_vectors = np.load(file_path) return usem_vectors diff --git a/aymurai/models/usem/factory.py b/aymurai/models/usem/factory.py new file mode 100644 index 00000000..7f3ae49a --- /dev/null +++ b/aymurai/models/usem/factory.py @@ -0,0 +1,107 @@ +""" +Factory for creating sentence encoder instances based on configuration. +""" + +import os +import platform +from enum import Enum +from typing import Optional + +from aymurai.logger import get_logger +from aymurai.models.usem.base import BaseSentenceEncoder + +logger = get_logger(__name__) + + +class EncoderType(str, Enum): + """Available encoder implementations.""" + + TENSORFLOW_USE = "tensorflow" + DISTILUSE = "distiluse" + MINILM = "minilm" + AUTO = "auto" + + +def _is_apple_silicon() -> bool: + """Check if running on Apple Silicon.""" + return platform.system() == "Darwin" and platform.machine() == "arm64" + + +def _get_encoder_type_from_env() -> EncoderType: + """Get encoder type from environment variable.""" + env_value = os.getenv("SENTENCE_ENCODER_TYPE", "auto").lower() + try: + return EncoderType(env_value) + except ValueError: + logger.warning( + f"Invalid SENTENCE_ENCODER_TYPE '{env_value}', falling back to 'auto'" + ) + return EncoderType.AUTO + + +def create_encoder( + encoder_type: Optional[EncoderType] = None, + device: Optional[str] = None, +) -> BaseSentenceEncoder: + """ + Factory function to create the appropriate sentence encoder. + + Args: + encoder_type: Type of encoder to create. If None, reads from + SENTENCE_ENCODER_TYPE env var (defaults to 'auto'). + device: Device for sentence-transformers models (ignored for TensorFlow). + + Returns: + An instance of BaseSentenceEncoder. + + Environment Variables: + SENTENCE_ENCODER_TYPE: One of 'tensorflow', 'distiluse', 'minilm', 'auto'. + - 'tensorflow': Use TensorFlow Hub USE-QA (not compatible with Apple Silicon) + - 'distiluse': Use distiluse-base-multilingual-cased-v2 + - 'minilm': Use paraphrase-multilingual-MiniLM-L12-v2 + - 'auto': Auto-detect based on platform (Apple Silicon -> distiluse, else tensorflow) + + Raises: + ImportError: If required dependencies are not available. + ValueError: If an invalid encoder type is specified. + """ + if encoder_type is None: + encoder_type = _get_encoder_type_from_env() + + # Auto-detect based on platform + if encoder_type == EncoderType.AUTO: + if _is_apple_silicon(): + logger.info( + "Apple Silicon detected, using DistilUSE encoder for compatibility" + ) + encoder_type = EncoderType.DISTILUSE + else: + logger.info("Using TensorFlow USE encoder") + encoder_type = EncoderType.TENSORFLOW_USE + + # Create the appropriate encoder + if encoder_type == EncoderType.TENSORFLOW_USE: + from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder + + return TensorFlowUSEEncoder() + + elif encoder_type == EncoderType.DISTILUSE: + from aymurai.models.usem.sentence_transformers_encoder import DistilUSEEncoder + + return DistilUSEEncoder(device=device) + + elif encoder_type == EncoderType.MINILM: + from aymurai.models.usem.sentence_transformers_encoder import ( + MultilingualMiniLMEncoder, + ) + + return MultilingualMiniLMEncoder(device=device) + + else: + raise ValueError(f"Unknown encoder type: {encoder_type}") + + +# Backwards compatibility alias +def get_encoder(**kwargs) -> BaseSentenceEncoder: + """Alias for create_encoder for backwards compatibility.""" + return create_encoder(**kwargs) diff --git a/aymurai/models/usem/sentence_transformers_encoder.py b/aymurai/models/usem/sentence_transformers_encoder.py new file mode 100644 index 00000000..b7cf81b4 --- /dev/null +++ b/aymurai/models/usem/sentence_transformers_encoder.py @@ -0,0 +1,124 @@ +""" +Sentence Transformers encoder implementations. +Compatible with Apple Silicon (M1/M2/M3) via PyTorch MPS backend. +""" + +from typing import Iterable, Optional + +import numpy as np +from sentence_transformers import SentenceTransformer + +from aymurai.logger import get_logger +from aymurai.models.usem.base import BaseSentenceEncoder + +logger = get_logger(__name__) + + +class DistilUSEEncoder(BaseSentenceEncoder): + """ + Knowledge-distilled Universal Sentence Encoder using sentence-transformers. + + This is a PyTorch-based distillation of the original USE multilingual model. + Supports 50+ languages and produces 512-dimensional embeddings. + + Compatible with Apple Silicon via MPS backend. + """ + + MODEL_NAME = "sentence-transformers/distiluse-base-multilingual-cased-v2" + + def __init__(self, device: Optional[str] = None): + """ + Initialize the DistilUSE encoder. + + Args: + device: Device to run the model on. If None, auto-detects + (will use 'mps' on Apple Silicon, 'cuda' if available, else 'cpu'). + """ + self.model = SentenceTransformer(self.MODEL_NAME, device=device) + logger.info(f"Loaded {self.MODEL_NAME} on device: {self.model.device}") + + def encode( + self, + text_array: list[str], + encoder_type: str, + context_array: Optional[list[str]] = None, + ) -> np.ndarray: + """ + Encode texts into embeddings. + + Note: encoder_type and context_array are kept for API compatibility + but are not used since sentence-transformers uses a single encoder. + """ + input_array = [self.normalize_text(text) for text in text_array] + return self.model.encode(input_array, convert_to_numpy=True) + + def batch_encode( + self, + text_array: Iterable[str], + encoder_type: str, + batch_size: int = 256, + ) -> np.ndarray: + """Encode texts in batches with progress bar.""" + text_list = list(text_array) + input_array = [self.normalize_text(text) for text in text_list] + return self.model.encode( + input_array, + batch_size=batch_size, + show_progress_bar=True, + convert_to_numpy=True, + ) + + +class MultilingualMiniLMEncoder(BaseSentenceEncoder): + """ + Multilingual MiniLM encoder using sentence-transformers. + + Higher quality embeddings than DistilUSE with faster inference. + Supports 50+ languages and produces 384-dimensional embeddings. + + Compatible with Apple Silicon via MPS backend. + """ + + MODEL_NAME = "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2" + + def __init__(self, device: Optional[str] = None): + """ + Initialize the Multilingual MiniLM encoder. + + Args: + device: Device to run the model on. If None, auto-detects + (will use 'mps' on Apple Silicon, 'cuda' if available, else 'cpu'). + """ + self.model = SentenceTransformer(self.MODEL_NAME, device=device) + logger.info(f"Loaded {self.MODEL_NAME} on device: {self.model.device}") + + def encode( + self, + text_array: list[str], + encoder_type: str, + context_array: Optional[list[str]] = None, + ) -> np.ndarray: + """ + Encode texts into embeddings. + + Note: encoder_type and context_array are kept for API compatibility + but are not used since sentence-transformers uses a single encoder. + """ + input_array = [self.normalize_text(text) for text in text_array] + return self.model.encode(input_array, convert_to_numpy=True) + + def batch_encode( + self, + text_array: Iterable[str], + encoder_type: str, + batch_size: int = 256, + ) -> np.ndarray: + """Encode texts in batches with progress bar.""" + text_list = list(text_array) + input_array = [self.normalize_text(text) for text in text_list] + return self.model.encode( + input_array, + batch_size=batch_size, + show_progress_bar=True, + convert_to_numpy=True, + ) diff --git a/aymurai/models/usem/tensorflow_encoder.py b/aymurai/models/usem/tensorflow_encoder.py new file mode 100644 index 00000000..243e948e --- /dev/null +++ b/aymurai/models/usem/tensorflow_encoder.py @@ -0,0 +1,81 @@ +""" +TensorFlow Hub Universal Sentence Encoder implementation. +""" + +from multiprocessing import cpu_count +from typing import Iterable, Optional + +import numpy as np +import tensorflow as tf +import tensorflow_hub as hub +import tensorflow_text # noqa +from more_itertools import chunked +from tqdm.auto import tqdm + +from aymurai.logger import get_logger +from aymurai.models.usem.base import BaseSentenceEncoder + +logger = get_logger(__name__) + +N_JOBS = cpu_count() + + +class TensorFlowUSEEncoder(BaseSentenceEncoder): + """ + TensorFlow Hub Universal Sentence Encoder Multilingual QA implementation. + + This implementation requires tensorflow-text which is not available on Apple Silicon. + Use SentenceTransformersEncoder for macOS ARM64 compatibility. + """ + + def __init__( + self, + usem_qa_url: str = "https://tfhub.dev/google/universal-sentence-encoder-multilingual-qa/3", + ): + self.embed = hub.load(usem_qa_url) + + def encode( + self, + text_array: list[str], + encoder_type: str, + context_array: Optional[list[str]] = None, + ) -> np.ndarray: + input_array = [self.normalize_text(text) for text in text_array] + + if encoder_type == "response_encoder": + encoder_params = { + "input": tf.constant(input_array), + "context": tf.constant(context_array), + } + + if encoder_type == "question_encoder": + encoder_params = { + "input": tf.constant(input_array), + } + + encoded = self.embed.signatures[encoder_type](**encoder_params) + encoded = encoded["outputs"] + + return encoded + + def batch_encode( + self, + text_array: Iterable[str], + encoder_type: str, + batch_size: int = 256, + ) -> np.ndarray: + text_list = list(text_array) + text_chunks = chunked(text_list, batch_size) + + encoded = [ + self.encode(list(text_chunk), encoder_type) + for text_chunk in tqdm( + text_chunks, + desc="creating USEM vectors...", + total=len(text_list) // batch_size, + ) + ] + + encoded = np.vstack(encoded) + + return encoded diff --git a/aymurai/transforms/entity_subcategories/usem.py b/aymurai/transforms/entity_subcategories/usem.py index c70df207..25645aa6 100644 --- a/aymurai/transforms/entity_subcategories/usem.py +++ b/aymurai/transforms/entity_subcategories/usem.py @@ -3,11 +3,10 @@ from copy import deepcopy import numpy as np -import tensorflow as tf from aymurai.logger import get_logger from aymurai.meta.types import DataItem -from aymurai.models.usem.core import USEMQA +from aymurai.models.usem import create_encoder from aymurai.utils.download import download from aymurai.utils.misc import is_url, get_element from aymurai.meta.pipeline_interfaces import Transform @@ -22,7 +21,7 @@ class USEMSubcategorizer(Transform): Use USEM to retrieve subcategories """ - usem = USEMQA() + usem = create_encoder() def __init__( self, @@ -81,11 +80,10 @@ def retrieve(self, text: str, top_k: int = 10) -> list[str]: """ Retrieve similar sentences using USEM """ - with tf.device(self.device): - query_vector = self.usem.encode( - [text], - encoder_type="question_encoder", - ) + query_vector = self.usem.encode( + [text], + encoder_type="question_encoder", + ) products = np.inner(query_vector, self.usem_vectors)[0] similar_idx = np.flip(products.argsort())[:top_k] diff --git a/notebooks/experiments/sentence-encoders/01-test-sentence-encoders-mac.ipynb b/notebooks/experiments/sentence-encoders/01-test-sentence-encoders-mac.ipynb new file mode 100644 index 00000000..378b1064 --- /dev/null +++ b/notebooks/experiments/sentence-encoders/01-test-sentence-encoders-mac.ipynb @@ -0,0 +1,346 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Test Sentence Encoders on Apple Silicon\n", + "\n", + "This notebook tests the sentence-transformers based encoders that are compatible with Apple Silicon (M1/M2/M3)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import platform\n", + "import time\n", + "\n", + "import numpy as np\n", + "\n", + "# Check platform\n", + "print(f\"Platform: {platform.system()}\")\n", + "print(f\"Machine: {platform.machine()}\")\n", + "print(\n", + " f\"Apple Silicon: {platform.system() == 'Darwin' and platform.machine() == 'arm64'}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Test DistilUSE Encoder\n", + "\n", + "Knowledge-distilled version of Universal Sentence Encoder. 512-dimensional embeddings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.models.usem import DistilUSEEncoder\n", + "\n", + "distiluse = DistilUSEEncoder()\n", + "print(f\"Model: {distiluse.MODEL_NAME}\")\n", + "print(f\"Device: {distiluse.model.device}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test encoding\n", + "test_sentences = [\n", + " \"El juez dictó sentencia en el caso de violencia de género.\",\n", + " \"La víctima presentó una denuncia por amenazas.\",\n", + " \"Se otorgó una medida de protección a la denunciante.\",\n", + " \"The judge issued a ruling in the gender violence case.\",\n", + " \"The victim filed a complaint for threats.\",\n", + "]\n", + "\n", + "start = time.time()\n", + "embeddings_distiluse = distiluse.encode(test_sentences, encoder_type=\"question_encoder\")\n", + "elapsed = time.time() - start\n", + "\n", + "print(f\"Embeddings shape: {embeddings_distiluse.shape}\")\n", + "print(f\"Encoding time: {elapsed:.3f}s\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Test Multilingual MiniLM Encoder\n", + "\n", + "Higher quality embeddings, faster inference. 384-dimensional embeddings." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.models.usem import MultilingualMiniLMEncoder\n", + "\n", + "minilm = MultilingualMiniLMEncoder()\n", + "print(f\"Model: {minilm.MODEL_NAME}\")\n", + "print(f\"Device: {minilm.model.device}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "start = time.time()\n", + "embeddings_minilm = minilm.encode(test_sentences, encoder_type=\"question_encoder\")\n", + "elapsed = time.time() - start\n", + "\n", + "print(f\"Embeddings shape: {embeddings_minilm.shape}\")\n", + "print(f\"Encoding time: {elapsed:.3f}s\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Test Factory Auto-Detection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.models.usem import create_encoder, EncoderType\n", + "\n", + "# Auto-detect (should use DistilUSE on Apple Silicon)\n", + "encoder_auto = create_encoder()\n", + "print(f\"Auto-detected encoder: {type(encoder_auto).__name__}\")\n", + "\n", + "# Explicit selection\n", + "encoder_minilm = create_encoder(EncoderType.MINILM)\n", + "print(f\"Explicit MiniLM encoder: {type(encoder_minilm).__name__}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Semantic Similarity Test\n", + "\n", + "Compare similarity between Spanish and English sentences." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def cosine_similarity(a, b):\n", + " \"\"\"Compute cosine similarity between two vectors.\"\"\"\n", + " return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))\n", + "\n", + "\n", + "def similarity_matrix(embeddings, sentences):\n", + " \"\"\"Compute and display similarity matrix.\"\"\"\n", + " n = len(sentences)\n", + " sim_matrix = np.zeros((n, n))\n", + " for i in range(n):\n", + " for j in range(n):\n", + " sim_matrix[i, j] = cosine_similarity(embeddings[i], embeddings[j])\n", + " return sim_matrix" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Compute similarity matrix for DistilUSE\n", + "sim_distiluse = similarity_matrix(embeddings_distiluse, test_sentences)\n", + "\n", + "print(\"DistilUSE Similarity Matrix:\")\n", + "print(\"Sentences:\")\n", + "for i, s in enumerate(test_sentences):\n", + " print(f\" [{i}] {s[:60]}...\" if len(s) > 60 else f\" [{i}] {s}\")\n", + "print()\n", + "print(np.round(sim_distiluse, 3))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Compute similarity matrix for MiniLM\n", + "sim_minilm = similarity_matrix(embeddings_minilm, test_sentences)\n", + "\n", + "print(\"MiniLM Similarity Matrix:\")\n", + "print(np.round(sim_minilm, 3))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Cross-lingual Similarity\n", + "\n", + "Test that Spanish-English translation pairs have high similarity." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Spanish sentence [0] should be similar to English sentence [3]\n", + "# Spanish sentence [1] should be similar to English sentence [4]\n", + "\n", + "print(\"Cross-lingual similarity (Spanish ↔ English):\")\n", + "print(f\"\\nDistilUSE:\")\n", + "print(\n", + " f\" '{test_sentences[0][:40]}...' ↔ '{test_sentences[3][:40]}...': {sim_distiluse[0, 3]:.3f}\"\n", + ")\n", + "print(\n", + " f\" '{test_sentences[1][:40]}...' ↔ '{test_sentences[4][:40]}...': {sim_distiluse[1, 4]:.3f}\"\n", + ")\n", + "\n", + "print(f\"\\nMiniLM:\")\n", + "print(\n", + " f\" '{test_sentences[0][:40]}...' ↔ '{test_sentences[3][:40]}...': {sim_minilm[0, 3]:.3f}\"\n", + ")\n", + "print(\n", + " f\" '{test_sentences[1][:40]}...' ↔ '{test_sentences[4][:40]}...': {sim_minilm[1, 4]:.3f}\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Batch Encoding Performance" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate more sentences for batch test\n", + "batch_sentences = test_sentences * 100 # 500 sentences\n", + "\n", + "print(f\"Batch size: {len(batch_sentences)} sentences\")\n", + "\n", + "# DistilUSE batch\n", + "start = time.time()\n", + "batch_embeddings_distiluse = distiluse.batch_encode(\n", + " batch_sentences, encoder_type=\"question_encoder\", batch_size=64\n", + ")\n", + "elapsed_distiluse = time.time() - start\n", + "print(\n", + " f\"\\nDistilUSE batch encoding: {elapsed_distiluse:.3f}s ({len(batch_sentences) / elapsed_distiluse:.1f} sent/s)\"\n", + ")\n", + "\n", + "# MiniLM batch\n", + "start = time.time()\n", + "batch_embeddings_minilm = minilm.batch_encode(\n", + " batch_sentences, encoder_type=\"question_encoder\", batch_size=64\n", + ")\n", + "elapsed_minilm = time.time() - start\n", + "print(\n", + " f\"MiniLM batch encoding: {elapsed_minilm:.3f}s ({len(batch_sentences) / elapsed_minilm:.1f} sent/s)\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Environment Variable Configuration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Test environment variable configuration\n", + "import importlib\n", + "import aymurai.models.usem.factory as factory_module\n", + "\n", + "# Set env var and reload\n", + "os.environ[\"SENTENCE_ENCODER_TYPE\"] = \"minilm\"\n", + "importlib.reload(factory_module)\n", + "from aymurai.models.usem.factory import create_encoder\n", + "\n", + "encoder_from_env = create_encoder()\n", + "print(f\"Encoder from SENTENCE_ENCODER_TYPE=minilm: {type(encoder_from_env).__name__}\")\n", + "\n", + "# Reset to auto\n", + "os.environ[\"SENTENCE_ENCODER_TYPE\"] = \"auto\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "Both `DistilUSEEncoder` and `MultilingualMiniLMEncoder` work on Apple Silicon:\n", + "\n", + "| Model | Embedding Dim | Speed | Quality |\n", + "|-------|---------------|-------|--------|\n", + "| DistilUSE | 512 | Good | Good (USE distillation) |\n", + "| MiniLM | 384 | Faster | Better |\n", + "\n", + "Use `SENTENCE_ENCODER_TYPE=auto` for automatic platform detection." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/pyproject.toml b/pyproject.toml index 9c0dbf08..0086a268 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,12 +59,10 @@ dependencies = [ "joblib>=1.4.2", "textract==1.6.5", "datetime_matcher @ git+https://github.com/jedzill4/datetime_matcher", - # "scikit-learn==1.5.2", "jiwer==3.0.5", "datasets>=3.2.0", "unidecode==1.3.8", "sentencepiece==0.2.0", - # "flair @ git+https://github.com/flairNLP/flair@v0.13.1", "flair==0.14.0", "fastapi[standard]>=0.115.6", "uvicorn>=0.34.0", @@ -79,13 +77,14 @@ dependencies = [ "torch==2.9.0", "torchtext==0.18.0", "pytorch-lightning==1.8.3.post1", - "tensorflow_text==2.10.0", # last version compatible with Windows + "tensorflow_text==2.10.0; sys_platform == 'linux' or (sys_platform == 'darwin' and platform_machine == 'x86_64') or sys_platform == 'win32'", # no ARM64 macOS wheels "psutil==6.1.0", "sqlmodel==0.0.22", "alembic>=1.13.3", "tenacity>=9.0.0", "python-dotenv>=1.0.1", "tensorflow-hub>=0.16.1", + "sentence-transformers>=2.2.0", "pymupdf>=1.25.2", "pymupdf4llm>=0.0.17", "pypandoc>=1.15", diff --git a/uv.lock b/uv.lock index 6890516d..401cc267 100644 --- a/uv.lock +++ b/uv.lock @@ -3,11 +3,11 @@ requires-python = "==3.10.*" [[package]] name = "absl-py" -version = "2.1.0" +version = "2.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7a/8f/fc001b92ecc467cc32ab38398bd0bfb45df46e7523bf33c2ad22a505f06e/absl-py-2.1.0.tar.gz", hash = "sha256:7820790efbb316739cde8b4e19357243fc3608a152024288513dd968d7d959ff", size = 118055 } +sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/ad/e0d3c824784ff121c03cc031f944bc7e139a8f1870ffd2845cc2dd76f6c4/absl_py-2.1.0-py3-none-any.whl", hash = "sha256:526a04eadab8b4ee719ce68f204172ead1027549089702d99b9059f129ff1308", size = 133706 }, + { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811 }, ] [[package]] @@ -30,16 +30,16 @@ wheels = [ [[package]] name = "aiohappyeyeballs" -version = "2.4.4" +version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/55/e4373e888fdacb15563ef6fa9fa8c8252476ea071e96fb46defac9f18bf2/aiohappyeyeballs-2.4.4.tar.gz", hash = "sha256:5fdd7d87889c63183afc18ce9271f9b0a7d32c2303e394468dd45d514a757745", size = 21977 } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/74/fbb6559de3607b3300b9be3cc64e97548d55678e44623db17820dbd20002/aiohappyeyeballs-2.4.4-py3-none-any.whl", hash = "sha256:a980909d50efcd44795c4afeca523296716d50cd756ddca6af8c65b996e27de8", size = 14756 }, + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265 }, ] [[package]] name = "aiohttp" -version = "3.11.11" +version = "3.13.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -51,49 +51,79 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/ed/f26db39d29cd3cb2f5a3374304c713fe5ab5a0e4c8ee25a0c45cc6adf844/aiohttp-3.11.11.tar.gz", hash = "sha256:bb49c7f1e6ebf3821a42d81d494f538107610c3a705987f53068546b0e90303e", size = 7669618 } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994 } wheels = [ - { url = "https://files.pythonhosted.org/packages/75/7d/ff2e314b8f9e0b1df833e2d4778eaf23eae6b8cc8f922495d110ddcbf9e1/aiohttp-3.11.11-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a60804bff28662cbcf340a4d61598891f12eea3a66af48ecfdc975ceec21e3c8", size = 708550 }, - { url = "https://files.pythonhosted.org/packages/09/b8/aeb4975d5bba233d6f246941f5957a5ad4e3def8b0855a72742e391925f2/aiohttp-3.11.11-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b4fa1cb5f270fb3eab079536b764ad740bb749ce69a94d4ec30ceee1b5940d5", size = 468430 }, - { url = "https://files.pythonhosted.org/packages/9c/5b/5b620279b3df46e597008b09fa1e10027a39467387c2332657288e25811a/aiohttp-3.11.11-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:731468f555656767cda219ab42e033355fe48c85fbe3ba83a349631541715ba2", size = 455593 }, - { url = "https://files.pythonhosted.org/packages/d8/75/0cdf014b816867d86c0bc26f3d3e3f194198dbf33037890beed629cd4f8f/aiohttp-3.11.11-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb23d8bb86282b342481cad4370ea0853a39e4a32a0042bb52ca6bdde132df43", size = 1584635 }, - { url = "https://files.pythonhosted.org/packages/df/2f/95b8f4e4dfeb57c1d9ad9fa911ede35a0249d75aa339edd2c2270dc539da/aiohttp-3.11.11-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f047569d655f81cb70ea5be942ee5d4421b6219c3f05d131f64088c73bb0917f", size = 1632363 }, - { url = "https://files.pythonhosted.org/packages/39/cb/70cf69ea7c50f5b0021a84f4c59c3622b2b3b81695f48a2f0e42ef7eba6e/aiohttp-3.11.11-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd7659baae9ccf94ae5fe8bfaa2c7bc2e94d24611528395ce88d009107e00c6d", size = 1668315 }, - { url = "https://files.pythonhosted.org/packages/2f/cc/3a3fc7a290eabc59839a7e15289cd48f33dd9337d06e301064e1e7fb26c5/aiohttp-3.11.11-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af01e42ad87ae24932138f154105e88da13ce7d202a6de93fafdafb2883a00ef", size = 1589546 }, - { url = "https://files.pythonhosted.org/packages/15/b4/0f7b0ed41ac6000e283e7332f0f608d734b675a8509763ca78e93714cfb0/aiohttp-3.11.11-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5854be2f3e5a729800bac57a8d76af464e160f19676ab6aea74bde18ad19d438", size = 1544581 }, - { url = "https://files.pythonhosted.org/packages/58/b9/4d06470fd85c687b6b0e31935ef73dde6e31767c9576d617309a2206556f/aiohttp-3.11.11-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6526e5fb4e14f4bbf30411216780c9967c20c5a55f2f51d3abd6de68320cc2f3", size = 1529256 }, - { url = "https://files.pythonhosted.org/packages/61/a2/6958b1b880fc017fd35f5dfb2c26a9a50c755b75fd9ae001dc2236a4fb79/aiohttp-3.11.11-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:85992ee30a31835fc482468637b3e5bd085fa8fe9392ba0bdcbdc1ef5e9e3c55", size = 1536592 }, - { url = "https://files.pythonhosted.org/packages/0f/dd/b974012a9551fd654f5bb95a6dd3f03d6e6472a17e1a8216dd42e9638d6c/aiohttp-3.11.11-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:88a12ad8ccf325a8a5ed80e6d7c3bdc247d66175afedbe104ee2aaca72960d8e", size = 1607446 }, - { url = "https://files.pythonhosted.org/packages/e0/d3/6c98fd87e638e51f074a3f2061e81fcb92123bcaf1439ac1b4a896446e40/aiohttp-3.11.11-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0a6d3fbf2232e3a08c41eca81ae4f1dff3d8f1a30bae415ebe0af2d2458b8a33", size = 1628809 }, - { url = "https://files.pythonhosted.org/packages/a8/2e/86e6f85cbca02be042c268c3d93e7f35977a0e127de56e319bdd1569eaa8/aiohttp-3.11.11-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84a585799c58b795573c7fa9b84c455adf3e1d72f19a2bf498b54a95ae0d194c", size = 1564291 }, - { url = "https://files.pythonhosted.org/packages/0b/8d/1f4ef3503b767717f65e1f5178b0173ab03cba1a19997ebf7b052161189f/aiohttp-3.11.11-cp310-cp310-win32.whl", hash = "sha256:bfde76a8f430cf5c5584553adf9926534352251d379dcb266ad2b93c54a29745", size = 416601 }, - { url = "https://files.pythonhosted.org/packages/ad/86/81cb83691b5ace3d9aa148dc42bacc3450d749fc88c5ec1973573c1c1779/aiohttp-3.11.11-cp310-cp310-win_amd64.whl", hash = "sha256:0fd82b8e9c383af11d2b26f27a478640b6b83d669440c0a71481f7c865a51da9", size = 442007 }, + { url = "https://files.pythonhosted.org/packages/6d/34/939730e66b716b76046dedfe0842995842fa906ccc4964bba414ff69e429/aiohttp-3.13.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2372b15a5f62ed37789a6b383ff7344fc5b9f243999b0cd9b629d8bc5f5b4155", size = 736471 }, + { url = "https://files.pythonhosted.org/packages/fd/cf/dcbdf2df7f6ca72b0bb4c0b4509701f2d8942cf54e29ca197389c214c07f/aiohttp-3.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7f8659a48995edee7229522984bd1009c1213929c769c2daa80b40fe49a180c", size = 493985 }, + { url = "https://files.pythonhosted.org/packages/9d/87/71c8867e0a1d0882dcbc94af767784c3cb381c1c4db0943ab4aae4fed65e/aiohttp-3.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:939ced4a7add92296b0ad38892ce62b98c619288a081170695c6babe4f50e636", size = 489274 }, + { url = "https://files.pythonhosted.org/packages/38/0f/46c24e8dae237295eaadd113edd56dee96ef6462adf19b88592d44891dc5/aiohttp-3.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6315fb6977f1d0dd41a107c527fee2ed5ab0550b7d885bc15fee20ccb17891da", size = 1668171 }, + { url = "https://files.pythonhosted.org/packages/eb/c6/4cdfb4440d0e28483681a48f69841fa5e39366347d66ef808cbdadddb20e/aiohttp-3.13.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e7352512f763f760baaed2637055c49134fd1d35b37c2dedfac35bfe5cf8725", size = 1636036 }, + { url = "https://files.pythonhosted.org/packages/84/37/8708cf678628216fb678ab327a4e1711c576d6673998f4f43e86e9ae90dd/aiohttp-3.13.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e09a0a06348a2dd73e7213353c90d709502d9786219f69b731f6caa0efeb46f5", size = 1727975 }, + { url = "https://files.pythonhosted.org/packages/e6/2e/3ebfe12fdcb9b5f66e8a0a42dffcd7636844c8a018f261efb2419f68220b/aiohttp-3.13.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a09a6d073fb5789456545bdee2474d14395792faa0527887f2f4ec1a486a59d3", size = 1815823 }, + { url = "https://files.pythonhosted.org/packages/a1/4f/ca2ef819488cbb41844c6cf92ca6dd15b9441e6207c58e5ae0e0fc8d70ad/aiohttp-3.13.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b59d13c443f8e049d9e94099c7e412e34610f1f49be0f230ec656a10692a5802", size = 1669374 }, + { url = "https://files.pythonhosted.org/packages/f8/fe/1fe2e1179a0d91ce09c99069684aab619bf2ccde9b20bd6ca44f8837203e/aiohttp-3.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:20db2d67985d71ca033443a1ba2001c4b5693fe09b0e29f6d9358a99d4d62a8a", size = 1555315 }, + { url = "https://files.pythonhosted.org/packages/5a/2b/f3781899b81c45d7cbc7140cddb8a3481c195e7cbff8e36374759d2ab5a5/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:960c2fc686ba27b535f9fd2b52d87ecd7e4fd1cf877f6a5cba8afb5b4a8bd204", size = 1639140 }, + { url = "https://files.pythonhosted.org/packages/72/27/c37e85cd3ece6f6c772e549bd5a253d0c122557b25855fb274224811e4f2/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6c00dbcf5f0d88796151e264a8eab23de2997c9303dd7c0bf622e23b24d3ce22", size = 1645496 }, + { url = "https://files.pythonhosted.org/packages/66/20/3af1ab663151bd3780b123e907761cdb86ec2c4e44b2d9b195ebc91fbe37/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fed38a5edb7945f4d1bcabe2fcd05db4f6ec7e0e82560088b754f7e08d93772d", size = 1697625 }, + { url = "https://files.pythonhosted.org/packages/95/eb/ae5cab15efa365e13d56b31b0d085a62600298bf398a7986f8388f73b598/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:b395bbca716c38bef3c764f187860e88c724b342c26275bc03e906142fc5964f", size = 1542025 }, + { url = "https://files.pythonhosted.org/packages/e9/2d/1683e8d67ec72d911397fe4e575688d2a9b8f6a6e03c8fdc9f3fd3d4c03f/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:204ffff2426c25dfda401ba08da85f9c59525cdc42bda26660463dd1cbcfec6f", size = 1714918 }, + { url = "https://files.pythonhosted.org/packages/99/a2/ffe8e0e1c57c5e542d47ffa1fcf95ef2b3ea573bf7c4d2ee877252431efc/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05c4dd3c48fb5f15db31f57eb35374cb0c09afdde532e7fb70a75aede0ed30f6", size = 1656113 }, + { url = "https://files.pythonhosted.org/packages/0d/42/d511aff5c3a2b06c09d7d214f508a4ad8ac7799817f7c3d23e7336b5e896/aiohttp-3.13.2-cp310-cp310-win32.whl", hash = "sha256:e574a7d61cf10351d734bcddabbe15ede0eaa8a02070d85446875dc11189a251", size = 432290 }, + { url = "https://files.pythonhosted.org/packages/8b/ea/1c2eb7098b5bad4532994f2b7a8228d27674035c9b3234fe02c37469ef14/aiohttp-3.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:364f55663085d658b8462a1c3f17b2b84a5c2e1ba858e1b79bff7b2e24ad1514", size = 455075 }, ] [[package]] name = "aiosignal" -version = "1.3.2" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424 } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490 }, ] [[package]] name = "alembic" -version = "1.14.1" +version = "1.17.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mako" }, { name = "sqlalchemy" }, + { name = "tomli" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/09/f844822e4e847a3f0bd41797f93c4674cd4d2462a3f6c459aa528cdf786e/alembic-1.14.1.tar.gz", hash = "sha256:496e888245a53adf1498fcab31713a469c65836f8de76e01399aa1c3e90dd213", size = 1918219 } +sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554 }, +] + +[[package]] +name = "altair" +version = "4.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "entrypoints" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "toolz" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ec/bf/781b607da4c1a2a7211cd570bd7e22e0accd4deaf1074c32ac7344a09339/altair-4.2.2.tar.gz", hash = "sha256:39399a267c49b30d102c10411e67ab26374156a84b1aeb9fcd15140429ba49c5", size = 740430 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/62/47452306e84d4d2e67f9c559380aeb230f5e6ca84fafb428dd36b96a99ba/altair-4.2.2-py3-none-any.whl", hash = "sha256:8b45ebeaf8557f2d760c5c77b79f02ae12aee7c46c27c06014febab6f849bc87", size = 813630 }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/7e/ac0991d1745f7d755fc1cd381b3990a45b404b4d008fc75e2a983516fbfe/alembic-1.14.1-py3-none-any.whl", hash = "sha256:1acdd7a3a478e208b0503cd73614d5e4c6efafa4e73518bb60e4f2846a37b1c5", size = 233565 }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303 }, ] [[package]] @@ -124,17 +154,16 @@ wheels = [ [[package]] name = "anyio" -version = "4.8.0" +version = "4.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup" }, { name = "idna" }, - { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/73/199a98fc2dae33535d6b8e8e6ec01f8c1d76c9adb096c6b7d64823038cde/anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a", size = 181126 } +sdist = { url = "https://files.pythonhosted.org/packages/16/ce/8a777047513153587e5434fd752e89334ac33e379aa3497db860eeb60377/anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0", size = 228266 } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/eb/e7f063ad1fec6b3178a3cd82d1a3c4de82cccf283fc42746168188e1cdd5/anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a", size = 96041 }, + { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362 }, ] [[package]] @@ -157,57 +186,62 @@ wheels = [ [[package]] name = "argon2-cffi" -version = "23.1.0" +version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/31/fa/57ec2c6d16ecd2ba0cf15f3c7d1c3c2e7b5fcb83555ff56d7ab10888ec8f/argon2_cffi-23.1.0.tar.gz", hash = "sha256:879c3e79a2729ce768ebb7d36d4609e3a78a4ca2ec3a9f12286ca057e3d0db08", size = 42798 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/6a/e8a041599e78b6b3752da48000b14c8d1e8a04ded09c88c714ba047f34f5/argon2_cffi-23.1.0-py3-none-any.whl", hash = "sha256:c670642b78ba29641818ab2e68bd4e6a78ba53b7eff7b4c3815ae16abf91c7ea", size = 15124 }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, ] [[package]] name = "argon2-cffi-bindings" -version = "21.2.0" +version = "25.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/e9/184b8ccce6683b0aa2fbb7ba5683ea4b9c5763f1356347f1312c32e3c66e/argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3", size = 1779911 } +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/13/838ce2620025e9666aa8f686431f67a29052241692a3dd1ae9d3692a89d3/argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367", size = 29658 }, - { url = "https://files.pythonhosted.org/packages/b3/02/f7f7bb6b6af6031edb11037639c697b912e1dea2db94d436e681aea2f495/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d", size = 80583 }, - { url = "https://files.pythonhosted.org/packages/ec/f7/378254e6dd7ae6f31fe40c8649eea7d4832a42243acaf0f1fff9083b2bed/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae", size = 86168 }, - { url = "https://files.pythonhosted.org/packages/74/f6/4a34a37a98311ed73bb80efe422fed95f2ac25a4cacc5ae1d7ae6a144505/argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c", size = 82709 }, - { url = "https://files.pythonhosted.org/packages/74/2b/73d767bfdaab25484f7e7901379d5f8793cccbb86c6e0cbc4c1b96f63896/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86", size = 83613 }, - { url = "https://files.pythonhosted.org/packages/4f/fd/37f86deef67ff57c76f137a67181949c2d408077e2e3dd70c6c42912c9bf/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f", size = 84583 }, - { url = "https://files.pythonhosted.org/packages/6f/52/5a60085a3dae8fded8327a4f564223029f5f54b0cb0455a31131b5363a01/argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e", size = 88475 }, - { url = "https://files.pythonhosted.org/packages/8b/95/143cd64feb24a15fa4b189a3e1e7efbaeeb00f39a51e99b26fc62fbacabd/argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082", size = 27698 }, - { url = "https://files.pythonhosted.org/packages/37/2c/e34e47c7dee97ba6f01a6203e0383e15b60fb85d78ac9a15cd066f6fe28b/argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f", size = 30817 }, - { url = "https://files.pythonhosted.org/packages/5a/e4/bf8034d25edaa495da3c8a3405627d2e35758e44ff6eaa7948092646fdcc/argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93", size = 53104 }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, + { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549 }, + { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539 }, + { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467 }, + { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355 }, + { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187 }, ] [[package]] name = "arrow" -version = "1.3.0" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, - { name = "types-python-dateutil" }, + { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419 }, + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797 }, ] [[package]] name = "asttokens" -version = "3.0.0" +version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978 } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918 }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, ] [[package]] @@ -225,14 +259,14 @@ wheels = [ [[package]] name = "async-lru" -version = "2.0.4" +version = "2.0.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/e2/2b4651eff771f6fd900d233e175ddc5e2be502c7eb62c0c42f975c6d36cd/async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627", size = 10019 } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/9f/3c3503693386c4b0f245eaf5ca6198e3b28879ca0a40bde6b0e319793453/async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224", size = 6111 }, + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069 }, ] [[package]] @@ -258,11 +292,11 @@ wheels = [ [[package]] name = "attrs" -version = "25.1.0" +version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/7c/fdf464bcc51d23881d110abd74b512a42b3d5d376a55a831b44c603ae17f/attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e", size = 810562 } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/30/d4986a882011f9df997a55e6becd864812ccfcd821d64aac8570ee39f719/attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a", size = 63152 }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615 }, ] [[package]] @@ -298,11 +332,12 @@ dependencies = [ { name = "pytorch-lightning" }, { name = "requests" }, { name = "scipy" }, + { name = "sentence-transformers" }, { name = "sentencepiece" }, { name = "sqlmodel" }, { name = "tenacity" }, { name = "tensorflow-hub" }, - { name = "tensorflow-text" }, + { name = "tensorflow-text", marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin') or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "textract" }, { name = "tiktoken" }, { name = "torch" }, @@ -356,15 +391,16 @@ requires-dist = [ { name = "pytorch-lightning", specifier = "==1.8.3.post1" }, { name = "requests", specifier = ">=2.32.3" }, { name = "scipy", specifier = "<1.14.1" }, + { name = "sentence-transformers", specifier = ">=2.2.0" }, { name = "sentencepiece", specifier = "==0.2.0" }, { name = "sqlmodel", specifier = "==0.0.22" }, { name = "tenacity", specifier = ">=9.0.0" }, { name = "tensorflow-hub", specifier = ">=0.16.1" }, - { name = "tensorflow-text", specifier = "==2.10.0" }, + { name = "tensorflow-text", marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin') or sys_platform == 'linux' or sys_platform == 'win32'", specifier = "==2.10.0" }, { name = "textract", specifier = "==1.6.5" }, { name = "tiktoken", specifier = "==0.12.0" }, - { name = "torch", specifier = "==2.9.0" }, - { name = "torchtext", specifier = "==0.18.0" }, + { name = "torch", specifier = "==1.12.1" }, + { name = "torchtext", specifier = "==0.13.1" }, { name = "unidecode", specifier = "==1.3.8" }, { name = "uvicorn", specifier = ">=0.34.0" }, { name = "xmltodict", specifier = "==0.14.2" }, @@ -386,11 +422,20 @@ dev = [ [[package]] name = "babel" -version = "2.16.0" +version = "2.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, +] + +[[package]] +name = "backoff" +version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 } +sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 }, + { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, ] [[package]] @@ -432,14 +477,14 @@ wheels = [ [[package]] name = "bleach" -version = "6.2.0" +version = "6.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/9a/0e33f5054c54d349ea62c277191c020c2d6ef1d65ab2cb1993f91ec846d1/bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f", size = 203083 } +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/55/96142937f66150805c25c4d0f31ee4132fd33497753400734f9dfdcbdc66/bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e", size = 163406 }, + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437 }, ] [package.optional-dependencies] @@ -458,80 +503,80 @@ wheels = [ [[package]] name = "boto3" -version = "1.36.6" +version = "1.42.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ec/31/f6189fcb81156cd2e7f7616e4c95958a47e53c12253c5e86a9dcc1a529c1/boto3-1.36.6.tar.gz", hash = "sha256:b36feae061dc0793cf311468956a0a9e99215ce38bc99a1a4e55a5b105f16297", size = 110998 } +sdist = { url = "https://files.pythonhosted.org/packages/ef/4e/b1add2d248d7120ee59df1ca1781a0d5fabdb9e45a477ef50c7598908e80/boto3-1.42.3.tar.gz", hash = "sha256:f7fe002c39806d5efe9105f0d74e836f001230e9520b4502c752dd4951f60041", size = 112797 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/44/4b4d7579297708b84d846a223b6e3be93767d12a3ee997e162e2a3a371a5/boto3-1.36.6-py3-none-any.whl", hash = "sha256:6d473f0f340d02b4e9ad5b8e68786a09728101a8b950231b89ebdaf72b6dca21", size = 139166 }, + { url = "https://files.pythonhosted.org/packages/73/ac/81fb1f37bef7f29f7d0d4b71eb64c6425917cb230da437b42a2a58335ddf/boto3-1.42.3-py3-none-any.whl", hash = "sha256:163df55a774402fa940e95a152c308a33fb0f49cbcb5ec1725936e48635512f7", size = 140619 }, ] [[package]] name = "botocore" -version = "1.36.6" +version = "1.42.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b0/b6/bd1a28becf386a70ca41aa6b76b0d65d03aed81d39fac662d1f97754ffca/botocore-1.36.6.tar.gz", hash = "sha256:4864c53d638da191a34daf3ede3ff1371a3719d952cc0c6bd24ce2836a38dd77", size = 13479626 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/e1/8238fbbab5c45def1b4f75d486a95d1d838e8e21a348563d075a2b09f74b/botocore-1.42.3.tar.gz", hash = "sha256:6bad2e512ab85926bbfb391a9486bb3120f4be71419e2f70b556d99783dcb1ce", size = 14842884 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/ef/a0ac0d749c82fbaba28aa7b87a8ef5760de744e57dcbbfe3b99a0d65cf87/botocore-1.36.6-py3-none-any.whl", hash = "sha256:f77bbbb03fb420e260174650fb5c0cc142ec20a96967734eed2b0ef24334ef34", size = 13308005 }, + { url = "https://files.pythonhosted.org/packages/05/7f/69721ba9d89b4053ac243016428cdd2ea1a1f1c7217572a965aab9f57a20/botocore-1.42.3-py3-none-any.whl", hash = "sha256:fa174f53224ab2adc3a01bb3215b41d314df2f6578381a4a0051bd60d5c718d9", size = 14517527 }, ] [[package]] name = "cachetools" -version = "5.5.1" +version = "6.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d9/74/57df1ab0ce6bc5f6fa868e08de20df8ac58f9c44330c7671ad922d2bbeae/cachetools-5.5.1.tar.gz", hash = "sha256:70f238fbba50383ef62e55c6aff6d9673175fe59f7c6782c7a0b9e38f4a9df95", size = 28044 } +sdist = { url = "https://files.pythonhosted.org/packages/fb/44/ca1675be2a83aeee1886ab745b28cda92093066590233cc501890eb8417a/cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6", size = 31571 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/4e/de4ff18bcf55857ba18d3a4bd48c8a9fde6bb0980c9d20b263f05387fd88/cachetools-5.5.1-py3-none-any.whl", hash = "sha256:b76651fdc3b24ead3c648bbdeeb940c1b04d365b38b4af66788f9ec4a81d42bb", size = 9530 }, + { url = "https://files.pythonhosted.org/packages/e6/46/eb6eca305c77a4489affe1c5d8f4cae82f285d9addd8de4ec084a7184221/cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace", size = 11503 }, ] [[package]] name = "certifi" -version = "2024.12.14" +version = "2025.11.12" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/bd/1d41ee578ce09523c81a15426705dd20969f5abf006d1afe8aeff0dd776a/certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db", size = 166010 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/32/8f6669fc4798494966bf446c8c4a162e0b5d893dff088afddf76414f70e1/certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56", size = 164927 }, + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438 }, ] [[package]] name = "cffi" -version = "1.17.1" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser" }, + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191 }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592 }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024 }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188 }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571 }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687 }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211 }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325 }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784 }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564 }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804 }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299 }, + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283 }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504 }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811 }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402 }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217 }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079 }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475 }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829 }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211 }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184 }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790 }, ] [[package]] name = "cfgv" -version = "3.4.0" +version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/74/539e56497d9bd1d484fd863dd69cbbfa653cd2aa27abfe35653494d85e94/cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560", size = 7114 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c5/55/51844dd50c4fc7a33b653bfaba4c2456f06955289ca770a5dbd5fd267374/cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9", size = 7249 }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, ] [[package]] @@ -545,36 +590,48 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/58/5580c1716040bc89206c77d8f74418caf82ce519aae06450393ca73475d1/charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", size = 198013 }, - { url = "https://files.pythonhosted.org/packages/d0/11/00341177ae71c6f5159a08168bcb98c6e6d196d372c94511f9f6c9afe0c6/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", size = 141285 }, - { url = "https://files.pythonhosted.org/packages/01/09/11d684ea5819e5a8f5100fb0b38cf8d02b514746607934134d31233e02c8/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", size = 151449 }, - { url = "https://files.pythonhosted.org/packages/08/06/9f5a12939db324d905dc1f70591ae7d7898d030d7662f0d426e2286f68c9/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", size = 143892 }, - { url = "https://files.pythonhosted.org/packages/93/62/5e89cdfe04584cb7f4d36003ffa2936681b03ecc0754f8e969c2becb7e24/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", size = 146123 }, - { url = "https://files.pythonhosted.org/packages/a9/ac/ab729a15c516da2ab70a05f8722ecfccc3f04ed7a18e45c75bbbaa347d61/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", size = 147943 }, - { url = "https://files.pythonhosted.org/packages/03/d2/3f392f23f042615689456e9a274640c1d2e5dd1d52de36ab8f7955f8f050/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", size = 142063 }, - { url = "https://files.pythonhosted.org/packages/f2/e3/e20aae5e1039a2cd9b08d9205f52142329f887f8cf70da3650326670bddf/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", size = 150578 }, - { url = "https://files.pythonhosted.org/packages/8d/af/779ad72a4da0aed925e1139d458adc486e61076d7ecdcc09e610ea8678db/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", size = 153629 }, - { url = "https://files.pythonhosted.org/packages/c2/b6/7aa450b278e7aa92cf7732140bfd8be21f5f29d5bf334ae987c945276639/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", size = 150778 }, - { url = "https://files.pythonhosted.org/packages/39/f4/d9f4f712d0951dcbfd42920d3db81b00dd23b6ab520419626f4023334056/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", size = 146453 }, - { url = "https://files.pythonhosted.org/packages/49/2b/999d0314e4ee0cff3cb83e6bc9aeddd397eeed693edb4facb901eb8fbb69/charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", size = 95479 }, - { url = "https://files.pythonhosted.org/packages/2d/ce/3cbed41cff67e455a386fb5e5dd8906cdda2ed92fbc6297921f2e4419309/charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", size = 102790 }, - { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709 }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814 }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467 }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280 }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454 }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609 }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586 }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290 }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663 }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964 }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064 }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015 }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792 }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198 }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262 }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, ] [[package]] name = "click" -version = "8.1.8" +version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, +] + +[[package]] +name = "cloudpickle" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 }, + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228 }, ] [[package]] @@ -609,21 +666,21 @@ wheels = [ [[package]] name = "comm" -version = "0.2.2" +version = "0.2.3" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "traitlets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/a8/fb783cb0abe2b5fded9f55e5703015cdf1c9c85b3669087c538dd15a6a86/comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e", size = 6210 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/75/49e5bfe642f71f272236b5b2d2691cf915a7283cc0ceda56357b61daa538/comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3", size = 7180 }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, ] [[package]] name = "compressed-rtf" -version = "1.0.6" +version = "1.0.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/ac/abb196bb0b42a239d605fe97c314c3312374749013a07da4e6e0408f223c/compressed_rtf-1.0.6.tar.gz", hash = "sha256:c1c827f1d124d24608981a56e8b8691eb1f2a69a78ccad6440e7d92fde1781dd", size = 5800 } +sdist = { url = "https://files.pythonhosted.org/packages/b7/0c/929a4e8ef9d7143f54d77dadb5f370cc7b98534b1bd6e1124d0abe8efb24/compressed_rtf-1.0.7.tar.gz", hash = "sha256:7c30859334839f3cdc7d10796af5b434bb326b9df7cb5a65e95a8eacb2951b0e", size = 8152 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/1d/62f5bf92e12335eb63517f42671ed78512d48bbc69e02a942dd7b90f03f0/compressed_rtf-1.0.7-py3-none-any.whl", hash = "sha256:b7904921d78c67a0a4b7fff9fb361a00ae2b447b6edca010ce321cd98fa0fcc0", size = 7968 }, +] [[package]] name = "conllu" @@ -636,26 +693,26 @@ wheels = [ [[package]] name = "contourpy" -version = "1.3.1" +version = "1.3.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/c2/fc7193cc5383637ff390a712e88e4ded0452c9fbcf84abe3de5ea3df1866/contourpy-1.3.1.tar.gz", hash = "sha256:dfd97abd83335045a913e3bcc4a09c0ceadbe66580cf573fe961f4a825efa699", size = 13465753 } +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/a3/80937fe3efe0edacf67c9a20b955139a1a622730042c1ea991956f2704ad/contourpy-1.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a045f341a77b77e1c5de31e74e966537bba9f3c4099b35bf4c2e3939dd54cdab", size = 268466 }, - { url = "https://files.pythonhosted.org/packages/82/1d/e3eaebb4aa2d7311528c048350ca8e99cdacfafd99da87bc0a5f8d81f2c2/contourpy-1.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:500360b77259914f7805af7462e41f9cb7ca92ad38e9f94d6c8641b089338124", size = 253314 }, - { url = "https://files.pythonhosted.org/packages/de/f3/d796b22d1a2b587acc8100ba8c07fb7b5e17fde265a7bb05ab967f4c935a/contourpy-1.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2f926efda994cdf3c8d3fdb40b9962f86edbc4457e739277b961eced3d0b4c1", size = 312003 }, - { url = "https://files.pythonhosted.org/packages/bf/f5/0e67902bc4394daee8daa39c81d4f00b50e063ee1a46cb3938cc65585d36/contourpy-1.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adce39d67c0edf383647a3a007de0a45fd1b08dedaa5318404f1a73059c2512b", size = 351896 }, - { url = "https://files.pythonhosted.org/packages/1f/d6/e766395723f6256d45d6e67c13bb638dd1fa9dc10ef912dc7dd3dcfc19de/contourpy-1.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abbb49fb7dac584e5abc6636b7b2a7227111c4f771005853e7d25176daaf8453", size = 320814 }, - { url = "https://files.pythonhosted.org/packages/a9/57/86c500d63b3e26e5b73a28b8291a67c5608d4aa87ebd17bd15bb33c178bc/contourpy-1.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a0cffcbede75c059f535725c1680dfb17b6ba8753f0c74b14e6a9c68c29d7ea3", size = 324969 }, - { url = "https://files.pythonhosted.org/packages/b8/62/bb146d1289d6b3450bccc4642e7f4413b92ebffd9bf2e91b0404323704a7/contourpy-1.3.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ab29962927945d89d9b293eabd0d59aea28d887d4f3be6c22deaefbb938a7277", size = 1265162 }, - { url = "https://files.pythonhosted.org/packages/18/04/9f7d132ce49a212c8e767042cc80ae390f728060d2eea47058f55b9eff1c/contourpy-1.3.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:974d8145f8ca354498005b5b981165b74a195abfae9a8129df3e56771961d595", size = 1324328 }, - { url = "https://files.pythonhosted.org/packages/46/23/196813901be3f97c83ababdab1382e13e0edc0bb4e7b49a7bff15fcf754e/contourpy-1.3.1-cp310-cp310-win32.whl", hash = "sha256:ac4578ac281983f63b400f7fe6c101bedc10651650eef012be1ccffcbacf3697", size = 173861 }, - { url = "https://files.pythonhosted.org/packages/e0/82/c372be3fc000a3b2005061ca623a0d1ecd2eaafb10d9e883a2fc8566e951/contourpy-1.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:174e758c66bbc1c8576992cec9599ce8b6672b741b5d336b5c74e35ac382b18e", size = 218566 }, - { url = "https://files.pythonhosted.org/packages/3e/4f/e56862e64b52b55b5ddcff4090085521fc228ceb09a88390a2b103dccd1b/contourpy-1.3.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b457d6430833cee8e4b8e9b6f07aa1c161e5e0d52e118dc102c8f9bd7dd060d6", size = 265605 }, - { url = "https://files.pythonhosted.org/packages/b0/2e/52bfeeaa4541889f23d8eadc6386b442ee2470bd3cff9baa67deb2dd5c57/contourpy-1.3.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb76c1a154b83991a3cbbf0dfeb26ec2833ad56f95540b442c73950af2013750", size = 315040 }, - { url = "https://files.pythonhosted.org/packages/52/94/86bfae441707205634d80392e873295652fc313dfd93c233c52c4dc07874/contourpy-1.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53", size = 218221 }, + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061 }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956 }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872 }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027 }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641 }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075 }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534 }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188 }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681 }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101 }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599 }, ] [[package]] @@ -669,13 +726,13 @@ wheels = [ [[package]] name = "datasets" -version = "3.2.0" +version = "4.4.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "aiohttp" }, { name = "dill" }, { name = "filelock" }, { name = "fsspec", extra = ["http"] }, + { name = "httpx" }, { name = "huggingface-hub" }, { name = "multiprocess" }, { name = "numpy" }, @@ -687,9 +744,9 @@ dependencies = [ { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/48/744286c044e2b942d4fa67f92816126522ad1f0675def0ea3264e6242005/datasets-3.2.0.tar.gz", hash = "sha256:9a6e1a356052866b5dbdd9c9eedb000bf3fc43d986e3584d9b028f4976937229", size = 558366 } +sdist = { url = "https://files.pythonhosted.org/packages/93/bf/0dae295d6d1ba0b1a200a9dd216838464b5bbd05da01407cb1330b377445/datasets-4.4.1.tar.gz", hash = "sha256:80322699aa8c0bbbdb7caa87906da689c3c2e29523cff698775c67f28fdab1fc", size = 585341 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/84/0df6c5981f5fc722381662ff8cfbdf8aad64bec875f75d80b55bfef394ce/datasets-3.2.0-py3-none-any.whl", hash = "sha256:f3d2ba2698b7284a4518019658596a6a8bc79f31e51516524249d6c59cf0fe2a", size = 480647 }, + { url = "https://files.pythonhosted.org/packages/3b/5e/6f8d874366788ad5d549e9ba258037d974dda6e004843be1bda794571701/datasets-4.4.1-py3-none-any.whl", hash = "sha256:c1163de5211e42546079ab355cc0250c7e6db16eb209ac5ac6252f801f596c44", size = 511591 }, ] [[package]] @@ -699,24 +756,24 @@ source = { git = "https://github.com/jedzill4/datetime_matcher#0e5793e8d1e3653f7 [[package]] name = "debugpy" -version = "1.8.12" +version = "1.8.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/25/c74e337134edf55c4dfc9af579eccb45af2393c40960e2795a94351e8140/debugpy-1.8.12.tar.gz", hash = "sha256:646530b04f45c830ceae8e491ca1c9320a2d2f0efea3141487c82130aba70dce", size = 1641122 } +sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129 } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/19/dd58334c0a1ec07babf80bf29fb8daf1a7ca4c1a3bbe61548e40616ac087/debugpy-1.8.12-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:a2ba7ffe58efeae5b8fad1165357edfe01464f9aef25e814e891ec690e7dd82a", size = 2076091 }, - { url = "https://files.pythonhosted.org/packages/4c/37/bde1737da15f9617d11ab7b8d5267165f1b7dae116b2585a6643e89e1fa2/debugpy-1.8.12-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbbd4149c4fc5e7d508ece083e78c17442ee13b0e69bfa6bd63003e486770f45", size = 3560717 }, - { url = "https://files.pythonhosted.org/packages/d9/ca/bc67f5a36a7de072908bc9e1156c0f0b272a9a2224cf21540ab1ffd71a1f/debugpy-1.8.12-cp310-cp310-win32.whl", hash = "sha256:b202f591204023b3ce62ff9a47baa555dc00bb092219abf5caf0e3718ac20e7c", size = 5180672 }, - { url = "https://files.pythonhosted.org/packages/c1/b9/e899c0a80dfa674dbc992f36f2b1453cd1ee879143cdb455bc04fce999da/debugpy-1.8.12-cp310-cp310-win_amd64.whl", hash = "sha256:9649eced17a98ce816756ce50433b2dd85dfa7bc92ceb60579d68c053f98dff9", size = 5212702 }, - { url = "https://files.pythonhosted.org/packages/38/c4/5120ad36405c3008f451f94b8f92ef1805b1e516f6ff870f331ccb3c4cc0/debugpy-1.8.12-py2.py3-none-any.whl", hash = "sha256:274b6a2040349b5c9864e475284bce5bb062e63dce368a394b8cc865ae3b00c6", size = 5229490 }, + { url = "https://files.pythonhosted.org/packages/38/36/b57c6e818d909f6e59c0182252921cf435e0951126a97e11de37e72ab5e1/debugpy-1.8.17-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:c41d2ce8bbaddcc0009cc73f65318eedfa3dbc88a8298081deb05389f1ab5542", size = 2098021 }, + { url = "https://files.pythonhosted.org/packages/be/01/0363c7efdd1e9febd090bb13cee4fb1057215b157b2979a4ca5ccb678217/debugpy-1.8.17-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:1440fd514e1b815edd5861ca394786f90eb24960eb26d6f7200994333b1d79e3", size = 3087399 }, + { url = "https://files.pythonhosted.org/packages/79/bc/4a984729674aa9a84856650438b9665f9a1d5a748804ac6f37932ce0d4aa/debugpy-1.8.17-cp310-cp310-win32.whl", hash = "sha256:3a32c0af575749083d7492dc79f6ab69f21b2d2ad4cd977a958a07d5865316e4", size = 5230292 }, + { url = "https://files.pythonhosted.org/packages/5d/19/2b9b3092d0cf81a5aa10c86271999453030af354d1a5a7d6e34c574515d7/debugpy-1.8.17-cp310-cp310-win_amd64.whl", hash = "sha256:a3aad0537cf4d9c1996434be68c6c9a6d233ac6f76c2a482c7803295b4e4f99a", size = 5261885 }, + { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210 }, ] [[package]] name = "decorator" -version = "5.1.1" +version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, ] [[package]] @@ -730,23 +787,23 @@ wheels = [ [[package]] name = "deprecated" -version = "1.2.17" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2f/20/caa25c084ebad492360bf28ba5cb74f27b50fc6f3df965fd0add2b5b5993/deprecated-1.2.17.tar.gz", hash = "sha256:0114a10f0bbb750b90b2c2296c90cf7e9eaeb0abb5cf06c80de2c60138de0a82", size = 2928237 } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523 } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/90/89be9a665bf63d3baaba6f34d9a514655abb42be2cc129f31c96df2cef51/Deprecated-1.2.17-py2.py3-none-any.whl", hash = "sha256:69cdc0a751671183f569495e2efb14baee4344b0236342eec29f1fde25d61818", size = 9140 }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298 }, ] [[package]] name = "dill" -version = "0.3.8" +version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/17/4d/ac7ffa80c69ea1df30a8aa11b3578692a5118e7cd1aa157e3ef73b092d15/dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca", size = 184847 } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/7a/cef76fd8438a42f96db64ddaa85280485a9c395e7df3db8158cfec1eee34/dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7", size = 116252 }, + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668 }, ] [[package]] @@ -760,11 +817,20 @@ wheels = [ [[package]] name = "distlib" -version = "0.3.9" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, +] + +[[package]] +name = "distro" +version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0d/dd/1bec4c5ddb504ca60fc29472f3d27e8d4da1257a854e1d96742f15c1d02d/distlib-0.3.9.tar.gz", hash = "sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403", size = 613923 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/a1/cf2472db20f7ce4a6be1253a81cfdf85ad9c7885ffbed7047fb72c24cf87/distlib-0.3.9-py2.py3-none-any.whl", hash = "sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87", size = 468973 }, + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, ] [[package]] @@ -778,11 +844,11 @@ wheels = [ [[package]] name = "dnspython" -version = "2.7.0" +version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251 } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094 }, ] [[package]] @@ -793,9 +859,46 @@ sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf57 [[package]] name = "docx2txt" -version = "0.8" +version = "0.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025 }, +] + +[[package]] +name = "dspy" +version = "3.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/7d/60ee3f2b16d9bfdfa72e8599470a2c1a5b759cb113c6fe1006be28359327/docx2txt-0.8.tar.gz", hash = "sha256:2c06d98d7cfe2d3947e5760a57d924e3ff07745b379c8737723922e7009236e5", size = 2814 } +dependencies = [ + { name = "anyio" }, + { name = "asyncer" }, + { name = "backoff" }, + { name = "cachetools" }, + { name = "cloudpickle" }, + { name = "diskcache" }, + { name = "gepa" }, + { name = "joblib" }, + { name = "json-repair" }, + { name = "litellm" }, + { name = "magicattr" }, + { name = "numpy" }, + { name = "openai" }, + { name = "optuna" }, + { name = "orjson" }, + { name = "pillow" }, + { name = "pydantic" }, + { name = "regex" }, + { name = "requests" }, + { name = "rich" }, + { name = "tenacity" }, + { name = "tqdm" }, + { name = "xxhash" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8e/18/0042d299cd5e85fdb381568f0cfcc7769122e8f70ea0a2d33e12fd63e705/dspy-3.0.4.tar.gz", hash = "sha256:cb4529df9a91353a16144d9d94ba6ff25f36fc5adfd921f127f4c49d0e309fb8", size = 236376 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/52/56eed4828175f48f712a50a994293065afa7cc98cb112992a0b071179b6c/dspy-3.0.4-py3-none-any.whl", hash = "sha256:c0a88c7936f41f6f613ee6ca8cd92e63746ff2bd780e3896615ade7628eb6a6a", size = 285224 }, +] [[package]] name = "dspy" @@ -841,15 +944,24 @@ wheels = [ [[package]] name = "email-validator" -version = "2.2.0" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967 } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604 }, +] + +[[package]] +name = "entrypoints" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/8d/a7121ffe5f402dc015277d2d31eb82d2187334503a011c18f2e78ecbb9b2/entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4", size = 13974 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, + { url = "https://files.pythonhosted.org/packages/35/a8/365059bbcd4572cbc41de17fd5b682be5868b218c3c5479071865cab9078/entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f", size = 5294 }, ] [[package]] @@ -863,20 +975,23 @@ wheels = [ [[package]] name = "exceptiongroup" -version = "1.2.2" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } wheels = [ - { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, ] [[package]] name = "executing" -version = "2.2.0" +version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702 }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, ] [[package]] @@ -909,16 +1024,17 @@ wheels = [ [[package]] name = "fastapi" -version = "0.115.7" +version = "0.123.9" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "annotated-doc" }, { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/f5/3f921e59f189e513adb9aef826e2841672d50a399fead4e69afdeb808ff4/fastapi-0.115.7.tar.gz", hash = "sha256:0f106da6c01d88a6786b3248fb4d7a940d071f6f488488898ad5d354b25ed015", size = 293177 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/01/c3fb48c0135d89586a03c3e2c5bc04540dda52079a1af5cac4a63598efb9/fastapi-0.123.9.tar.gz", hash = "sha256:ab33d672d8e1cc6e0b49777eb73c32ccf20761011f5ca16755889ab406fd1de0", size = 355616 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/7f/bbd4dcf0faf61bc68a01939256e2ed02d681e9334c1a3cef24d5f77aba9f/fastapi-0.115.7-py3-none-any.whl", hash = "sha256:eb6a8c8bf7f26009e8147111ff15b5177a0e19bb4a45bc3486ab14804539d21e", size = 94777 }, + { url = "https://files.pythonhosted.org/packages/db/15/a785e992a27620e022d0bc61b6c897ec14cff07c5ab7ff9f27651a21570b/fastapi-0.123.9-py3-none-any.whl", hash = "sha256:f54c69f23db14bd3dbcdfaf3fdce0483ca5f499512380c8e379a70cda30aa920", size = 111776 }, ] [package.optional-dependencies] @@ -933,30 +1049,104 @@ standard = [ [[package]] name = "fastapi-cli" -version = "0.0.7" +version = "0.0.16" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "rich-toolkit" }, + { name = "tomli" }, { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753 } +sdist = { url = "https://files.pythonhosted.org/packages/99/75/9407a6b452be4c988feacec9c9d2f58d8f315162a6c7258d5a649d933ebe/fastapi_cli-0.0.16.tar.gz", hash = "sha256:e8a2a1ecf7a4e062e3b2eec63ae34387d1e142d4849181d936b23c4bdfe29073", size = 19447 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705 }, + { url = "https://files.pythonhosted.org/packages/55/43/678528c19318394320ee43757648d5e0a8070cf391b31f69d931e5c840d2/fastapi_cli-0.0.16-py3-none-any.whl", hash = "sha256:addcb6d130b5b9c91adbbf3f2947fe115991495fdb442fe3e51b5fc6327df9f4", size = 12312 }, ] [package.optional-dependencies] standard = [ + { name = "fastapi-cloud-cli" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[[package]] +name = "fastapi-cloud-cli" +version = "0.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastar" }, + { name = "httpx" }, + { name = "pydantic", extra = ["email"] }, + { name = "rich-toolkit" }, + { name = "rignore" }, + { name = "sentry-sdk" }, + { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] +sdist = { url = "https://files.pythonhosted.org/packages/c2/dd/e5890bb4ee63f9d8988660b755490e346cf5769aaa7f5f3ced9afb9f090a/fastapi_cloud_cli-0.6.0.tar.gz", hash = "sha256:2c333fff2e4b93b9efbec7896ce3ffa3e77ce4cf3d8cb14e35b4f823dfddac02", size = 30579 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/2f/5ba9b5faa75067e30ff48e3c454263ebc2d2301d5509cfefe12cf9fc8156/fastapi_cloud_cli-0.6.0-py3-none-any.whl", hash = "sha256:b654890b5302c90d2f347b123a35186096328838a526316c470b6005cabd4983", size = 23215 }, +] + +[[package]] +name = "fastar" +version = "0.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536 }, + { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235 }, + { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386 }, + { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955 }, + { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987 }, + { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900 }, + { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523 }, + { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268 }, + { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286 }, + { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921 }, + { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302 }, + { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141 }, + { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544 }, + { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701 }, + { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544 }, + { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020 }, + { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735 }, + { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779 }, + { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755 }, + { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732 }, + { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571 }, + { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440 }, + { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424 }, + { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675 }, + { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098 }, + { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397 }, +] [[package]] name = "fastjsonschema" -version = "2.21.1" +version = "2.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8b/50/4b769ce1ac4071a1ef6d86b1a3fb56cdc3a37615e8c5519e1af96cdac366/fastjsonschema-2.21.1.tar.gz", hash = "sha256:794d4f0a58f848961ba16af7b9c85a3e88cd360df008c59aac6fc5ae9323b5d4", size = 373939 } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024 }, +] + +[[package]] +name = "fastuuid" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232 } wheels = [ - { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924 }, + { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760 }, + { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748 }, + { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537 }, + { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994 }, + { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003 }, + { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583 }, + { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955 }, + { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763 }, + { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613 }, + { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045 }, + { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122 }, ] [[package]] @@ -980,21 +1170,24 @@ wheels = [ [[package]] name = "filelock" -version = "3.17.0" +version = "3.20.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dc/9c/0b15fb47b464e1b663b1acd1253a062aa5feecb07d4e597daea542ebd2b5/filelock-3.17.0.tar.gz", hash = "sha256:ee4e77401ef576ebb38cd7f13b9b28893194acc20a8e68e18730ba9c0e54660e", size = 18027 } +sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922 } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/ec/00d68c4ddfedfe64159999e5f8a98fb8442729a63e2077eb9dcd89623d27/filelock-3.17.0-py3-none-any.whl", hash = "sha256:533dc2f7ba78dc2f0f531fc6c4940addf7b70a481e269a5a3b93be94ffbe8338", size = 16164 }, + { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054 }, ] [[package]] name = "fire" -version = "0.7.0" +version = "0.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "termcolor" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/b6/82c7e601d6d3c3278c40b7bd35e17e82aa227f050aa9f66cb7b7fce29471/fire-0.7.0.tar.gz", hash = "sha256:961550f07936eaf65ad1dc8360f2b2bf8408fad46abbfa4d2a3794f8d2a95cdf", size = 87189 } +sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945 }, +] [[package]] name = "flair" @@ -1035,28 +1228,28 @@ wheels = [ [[package]] name = "flatbuffers" -version = "25.1.24" +version = "25.9.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/64/20/c380c311843318b577650286b2c7eaaac3a011fb982df0050bdbd7e453c5/flatbuffers-25.1.24.tar.gz", hash = "sha256:e0f7b7d806c0abdf166275492663130af40c11f89445045fbef0aa3c9a8643ad", size = 22155 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/1f/3ee70b0a55137442038f2a33469cc5fddd7e0ad2abf83d7497c18a2b6923/flatbuffers-25.9.23.tar.gz", hash = "sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12", size = 22067 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/e2/b066e6e02d67bf5261a6d7539648c6da3365cc9eff3eb6d82009595d84d9/flatbuffers-25.1.24-py2.py3-none-any.whl", hash = "sha256:1abfebaf4083117225d0723087ea909896a34e3fec933beedb490d595ba24145", size = 30955 }, + { url = "https://files.pythonhosted.org/packages/ee/1b/00a78aa2e8fbd63f9af08c9c19e6deb3d5d66b4dda677a0f61654680ee89/flatbuffers-25.9.23-py2.py3-none-any.whl", hash = "sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2", size = 30869 }, ] [[package]] name = "fonttools" -version = "4.55.6" +version = "4.61.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2e/0b11e907b90665253dbad425479e874e38a9e81ced397a4e3312b9116935/fonttools-4.55.6.tar.gz", hash = "sha256:1beb4647a0df5ceaea48015656525eb8081af226fe96554089fd3b274d239ef0", size = 3500677 } +sdist = { url = "https://files.pythonhosted.org/packages/33/f9/0e84d593c0e12244150280a630999835a64f2852276161b62a0f98318de0/fonttools-4.61.0.tar.gz", hash = "sha256:ec520a1f0c7758d7a858a00f090c1745f6cde6a7c5e76fb70ea4044a15f712e7", size = 3561884 } wheels = [ - { url = "https://files.pythonhosted.org/packages/24/05/8c1a6ab8c443525c1cedee94d0371ec45cbcd11e4b01328ff10dcc483134/fonttools-4.55.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:57d55fc965e5dd20c8a60d880e0f43bafb506be87af0b650bdc42591e41e0d0d", size = 2774906 }, - { url = "https://files.pythonhosted.org/packages/cd/53/de15cea829b49d50a0d0942d75bc71ca680536265abed03ce873ae71787b/fonttools-4.55.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:127999618afe3a2490fad54bab0650c5fbeab1f8109bdc0205f6ad34306deb8b", size = 2303345 }, - { url = "https://files.pythonhosted.org/packages/d2/23/90159149cc907ea2da0ca7b7baf5ad783c902de219ecb28bca3f789b82c3/fonttools-4.55.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3226d40cb92787e09dcc3730f54b3779dfe56bdfea624e263685ba17a6faac4", size = 4584790 }, - { url = "https://files.pythonhosted.org/packages/26/db/8d33a4575efe7ecd0487d4a53369d086ab7d879069e4c62d3687dec53941/fonttools-4.55.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e82772f70b84e17aa36e9f236feb2a4f73cb686ec1e162557a36cf759d1acd58", size = 4627464 }, - { url = "https://files.pythonhosted.org/packages/a3/c9/e90342b5eebce21ba2b04ce879c66e0316a5faaa7337498dfb5032953055/fonttools-4.55.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a632f85bd73e002b771bcbcdc512038fa5d2e09bb18c03a22fb8d400ea492ddf", size = 4581741 }, - { url = "https://files.pythonhosted.org/packages/e1/98/f4297b65849f15f6b49349a1ffc21e93d1859fa3579d0d5cb1590317060c/fonttools-4.55.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:791e0cf862cdd3a252df395f1bb5f65e3a760f1da3c7ce184d0f7998c266614d", size = 4751195 }, - { url = "https://files.pythonhosted.org/packages/63/73/9dcf4040edbdc5e33cc23d2b7d6a6d4bb50605efd5686d6b782815f4a818/fonttools-4.55.6-cp310-cp310-win32.whl", hash = "sha256:94f7f2c5c5f3a6422e954ecb6d37cc363e27d6f94050a7ed3f79f12157af6bb2", size = 2178422 }, - { url = "https://files.pythonhosted.org/packages/45/f0/ec0ce63f910db60a566201a550c06205595c10c980f6c74885f53cdf512b/fonttools-4.55.6-cp310-cp310-win_amd64.whl", hash = "sha256:2d15e02b93a46982a8513a208e8f89148bca8297640527365625be56151687d0", size = 2222886 }, - { url = "https://files.pythonhosted.org/packages/1e/6a/6afc55d75036b8d3fe5ceaea2e8da2c04e8f3b298325de73a35f098cb9a8/fonttools-4.55.6-py3-none-any.whl", hash = "sha256:d20ab5a78d0536c26628eaadba661e7ae2427b1e5c748a0a510a44d914e1b155", size = 1112524 }, + { url = "https://files.pythonhosted.org/packages/29/f3/91bba2721fb173fc68e09d15b6ccf3ad4f83d127fbff579be7e5984888a6/fonttools-4.61.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dc25a4a9c1225653e4431a9413d0381b1c62317b0f543bdcec24e1991f612f33", size = 2850151 }, + { url = "https://files.pythonhosted.org/packages/f5/8c/a1691dec01038ac7e7bb3ab83300dcc5087b11d8f48640928c02a873eb92/fonttools-4.61.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b493c32d2555e9944ec1b911ea649ff8f01a649ad9cba6c118d6798e932b3f0", size = 2389769 }, + { url = "https://files.pythonhosted.org/packages/2d/dd/5bb369a44319d92ba25612511eb8ed2a6fa75239979e0388907525626902/fonttools-4.61.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad751319dc532a79bdf628b8439af167181b4210a0cd28a8935ca615d9fdd727", size = 4893189 }, + { url = "https://files.pythonhosted.org/packages/5e/02/51373fa8846bd22bb54e5efb30a824b417b058083f775a194a432f21a45f/fonttools-4.61.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2de14557d113faa5fb519f7f29c3abe4d69c17fe6a5a2595cc8cda7338029219", size = 4854415 }, + { url = "https://files.pythonhosted.org/packages/8b/64/9cdbbb804577a7e6191448851c57e6a36eb02aa4bf6a9668b528c968e44e/fonttools-4.61.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:59587bbe455dbdf75354a9dbca1697a35a8903e01fab4248d6b98a17032cee52", size = 4870927 }, + { url = "https://files.pythonhosted.org/packages/92/68/e40b22919dc96dc30a70b58fec609ab85112de950bdecfadf8dd478c5a88/fonttools-4.61.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:46cb3d9279f758ac0cf671dc3482da877104b65682679f01b246515db03dbb72", size = 4988674 }, + { url = "https://files.pythonhosted.org/packages/9b/5c/e857349ce8aedb2451b9448282e86544b2b7f1c8b10ea0fe49b7cb369b72/fonttools-4.61.0-cp310-cp310-win32.whl", hash = "sha256:58b4f1b78dfbfe855bb8a6801b31b8cdcca0e2847ec769ad8e0b0b692832dd3b", size = 1497663 }, + { url = "https://files.pythonhosted.org/packages/f9/0c/62961d5fe6f764d6cbc387ef2c001f5f610808c7aded837409836c0b3e7c/fonttools-4.61.0-cp310-cp310-win_amd64.whl", hash = "sha256:68704a8bbe0b61976262b255e90cde593dc0fe3676542d9b4d846bad2a890a76", size = 1546143 }, + { url = "https://files.pythonhosted.org/packages/0c/14/634f7daea5ffe6a5f7a0322ba8e1a0e23c9257b80aa91458107896d1dfc7/fonttools-4.61.0-py3-none-any.whl", hash = "sha256:276f14c560e6f98d24ef7f5f44438e55ff5a67f78fa85236b218462c9f5d0635", size = 1144485 }, ] [[package]] @@ -1070,35 +1263,36 @@ wheels = [ [[package]] name = "frozenlist" -version = "1.5.0" +version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/79/29d44c4af36b2b240725dce566b20f63f9b36ef267aaaa64ee7466f4f2f8/frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a", size = 94451 }, - { url = "https://files.pythonhosted.org/packages/47/47/0c999aeace6ead8a44441b4f4173e2261b18219e4ad1fe9a479871ca02fc/frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb", size = 54301 }, - { url = "https://files.pythonhosted.org/packages/8d/60/107a38c1e54176d12e06e9d4b5d755b677d71d1219217cee063911b1384f/frozenlist-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:15538c0cbf0e4fa11d1e3a71f823524b0c46299aed6e10ebb4c2089abd8c3bec", size = 52213 }, - { url = "https://files.pythonhosted.org/packages/17/62/594a6829ac5679c25755362a9dc93486a8a45241394564309641425d3ff6/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e79225373c317ff1e35f210dd5f1344ff31066ba8067c307ab60254cd3a78ad5", size = 240946 }, - { url = "https://files.pythonhosted.org/packages/7e/75/6c8419d8f92c80dd0ee3f63bdde2702ce6398b0ac8410ff459f9b6f2f9cb/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9272fa73ca71266702c4c3e2d4a28553ea03418e591e377a03b8e3659d94fa76", size = 264608 }, - { url = "https://files.pythonhosted.org/packages/88/3e/82a6f0b84bc6fb7e0be240e52863c6d4ab6098cd62e4f5b972cd31e002e8/frozenlist-1.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:498524025a5b8ba81695761d78c8dd7382ac0b052f34e66939c42df860b8ff17", size = 261361 }, - { url = "https://files.pythonhosted.org/packages/fd/85/14e5f9ccac1b64ff2f10c927b3ffdf88772aea875882406f9ba0cec8ad84/frozenlist-1.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92b5278ed9d50fe610185ecd23c55d8b307d75ca18e94c0e7de328089ac5dcba", size = 231649 }, - { url = "https://files.pythonhosted.org/packages/ee/59/928322800306f6529d1852323014ee9008551e9bb027cc38d276cbc0b0e7/frozenlist-1.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f3c8c1dacd037df16e85227bac13cca58c30da836c6f936ba1df0c05d046d8d", size = 241853 }, - { url = "https://files.pythonhosted.org/packages/7d/bd/e01fa4f146a6f6c18c5d34cab8abdc4013774a26c4ff851128cd1bd3008e/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2ac49a9bedb996086057b75bf93538240538c6d9b38e57c82d51f75a73409d2", size = 243652 }, - { url = "https://files.pythonhosted.org/packages/a5/bd/e4771fd18a8ec6757033f0fa903e447aecc3fbba54e3630397b61596acf0/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e66cc454f97053b79c2ab09c17fbe3c825ea6b4de20baf1be28919460dd7877f", size = 241734 }, - { url = "https://files.pythonhosted.org/packages/21/13/c83821fa5544af4f60c5d3a65d054af3213c26b14d3f5f48e43e5fb48556/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:5a3ba5f9a0dfed20337d3e966dc359784c9f96503674c2faf015f7fe8e96798c", size = 260959 }, - { url = "https://files.pythonhosted.org/packages/71/f3/1f91c9a9bf7ed0e8edcf52698d23f3c211d8d00291a53c9f115ceb977ab1/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6321899477db90bdeb9299ac3627a6a53c7399c8cd58d25da094007402b039ab", size = 262706 }, - { url = "https://files.pythonhosted.org/packages/4c/22/4a256fdf5d9bcb3ae32622c796ee5ff9451b3a13a68cfe3f68e2c95588ce/frozenlist-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76e4753701248476e6286f2ef492af900ea67d9706a0155335a40ea21bf3b2f5", size = 250401 }, - { url = "https://files.pythonhosted.org/packages/af/89/c48ebe1f7991bd2be6d5f4ed202d94960c01b3017a03d6954dd5fa9ea1e8/frozenlist-1.5.0-cp310-cp310-win32.whl", hash = "sha256:977701c081c0241d0955c9586ffdd9ce44f7a7795df39b9151cd9a6fd0ce4cfb", size = 45498 }, - { url = "https://files.pythonhosted.org/packages/28/2f/cc27d5f43e023d21fe5c19538e08894db3d7e081cbf582ad5ed366c24446/frozenlist-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:189f03b53e64144f90990d29a27ec4f7997d91ed3d01b51fa39d2dbe77540fd4", size = 51622 }, - { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230 }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621 }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889 }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464 }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649 }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188 }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748 }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351 }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767 }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887 }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785 }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312 }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650 }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659 }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837 }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989 }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, ] [[package]] name = "fsspec" -version = "2024.9.0" +version = "2025.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/62/7c/12b0943011daaaa9c35c2a2e22e5eb929ac90002f08f1259d69aedad84de/fsspec-2024.9.0.tar.gz", hash = "sha256:4b0afb90c2f21832df142f292649035d80b421f60a9e1c027802e5a0da2b04e8", size = 286206 } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/a0/6aaea0c2fbea2f89bfd5db25fb1e3481896a423002ebe4e55288907a97a3/fsspec-2024.9.0-py3-none-any.whl", hash = "sha256:a0947d552d8a6efa72cc2c730b12c41d043509156966cca4fb157b0f2a0c574b", size = 179253 }, + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966 }, ] [package.optional-dependencies] @@ -1194,16 +1388,21 @@ wheels = [ [[package]] name = "google-auth" -version = "2.38.0" +version = "2.43.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cachetools" }, { name = "pyasn1-modules" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/eb/d504ba1daf190af6b204a9d4714d457462b486043744901a6eeea711f913/google_auth-2.38.0.tar.gz", hash = "sha256:8285113607d3b80a3f1543b75962447ba8a09fe85783432a784fdeef6ac094c4", size = 270866 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/ef/66d14cf0e01b08d2d51ffc3c20410c4e134a1548fc246a6081eae585a4fe/google_auth-2.43.0.tar.gz", hash = "sha256:88228eee5fc21b62a1b5fe773ca15e67778cb07dc8363adcb4a8827b52d81483", size = 296359 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9d/47/603554949a37bca5b7f894d51896a9c534b9eab808e2520a748e081669d0/google_auth-2.38.0-py2.py3-none-any.whl", hash = "sha256:e7dae6694313f434a2727bf2906f27ad259bae090d7aa896590d86feec3d9d4a", size = 210770 }, + { url = "https://files.pythonhosted.org/packages/6f/d1/385110a9ae86d91cc14c5282c61fe9f4dc41c0b9f7d423c6ad77038c4448/google_auth-2.43.0-py2.py3-none-any.whl", hash = "sha256:af628ba6fa493f75c7e9dbe9373d148ca9f4399b5ea29976519e0a3848eddd16", size = 223114 }, +] + +[package.optional-dependencies] +requests = [ + { name = "requests" }, ] [[package]] @@ -1267,11 +1466,11 @@ wheels = [ [[package]] name = "google-genai" -version = "1.51.0" +version = "1.53.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, - { name = "google-auth" }, + { name = "google-auth", extra = ["requests"] }, { name = "httpx" }, { name = "pydantic" }, { name = "requests" }, @@ -1279,9 +1478,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/1c/29245699c7c274ed5709b33b6a5192af2d57da5da3d2f189f222d1895336/google_genai-1.51.0.tar.gz", hash = "sha256:596c1ec964b70fec17a6ccfe6ee4edede31022584e8b1d33371d93037c4001b1", size = 258060 } +sdist = { url = "https://files.pythonhosted.org/packages/de/b3/36fbfde2e21e6d3bc67780b61da33632f495ab1be08076cf0a16af74098f/google_genai-1.53.0.tar.gz", hash = "sha256:938a26d22f3fd32c6eeeb4276ef204ef82884e63af9842ce3eac05ceb39cbd8d", size = 260102 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/28/0185dcda66f1994171067cfdb0e44a166450239d5b11b3a8a281dd2da459/google_genai-1.51.0-py3-none-any.whl", hash = "sha256:bfb7d0c6ba48ba9bda539f0d5e69dad827d8735a8b1e4703bafa0a2945d293e1", size = 260483 }, + { url = "https://files.pythonhosted.org/packages/40/f2/97fefdd1ad1f3428321bac819ae7a83ccc59f6439616054736b7819fa56c/google_genai-1.53.0-py3-none-any.whl", hash = "sha256:65a3f99e5c03c372d872cda7419f5940e723374bb12a2f3ffd5e3e56e8eb2094", size = 262015 }, ] [[package]] @@ -1322,89 +1521,105 @@ wheels = [ [[package]] name = "greenlet" -version = "3.1.1" +version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2f/ff/df5fede753cc10f6a5be0931204ea30c35fa2f2ea7a35b25bdaf4fe40e46/greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467", size = 186022 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/90/5234a78dc0ef6496a6eb97b67a42a8e96742a56f7dc808cb954a85390448/greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563", size = 271235 }, - { url = "https://files.pythonhosted.org/packages/7c/16/cd631fa0ab7d06ef06387135b7549fdcc77d8d859ed770a0d28e47b20972/greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83", size = 637168 }, - { url = "https://files.pythonhosted.org/packages/2f/b1/aed39043a6fec33c284a2c9abd63ce191f4f1a07319340ffc04d2ed3256f/greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0", size = 648826 }, - { url = "https://files.pythonhosted.org/packages/76/25/40e0112f7f3ebe54e8e8ed91b2b9f970805143efef16d043dfc15e70f44b/greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120", size = 644443 }, - { url = "https://files.pythonhosted.org/packages/fb/2f/3850b867a9af519794784a7eeed1dd5bc68ffbcc5b28cef703711025fd0a/greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc", size = 643295 }, - { url = "https://files.pythonhosted.org/packages/cf/69/79e4d63b9387b48939096e25115b8af7cd8a90397a304f92436bcb21f5b2/greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617", size = 599544 }, - { url = "https://files.pythonhosted.org/packages/46/1d/44dbcb0e6c323bd6f71b8c2f4233766a5faf4b8948873225d34a0b7efa71/greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7", size = 1125456 }, - { url = "https://files.pythonhosted.org/packages/e0/1d/a305dce121838d0278cee39d5bb268c657f10a5363ae4b726848f833f1bb/greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6", size = 1149111 }, - { url = "https://files.pythonhosted.org/packages/96/28/d62835fb33fb5652f2e98d34c44ad1a0feacc8b1d3f1aecab035f51f267d/greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80", size = 298392 }, + { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658 }, + { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810 }, + { url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248 }, + { url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403 }, + { url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910 }, + { url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206 }, + { url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359 }, + { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740 }, ] [[package]] name = "grpcio" -version = "1.70.0" +version = "1.67.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/e1/4b21b5017c33f3600dcc32b802bb48fe44a4d36d6c066f52650c7c2690fa/grpcio-1.70.0.tar.gz", hash = "sha256:8d1584a68d5922330025881e63a6c1b54cc8117291d382e4fa69339b6d914c56", size = 12788932 } +sdist = { url = "https://files.pythonhosted.org/packages/20/53/d9282a66a5db45981499190b77790570617a604a38f3d103d0400974aeb5/grpcio-1.67.1.tar.gz", hash = "sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732", size = 12580022 } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/e9/f72408bac1f7b05b25e4df569b02d6b200c8e7857193aa9f1df7a3744add/grpcio-1.70.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:95469d1977429f45fe7df441f586521361e235982a0b39e33841549143ae2851", size = 5229736 }, - { url = "https://files.pythonhosted.org/packages/b3/17/e65139ea76dac7bcd8a3f17cbd37e3d1a070c44db3098d0be5e14c5bd6a1/grpcio-1.70.0-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:ed9718f17fbdb472e33b869c77a16d0b55e166b100ec57b016dc7de9c8d236bf", size = 11432751 }, - { url = "https://files.pythonhosted.org/packages/a0/12/42de6082b4ab14a59d30b2fc7786882fdaa75813a4a4f3d4a8c4acd6ed59/grpcio-1.70.0-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:374d014f29f9dfdb40510b041792e0e2828a1389281eb590df066e1cc2b404e5", size = 5711439 }, - { url = "https://files.pythonhosted.org/packages/34/f8/b5a19524d273cbd119274a387bb72d6fbb74578e13927a473bc34369f079/grpcio-1.70.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2af68a6f5c8f78d56c145161544ad0febbd7479524a59c16b3e25053f39c87f", size = 6330777 }, - { url = "https://files.pythonhosted.org/packages/1a/67/3d6c0ad786238aac7fa93b79246fc452978fbfe9e5f86f70da8e8a2797d0/grpcio-1.70.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce7df14b2dcd1102a2ec32f621cc9fab6695effef516efbc6b063ad749867295", size = 5944639 }, - { url = "https://files.pythonhosted.org/packages/76/0d/d9f7cbc41c2743cf18236a29b6a582f41bd65572a7144d92b80bc1e68479/grpcio-1.70.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c78b339869f4dbf89881e0b6fbf376313e4f845a42840a7bdf42ee6caed4b11f", size = 6643543 }, - { url = "https://files.pythonhosted.org/packages/fc/24/bdd7e606b3400c14330e33a4698fa3a49e38a28c9e0a831441adbd3380d2/grpcio-1.70.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58ad9ba575b39edef71f4798fdb5c7b6d02ad36d47949cd381d4392a5c9cbcd3", size = 6199897 }, - { url = "https://files.pythonhosted.org/packages/d1/33/8132eb370087960c82d01b89faeb28f3e58f5619ffe19889f57c58a19c18/grpcio-1.70.0-cp310-cp310-win32.whl", hash = "sha256:2b0d02e4b25a5c1f9b6c7745d4fa06efc9fd6a611af0fb38d3ba956786b95199", size = 3617513 }, - { url = "https://files.pythonhosted.org/packages/99/bc/0fce5cfc0ca969df66f5dca6cf8d2258abb88146bf9ab89d8cf48e970137/grpcio-1.70.0-cp310-cp310-win_amd64.whl", hash = "sha256:0de706c0a5bb9d841e353f6343a9defc9fc35ec61d6eb6111802f3aa9fef29e1", size = 4303342 }, + { url = "https://files.pythonhosted.org/packages/4e/cd/f6ca5c49aa0ae7bc6d0757f7dae6f789569e9490a635eaabe02bc02de7dc/grpcio-1.67.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f", size = 5112450 }, + { url = "https://files.pythonhosted.org/packages/d4/f0/d9bbb4a83cbee22f738ee7a74aa41e09ccfb2dcea2cc30ebe8dab5b21771/grpcio-1.67.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d", size = 10937518 }, + { url = "https://files.pythonhosted.org/packages/5b/17/0c5dbae3af548eb76669887642b5f24b232b021afe77eb42e22bc8951d9c/grpcio-1.67.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:43112046864317498a33bdc4797ae6a268c36345a910de9b9c17159d8346602f", size = 5633610 }, + { url = "https://files.pythonhosted.org/packages/17/48/e000614e00153d7b2760dcd9526b95d72f5cfe473b988e78f0ff3b472f6c/grpcio-1.67.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9b929f13677b10f63124c1a410994a401cdd85214ad83ab67cc077fc7e480f0", size = 6240678 }, + { url = "https://files.pythonhosted.org/packages/64/19/a16762a70eeb8ddfe43283ce434d1499c1c409ceec0c646f783883084478/grpcio-1.67.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7d1797a8a3845437d327145959a2c0c47c05947c9eef5ff1a4c80e499dcc6fa", size = 5884528 }, + { url = "https://files.pythonhosted.org/packages/6b/dc/bd016aa3684914acd2c0c7fa4953b2a11583c2b844f3d7bae91fa9b98fbb/grpcio-1.67.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0489063974d1452436139501bf6b180f63d4977223ee87488fe36858c5725292", size = 6583680 }, + { url = "https://files.pythonhosted.org/packages/1a/93/1441cb14c874f11aa798a816d582f9da82194b6677f0f134ea53d2d5dbeb/grpcio-1.67.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9fd042de4a82e3e7aca44008ee2fb5da01b3e5adb316348c21980f7f58adc311", size = 6162967 }, + { url = "https://files.pythonhosted.org/packages/29/e9/9295090380fb4339b7e935b9d005fa9936dd573a22d147c9e5bb2df1b8d4/grpcio-1.67.1-cp310-cp310-win32.whl", hash = "sha256:638354e698fd0c6c76b04540a850bf1db27b4d2515a19fcd5cf645c48d3eb1ed", size = 3616336 }, + { url = "https://files.pythonhosted.org/packages/ce/de/7c783b8cb8f02c667ca075c49680c4aeb8b054bc69784bcb3e7c1bbf4985/grpcio-1.67.1-cp310-cp310-win_amd64.whl", hash = "sha256:608d87d1bdabf9e2868b12338cd38a79969eaf920c89d698ead08f48de9c0f9e", size = 4352071 }, ] [[package]] name = "h11" -version = "0.14.0" +version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, ] [[package]] name = "h5py" -version = "3.12.1" +version = "3.15.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cc/0c/5c2b0a88158682aeafb10c1c2b735df5bc31f165bfe192f2ee9f2a23b5f1/h5py-3.12.1.tar.gz", hash = "sha256:326d70b53d31baa61f00b8aa5f95c2fcb9621a3ee8365d770c551a13dbbcbfdf", size = 411457 } +sdist = { url = "https://files.pythonhosted.org/packages/4d/6a/0d79de0b025aa85dc8864de8e97659c94cf3d23148394a954dc5ca52f8c8/h5py-3.15.1.tar.gz", hash = "sha256:c86e3ed45c4473564de55aa83b6fc9e5ead86578773dfbd93047380042e26b69", size = 426236 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/30/8fa61698b438dd751fa46a359792e801191dadab560d0a5f1c709443ef8e/h5py-3.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67e59f6c2f19a32973a40f43d9a088ae324fe228c8366e25ebc57ceebf093a6b", size = 3414477 }, + { url = "https://files.pythonhosted.org/packages/16/16/db2f63302937337c4e9e51d97a5984b769bdb7488e3d37632a6ac297f8ef/h5py-3.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e2f471688402c3404fa4e13466e373e622fd4b74b47b56cfdff7cc688209422", size = 2850298 }, + { url = "https://files.pythonhosted.org/packages/fc/2e/f1bb7de9b05112bfd14d5206090f0f92f1e75bbb412fbec5d4653c3d44dd/h5py-3.15.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c45802bcb711e128a6839cb6c01e9ac648dc55df045c9542a675c771f15c8d5", size = 4523605 }, + { url = "https://files.pythonhosted.org/packages/05/8a/63f4b08f3628171ce8da1a04681a65ee7ac338fde3cb3e9e3c9f7818e4da/h5py-3.15.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64ce3f6470adb87c06e3a8dd1b90e973699f1759ad79bfa70c230939bff356c9", size = 4735346 }, + { url = "https://files.pythonhosted.org/packages/74/48/f16d12d9de22277605bcc11c0dcab5e35f06a54be4798faa2636b5d44b3c/h5py-3.15.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4411c1867b9899a25e983fff56d820a66f52ac326bbe10c7cdf7d832c9dcd883", size = 4175305 }, + { url = "https://files.pythonhosted.org/packages/d6/2f/47cdbff65b2ce53c27458c6df63a232d7bb1644b97df37b2342442342c84/h5py-3.15.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2cbc4104d3d4aca9d6db8c0c694555e255805bfeacf9eb1349bda871e26cacbe", size = 4653602 }, + { url = "https://files.pythonhosted.org/packages/c3/28/dc08de359c2f43a67baa529cb70d7f9599848750031975eed92d6ae78e1d/h5py-3.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:01f55111ca516f5568ae7a7fc8247dfce607de331b4467ee8a9a6ed14e5422c7", size = 2873601 }, +] + +[[package]] +name = "hf-xet" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020 } wheels = [ - { url = "https://files.pythonhosted.org/packages/df/7d/b21045fbb004ad8bb6fb3be4e6ca903841722706f7130b9bba31ef2f88e3/h5py-3.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f0f1a382cbf494679c07b4371f90c70391dedb027d517ac94fa2c05299dacda", size = 3402133 }, - { url = "https://files.pythonhosted.org/packages/29/a7/3c2a33fba1da64a0846744726fd067a92fb8abb887875a0dd8e3bac8b45d/h5py-3.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cb65f619dfbdd15e662423e8d257780f9a66677eae5b4b3fc9dca70b5fd2d2a3", size = 2866436 }, - { url = "https://files.pythonhosted.org/packages/1e/d0/4bf67c3937a2437c20844165766ddd1a1817ae6b9544c3743050d8e0f403/h5py-3.12.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b15d8dbd912c97541312c0e07438864d27dbca857c5ad634de68110c6beb1c2", size = 5168596 }, - { url = "https://files.pythonhosted.org/packages/85/bc/e76f4b2096e0859225f5441d1b7f5e2041fffa19fc2c16756c67078417aa/h5py-3.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59685fe40d8c1fbbee088c88cd4da415a2f8bee5c270337dc5a1c4aa634e3307", size = 5341537 }, - { url = "https://files.pythonhosted.org/packages/99/bd/fb8ed45308bb97e04c02bd7aed324ba11e6a4bf9ed73967ca2a168e9cf92/h5py-3.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:577d618d6b6dea3da07d13cc903ef9634cde5596b13e832476dd861aaf651f3e", size = 2990575 }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099 }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178 }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214 }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054 }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812 }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920 }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735 }, ] [[package]] name = "httpcore" -version = "1.0.7" +version = "1.0.9" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, ] [[package]] name = "httptools" -version = "0.6.4" +version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780 }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297 }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130 }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148 }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949 }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591 }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344 }, + { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531 }, + { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408 }, + { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889 }, + { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460 }, + { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267 }, + { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429 }, + { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173 }, ] [[package]] @@ -1424,38 +1639,39 @@ wheels = [ [[package]] name = "huggingface-hub" -version = "0.27.1" +version = "0.36.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, { name = "packaging" }, { name = "pyyaml" }, { name = "requests" }, { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/d2/d6976de7542792fc077b498d64af64882b6d8bb40679284ec0bff77d5929/huggingface_hub-0.27.1.tar.gz", hash = "sha256:c004463ca870283909d715d20f066ebd6968c2207dae9393fdffb3c1d4d8f98b", size = 379407 } +sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/3f/50f6b25fafdcfb1c089187a328c95081abf882309afd86f4053951507cd1/huggingface_hub-0.27.1-py3-none-any.whl", hash = "sha256:1c5155ca7d60b60c2e2fc38cbb3ffb7f7c3adf48f824015b219af9061771daec", size = 450658 }, + { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094 }, ] [[package]] name = "identify" -version = "2.6.6" +version = "2.6.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/bf/c68c46601bacd4c6fb4dd751a42b6e7087240eaabc6487f2ef7a48e0e8fc/identify-2.6.6.tar.gz", hash = "sha256:7bec12768ed44ea4761efb47806f0a41f86e7c0a5fdf5950d4648c90eca7e251", size = 99217 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311 } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/a1/68a395c17eeefb04917034bd0a1bfa765e7654fa150cca473d669aa3afb5/identify-2.6.6-py2.py3-none-any.whl", hash = "sha256:cbd1810bce79f8b671ecb20f53ee0ae8e86ae84b557de31d89709dc2a48ba881", size = 99083 }, + { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183 }, ] [[package]] name = "idna" -version = "3.10" +version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, ] [[package]] @@ -1493,7 +1709,7 @@ sdist = { url = "https://files.pythonhosted.org/packages/50/fb/396d568039d213446 [[package]] name = "ipykernel" -version = "6.29.5" +version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "appnope", marker = "platform_system == 'Darwin'" }, @@ -1510,14 +1726,14 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/5c/67594cb0c7055dc50814b21731c22a601101ea3b1b50a9a1b090e11f5d0f/ipykernel-6.29.5.tar.gz", hash = "sha256:f093a22c4a40f8828f8e330a9c297cb93dcab13bd9678ded6de8e5cf81c56215", size = 163367 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579 } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5c/368ae6c01c7628438358e6d337c19b05425727fbb221d2a3c4303c372f42/ipykernel-6.29.5-py3-none-any.whl", hash = "sha256:afdb66ba5aa354b09b91379bac28ae4afebbb30e8b39510c9690afb7a10421b5", size = 117173 }, + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968 }, ] [[package]] name = "ipython" -version = "8.31.0" +version = "8.37.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1532,14 +1748,14 @@ dependencies = [ { name = "traitlets" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/35/6f90fdddff7a08b7b715fccbd2427b5212c9525cd043d26fdc45bee0708d/ipython-8.31.0.tar.gz", hash = "sha256:b6a2274606bec6166405ff05e54932ed6e5cfecaca1fc05f2cacde7bb074d70b", size = 5501011 } +sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/60/d0feb6b6d9fe4ab89fe8fe5b47cbf6cd936bfd9f1e7ffa9d0015425aeed6/ipython-8.31.0-py3-none-any.whl", hash = "sha256:46ec58f8d3d076a61d128fe517a51eb730e3aaf0c184ea8c17d16e366660c6a6", size = 821583 }, + { url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2", size = 831864 }, ] [[package]] name = "ipywidgets" -version = "8.1.5" +version = "8.1.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "comm" }, @@ -1548,9 +1764,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/4c/dab2a281b07596a5fc220d49827fe6c794c66f1493d7a74f1df0640f2cc5/ipywidgets-8.1.5.tar.gz", hash = "sha256:870e43b1a35656a80c18c9503bbf2d16802db1cb487eec6fab27d683381dde17", size = 116723 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/2d/9c0b76f2f9cc0ebede1b9371b6f317243028ed60b90705863d493bae622e/ipywidgets-8.1.5-py3-none-any.whl", hash = "sha256:3290f526f87ae6e77655555baba4f36681c555b8bdbbff430b70e52c34c86245", size = 139767 }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808 }, ] [[package]] @@ -1579,14 +1795,42 @@ wheels = [ [[package]] name = "jinja2" -version = "3.1.5" +version = "3.1.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/af/92/b3130cbbf5591acf9ade8708c365f3238046ac7cb8ccba6e81abccb0ccff/jinja2-3.1.5.tar.gz", hash = "sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb", size = 244674 } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "jiter" +version = "0.12.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/0f/2ba5fbcd631e3e88689309dbe978c5769e883e4b84ebfe7da30b43275c5a/jinja2-3.1.5-py3-none-any.whl", hash = "sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb", size = 134596 }, + { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652 }, + { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829 }, + { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568 }, + { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052 }, + { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585 }, + { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541 }, + { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423 }, + { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958 }, + { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084 }, + { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054 }, + { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368 }, + { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847 }, + { url = "https://files.pythonhosted.org/packages/fe/54/5339ef1ecaa881c6948669956567a64d2670941925f245c434f494ffb0e5/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8", size = 311144 }, + { url = "https://files.pythonhosted.org/packages/27/74/3446c652bffbd5e81ab354e388b1b5fc1d20daac34ee0ed11ff096b1b01a/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3", size = 305877 }, + { url = "https://files.pythonhosted.org/packages/a1/f4/ed76ef9043450f57aac2d4fbeb27175aa0eb9c38f833be6ef6379b3b9a86/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e", size = 340419 }, + { url = "https://files.pythonhosted.org/packages/21/01/857d4608f5edb0664aa791a3d45702e1a5bcfff9934da74035e7b9803846/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d", size = 347212 }, + { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974 }, + { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233 }, + { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537 }, + { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110 }, ] [[package]] @@ -1641,11 +1885,20 @@ wheels = [ [[package]] name = "joblib" -version = "1.4.2" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396 }, +] + +[[package]] +name = "json-repair" +version = "0.54.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/64/33/60135848598c076ce4b231e1b1895170f45fbcaeaa2c9d5e38b04db70c35/joblib-1.4.2.tar.gz", hash = "sha256:2382c5816b2636fbd20a09e0f4e9dad4736765fdfb7dca582943b9c1366b3f0e", size = 2116621 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/05/9fbcd5ffab9c41455e7d80af65a90876718b8ea2fb4525e187ab11836dd4/json_repair-0.54.2.tar.gz", hash = "sha256:4b6b62ce17f1a505b220fa4aadba1fc37dc9c221544f158471efe3775620bad6", size = 38575 } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl", hash = "sha256:06d478d5674cbc267e7496a410ee875abd68e4340feff4490bcb7afb88060ae6", size = 301817 }, + { url = "https://files.pythonhosted.org/packages/53/3a/1b4df9adcd69fee9c9e4b439c13e8c866f2fae520054aede7030b2278be9/json_repair-0.54.2-py3-none-any.whl", hash = "sha256:be51cce5dca97e0c24ebdf61a1ede2449a8a7666012de99467bb7b0afb35179b", size = 29322 }, ] [[package]] @@ -1659,11 +1912,11 @@ wheels = [ [[package]] name = "json5" -version = "0.10.0" +version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/85/3d/bbe62f3d0c05a689c711cff57b2e3ac3d3e526380adb7c781989f075115c/json5-0.10.0.tar.gz", hash = "sha256:e66941c8f0a02026943c52c2eb34ebeb2a6f819a0be05920a6f5243cd30fd559", size = 48202 } +sdist = { url = "https://files.pythonhosted.org/packages/12/ae/929aee9619e9eba9015207a9d2c1c54db18311da7eb4dcf6d41ad6f0eb67/json5-0.12.1.tar.gz", hash = "sha256:b2743e77b3242f8d03c143dd975a6ec7c52e2f2afe76ed934e53503dd4ad4990", size = 52191 } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/42/797895b952b682c3dafe23b1834507ee7f02f4d6299b65aaa61425763278/json5-0.10.0-py3-none-any.whl", hash = "sha256:19b23410220a7271e8377f81ba8aacba2fdd56947fbb137ee5977cbe1f5e8dfa", size = 34049 }, + { url = "https://files.pythonhosted.org/packages/85/e2/05328bd2621be49a6fed9e3030b1e51a2d04537d3f816d211b9cc53c5262/json5-0.12.1-py3-none-any.whl", hash = "sha256:d9c9b3bc34a5f54d43c35e11ef7cb87d8bdd098c6ace87117a7b7e83e705c1d5", size = 36119 }, ] [[package]] @@ -1689,7 +1942,7 @@ wheels = [ [[package]] name = "jsonschema" -version = "4.23.0" +version = "4.25.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -1697,9 +1950,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/2e/03362ee4034a4c917f697890ccd4aec0800ccf9ded7f511971c75451deec/jsonschema-4.23.0.tar.gz", hash = "sha256:d71497fef26351a33265337fa77ffeb82423f3ea21283cd9467bb03999266bc4", size = 325778 } +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/4a/4f9dbeb84e8850557c02365a0eee0649abe5eb1d84af92a25731c6c0f922/jsonschema-4.23.0-py3-none-any.whl", hash = "sha256:fbadb6f8b144a8f8cf9f0b89ba94501d143e50411a1278633f56a7acf7fd5566", size = 88462 }, + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040 }, ] [package.optional-dependencies] @@ -1710,20 +1963,21 @@ format-nongpl = [ { name = "jsonpointer" }, { name = "rfc3339-validator" }, { name = "rfc3986-validator" }, + { name = "rfc3987-syntax" }, { name = "uri-template" }, { name = "webcolors" }, ] [[package]] name = "jsonschema-specifications" -version = "2024.10.1" +version = "2025.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/10/db/58f950c996c793472e336ff3655b13fbcf1e3b359dcf52dcf3ed3b52c352/jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272", size = 15561 } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437 }, ] [[package]] @@ -1780,24 +2034,24 @@ wheels = [ [[package]] name = "jupyter-core" -version = "5.7.2" +version = "5.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "platformdirs" }, - { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/11/b56381fa6c3f4cc5d2cf54a7dbf98ad9aa0b339ef7a601d6053538b079a7/jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9", size = 87629 } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c9/fb/108ecd1fe961941959ad0ee4e12ee7b8b1477247f30b1fdfd83ceaf017f0/jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409", size = 28965 }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, ] [[package]] name = "jupyter-events" -version = "0.11.0" +version = "0.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonschema", extra = ["format-nongpl"] }, + { name = "packaging" }, { name = "python-json-logger" }, { name = "pyyaml" }, { name = "referencing" }, @@ -1805,26 +2059,26 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/65/5791c8a979b5646ca29ea50e42b6708908b789f7ff389d1a03c1b93a1c54/jupyter_events-0.11.0.tar.gz", hash = "sha256:c0bc56a37aac29c1fbc3bcfbddb8c8c49533f9cf11f1c4e6adadba936574ab90", size = 62039 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/8c/9b65cb2cd4ea32d885993d5542244641590530836802a2e8c7449a4c61c9/jupyter_events-0.11.0-py3-none-any.whl", hash = "sha256:36399b41ce1ca45fe8b8271067d6a140ffa54cec4028e95491c93b78a855cacf", size = 19423 }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, ] [[package]] name = "jupyter-lsp" -version = "2.2.5" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/85/b4/3200b0b09c12bc3b72d943d923323c398eff382d1dcc7c0dbc8b74630e40/jupyter-lsp-2.2.5.tar.gz", hash = "sha256:793147a05ad446f809fd53ef1cd19a9f5256fd0a2d6b7ce943a982cb4f545001", size = 48741 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/e0/7bd7cff65594fd9936e2f9385701e44574fc7d721331ff676ce440b14100/jupyter_lsp-2.2.5-py3-none-any.whl", hash = "sha256:45fbddbd505f3fbfb0b6cb2f1bc5e15e83ab7c79cd6e89416b248cb3c00c11da", size = 69146 }, + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687 }, ] [[package]] name = "jupyter-server" -version = "2.15.0" +version = "2.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1847,9 +2101,9 @@ dependencies = [ { name = "traitlets" }, { name = "websocket-client" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/8c/df09d4ab646141f130f9977b32b206ba8615d1969b2eba6a2e84b7f89137/jupyter_server-2.15.0.tar.gz", hash = "sha256:9d446b8697b4f7337a1b7cdcac40778babdd93ba614b6d68ab1c0c918f1c4084", size = 725227 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/a2/89eeaf0bb954a123a909859fa507fa86f96eb61b62dc30667b60dbd5fdaf/jupyter_server-2.15.0-py3-none-any.whl", hash = "sha256:872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3", size = 385826 }, + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221 }, ] [[package]] @@ -1867,7 +2121,7 @@ wheels = [ [[package]] name = "jupyterlab" -version = "4.3.4" +version = "4.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-lru" }, @@ -1885,9 +2139,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/45/1052f842e066902b1d78126df7e2269b1b9408991e1344e167b2e429f9e1/jupyterlab-4.3.4.tar.gz", hash = "sha256:f0bb9b09a04766e3423cccc2fc23169aa2ffedcdf8713e9e0fb33cac0b6859d0", size = 21797583 } +sdist = { url = "https://files.pythonhosted.org/packages/df/e5/4fa382a796a6d8e2cd867816b64f1ff27f906e43a7a83ad9eb389e448cd8/jupyterlab-4.5.0.tar.gz", hash = "sha256:aec33d6d8f1225b495ee2cf20f0514f45e6df8e360bdd7ac9bace0b7ac5177ea", size = 23989880 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/48/af57263e53cfc220e522de047aa0993f53bab734fe812af1e03e33ac6d7c/jupyterlab-4.3.4-py3-none-any.whl", hash = "sha256:b754c2601c5be6adf87cb5a1d8495d653ffb945f021939f77776acaa94dae952", size = 11665373 }, + { url = "https://files.pythonhosted.org/packages/6c/1e/5a4d5498eba382fee667ed797cf64ae5d1b13b04356df62f067f48bb0f61/jupyterlab-4.5.0-py3-none-any.whl", hash = "sha256:88e157c75c1afff64c7dc4b801ec471450b922a4eae4305211ddd40da8201c8a", size = 12380641 }, ] [[package]] @@ -1901,7 +2155,7 @@ wheels = [ [[package]] name = "jupyterlab-server" -version = "2.27.3" +version = "2.28.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "babel" }, @@ -1912,18 +2166,18 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/c9/a883ce65eb27905ce77ace410d83587c82ea64dc85a48d1f7ed52bcfa68d/jupyterlab_server-2.27.3.tar.gz", hash = "sha256:eb36caca59e74471988f0ae25c77945610b887f777255aa21f8065def9e51ed4", size = 76173 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/09/2032e7d15c544a0e3cd831c51d77a8ca57f7555b2e1b2922142eddb02a84/jupyterlab_server-2.27.3-py3-none-any.whl", hash = "sha256:e697488f66c3db49df675158a77b3b017520d772c6e1548c7d9bcc5df7944ee4", size = 59700 }, + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830 }, ] [[package]] name = "jupyterlab-widgets" -version = "3.0.13" +version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/59/73/fa26bbb747a9ea4fca6b01453aa22990d52ab62dd61384f1ac0dc9d4e7ba/jupyterlab_widgets-3.0.13.tar.gz", hash = "sha256:a2966d385328c1942b683a8cd96b89b8dd82c8b8f81dda902bb2bc06d46f5bed", size = 203556 } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/93/858e87edc634d628e5d752ba944c2833133a28fa87bb093e6832ced36a3e/jupyterlab_widgets-3.0.13-py3-none-any.whl", hash = "sha256:e3cda2c233ce144192f1e29914ad522b2f4c40e77214b0cc97377ca3d323db54", size = 214392 }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, ] [[package]] @@ -1949,31 +2203,28 @@ wheels = [ [[package]] name = "kiwisolver" -version = "1.4.8" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/5f/4d8e9e852d98ecd26cdf8eaf7ed8bc33174033bba5e07001b289f07308fd/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db", size = 124623 }, - { url = "https://files.pythonhosted.org/packages/1d/70/7f5af2a18a76fe92ea14675f8bd88ce53ee79e37900fa5f1a1d8e0b42998/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b", size = 66720 }, - { url = "https://files.pythonhosted.org/packages/c6/13/e15f804a142353aefd089fadc8f1d985561a15358c97aca27b0979cb0785/kiwisolver-1.4.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce2cf1e5688edcb727fdf7cd1bbd0b6416758996826a8be1d958f91880d0809d", size = 65413 }, - { url = "https://files.pythonhosted.org/packages/ce/6d/67d36c4d2054e83fb875c6b59d0809d5c530de8148846b1370475eeeece9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c8bf637892dc6e6aad2bc6d4d69d08764166e5e3f69d469e55427b6ac001b19d", size = 1650826 }, - { url = "https://files.pythonhosted.org/packages/de/c6/7b9bb8044e150d4d1558423a1568e4f227193662a02231064e3824f37e0a/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:034d2c891f76bd3edbdb3ea11140d8510dca675443da7304205a2eaa45d8334c", size = 1628231 }, - { url = "https://files.pythonhosted.org/packages/b6/38/ad10d437563063eaaedbe2c3540a71101fc7fb07a7e71f855e93ea4de605/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47b28d1dfe0793d5e96bce90835e17edf9a499b53969b03c6c47ea5985844c3", size = 1408938 }, - { url = "https://files.pythonhosted.org/packages/52/ce/c0106b3bd7f9e665c5f5bc1e07cc95b5dabd4e08e3dad42dbe2faad467e7/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb158fe28ca0c29f2260cca8c43005329ad58452c36f0edf298204de32a9a3ed", size = 1422799 }, - { url = "https://files.pythonhosted.org/packages/d0/87/efb704b1d75dc9758087ba374c0f23d3254505edaedd09cf9d247f7878b9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5536185fce131780ebd809f8e623bf4030ce1b161353166c49a3c74c287897f", size = 1354362 }, - { url = "https://files.pythonhosted.org/packages/eb/b3/fd760dc214ec9a8f208b99e42e8f0130ff4b384eca8b29dd0efc62052176/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:369b75d40abedc1da2c1f4de13f3482cb99e3237b38726710f4a793432b1c5ff", size = 2222695 }, - { url = "https://files.pythonhosted.org/packages/a2/09/a27fb36cca3fc01700687cc45dae7a6a5f8eeb5f657b9f710f788748e10d/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:641f2ddf9358c80faa22e22eb4c9f54bd3f0e442e038728f500e3b978d00aa7d", size = 2370802 }, - { url = "https://files.pythonhosted.org/packages/3d/c3/ba0a0346db35fe4dc1f2f2cf8b99362fbb922d7562e5f911f7ce7a7b60fa/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d561d2d8883e0819445cfe58d7ddd673e4015c3c57261d7bdcd3710d0d14005c", size = 2334646 }, - { url = "https://files.pythonhosted.org/packages/41/52/942cf69e562f5ed253ac67d5c92a693745f0bed3c81f49fc0cbebe4d6b00/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1732e065704b47c9afca7ffa272f845300a4eb959276bf6970dc07265e73b605", size = 2467260 }, - { url = "https://files.pythonhosted.org/packages/32/26/2d9668f30d8a494b0411d4d7d4ea1345ba12deb6a75274d58dd6ea01e951/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bcb1ebc3547619c3b58a39e2448af089ea2ef44b37988caf432447374941574e", size = 2288633 }, - { url = "https://files.pythonhosted.org/packages/98/99/0dd05071654aa44fe5d5e350729961e7bb535372935a45ac89a8924316e6/kiwisolver-1.4.8-cp310-cp310-win_amd64.whl", hash = "sha256:89c107041f7b27844179ea9c85d6da275aa55ecf28413e87624d033cf1f6b751", size = 71885 }, - { url = "https://files.pythonhosted.org/packages/6c/fc/822e532262a97442989335394d441cd1d0448c2e46d26d3e04efca84df22/kiwisolver-1.4.8-cp310-cp310-win_arm64.whl", hash = "sha256:b5773efa2be9eb9fcf5415ea3ab70fc785d598729fd6057bea38d539ead28271", size = 65175 }, - { url = "https://files.pythonhosted.org/packages/1f/f9/ae81c47a43e33b93b0a9819cac6723257f5da2a5a60daf46aa5c7226ea85/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e7a019419b7b510f0f7c9dceff8c5eae2392037eae483a7f9162625233802b0a", size = 60403 }, - { url = "https://files.pythonhosted.org/packages/58/ca/f92b5cb6f4ce0c1ebfcfe3e2e42b96917e16f7090e45b21102941924f18f/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:286b18e86682fd2217a48fc6be6b0f20c1d0ed10958d8dc53453ad58d7be0bf8", size = 58657 }, - { url = "https://files.pythonhosted.org/packages/80/28/ae0240f732f0484d3a4dc885d055653c47144bdf59b670aae0ec3c65a7c8/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4191ee8dfd0be1c3666ccbac178c5a05d5f8d689bbe3fc92f3c4abec817f8fe0", size = 84948 }, - { url = "https://files.pythonhosted.org/packages/5d/eb/78d50346c51db22c7203c1611f9b513075f35c4e0e4877c5dde378d66043/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd2785b9391f2873ad46088ed7599a6a71e762e1ea33e87514b1a441ed1da1c", size = 81186 }, - { url = "https://files.pythonhosted.org/packages/43/f8/7259f18c77adca88d5f64f9a522792e178b2691f3748817a8750c2d216ef/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07b29089b7ba090b6f1a669f1411f27221c3662b3a1b7010e67b59bb5a6f10b", size = 80279 }, - { url = "https://files.pythonhosted.org/packages/3a/1d/50ad811d1c5dae091e4cf046beba925bcae0a610e79ae4c538f996f63ed5/kiwisolver-1.4.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:65ea09a5a3faadd59c2ce96dc7bf0f364986a315949dc6374f04396b0d60e09b", size = 71762 }, +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159 }, + { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578 }, + { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312 }, + { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458 }, + { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640 }, + { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074 }, + { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036 }, + { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310 }, + { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943 }, + { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488 }, + { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787 }, + { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730 }, + { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036 }, + { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183 }, + { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675 }, + { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277 }, + { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994 }, + { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744 }, ] [[package]] @@ -2017,6 +2268,15 @@ openai = [ { name = "openai" }, ] +[[package]] +name = "lark" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, +] + [[package]] name = "libclang" version = "18.1.1" @@ -2048,12 +2308,13 @@ wheels = [ [[package]] name = "litellm" -version = "1.80.5" +version = "1.80.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "click" }, { name = "fastuuid" }, + { name = "grpcio" }, { name = "httpx" }, { name = "importlib-metadata" }, { name = "jinja2" }, @@ -2064,40 +2325,47 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/85/b8/357544534bef87dd2858432f3cbd3a0e5cc267caebca5ea86b03618786c5/litellm-1.80.5.tar.gz", hash = "sha256:922791c264845d9ed59e540c8fa74a74d237c1b209568a05ffeacd8b51770deb", size = 11885764 } +sdist = { url = "https://files.pythonhosted.org/packages/a5/3f/af532014449c3931ae6cad2d97d267dd43d0de006060a8cbf0962e004024/litellm-1.80.7.tar.gz", hash = "sha256:3977a8d195aef842d01c18bf9e22984829363c6a4b54daf9a43c9dd9f190b42c", size = 12023127 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/af/1d4693746ff9fbbe27a6e7d6394b801acf234e00c83f45ad1cb5bf2eaa6c/litellm-1.80.5-py3-none-any.whl", hash = "sha256:2ac5f4e88cd57ae056e00da8f872e1c2956653750929fba2fd9b007b400fdb77", size = 10671970 }, + { url = "https://files.pythonhosted.org/packages/54/e0/2e60a0c09235fd7b55297390c557923f3c35a9cf001914222c26a7857d2b/litellm-1.80.7-py3-none-any.whl", hash = "sha256:f7d993f78c1e0e4e1202b2a925cc6540b55b6e5fb055dd342d88b145ab3102ed", size = 10848321 }, ] [[package]] name = "lxml" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/6b/20c3a4b24751377aaa6307eb230b66701024012c29dd374999cc92983269/lxml-5.3.0.tar.gz", hash = "sha256:4e109ca30d1edec1ac60cdbe341905dc3b8f55b16855e03a54aaf59e51ec8c6f", size = 3679318 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ce/2789e39eddf2b13fac29878bfa465f0910eb6b0096e29090e5176bc8cf43/lxml-5.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dd36439be765e2dde7660212b5275641edbc813e7b24668831a5c8ac91180656", size = 8124570 }, - { url = "https://files.pythonhosted.org/packages/24/a8/f4010166a25d41715527129af2675981a50d3bbf7df09c5d9ab8ca24fbf9/lxml-5.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ae5fe5c4b525aa82b8076c1a59d642c17b6e8739ecf852522c6321852178119d", size = 4413042 }, - { url = "https://files.pythonhosted.org/packages/41/a4/7e45756cecdd7577ddf67a68b69c1db0f5ddbf0c9f65021ee769165ffc5a/lxml-5.3.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:501d0d7e26b4d261fca8132854d845e4988097611ba2531408ec91cf3fd9d20a", size = 5139213 }, - { url = "https://files.pythonhosted.org/packages/02/e2/ecf845b12323c92748077e1818b64e8b4dba509a4cb12920b3762ebe7552/lxml-5.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66442c2546446944437df74379e9cf9e9db353e61301d1a0e26482f43f0dd8", size = 4838814 }, - { url = "https://files.pythonhosted.org/packages/12/91/619f9fb72cf75e9ceb8700706f7276f23995f6ad757e6d400fbe35ca4990/lxml-5.3.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9e41506fec7a7f9405b14aa2d5c8abbb4dbbd09d88f9496958b6d00cb4d45330", size = 5425084 }, - { url = "https://files.pythonhosted.org/packages/25/3b/162a85a8f0fd2a3032ec3f936636911c6e9523a8e263fffcfd581ce98b54/lxml-5.3.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f7d4a670107d75dfe5ad080bed6c341d18c4442f9378c9f58e5851e86eb79965", size = 4875993 }, - { url = "https://files.pythonhosted.org/packages/43/af/dd3f58cc7d946da6ae42909629a2b1d5dd2d1b583334d4af9396697d6863/lxml-5.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41ce1f1e2c7755abfc7e759dc34d7d05fd221723ff822947132dc934d122fe22", size = 5012462 }, - { url = "https://files.pythonhosted.org/packages/69/c1/5ea46b2d4c98f5bf5c83fffab8a0ad293c9bc74df9ecfbafef10f77f7201/lxml-5.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:44264ecae91b30e5633013fb66f6ddd05c006d3e0e884f75ce0b4755b3e3847b", size = 4815288 }, - { url = "https://files.pythonhosted.org/packages/1d/51/a0acca077ad35da458f4d3f729ef98effd2b90f003440d35fc36323f8ae6/lxml-5.3.0-cp310-cp310-manylinux_2_28_ppc64le.whl", hash = "sha256:3c174dc350d3ec52deb77f2faf05c439331d6ed5e702fc247ccb4e6b62d884b7", size = 5472435 }, - { url = "https://files.pythonhosted.org/packages/4d/6b/0989c9368986961a6b0f55b46c80404c4b758417acdb6d87bfc3bd5f4967/lxml-5.3.0-cp310-cp310-manylinux_2_28_s390x.whl", hash = "sha256:2dfab5fa6a28a0b60a20638dc48e6343c02ea9933e3279ccb132f555a62323d8", size = 4976354 }, - { url = "https://files.pythonhosted.org/packages/05/9e/87492d03ff604fbf656ed2bf3e2e8d28f5d58ea1f00ff27ac27b06509079/lxml-5.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b1c8c20847b9f34e98080da785bb2336ea982e7f913eed5809e5a3c872900f32", size = 5029973 }, - { url = "https://files.pythonhosted.org/packages/f9/cc/9ae1baf5472af88e19e2c454b3710c1be9ecafb20eb474eeabcd88a055d2/lxml-5.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c86bf781b12ba417f64f3422cfc302523ac9cd1d8ae8c0f92a1c66e56ef2e86", size = 4888837 }, - { url = "https://files.pythonhosted.org/packages/d2/10/5594ffaec8c120d75b17e3ad23439b740a51549a9b5fd7484b2179adfe8f/lxml-5.3.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:c162b216070f280fa7da844531169be0baf9ccb17263cf5a8bf876fcd3117fa5", size = 5530555 }, - { url = "https://files.pythonhosted.org/packages/ea/9b/de17f05377c8833343b629905571fb06cff2028f15a6f58ae2267662e341/lxml-5.3.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:36aef61a1678cb778097b4a6eeae96a69875d51d1e8f4d4b491ab3cfb54b5a03", size = 5405314 }, - { url = "https://files.pythonhosted.org/packages/8a/b4/227be0f1f3cca8255925985164c3838b8b36e441ff0cc10c1d3c6bdba031/lxml-5.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f65e5120863c2b266dbcc927b306c5b78e502c71edf3295dfcb9501ec96e5fc7", size = 5079303 }, - { url = "https://files.pythonhosted.org/packages/5c/ee/19abcebb7fc40319bb71cd6adefa1ad94d09b5660228715854d6cc420713/lxml-5.3.0-cp310-cp310-win32.whl", hash = "sha256:ef0c1fe22171dd7c7c27147f2e9c3e86f8bdf473fed75f16b0c2e84a5030ce80", size = 3475126 }, - { url = "https://files.pythonhosted.org/packages/a1/35/183d32551447e280032b2331738cd850da435a42f850b71ebeaab42c1313/lxml-5.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:052d99051e77a4f3e8482c65014cf6372e61b0a6f4fe9edb98503bb5364cfee3", size = 3805065 }, - { url = "https://files.pythonhosted.org/packages/99/f7/b73a431c8500565aa500e99e60b448d305eaf7c0b4c893c7c5a8a69cc595/lxml-5.3.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7b1cd427cb0d5f7393c31b7496419da594fe600e6fdc4b105a54f82405e6626c", size = 3925431 }, - { url = "https://files.pythonhosted.org/packages/db/48/4a206623c0d093d0e3b15f415ffb4345b0bdf661a3d0b15a112948c033c7/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51806cfe0279e06ed8500ce19479d757db42a30fd509940b1701be9c86a5ff9a", size = 4216683 }, - { url = "https://files.pythonhosted.org/packages/54/47/577820c45dd954523ae8453b632d91e76da94ca6d9ee40d8c98dd86f916b/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee70d08fd60c9565ba8190f41a46a54096afa0eeb8f76bd66f2c25d3b1b83005", size = 4326732 }, - { url = "https://files.pythonhosted.org/packages/68/de/96cb6d3269bc994b4f5ede8ca7bf0840f5de0a278bc6e50cb317ff71cafa/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8dc2c0395bea8254d8daebc76dcf8eb3a95ec2a46fa6fae5eaccee366bfe02ce", size = 4218377 }, - { url = "https://files.pythonhosted.org/packages/a5/43/19b1ef6cbffa4244a217f95cc5f41a6cb4720fed33510a49670b03c5f1a0/lxml-5.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6ba0d3dcac281aad8a0e5b14c7ed6f9fa89c8612b47939fc94f80b16e2e9bc83", size = 4351237 }, - { url = "https://files.pythonhosted.org/packages/ba/b2/6a22fb5c0885da3b00e116aee81f0b829ec9ac8f736cd414b4a09413fc7d/lxml-5.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:6e91cf736959057f7aac7adfc83481e03615a8e8dd5758aa1d95ea69e8931dba", size = 3487557 }, +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589 }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671 }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961 }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087 }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620 }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664 }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397 }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178 }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148 }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035 }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111 }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662 }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973 }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953 }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695 }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051 }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264 }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435 }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913 }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357 }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295 }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913 }, +] + +[[package]] +name = "magicattr" +version = "0.1.6" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/7e/76b7e0c391bee7e9273725c29c8fe41c4df62a215ce58aa8e3518baee0bb/magicattr-0.1.6-py2.py3-none-any.whl", hash = "sha256:d96b18ee45b5ee83b09c17e15d3459a64de62d538808c2f71182777dd9dbbbdf", size = 4664 }, ] [[package]] @@ -2110,58 +2378,59 @@ wheels = [ [[package]] name = "mako" -version = "1.3.8" +version = "1.3.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5f/d9/8518279534ed7dace1795d5a47e49d5299dd0994eed1053996402a8902f9/mako-1.3.8.tar.gz", hash = "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8", size = 392069 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/bf/7a6a36ce2e4cafdfb202752be68850e22607fccd692847c45c1ae3c17ba6/Mako-1.3.8-py3-none-any.whl", hash = "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627", size = 78569 }, + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509 }, ] [[package]] name = "markdown" -version = "3.7" +version = "3.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/28/3af612670f82f4c056911fbbbb42760255801b3068c48de792d354ff4472/markdown-3.7.tar.gz", hash = "sha256:2ae2471477cfd02dbbf038d5d9bc226d40def84b4fe2986e49b59b6b472bbed2", size = 357086 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/08/83871f3c50fc983b88547c196d11cf8c3340e37c32d2e9d6152abe2c61f7/Markdown-3.7-py3-none-any.whl", hash = "sha256:7eb6df5690b81a1d7942992c97fad2938e956e79df20cbc6186e9c3a77b1c803", size = 106349 }, + { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678 }, ] [[package]] name = "markdown-it-py" -version = "3.0.0" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070 } wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321 }, ] [[package]] name = "markupsafe" -version = "3.0.2" +version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 }, + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631 }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057 }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050 }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681 }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705 }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524 }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282 }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745 }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571 }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056 }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932 }, ] [[package]] name = "matplotlib" -version = "3.10.0" +version = "3.10.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy" }, @@ -2174,29 +2443,29 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/dd/fa2e1a45fce2d09f4aea3cee169760e672c8262325aa5796c49d543dc7e6/matplotlib-3.10.0.tar.gz", hash = "sha256:b886d02a581b96704c9d1ffe55709e49b4d2d52709ccebc4be42db856e511278", size = 36686418 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/e2/d2d5295be2f44c678ebaf3544ba32d20c1f9ef08c49fe47f496180e1db15/matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7", size = 34804865 } wheels = [ - { url = "https://files.pythonhosted.org/packages/09/ec/3cdff7b5239adaaacefcc4f77c316dfbbdf853c4ed2beec467e0fec31b9f/matplotlib-3.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2c5829a5a1dd5a71f0e31e6e8bb449bc0ee9dbfb05ad28fc0c6b55101b3a4be6", size = 8160551 }, - { url = "https://files.pythonhosted.org/packages/41/f2/b518f2c7f29895c9b167bf79f8529c63383ae94eaf49a247a4528e9a148d/matplotlib-3.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2a43cbefe22d653ab34bb55d42384ed30f611bcbdea1f8d7f431011a2e1c62e", size = 8034853 }, - { url = "https://files.pythonhosted.org/packages/ed/8d/45754b4affdb8f0d1a44e4e2bcd932cdf35b256b60d5eda9f455bb293ed0/matplotlib-3.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:607b16c8a73943df110f99ee2e940b8a1cbf9714b65307c040d422558397dac5", size = 8446724 }, - { url = "https://files.pythonhosted.org/packages/09/5a/a113495110ae3e3395c72d82d7bc4802902e46dc797f6b041e572f195c56/matplotlib-3.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01d2b19f13aeec2e759414d3bfe19ddfb16b13a1250add08d46d5ff6f9be83c6", size = 8583905 }, - { url = "https://files.pythonhosted.org/packages/12/b1/8b1655b4c9ed4600c817c419f7eaaf70082630efd7556a5b2e77a8a3cdaf/matplotlib-3.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e6c6461e1fc63df30bf6f80f0b93f5b6784299f721bc28530477acd51bfc3d1", size = 9395223 }, - { url = "https://files.pythonhosted.org/packages/5a/85/b9a54d64585a6b8737a78a61897450403c30f39e0bd3214270bb0b96f002/matplotlib-3.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:994c07b9d9fe8d25951e3202a68c17900679274dadfc1248738dcfa1bd40d7f3", size = 8025355 }, - { url = "https://files.pythonhosted.org/packages/32/5f/29def7ce4e815ab939b56280976ee35afffb3bbdb43f332caee74cb8c951/matplotlib-3.10.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:81713dd0d103b379de4516b861d964b1d789a144103277769238c732229d7f03", size = 8155500 }, - { url = "https://files.pythonhosted.org/packages/de/6d/d570383c9f7ca799d0a54161446f9ce7b17d6c50f2994b653514bcaa108f/matplotlib-3.10.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:359f87baedb1f836ce307f0e850d12bb5f1936f70d035561f90d41d305fdacea", size = 8032398 }, - { url = "https://files.pythonhosted.org/packages/c9/b4/680aa700d99b48e8c4393fa08e9ab8c49c0555ee6f4c9c0a5e8ea8dfde5d/matplotlib-3.10.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae80dc3a4add4665cf2faa90138384a7ffe2a4e37c58d83e115b54287c4f06ef", size = 8587361 }, + { url = "https://files.pythonhosted.org/packages/6c/87/3932d5778ab4c025db22710b61f49ccaed3956c5cf46ffb2ffa7492b06d9/matplotlib-3.10.7-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ac81eee3b7c266dd92cee1cd658407b16c57eed08c7421fa354ed68234de380", size = 8247141 }, + { url = "https://files.pythonhosted.org/packages/45/a8/bfed45339160102bce21a44e38a358a1134a5f84c26166de03fb4a53208f/matplotlib-3.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:667ecd5d8d37813a845053d8f5bf110b534c3c9f30e69ebd25d4701385935a6d", size = 8107995 }, + { url = "https://files.pythonhosted.org/packages/e2/3c/5692a2d9a5ba848fda3f48d2b607037df96460b941a59ef236404b39776b/matplotlib-3.10.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc1c51b846aca49a5a8b44fbba6a92d583a35c64590ad9e1e950dc88940a4297", size = 8680503 }, + { url = "https://files.pythonhosted.org/packages/ab/a0/86ace53c48b05d0e6e9c127b2ace097434901f3e7b93f050791c8243201a/matplotlib-3.10.7-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a11c2e9e72e7de09b7b72e62f3df23317c888299c875e2b778abf1eda8c0a42", size = 9514982 }, + { url = "https://files.pythonhosted.org/packages/a6/81/ead71e2824da8f72640a64166d10e62300df4ae4db01a0bac56c5b39fa51/matplotlib-3.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f19410b486fdd139885ace124e57f938c1e6a3210ea13dd29cab58f5d4bc12c7", size = 9566429 }, + { url = "https://files.pythonhosted.org/packages/65/7d/954b3067120456f472cce8fdcacaf4a5fcd522478db0c37bb243c7cb59dd/matplotlib-3.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:b498e9e4022f93de2d5a37615200ca01297ceebbb56fe4c833f46862a490f9e3", size = 8108174 }, + { url = "https://files.pythonhosted.org/packages/1e/6c/a9bcf03e9afb2a873e0a5855f79bce476d1023f26f8212969f2b7504756c/matplotlib-3.10.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5c09cf8f2793f81368f49f118b6f9f937456362bee282eac575cca7f84cda537", size = 8241204 }, + { url = "https://files.pythonhosted.org/packages/5b/fd/0e6f5aa762ed689d9fa8750b08f1932628ffa7ed30e76423c399d19407d2/matplotlib-3.10.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:de66744b2bb88d5cd27e80dfc2ec9f0517d0a46d204ff98fe9e5f2864eb67657", size = 8104607 }, + { url = "https://files.pythonhosted.org/packages/b9/a9/21c9439d698fac5f0de8fc68b2405b738ed1f00e1279c76f2d9aa5521ead/matplotlib-3.10.7-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53cc80662dd197ece414dd5b66e07370201515a3eaf52e7c518c68c16814773b", size = 8682257 }, ] [[package]] name = "matplotlib-inline" -version = "0.1.7" +version = "0.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516 }, ] [[package]] @@ -2210,14 +2479,27 @@ wheels = [ [[package]] name = "mistune" -version = "3.1.0" +version = "3.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/79/6e/96fc7cb3288666c5de2c396eb0e338dc95f7a8e4920e43e38783a22d0084/mistune-3.1.0.tar.gz", hash = "sha256:dbcac2f78292b9dc066cd03b7a3a26b62d85f8159f2ea5fd28e55df79908d667", size = 94401 } +sdist = { url = "https://files.pythonhosted.org/packages/d7/02/a7fb8b21d4d55ac93cdcde9d3638da5dd0ebdd3a4fed76c7725e10b81cbe/mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164", size = 94588 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/f0/8282d9641415e9e33df173516226b404d367a0fc55e1a60424a152913abc/mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d", size = 53481 }, +] + +[[package]] +name = "ml-collections" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "absl-py" }, + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/b3/743ffc3f59da380da504d84ccd1faf9a857a1445991ff19bf2ec754163c2/mistune-3.1.0-py3-none-any.whl", hash = "sha256:b05198cf6d671b3deba6c87ec6cf0d4eb7b72c524636eddb6dbf13823b52cee1", size = 53694 }, + { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, ] [[package]] @@ -2235,24 +2517,24 @@ wheels = [ [[package]] name = "more-itertools" -version = "10.5.0" +version = "10.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/78/65922308c4248e0eb08ebcbe67c95d48615cc6f27854b6f2e57143e9178f/more-itertools-10.5.0.tar.gz", hash = "sha256:5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6", size = 121020 } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl", hash = "sha256:037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef", size = 60952 }, + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 }, ] [[package]] name = "mpld3" -version = "0.5.10" +version = "0.5.12" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jinja2" }, { name = "matplotlib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/58/19378f4189a034eb3efc17b133426b8551af1d3b2c70d641a63124579629/mpld3-0.5.10.tar.gz", hash = "sha256:a478eb404fa5212505c59133cf272cd9a94105872e605597720e7f84de38fbc7", size = 1027709 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433 } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/6a/e3691bcc47485f38b09853207c928130571821d187cf174eed5418d45e82/mpld3-0.5.10-py3-none-any.whl", hash = "sha256:80877acce87ea447380fad7374668737505c8c0684aab05238e7c5dc1fab38c1", size = 202561 }, + { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, ] [[package]] @@ -2266,45 +2548,58 @@ wheels = [ [[package]] name = "multidict" -version = "6.1.0" +version = "6.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/68/259dee7fd14cf56a17c554125e534f6274c2860159692a414d0b402b9a6d/multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60", size = 48628 }, - { url = "https://files.pythonhosted.org/packages/50/79/53ba256069fe5386a4a9e80d4e12857ced9de295baf3e20c68cdda746e04/multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1", size = 29327 }, - { url = "https://files.pythonhosted.org/packages/ff/10/71f1379b05b196dae749b5ac062e87273e3f11634f447ebac12a571d90ae/multidict-6.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a114d03b938376557927ab23f1e950827c3b893ccb94b62fd95d430fd0e5cf53", size = 29689 }, - { url = "https://files.pythonhosted.org/packages/71/45/70bac4f87438ded36ad4793793c0095de6572d433d98575a5752629ef549/multidict-6.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1c416351ee6271b2f49b56ad7f308072f6f44b37118d69c2cad94f3fa8a40d5", size = 126639 }, - { url = "https://files.pythonhosted.org/packages/80/cf/17f35b3b9509b4959303c05379c4bfb0d7dd05c3306039fc79cf035bbac0/multidict-6.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b5d83030255983181005e6cfbac1617ce9746b219bc2aad52201ad121226581", size = 134315 }, - { url = "https://files.pythonhosted.org/packages/ef/1f/652d70ab5effb33c031510a3503d4d6efc5ec93153562f1ee0acdc895a57/multidict-6.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3e97b5e938051226dc025ec80980c285b053ffb1e25a3db2a3aa3bc046bf7f56", size = 129471 }, - { url = "https://files.pythonhosted.org/packages/a6/64/2dd6c4c681688c0165dea3975a6a4eab4944ea30f35000f8b8af1df3148c/multidict-6.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d618649d4e70ac6efcbba75be98b26ef5078faad23592f9b51ca492953012429", size = 124585 }, - { url = "https://files.pythonhosted.org/packages/87/56/e6ee5459894c7e554b57ba88f7257dc3c3d2d379cb15baaa1e265b8c6165/multidict-6.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10524ebd769727ac77ef2278390fb0068d83f3acb7773792a5080f2b0abf7748", size = 116957 }, - { url = "https://files.pythonhosted.org/packages/36/9e/616ce5e8d375c24b84f14fc263c7ef1d8d5e8ef529dbc0f1df8ce71bb5b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ff3827aef427c89a25cc96ded1759271a93603aba9fb977a6d264648ebf989db", size = 128609 }, - { url = "https://files.pythonhosted.org/packages/8c/4f/4783e48a38495d000f2124020dc96bacc806a4340345211b1ab6175a6cb4/multidict-6.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:06809f4f0f7ab7ea2cabf9caca7d79c22c0758b58a71f9d32943ae13c7ace056", size = 123016 }, - { url = "https://files.pythonhosted.org/packages/3e/b3/4950551ab8fc39862ba5e9907dc821f896aa829b4524b4deefd3e12945ab/multidict-6.1.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f179dee3b863ab1c59580ff60f9d99f632f34ccb38bf67a33ec6b3ecadd0fd76", size = 133542 }, - { url = "https://files.pythonhosted.org/packages/96/4d/f0ce6ac9914168a2a71df117935bb1f1781916acdecbb43285e225b484b8/multidict-6.1.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:aaed8b0562be4a0876ee3b6946f6869b7bcdb571a5d1496683505944e268b160", size = 130163 }, - { url = "https://files.pythonhosted.org/packages/be/72/17c9f67e7542a49dd252c5ae50248607dfb780bcc03035907dafefb067e3/multidict-6.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c8b88a2ccf5493b6c8da9076fb151ba106960a2df90c2633f342f120751a9e7", size = 126832 }, - { url = "https://files.pythonhosted.org/packages/71/9f/72d719e248cbd755c8736c6d14780533a1606ffb3fbb0fbd77da9f0372da/multidict-6.1.0-cp310-cp310-win32.whl", hash = "sha256:4a9cb68166a34117d6646c0023c7b759bf197bee5ad4272f420a0141d7eb03a0", size = 26402 }, - { url = "https://files.pythonhosted.org/packages/04/5a/d88cd5d00a184e1ddffc82aa2e6e915164a6d2641ed3606e766b5d2f275a/multidict-6.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:20b9b5fbe0b88d0bdef2012ef7dee867f874b72528cf1d08f1d59b0e3850129d", size = 28800 }, - { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153 }, + { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993 }, + { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607 }, + { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847 }, + { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616 }, + { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333 }, + { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239 }, + { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618 }, + { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655 }, + { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245 }, + { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523 }, + { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129 }, + { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999 }, + { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711 }, + { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504 }, + { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422 }, + { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050 }, + { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153 }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317 }, ] [[package]] name = "multiprocess" -version = "0.70.16" +version = "0.70.18" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/ae/04f39c5d0d0def03247c2893d6f2b83c136bf3320a2154d7b8858f2ba72d/multiprocess-0.70.16.tar.gz", hash = "sha256:161af703d4652a0e1410be6abccecde4a7ddffd19341be0a7011b94aeb171ac1", size = 1772603 } +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083 }, + { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128 }, + { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132 }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948 }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636 }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478 }, +] + +[[package]] +name = "narwhals" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/89/ea/f82ef99ced4d03c33bb314c9b84a08a0a86c448aaa11ffd6256b99538aa5/narwhals-2.13.0.tar.gz", hash = "sha256:ee94c97f4cf7cfeebbeca8d274784df8b3d7fd3f955ce418af998d405576fdd9", size = 594555 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/76/6e712a2623d146d314f17598df5de7224c85c0060ef63fd95cc15a25b3fa/multiprocess-0.70.16-pp310-pypy310_pp73-macosx_10_13_x86_64.whl", hash = "sha256:476887be10e2f59ff183c006af746cb6f1fd0eadcfd4ef49e605cbe2659920ee", size = 134980 }, - { url = "https://files.pythonhosted.org/packages/0f/ab/1e6e8009e380e22254ff539ebe117861e5bdb3bff1fc977920972237c6c7/multiprocess-0.70.16-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d951bed82c8f73929ac82c61f01a7b5ce8f3e5ef40f5b52553b4f547ce2b08ec", size = 134982 }, - { url = "https://files.pythonhosted.org/packages/bc/f7/7ec7fddc92e50714ea3745631f79bd9c96424cb2702632521028e57d3a36/multiprocess-0.70.16-py310-none-any.whl", hash = "sha256:c4a9944c67bd49f823687463660a2d6daae94c289adff97e0f9d696ba6371d02", size = 134824 }, - { url = "https://files.pythonhosted.org/packages/ea/89/38df130f2c799090c978b366cfdf5b96d08de5b29a4a293df7f7429fa50b/multiprocess-0.70.16-py38-none-any.whl", hash = "sha256:a71d82033454891091a226dfc319d0cfa8019a4e888ef9ca910372a446de4435", size = 132628 }, - { url = "https://files.pythonhosted.org/packages/da/d9/f7f9379981e39b8c2511c9e0326d212accacb82f12fbfdc1aa2ce2a7b2b6/multiprocess-0.70.16-py39-none-any.whl", hash = "sha256:a0bafd3ae1b732eac64be2e72038231c1ba97724b60b09400d68f229fcc2fbf3", size = 133351 }, + { url = "https://files.pythonhosted.org/packages/87/0d/1861d1599571974b15b025e12b142d8e6b42ad66c8a07a89cb0fc21f1e03/narwhals-2.13.0-py3-none-any.whl", hash = "sha256:9b795523c179ca78204e3be53726da374168f906e38de2ff174c2363baaaf481", size = 426407 }, ] [[package]] @@ -2324,7 +2619,7 @@ wheels = [ [[package]] name = "nbconvert" -version = "7.16.5" +version = "7.16.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -2342,9 +2637,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/46/2c/d026c0367f2be2463d4c2f5b538e28add2bc67bc13730abb7f364ae4eb8b/nbconvert-7.16.5.tar.gz", hash = "sha256:c83467bb5777fdfaac5ebbb8e864f300b277f68692ecc04d6dab72f2d8442344", size = 856367 } +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/9e/2dcc9fe00cf55d95a8deae69384e9cea61816126e345754f6c75494d32ec/nbconvert-7.16.5-py3-none-any.whl", hash = "sha256:e12eac052d6fd03040af4166c563d76e7aeead2e9aadf5356db552a1784bd547", size = 258061 }, + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525 }, ] [[package]] @@ -2364,14 +2659,14 @@ wheels = [ [[package]] name = "nbstripout" -version = "0.8.0" +version = "0.8.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nbformat" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d0/34/e0a9ae627f02d40861656be351da44647406d7f0ce5cbc09e85abba52935/nbstripout-0.8.0.tar.gz", hash = "sha256:4b9b563c3704f9b59067627bec7d0d5c7437527ab6c3a72dd3cf895d46bf5a44", size = 26018 } +sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/f2/7aca174fb55ea04eb5918da199ffb6aa03258ee23e169d10a4d2a8cd4838/nbstripout-0.8.0-py2.py3-none-any.whl", hash = "sha256:b37f7b297fc6c02647d387d1049e4be8d0ecbf74640e502dce36ae93120ad420", size = 16237 }, + { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122 }, ] [[package]] @@ -2403,7 +2698,7 @@ wheels = [ [[package]] name = "notebook" -version = "7.3.2" +version = "7.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, @@ -2412,9 +2707,9 @@ dependencies = [ { name = "notebook-shim" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ea/04/ac488379d5afef43402b3fb4be2857db1a09804fecf98b9b714c741b225b/notebook-7.3.2.tar.gz", hash = "sha256:705e83a1785f45b383bf3ee13cb76680b92d24f56fb0c7d2136fe1d850cd3ca8", size = 12781804 } +sdist = { url = "https://files.pythonhosted.org/packages/89/ac/a97041621250a4fc5af379fb377942841eea2ca146aab166b8fcdfba96c2/notebook-7.5.0.tar.gz", hash = "sha256:3b27eaf9913033c28dde92d02139414c608992e1df4b969c843219acf2ff95e4", size = 14052074 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/9b/76e50ee18f183ea5fe1784a9eeaa50f2c71802e4740d6e959592b0993298/notebook-7.3.2-py3-none-any.whl", hash = "sha256:e5f85fc59b69d3618d73cf27544418193ff8e8058d5bf61d315ce4f473556288", size = 13163630 }, + { url = "https://files.pythonhosted.org/packages/73/96/00df2a4760f10f5af0f45c4955573cae6189931f9a30265a35865f8c1031/notebook-7.5.0-py3-none-any.whl", hash = "sha256:3300262d52905ca271bd50b22617681d95f08a8360d099e097726e6d2efb5811", size = 14460968 }, ] [[package]] @@ -2596,11 +2891,11 @@ wheels = [ [[package]] name = "oauthlib" -version = "3.2.2" +version = "3.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/fa/fbf4001037904031639e6bfbfc02badfc7e12f137a8afa254df6c4c8a670/oauthlib-3.2.2.tar.gz", hash = "sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918", size = 177352 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/80/cab10959dc1faead58dc8384a781dfbf93cb4d33d50988f7a69f1b7c9bbe/oauthlib-3.2.2-py3-none-any.whl", hash = "sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca", size = 151688 }, + { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065 }, ] [[package]] @@ -2636,7 +2931,7 @@ wheels = [ [[package]] name = "openai" -version = "2.8.1" +version = "2.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -2648,9 +2943,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d5/e4/42591e356f1d53c568418dc7e30dcda7be31dd5a4d570bca22acb0525862/openai-2.8.1.tar.gz", hash = "sha256:cb1b79eef6e809f6da326a7ef6038719e35aa944c42d081807bfa1be8060f15f", size = 602490 } +sdist = { url = "https://files.pythonhosted.org/packages/09/48/516290f38745cc1e72856f50e8afed4a7f9ac396a5a18f39e892ab89dfc2/openai-2.9.0.tar.gz", hash = "sha256:b52ec65727fc8f1eed2fbc86c8eac0998900c7ef63aa2eb5c24b69717c56fa5f", size = 608202 } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/4f/dbc0c124c40cb390508a82770fb9f6e3ed162560181a85089191a851c59a/openai-2.8.1-py3-none-any.whl", hash = "sha256:c6c3b5a04994734386e8dad3c00a393f56d3b68a27cd2e8acae91a59e4122463", size = 1022688 }, + { url = "https://files.pythonhosted.org/packages/59/fd/ae2da789cd923dd033c99b8d544071a827c92046b150db01cfa5cea5b3fd/openai-2.9.0-py3-none-any.whl", hash = "sha256:0d168a490fbb45630ad508a6f3022013c155a68fd708069b6a1a01a5e8f0ffad", size = 1030836 }, ] [[package]] @@ -2712,11 +3007,11 @@ wheels = [ [[package]] name = "packaging" -version = "24.2" +version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, ] [[package]] @@ -2749,11 +3044,11 @@ wheels = [ [[package]] name = "parso" -version = "0.8.4" +version = "0.8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668 }, ] [[package]] @@ -2785,59 +3080,52 @@ wheels = [ [[package]] name = "pillow" -version = "11.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/af/c097e544e7bd278333db77933e535098c259609c4eb3b85381109602fb5b/pillow-11.1.0.tar.gz", hash = "sha256:368da70808b36d73b4b390a8ffac11069f8a5c85f29eff1f1b01bcf3ef5b2a20", size = 46742715 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/1c/2dcea34ac3d7bc96a1fd1bd0a6e06a57c67167fec2cff8d95d88229a8817/pillow-11.1.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:e1abe69aca89514737465752b4bcaf8016de61b3be1397a8fc260ba33321b3a8", size = 3229983 }, - { url = "https://files.pythonhosted.org/packages/14/ca/6bec3df25e4c88432681de94a3531cc738bd85dea6c7aa6ab6f81ad8bd11/pillow-11.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c640e5a06869c75994624551f45e5506e4256562ead981cce820d5ab39ae2192", size = 3101831 }, - { url = "https://files.pythonhosted.org/packages/d4/2c/668e18e5521e46eb9667b09e501d8e07049eb5bfe39d56be0724a43117e6/pillow-11.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a07dba04c5e22824816b2615ad7a7484432d7f540e6fa86af60d2de57b0fcee2", size = 4314074 }, - { url = "https://files.pythonhosted.org/packages/02/80/79f99b714f0fc25f6a8499ecfd1f810df12aec170ea1e32a4f75746051ce/pillow-11.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e267b0ed063341f3e60acd25c05200df4193e15a4a5807075cd71225a2386e26", size = 4394933 }, - { url = "https://files.pythonhosted.org/packages/81/aa/8d4ad25dc11fd10a2001d5b8a80fdc0e564ac33b293bdfe04ed387e0fd95/pillow-11.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:bd165131fd51697e22421d0e467997ad31621b74bfc0b75956608cb2906dda07", size = 4353349 }, - { url = "https://files.pythonhosted.org/packages/84/7a/cd0c3eaf4a28cb2a74bdd19129f7726277a7f30c4f8424cd27a62987d864/pillow-11.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:abc56501c3fd148d60659aae0af6ddc149660469082859fa7b066a298bde9482", size = 4476532 }, - { url = "https://files.pythonhosted.org/packages/8f/8b/a907fdd3ae8f01c7670dfb1499c53c28e217c338b47a813af8d815e7ce97/pillow-11.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:54ce1c9a16a9561b6d6d8cb30089ab1e5eb66918cb47d457bd996ef34182922e", size = 4279789 }, - { url = "https://files.pythonhosted.org/packages/6f/9a/9f139d9e8cccd661c3efbf6898967a9a337eb2e9be2b454ba0a09533100d/pillow-11.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73ddde795ee9b06257dac5ad42fcb07f3b9b813f8c1f7f870f402f4dc54b5269", size = 4413131 }, - { url = "https://files.pythonhosted.org/packages/a8/68/0d8d461f42a3f37432203c8e6df94da10ac8081b6d35af1c203bf3111088/pillow-11.1.0-cp310-cp310-win32.whl", hash = "sha256:3a5fe20a7b66e8135d7fd617b13272626a28278d0e578c98720d9ba4b2439d49", size = 2291213 }, - { url = "https://files.pythonhosted.org/packages/14/81/d0dff759a74ba87715509af9f6cb21fa21d93b02b3316ed43bda83664db9/pillow-11.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:b6123aa4a59d75f06e9dd3dac5bf8bc9aa383121bb3dd9a7a612e05eabc9961a", size = 2625725 }, - { url = "https://files.pythonhosted.org/packages/ce/1f/8d50c096a1d58ef0584ddc37e6f602828515219e9d2428e14ce50f5ecad1/pillow-11.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:a76da0a31da6fcae4210aa94fd779c65c75786bc9af06289cd1c184451ef7a65", size = 2375213 }, - { url = "https://files.pythonhosted.org/packages/fa/c5/389961578fb677b8b3244fcd934f720ed25a148b9a5cc81c91bdf59d8588/pillow-11.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:8c730dc3a83e5ac137fbc92dfcfe1511ce3b2b5d7578315b63dbbb76f7f51d90", size = 3198345 }, - { url = "https://files.pythonhosted.org/packages/c4/fa/803c0e50ffee74d4b965229e816af55276eac1d5806712de86f9371858fd/pillow-11.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:7d33d2fae0e8b170b6a6c57400e077412240f6f5bb2a342cf1ee512a787942bb", size = 3072938 }, - { url = "https://files.pythonhosted.org/packages/dc/67/2a3a5f8012b5d8c63fe53958ba906c1b1d0482ebed5618057ef4d22f8076/pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8d65b38173085f24bc07f8b6c505cbb7418009fa1a1fcb111b1f4961814a442", size = 3400049 }, - { url = "https://files.pythonhosted.org/packages/e5/a0/514f0d317446c98c478d1872497eb92e7cde67003fed74f696441e647446/pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:015c6e863faa4779251436db398ae75051469f7c903b043a48f078e437656f83", size = 3422431 }, - { url = "https://files.pythonhosted.org/packages/cd/00/20f40a935514037b7d3f87adfc87d2c538430ea625b63b3af8c3f5578e72/pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d44ff19eea13ae4acdaaab0179fa68c0c6f2f45d66a4d8ec1eda7d6cecbcc15f", size = 3446208 }, - { url = "https://files.pythonhosted.org/packages/28/3c/7de681727963043e093c72e6c3348411b0185eab3263100d4490234ba2f6/pillow-11.1.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d3d8da4a631471dfaf94c10c85f5277b1f8e42ac42bade1ac67da4b4a7359b73", size = 3509746 }, - { url = "https://files.pythonhosted.org/packages/41/67/936f9814bdd74b2dfd4822f1f7725ab5d8ff4103919a1664eb4874c58b2f/pillow-11.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0", size = 2626353 }, +version = "12.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/08/26e68b6b5da219c2a2cb7b563af008b53bb8e6b6fcb3fa40715fcdb2523a/pillow-12.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b", size = 5289809 }, + { url = "https://files.pythonhosted.org/packages/cb/e9/4e58fb097fb74c7b4758a680aacd558810a417d1edaa7000142976ef9d2f/pillow-12.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1", size = 4650606 }, + { url = "https://files.pythonhosted.org/packages/4b/e0/1fa492aa9f77b3bc6d471c468e62bfea1823056bf7e5e4f1914d7ab2565e/pillow-12.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363", size = 6221023 }, + { url = "https://files.pythonhosted.org/packages/c1/09/4de7cd03e33734ccd0c876f0251401f1314e819cbfd89a0fcb6e77927cc6/pillow-12.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca", size = 8024937 }, + { url = "https://files.pythonhosted.org/packages/2e/69/0688e7c1390666592876d9d474f5e135abb4acb39dcb583c4dc5490f1aff/pillow-12.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e", size = 6334139 }, + { url = "https://files.pythonhosted.org/packages/ed/1c/880921e98f525b9b44ce747ad1ea8f73fd7e992bafe3ca5e5644bf433dea/pillow-12.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782", size = 7026074 }, + { url = "https://files.pythonhosted.org/packages/28/03/96f718331b19b355610ef4ebdbbde3557c726513030665071fd025745671/pillow-12.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10", size = 6448852 }, + { url = "https://files.pythonhosted.org/packages/3a/a0/6a193b3f0cc9437b122978d2c5cbce59510ccf9a5b48825096ed7472da2f/pillow-12.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa", size = 7117058 }, + { url = "https://files.pythonhosted.org/packages/a7/c4/043192375eaa4463254e8e61f0e2ec9a846b983929a8d0a7122e0a6d6fff/pillow-12.0.0-cp310-cp310-win32.whl", hash = "sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275", size = 6295431 }, + { url = "https://files.pythonhosted.org/packages/92/c6/c2f2fc7e56301c21827e689bb8b0b465f1b52878b57471a070678c0c33cd/pillow-12.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d", size = 7000412 }, + { url = "https://files.pythonhosted.org/packages/b2/d2/5f675067ba82da7a1c238a73b32e3fd78d67f9d9f80fbadd33a40b9c0481/pillow-12.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7", size = 2435903 }, ] [[package]] name = "pip" -version = "24.3.1" +version = "25.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/b422acd212ad7eedddaf7981eee6e5de085154ff726459cf2da7c5a184c1/pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99", size = 1931073 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/7d/500c9ad20238fcfcb4cb9243eede163594d7020ce87bd9610c9e02771876/pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed", size = 1822182 }, + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622 }, ] [[package]] name = "platformdirs" -version = "4.3.6" +version = "4.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/fc/128cc9cb8f03208bdbf93d3aa862e16d376844a14f9a0ce5cf4507372de4/platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907", size = 21302 } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/a6/bc1012356d8ece4d66dd75c4b9fc6c1f6650ddd5991e421177d9f8f671be/platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb", size = 18439 }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731 }, ] [[package]] name = "plotly" -version = "5.24.1" +version = "6.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "narwhals" }, { name = "packaging" }, - { name = "tenacity" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/79/4f/428f6d959818d7425a94c190a6b26fbc58035cbef40bf249be0b62a9aedd/plotly-5.24.1.tar.gz", hash = "sha256:dbc8ac8339d248a4bcc36e08a5659bacfe1b079390b8953533f4eb22169b4bae", size = 9479398 } +sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/ae/580600f441f6fc05218bd6c9d5794f4aef072a7d9093b291f1c50a9db8bc/plotly-5.24.1-py3-none-any.whl", hash = "sha256:f67073a1e637eb0dc3e46324d9d51e2fe76e9727c892dde64ddf1e1b51f29089", size = 19054220 }, + { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174 }, ] [[package]] @@ -2848,7 +3136,7 @@ sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d [[package]] name = "pre-commit" -version = "4.0.1" +version = "4.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -2857,55 +3145,66 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/c8/e22c292035f1bac8b9f5237a2622305bc0304e776080b246f3df57c4ff9f/pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2", size = 191678 } +sdist = { url = "https://files.pythonhosted.org/packages/f4/9b/6a4ffb4ed980519da959e1cf3122fc6cb41211daa58dbae1c73c0e519a37/pre_commit-4.5.0.tar.gz", hash = "sha256:dc5a065e932b19fc1d4c653c6939068fe54325af8e741e74e88db4d28a4dd66b", size = 198428 } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/8f/496e10d51edd6671ebe0432e33ff800aa86775d2d147ce7d43389324a525/pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878", size = 218713 }, + { url = "https://files.pythonhosted.org/packages/5d/c4/b2d28e9d2edf4f1713eb3c29307f1a63f3d67cf09bdda29715a36a68921a/pre_commit-4.5.0-py2.py3-none-any.whl", hash = "sha256:25e2ce09595174d9c97860a95609f9f852c0614ba602de3561e267547f2335e1", size = 226429 }, ] [[package]] name = "prometheus-client" -version = "0.21.1" +version = "0.23.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/62/14/7d0f567991f3a9af8d1cd4f619040c93b68f09a02b6d0b6ab1b2d1ded5fe/prometheus_client-0.21.1.tar.gz", hash = "sha256:252505a722ac04b0456be05c05f75f45d760c2911ffc45f2a06bcaed9f3ae3fb", size = 78551 } +sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ff/c2/ab7d37426c179ceb9aeb109a85cda8948bb269b7561a0be870cc656eefe4/prometheus_client-0.21.1-py3-none-any.whl", hash = "sha256:594b45c410d6f4f8888940fe80b5cc2521b305a1fafe1c58609ef715a001f301", size = 54682 }, + { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145 }, ] [[package]] name = "prompt-toolkit" -version = "3.0.50" +version = "3.0.52" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/e1/bd15cb8ffdcfeeb2bdc215de3c3cffca11408d829e4b8416dcfe71ba8854/prompt_toolkit-3.0.50.tar.gz", hash = "sha256:544748f3860a2623ca5cd6d2795e7a14f3d0e1c3c9728359013f79877fc89bab", size = 429087 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/ea/d836f008d33151c7a1f62caf3d8dd782e4d15f6a43897f64480c2b8de2ad/prompt_toolkit-3.0.50-py3-none-any.whl", hash = "sha256:9b6427eb19e479d98acff65196a307c555eb567989e6d88ebbb1b509d9779198", size = 387816 }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, ] [[package]] name = "propcache" -version = "0.2.1" +version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/c8/2a13f78d82211490855b2fb303b6721348d0787fdd9a12ac46d99d3acde1/propcache-0.2.1.tar.gz", hash = "sha256:3f77ce728b19cb537714499928fe800c3dda29e8d9428778fc7c186da4c09a64", size = 41735 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534 }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526 }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263 }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012 }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491 }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319 }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856 }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241 }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552 }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113 }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778 }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047 }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093 }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638 }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229 }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, +] + +[[package]] +name = "proto-plus" +version = "1.26.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/a5/0ea64c9426959ef145a938e38c832fc551843481d356713ececa9a8a64e8/propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6", size = 79296 }, - { url = "https://files.pythonhosted.org/packages/76/5a/916db1aba735f55e5eca4733eea4d1973845cf77dfe67c2381a2ca3ce52d/propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2", size = 45622 }, - { url = "https://files.pythonhosted.org/packages/2d/62/685d3cf268b8401ec12b250b925b21d152b9d193b7bffa5fdc4815c392c2/propcache-0.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6445804cf4ec763dc70de65a3b0d9954e868609e83850a47ca4f0cb64bd79fea", size = 45133 }, - { url = "https://files.pythonhosted.org/packages/4d/3d/31c9c29ee7192defc05aa4d01624fd85a41cf98e5922aaed206017329944/propcache-0.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9479aa06a793c5aeba49ce5c5692ffb51fcd9a7016e017d555d5e2b0045d212", size = 204809 }, - { url = "https://files.pythonhosted.org/packages/10/a1/e4050776f4797fc86140ac9a480d5dc069fbfa9d499fe5c5d2fa1ae71f07/propcache-0.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9631c5e8b5b3a0fda99cb0d29c18133bca1e18aea9effe55adb3da1adef80d3", size = 219109 }, - { url = "https://files.pythonhosted.org/packages/c9/c0/e7ae0df76343d5e107d81e59acc085cea5fd36a48aa53ef09add7503e888/propcache-0.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3156628250f46a0895f1f36e1d4fbe062a1af8718ec3ebeb746f1d23f0c5dc4d", size = 217368 }, - { url = "https://files.pythonhosted.org/packages/fc/e1/e0a2ed6394b5772508868a977d3238f4afb2eebaf9976f0b44a8d347ad63/propcache-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b6fb63ae352e13748289f04f37868099e69dba4c2b3e271c46061e82c745634", size = 205124 }, - { url = "https://files.pythonhosted.org/packages/50/c1/e388c232d15ca10f233c778bbdc1034ba53ede14c207a72008de45b2db2e/propcache-0.2.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:887d9b0a65404929641a9fabb6452b07fe4572b269d901d622d8a34a4e9043b2", size = 195463 }, - { url = "https://files.pythonhosted.org/packages/0a/fd/71b349b9def426cc73813dbd0f33e266de77305e337c8c12bfb0a2a82bfb/propcache-0.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a96dc1fa45bd8c407a0af03b2d5218392729e1822b0c32e62c5bf7eeb5fb3958", size = 198358 }, - { url = "https://files.pythonhosted.org/packages/02/f2/d7c497cd148ebfc5b0ae32808e6c1af5922215fe38c7a06e4e722fe937c8/propcache-0.2.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a7e65eb5c003a303b94aa2c3852ef130230ec79e349632d030e9571b87c4698c", size = 195560 }, - { url = "https://files.pythonhosted.org/packages/bb/57/f37041bbe5e0dfed80a3f6be2612a3a75b9cfe2652abf2c99bef3455bbad/propcache-0.2.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:999779addc413181912e984b942fbcc951be1f5b3663cd80b2687758f434c583", size = 196895 }, - { url = "https://files.pythonhosted.org/packages/83/36/ae3cc3e4f310bff2f064e3d2ed5558935cc7778d6f827dce74dcfa125304/propcache-0.2.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:19a0f89a7bb9d8048d9c4370c9c543c396e894c76be5525f5e1ad287f1750ddf", size = 207124 }, - { url = "https://files.pythonhosted.org/packages/8c/c4/811b9f311f10ce9d31a32ff14ce58500458443627e4df4ae9c264defba7f/propcache-0.2.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1ac2f5fe02fa75f56e1ad473f1175e11f475606ec9bd0be2e78e4734ad575034", size = 210442 }, - { url = "https://files.pythonhosted.org/packages/18/dd/a1670d483a61ecac0d7fc4305d91caaac7a8fc1b200ea3965a01cf03bced/propcache-0.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:574faa3b79e8ebac7cb1d7930f51184ba1ccf69adfdec53a12f319a06030a68b", size = 203219 }, - { url = "https://files.pythonhosted.org/packages/f9/2d/30ced5afde41b099b2dc0c6573b66b45d16d73090e85655f1a30c5a24e07/propcache-0.2.1-cp310-cp310-win32.whl", hash = "sha256:03ff9d3f665769b2a85e6157ac8b439644f2d7fd17615a82fa55739bc97863f4", size = 40313 }, - { url = "https://files.pythonhosted.org/packages/23/84/bd9b207ac80da237af77aa6e153b08ffa83264b1c7882495984fcbfcf85c/propcache-0.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:2d3af2e79991102678f53e0dbf4c35de99b6b8b58f29a27ca0325816364caaba", size = 44428 }, - { url = "https://files.pythonhosted.org/packages/41/b6/c5319caea262f4821995dca2107483b94a3345d4607ad797c76cb9c36bcc/propcache-0.2.1-py3-none-any.whl", hash = "sha256:52277518d6aae65536e9cea52d4e7fd2f7a66f4aa2d30ed3f2fcea620ace3c54", size = 11818 }, + { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163 }, ] [[package]] @@ -2968,17 +3267,17 @@ wheels = [ [[package]] name = "pyarrow" -version = "19.0.0" +version = "22.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/01/fe1fd04744c2aa038e5a11c7a4adb3d62bce09798695e54f7274b5977134/pyarrow-19.0.0.tar.gz", hash = "sha256:8d47c691765cf497aaeed4954d226568563f1b3b74ff61139f2d77876717084b", size = 1129096 } +sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/02/1ad80ffd3c558916858a49c83b6e494a9d93009bbebc603cf0cb8263bea7/pyarrow-19.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c318eda14f6627966997a7d8c374a87d084a94e4e38e9abbe97395c215830e0c", size = 30686262 }, - { url = "https://files.pythonhosted.org/packages/1b/f0/adab5f142eb8203db8bfbd3a816816e37a85423ae684567e7f3555658315/pyarrow-19.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:62ef8360ff256e960f57ce0299090fb86423afed5e46f18f1225f960e05aae3d", size = 32100005 }, - { url = "https://files.pythonhosted.org/packages/94/8b/e674083610e5efc48d2f205c568d842cdfdf683d12f9ff0d546e38757722/pyarrow-19.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2795064647add0f16563e57e3d294dbfc067b723f0fd82ecd80af56dad15f503", size = 41144815 }, - { url = "https://files.pythonhosted.org/packages/d5/fb/2726241a792b7f8a58789e5a63d1be9a5a4059206318fd0ff9485a578952/pyarrow-19.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a218670b26fb1bc74796458d97bcab072765f9b524f95b2fccad70158feb8b17", size = 42180380 }, - { url = "https://files.pythonhosted.org/packages/7d/09/7aef12446d8e7002dfc07bb7bc71f594c1d5844ca78b364a49f07efb65b1/pyarrow-19.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:66732e39eaa2247996a6b04c8aa33e3503d351831424cdf8d2e9a0582ac54b34", size = 40515021 }, - { url = "https://files.pythonhosted.org/packages/31/55/f05fc5608cc96060c2b24de505324d641888bd62d4eed2fa1dacd872a1e1/pyarrow-19.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e675a3ad4732b92d72e4d24009707e923cab76b0d088e5054914f11a797ebe44", size = 42067488 }, - { url = "https://files.pythonhosted.org/packages/f0/01/097653cec7a944c16313cb748a326771133c142034b252076bd84743b98d/pyarrow-19.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:f094742275586cdd6b1a03655ccff3b24b2610c3af76f810356c4c71d24a2a6c", size = 25276726 }, + { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968 }, + { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085 }, + { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613 }, + { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059 }, + { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043 }, + { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505 }, + { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641 }, ] [[package]] @@ -2992,107 +3291,136 @@ wheels = [ [[package]] name = "pyasn1-modules" -version = "0.4.1" +version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1d/67/6afbf0d507f73c32d21084a79946bfcfca5fbc62a72057e9c23797a737c9/pyasn1_modules-0.4.1.tar.gz", hash = "sha256:c28e2dbf9c06ad61c71a075c7e0f9fd0f1b0bb2d2ad4377f240d33ac2ab60a7c", size = 310028 } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892 } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/89/bc88a6711935ba795a679ea6ebee07e128050d6382eaa35a0a47c8032bdc/pyasn1_modules-0.4.1-py3-none-any.whl", hash = "sha256:49bfa96b45a292b711e986f222502c1c9a5e1f4e568fc30e2574a6c7d07838fd", size = 181537 }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259 }, ] [[package]] name = "pycparser" -version = "2.22" +version = "2.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, ] [[package]] name = "pycryptodome" -version = "3.21.0" +version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/52/13b9db4a913eee948152a079fe58d035bd3d1a519584155da8e786f767e6/pycryptodome-3.21.0.tar.gz", hash = "sha256:f7787e0d469bdae763b876174cf2e6c0f7be79808af26b1da96f1a64bcf47297", size = 4818071 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/88/5e83de10450027c96c79dc65ac45e9d0d7a7fef334f39d3789a191f33602/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_universal2.whl", hash = "sha256:2480ec2c72438430da9f601ebc12c518c093c13111a5c1644c82cdfc2e50b1e4", size = 2495937 }, - { url = "https://files.pythonhosted.org/packages/66/e1/8f28cd8cf7f7563319819d1e172879ccce2333781ae38da61c28fe22d6ff/pycryptodome-3.21.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:de18954104667f565e2fbb4783b56667f30fb49c4d79b346f52a29cb198d5b6b", size = 1634629 }, - { url = "https://files.pythonhosted.org/packages/6a/c1/f75a1aaff0c20c11df8dc8e2bf8057e7f73296af7dfd8cbb40077d1c930d/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2de4b7263a33947ff440412339cb72b28a5a4c769b5c1ca19e33dd6cd1dcec6e", size = 2168708 }, - { url = "https://files.pythonhosted.org/packages/ea/66/6f2b7ddb457b19f73b82053ecc83ba768680609d56dd457dbc7e902c41aa/pycryptodome-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0714206d467fc911042d01ea3a1847c847bc10884cf674c82e12915cfe1649f8", size = 2254555 }, - { url = "https://files.pythonhosted.org/packages/2c/2b/152c330732a887a86cbf591ed69bd1b489439b5464806adb270f169ec139/pycryptodome-3.21.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7d85c1b613121ed3dbaa5a97369b3b757909531a959d229406a75b912dd51dd1", size = 2294143 }, - { url = "https://files.pythonhosted.org/packages/55/92/517c5c498c2980c1b6d6b9965dffbe31f3cd7f20f40d00ec4069559c5902/pycryptodome-3.21.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:8898a66425a57bcf15e25fc19c12490b87bd939800f39a03ea2de2aea5e3611a", size = 2160509 }, - { url = "https://files.pythonhosted.org/packages/39/1f/c74288f54d80a20a78da87df1818c6464ac1041d10988bb7d982c4153fbc/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_i686.whl", hash = "sha256:932c905b71a56474bff8a9c014030bc3c882cee696b448af920399f730a650c2", size = 2329480 }, - { url = "https://files.pythonhosted.org/packages/39/1b/d0b013bf7d1af7cf0a6a4fce13f5fe5813ab225313755367b36e714a63f8/pycryptodome-3.21.0-cp36-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:18caa8cfbc676eaaf28613637a89980ad2fd96e00c564135bf90bc3f0b34dd93", size = 2254397 }, - { url = "https://files.pythonhosted.org/packages/14/71/4cbd3870d3e926c34706f705d6793159ac49d9a213e3ababcdade5864663/pycryptodome-3.21.0-cp36-abi3-win32.whl", hash = "sha256:280b67d20e33bb63171d55b1067f61fbd932e0b1ad976b3a184303a3dad22764", size = 1775641 }, - { url = "https://files.pythonhosted.org/packages/43/1d/81d59d228381576b92ecede5cd7239762c14001a828bdba30d64896e9778/pycryptodome-3.21.0-cp36-abi3-win_amd64.whl", hash = "sha256:b7aa25fc0baa5b1d95b7633af4f5f1838467f1815442b22487426f94e0d66c53", size = 1812863 }, - { url = "https://files.pythonhosted.org/packages/25/b3/09ff7072e6d96c9939c24cf51d3c389d7c345bf675420355c22402f71b68/pycryptodome-3.21.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:2cb635b67011bc147c257e61ce864879ffe6d03342dc74b6045059dfbdedafca", size = 1691593 }, - { url = "https://files.pythonhosted.org/packages/a8/91/38e43628148f68ba9b68dedbc323cf409e537fd11264031961fd7c744034/pycryptodome-3.21.0-pp27-pypy_73-win32.whl", hash = "sha256:4c26a2f0dc15f81ea3afa3b0c87b87e501f235d332b7f27e2225ecb80c0b1cdd", size = 1765997 }, - { url = "https://files.pythonhosted.org/packages/08/16/ae464d4ac338c1dd41f89c41f9488e54f7d2a3acf93bb920bb193b99f8e3/pycryptodome-3.21.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d5ebe0763c982f069d3877832254f64974139f4f9655058452603ff559c482e8", size = 1615855 }, - { url = "https://files.pythonhosted.org/packages/1e/8c/b0cee957eee1950ce7655006b26a8894cee1dc4b8747ae913684352786eb/pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee86cbde706be13f2dec5a42b52b1c1d1cbb90c8e405c68d0755134735c8dc6", size = 1650018 }, - { url = "https://files.pythonhosted.org/packages/93/4d/d7138068089b99f6b0368622e60f97a577c936d75f533552a82613060c58/pycryptodome-3.21.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fd54003ec3ce4e0f16c484a10bc5d8b9bd77fa662a12b85779a2d2d85d67ee0", size = 1687977 }, - { url = "https://files.pythonhosted.org/packages/96/02/90ae1ac9f28be4df0ed88c127bf4acc1b102b40053e172759d4d1c54d937/pycryptodome-3.21.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5dfafca172933506773482b0e18f0cd766fd3920bd03ec85a283df90d8a17bc6", size = 1788273 }, +sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627 }, + { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362 }, + { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625 }, + { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954 }, + { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534 }, + { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853 }, + { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465 }, + { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414 }, + { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484 }, + { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636 }, + { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675 }, + { url = "https://files.pythonhosted.org/packages/9f/7c/f5b0556590e7b4e710509105e668adb55aa9470a9f0e4dea9c40a4a11ce1/pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56", size = 1705791 }, + { url = "https://files.pythonhosted.org/packages/33/38/dcc795578d610ea1aaffef4b148b8cafcfcf4d126b1e58231ddc4e475c70/pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7", size = 1780265 }, + { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886 }, + { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151 }, + { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461 }, + { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440 }, + { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005 }, ] [[package]] name = "pydantic" -version = "2.10.6" +version = "2.12.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, { name = "typing-extensions" }, + { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580 }, +] + +[package.optional-dependencies] +email = [ + { name = "email-validator" }, ] [[package]] name = "pydantic-core" -version = "2.27.2" +version = "2.41.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938 }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684 }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169 }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227 }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695 }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662 }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370 }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813 }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287 }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414 }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301 }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685 }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876 }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159 }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331 }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467 }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797 }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839 }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861 }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582 }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985 }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715 }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298 }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475 }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815 }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567 }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442 }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956 }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253 }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050 }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178 }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833 }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156 }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378 }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622 }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441 }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291 }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632 }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905 }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495 }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388 }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879 }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017 }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351 }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363 }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615 }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369 }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218 }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951 }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428 }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009 }, ] [[package]] name = "pydantic-settings" -version = "2.7.1" +version = "2.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880 }, +] + +[[package]] +name = "pydeck" +version = "0.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jinja2" }, + { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/73/7b/c58a586cd7d9ac66d2ee4ba60ca2d241fa837c02bca9bea80a9a8c3d22a9/pydantic_settings-2.7.1.tar.gz", hash = "sha256:10c9caad35e64bfb3c2fbf70a078c0e25cc92499782e5200747f942a065dec93", size = 79920 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/46/93416fdae86d40879714f72956ac14df9c7b76f7d41a4d68aa9f71a0028b/pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd", size = 29718 }, + { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, ] [[package]] @@ -3110,11 +3438,23 @@ wheels = [ [[package]] name = "pygments" -version = "2.19.1" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, +] + +[[package]] +name = "pympler" +version = "1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 } +dependencies = [ + { name = "pywin32", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dd/37/c384631908029676d8e7213dd956bb686af303a80db7afbc9be36bc49495/pympler-1.1.tar.gz", hash = "sha256:1eaa867cb8992c218430f1708fdaccda53df064144d1c5656b1e6f1ee6000424", size = 179954 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 }, + { url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl", hash = "sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506", size = 165766 }, ] [[package]] @@ -3131,47 +3471,47 @@ wheels = [ [[package]] name = "pymupdf" -version = "1.25.2" +version = "1.26.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/fc/dd8776dc5c2f8cf0e51cf81a5f1de3840996bed7ca03ec768b0733024fb9/pymupdf-1.25.2.tar.gz", hash = "sha256:9ea88ff1b3ccb359620f106a6fd5ba6877d959d21d78272052c3496ceede6eec", size = 63814915 } +sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/a6f0e03a117fa2ad79c4b898203bb212b17804f92558a6a339298faca7bb/pymupdf-1.26.6.tar.gz", hash = "sha256:a2b4531cd4ab36d6f1f794bb6d3c33b49bda22f36d58bb1f3e81cbc10183bd2b", size = 84322494 } wheels = [ - { url = "https://files.pythonhosted.org/packages/24/34/8c3d82719d118beb48fded78fcab7cbe9ac3bf1906dc87a9ca4fd950087d/pymupdf-1.25.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:59dea22b633cc4fc13670b4c5db50d71f8cd4f420814420f33ce47ddcb61e1f6", size = 19336722 }, - { url = "https://files.pythonhosted.org/packages/4f/ec/c7f742f56ee42be27b3afdbf3364da12f03e309f6638e666a7816d9eef23/pymupdf-1.25.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:e8b8a874497cd0deee89a6a4fb76a3a08173c8d39e88fc7cf715764ec5a243e9", size = 18570847 }, - { url = "https://files.pythonhosted.org/packages/9d/27/557ee235aded5185e4824459e1540142fbb9323e1b83f77cbefe2e2c4e1e/pymupdf-1.25.2-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f61e5cdb25b86eb28d34aa3557b49ecf9e361d5f5cd3b1660406f8f0bf813af7", size = 19430802 }, - { url = "https://files.pythonhosted.org/packages/0e/de/35fde3d49e0d187b95ab64cc61b4d275ebc7fd4f45e152b206b0e17e6b69/pymupdf-1.25.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ae8cfa7a97d78f813d286ecba32369059d88073edd1e5cf105f4cd0811f71925", size = 19994315 }, - { url = "https://files.pythonhosted.org/packages/9d/d3/a8a09b550c62306c76e1c2d892c0890287470164d7941aea35330cceee4d/pymupdf-1.25.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:295505fe1ecb7c7b57d4124d373e207ea311d8e40bc7ac3016d8ec2d60b091e9", size = 21117143 }, - { url = "https://files.pythonhosted.org/packages/ef/ac/fc4f37c7620a20d25443868ed665291e96f283eda068cda673e9edebf5f0/pymupdf-1.25.2-cp39-abi3-win32.whl", hash = "sha256:b9488c8b82bb9be36fb13ee0c8d43b0ddcc50af83b61da01e6040413d9e67da6", size = 15084555 }, - { url = "https://files.pythonhosted.org/packages/64/8e/1d0ff215b37343c7e0bec4d571f1413e4f76a416591276b97081f1814710/pymupdf-1.25.2-cp39-abi3-win_amd64.whl", hash = "sha256:1b4ca6f5780d319a08dff885a5a0e3585c5d7af04dcfa063c535b88371fd91c1", size = 16531823 }, + { url = "https://files.pythonhosted.org/packages/9e/5c/dec354eee5fe4966c715f33818ed4193e0e6c986cf8484de35b6c167fb8e/pymupdf-1.26.6-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e46f320a136ad55e5219e8f0f4061bdf3e4c12b126d2740d5a49f73fae7ea176", size = 23178988 }, + { url = "https://files.pythonhosted.org/packages/ec/a0/11adb742d18142bd623556cd3b5d64649816decc5eafd30efc9498657e76/pymupdf-1.26.6-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:6844cd2396553c0fa06de4869d5d5ecb1260e6fc3b9d85abe8fa35f14dd9d688", size = 22469764 }, + { url = "https://files.pythonhosted.org/packages/e4/c8/377cf20e31f58d4c243bfcf2d3cb7466d5b97003b10b9f1161f11eb4a994/pymupdf-1.26.6-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:617ba69e02c44f0da1c0e039ea4a26cf630849fd570e169c71daeb8ac52a81d6", size = 23502227 }, + { url = "https://files.pythonhosted.org/packages/4f/bf/6e02e3d84b32c137c71a0a3dcdba8f2f6e9950619a3bc272245c7c06a051/pymupdf-1.26.6-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7777d0b7124c2ebc94849536b6a1fb85d158df3b9d873935e63036559391534c", size = 24115381 }, + { url = "https://files.pythonhosted.org/packages/ab/9d/30f7fcb3776bfedde66c06297960debe4883b1667294a1ee9426c942e94d/pymupdf-1.26.6-cp310-abi3-win32.whl", hash = "sha256:8f3ef05befc90ca6bb0f12983200a7048d5bff3e1c1edef1bb3de60b32cb5274", size = 17203613 }, + { url = "https://files.pythonhosted.org/packages/f9/e8/989f4eaa369c7166dc24f0eaa3023f13788c40ff1b96701f7047421554a8/pymupdf-1.26.6-cp310-abi3-win_amd64.whl", hash = "sha256:ce02ca96ed0d1acfd00331a4d41a34c98584d034155b06fd4ec0f051718de7ba", size = 18405680 }, ] [[package]] name = "pymupdf4llm" -version = "0.0.17" +version = "0.2.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pymupdf" }, + { name = "tabulate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2e/3c/1a530a410bdf76d83289bf30b3b86236d338b3f5f21842790c2cf7e9c1f6/pymupdf4llm-0.0.17.tar.gz", hash = "sha256:27287ef9fe0217cf37841a3ef2bcf70da2553c43d95ea39b664a6de6485678c3", size = 25180 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/bd/5c1958ac1ab68c12a09aef1128b3522e1ada6086c6cb42f880dcb294b13e/pymupdf4llm-0.2.6.tar.gz", hash = "sha256:e2deb44ba35aef92c4d84254ef70739feb982256235de2740ffb016b25480da4", size = 64787 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/af/1576ecfc8a62d31c0c8b34b856e52f6b05f1d76546dbac0e1d037f044a9e/pymupdf4llm-0.0.17-py3-none-any.whl", hash = "sha256:26de9996945f15e3ca507908f80dc18a959f5b5214bb2e302c7f7034089665a0", size = 26190 }, + { url = "https://files.pythonhosted.org/packages/b8/fa/2c7d7ce85d7844097d96a8085e719ef5508eaf60e0d0ec24d2d3d42fffc9/pymupdf4llm-0.2.6-py3-none-any.whl", hash = "sha256:0b8f19d867ca3d9f1e0835a376431b74ef799a0bc0bae1442d1d429fde2d355b", size = 66562 }, ] [[package]] name = "pypandoc" -version = "1.15" +version = "1.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e1/88/26e650d053df5f3874aa3c05901a14166ce3271f58bfe114fd776987efbd/pypandoc-1.15.tar.gz", hash = "sha256:ea25beebe712ae41d63f7410c08741a3cab0e420f6703f95bc9b3a749192ce13", size = 32940 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/06/0763e0ccc81754d3eadb21b2cb86cf21bdedc9b52698c2ad6785db7f0a4e/pypandoc-1.15-py3-none-any.whl", hash = "sha256:4ededcc76c8770f27aaca6dff47724578428eca84212a31479403a9731fc2b16", size = 21321 }, + { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451 }, ] [[package]] name = "pyparsing" -version = "3.2.1" +version = "3.2.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8b/1a/3544f4f299a47911c2ab3710f534e52fea62a633c96806995da5d25be4b2/pyparsing-3.2.1.tar.gz", hash = "sha256:61980854fd66de3a90028d679a954d5f2623e83144b5afe5ee86f43d762e5f0a", size = 1067694 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/a7/c8a2d361bf89c0d9577c934ebb7421b25dc84bf3a8e3ac0a40aed9acc547/pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1", size = 107716 }, + { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890 }, ] [[package]] @@ -3210,20 +3550,20 @@ wheels = [ [[package]] name = "python-dotenv" -version = "1.0.1" +version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, ] [[package]] name = "python-json-logger" -version = "3.2.1" +version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/c4/358cd13daa1d912ef795010897a483ab2f0b41c9ea1b35235a8b2f7d15a7/python_json_logger-3.2.1.tar.gz", hash = "sha256:8eb0554ea17cb75b05d2848bc14fb02fbdbd9d6972120781b974380bfa162008", size = 16287 } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/72/2f30cf26664fcfa0bd8ec5ee62ec90c03bd485e4a294d92aabc76c5203a5/python_json_logger-3.2.1-py3-none-any.whl", hash = "sha256:cdc17047eb5374bd311e748b42f99d71223f3b0e186f4206cc5d52aefe85b090", size = 14924 }, + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548 }, ] [[package]] @@ -3285,147 +3625,144 @@ wheels = [ [[package]] name = "pytz" -version = "2024.2" +version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3a/31/3c70bf7603cc2dca0f19bdc53b4537a797747a58875b552c8c413d963a3f/pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a", size = 319692 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/c3/005fcca25ce078d2cc29fd559379817424e94885510568bc1bc53d7d5846/pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725", size = 508002 }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, ] [[package]] name = "pywin32" -version = "308" +version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/72/a6/3e9f2c474895c1bb61b11fa9640be00067b5c5b363c501ee9c3fa53aec01/pywin32-308-cp310-cp310-win32.whl", hash = "sha256:796ff4426437896550d2981b9c2ac0ffd75238ad9ea2d3bfa67a1abd546d262e", size = 5927028 }, - { url = "https://files.pythonhosted.org/packages/d9/b4/84e2463422f869b4b718f79eb7530a4c1693e96b8a4e5e968de38be4d2ba/pywin32-308-cp310-cp310-win_amd64.whl", hash = "sha256:4fc888c59b3c0bef905ce7eb7e2106a07712015ea1c8234b703a088d46110e8e", size = 6558484 }, - { url = "https://files.pythonhosted.org/packages/9f/8f/fb84ab789713f7c6feacaa08dad3ec8105b88ade8d1c4f0f0dfcaaa017d6/pywin32-308-cp310-cp310-win_arm64.whl", hash = "sha256:a5ab5381813b40f264fa3495b98af850098f814a25a63589a8e9eb12560f450c", size = 7971454 }, + { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432 }, + { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103 }, + { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557 }, ] [[package]] name = "pywinpty" -version = "2.0.14" +version = "3.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/82/90f8750423cba4b9b6c842df227609fb60704482d7abf6dd47e2babc055a/pywinpty-2.0.14.tar.gz", hash = "sha256:18bd9529e4a5daf2d9719aa17788ba6013e594ae94c5a0c27e83df3278b0660e", size = 27769 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/09/56376af256eab8cc5f8982a3b138d387136eca27fa1a8a68660e8ed59e4b/pywinpty-2.0.14-cp310-none-win_amd64.whl", hash = "sha256:0b149c2918c7974f575ba79f5a4aad58bd859a52fa9eb1296cc22aa412aa411f", size = 1397115 }, + { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330 }, ] [[package]] name = "pyyaml" -version = "6.0.2" +version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199 }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758 }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463 }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280 }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239 }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802 }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527 }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052 }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774 }, + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, ] [[package]] name = "pyzmq" -version = "26.2.0" +version = "27.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/05/bed626b9f7bb2322cdbbf7b4bd8f54b1b617b0d2ab2d3547d6e39428a48e/pyzmq-26.2.0.tar.gz", hash = "sha256:070672c258581c8e4f640b5159297580a9974b026043bd4ab0470be9ed324f1f", size = 271975 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/a8/9837c39aba390eb7d01924ace49d761c8dbe7bc2d6082346d00c8332e431/pyzmq-26.2.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:ddf33d97d2f52d89f6e6e7ae66ee35a4d9ca6f36eda89c24591b0c40205a3629", size = 1340058 }, - { url = "https://files.pythonhosted.org/packages/a2/1f/a006f2e8e4f7d41d464272012695da17fb95f33b54342612a6890da96ff6/pyzmq-26.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dacd995031a01d16eec825bf30802fceb2c3791ef24bcce48fa98ce40918c27b", size = 1008818 }, - { url = "https://files.pythonhosted.org/packages/b6/09/b51b6683fde5ca04593a57bbe81788b6b43114d8f8ee4e80afc991e14760/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89289a5ee32ef6c439086184529ae060c741334b8970a6855ec0b6ad3ff28764", size = 673199 }, - { url = "https://files.pythonhosted.org/packages/c9/78/486f3e2e824f3a645238332bf5a4c4b4477c3063033a27c1e4052358dee2/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5506f06d7dc6ecf1efacb4a013b1f05071bb24b76350832c96449f4a2d95091c", size = 911762 }, - { url = "https://files.pythonhosted.org/packages/5e/3b/2eb1667c9b866f53e76ee8b0c301b0469745a23bd5a87b7ee3d5dd9eb6e5/pyzmq-26.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8ea039387c10202ce304af74def5021e9adc6297067f3441d348d2b633e8166a", size = 868773 }, - { url = "https://files.pythonhosted.org/packages/16/29/ca99b4598a9dc7e468b5417eda91f372b595be1e3eec9b7cbe8e5d3584e8/pyzmq-26.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a2224fa4a4c2ee872886ed00a571f5e967c85e078e8e8c2530a2fb01b3309b88", size = 868834 }, - { url = "https://files.pythonhosted.org/packages/ad/e5/9efaeb1d2f4f8c50da04144f639b042bc52869d3a206d6bf672ab3522163/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:28ad5233e9c3b52d76196c696e362508959741e1a005fb8fa03b51aea156088f", size = 1202861 }, - { url = "https://files.pythonhosted.org/packages/c3/62/c721b5608a8ac0a69bb83cbb7d07a56f3ff00b3991a138e44198a16f94c7/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:1c17211bc037c7d88e85ed8b7d8f7e52db6dc8eca5590d162717c654550f7282", size = 1515304 }, - { url = "https://files.pythonhosted.org/packages/87/84/e8bd321aa99b72f48d4606fc5a0a920154125bd0a4608c67eab742dab087/pyzmq-26.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b8f86dd868d41bea9a5f873ee13bf5551c94cf6bc51baebc6f85075971fe6eea", size = 1414712 }, - { url = "https://files.pythonhosted.org/packages/cd/cd/420e3fd1ac6977b008b72e7ad2dae6350cc84d4c5027fc390b024e61738f/pyzmq-26.2.0-cp310-cp310-win32.whl", hash = "sha256:46a446c212e58456b23af260f3d9fb785054f3e3653dbf7279d8f2b5546b21c2", size = 578113 }, - { url = "https://files.pythonhosted.org/packages/5c/57/73930d56ed45ae0cb4946f383f985c855c9b3d4063f26416998f07523c0e/pyzmq-26.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:49d34ab71db5a9c292a7644ce74190b1dd5a3475612eefb1f8be1d6961441971", size = 641631 }, - { url = "https://files.pythonhosted.org/packages/61/d2/ae6ac5c397f1ccad59031c64beaafce7a0d6182e0452cc48f1c9c87d2dd0/pyzmq-26.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:bfa832bfa540e5b5c27dcf5de5d82ebc431b82c453a43d141afb1e5d2de025fa", size = 543528 }, - { url = "https://files.pythonhosted.org/packages/53/fb/36b2b2548286e9444e52fcd198760af99fd89102b5be50f0660fcfe902df/pyzmq-26.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:706e794564bec25819d21a41c31d4df2d48e1cc4b061e8d345d7fb4dd3e94072", size = 906955 }, - { url = "https://files.pythonhosted.org/packages/77/8f/6ce54f8979a01656e894946db6299e2273fcee21c8e5fa57c6295ef11f57/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b435f2753621cd36e7c1762156815e21c985c72b19135dac43a7f4f31d28dd1", size = 565701 }, - { url = "https://files.pythonhosted.org/packages/ee/1c/bf8cd66730a866b16db8483286078892b7f6536f8c389fb46e4beba0a970/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160c7e0a5eb178011e72892f99f918c04a131f36056d10d9c1afb223fc952c2d", size = 794312 }, - { url = "https://files.pythonhosted.org/packages/71/43/91fa4ff25bbfdc914ab6bafa0f03241d69370ef31a761d16bb859f346582/pyzmq-26.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4a71d5d6e7b28a47a394c0471b7e77a0661e2d651e7ae91e0cab0a587859ca", size = 752775 }, - { url = "https://files.pythonhosted.org/packages/ec/d2/3b2ab40f455a256cb6672186bea95cd97b459ce4594050132d71e76f0d6f/pyzmq-26.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:90412f2db8c02a3864cbfc67db0e3dcdbda336acf1c469526d3e869394fe001c", size = 550762 }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850 }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380 }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421 }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149 }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070 }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441 }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529 }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276 }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208 }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766 }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266 }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206 }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747 }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371 }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862 }, ] [[package]] name = "rapidfuzz" -version = "3.11.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a4/aa/25e5a20131369d82c7b8288c99c2c3011ec47a3f5953ccc9cb8145720be5/rapidfuzz-3.11.0.tar.gz", hash = "sha256:a53ca4d3f52f00b393fab9b5913c5bafb9afc27d030c8a1db1283da6917a860f", size = 57983000 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/70/820ebf9eb22ad97b9e0bb9fd1ad8c6be4c8db5a0974d12ce27b5c9a30db0/rapidfuzz-3.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:eb8a54543d16ab1b69e2c5ed96cabbff16db044a50eddfc028000138ca9ddf33", size = 1954240 }, - { url = "https://files.pythonhosted.org/packages/41/bc/e39abdc28160d8147ccab0aa922a29be50529dcf149615a68a324ff6f9b1/rapidfuzz-3.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:231c8b2efbd7f8d2ecd1ae900363ba168b8870644bb8f2b5aa96e4a7573bde19", size = 1427139 }, - { url = "https://files.pythonhosted.org/packages/b6/2d/19b8e5d80257b13d73ba994552b78a69ac2ed70f1de716f1b02fcb84d09c/rapidfuzz-3.11.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54e7f442fb9cca81e9df32333fb075ef729052bcabe05b0afc0441f462299114", size = 1419602 }, - { url = "https://files.pythonhosted.org/packages/8c/82/1fc80cc531ec712872025c19118d78eb23aff09c7144b380c2c4b544b0d1/rapidfuzz-3.11.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:906f1f2a1b91c06599b3dd1be207449c5d4fc7bd1e1fa2f6aef161ea6223f165", size = 5635370 }, - { url = "https://files.pythonhosted.org/packages/3c/5c/007b90af25f98e301b5f7a095059b09f602701443d555724c9226a45514c/rapidfuzz-3.11.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed59044aea9eb6c663112170f2399b040d5d7b162828b141f2673e822093fa8", size = 1680848 }, - { url = "https://files.pythonhosted.org/packages/01/04/e481530eff5d1cf337b86a3095dd4de0b758c37291e51eb0d8c4f7d49719/rapidfuzz-3.11.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cb1965a28b0fa64abdee130c788a0bc0bb3cf9ef7e3a70bf055c086c14a3d7e", size = 1682131 }, - { url = "https://files.pythonhosted.org/packages/10/15/b0ec18edfe6146d8915679644ab7584cd0165724d6a53bcc43bd59f8edb5/rapidfuzz-3.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b488b244931d0291412917e6e46ee9f6a14376625e150056fe7c4426ef28225", size = 3134097 }, - { url = "https://files.pythonhosted.org/packages/8b/0e/cf0a5d62977381bca981fc171fd6c85dc52ca1239eaacf9c1d38978c5866/rapidfuzz-3.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f0ba13557fec9d5ffc0a22826754a7457cc77f1b25145be10b7bb1d143ce84c6", size = 2332928 }, - { url = "https://files.pythonhosted.org/packages/dc/71/568d383eb36586c9e7e13f1327203e2be0938e5ff070c1fa2a99b418808e/rapidfuzz-3.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3871fa7dfcef00bad3c7e8ae8d8fd58089bad6fb21f608d2bf42832267ca9663", size = 6940409 }, - { url = "https://files.pythonhosted.org/packages/ba/23/02972657d69e6d3aae2cdbd67debad080410ff9ef8849d8eab5e580a48a5/rapidfuzz-3.11.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b2669eafee38c5884a6e7cc9769d25c19428549dcdf57de8541cf9e82822e7db", size = 2715928 }, - { url = "https://files.pythonhosted.org/packages/17/17/d964d770faa4e25e125618c00e31607cf8ce639d518fc29d200edf06cfda/rapidfuzz-3.11.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ffa1bb0e26297b0f22881b219ffc82a33a3c84ce6174a9d69406239b14575bd5", size = 3265078 }, - { url = "https://files.pythonhosted.org/packages/bc/13/a117412b1e4ed0bb23b9891a45a59812d96fde8c076b8b8b828aa7ca3710/rapidfuzz-3.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:45b15b8a118856ac9caac6877f70f38b8a0d310475d50bc814698659eabc1cdb", size = 4169215 }, - { url = "https://files.pythonhosted.org/packages/9f/0d/89ef496aedf885db4bfe7f46ac6727666afe0d9d8ca5b4f9c7cc8eef0378/rapidfuzz-3.11.0-cp310-cp310-win32.whl", hash = "sha256:22033677982b9c4c49676f215b794b0404073f8974f98739cb7234e4a9ade9ad", size = 1841736 }, - { url = "https://files.pythonhosted.org/packages/47/9a/69019f4e9c8a42e4aca0169dbae71602aba4e0fa4c5e84515f3ed682e59a/rapidfuzz-3.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:be15496e7244361ff0efcd86e52559bacda9cd975eccf19426a0025f9547c792", size = 1614955 }, - { url = "https://files.pythonhosted.org/packages/37/65/6fb036e39d175299ce44e5186ee2d08b9ea02d732ed6dbd70280f63b4eba/rapidfuzz-3.11.0-cp310-cp310-win_arm64.whl", hash = "sha256:714a7ba31ba46b64d30fccfe95f8013ea41a2e6237ba11a805a27cdd3bce2573", size = 863543 }, - { url = "https://files.pythonhosted.org/packages/30/5a/8ac67667663d24cc4d4b76f63783e58ef03e4d4843d02dab6b2f8470ea5e/rapidfuzz-3.11.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f06e3c4c0a8badfc4910b9fd15beb1ad8f3b8fafa8ea82c023e5e607b66a78e4", size = 1853100 }, - { url = "https://files.pythonhosted.org/packages/dc/72/b043c26e93fb1bc5dfab1e5dd0f8d2f6135c2aa48e6db0660d4ecc5b157a/rapidfuzz-3.11.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fe7aaf5a54821d340d21412f7f6e6272a9b17a0cbafc1d68f77f2fc11009dcd5", size = 1361961 }, - { url = "https://files.pythonhosted.org/packages/5c/4a/29916c0dd853d22ef7b988af43f4e34d327581e16f60b4c9b0f229fa306c/rapidfuzz-3.11.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25398d9ac7294e99876a3027ffc52c6bebeb2d702b1895af6ae9c541ee676702", size = 1354313 }, - { url = "https://files.pythonhosted.org/packages/41/39/f352af4ede7faeeea20bae2537f1fa60c3bbbf2696f0f2f3dda696745239/rapidfuzz-3.11.0-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a52eea839e4bdc72c5e60a444d26004da00bb5bc6301e99b3dde18212e41465", size = 5478019 }, - { url = "https://files.pythonhosted.org/packages/99/8e/86f8a11ac0edda63ff5314d992aa1576fff5d8233f4310d46a6bb0551122/rapidfuzz-3.11.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c87319b0ab9d269ab84f6453601fd49b35d9e4a601bbaef43743f26fabf496c", size = 3056881 }, - { url = "https://files.pythonhosted.org/packages/98/53/222dceb24a83c7d7d76086b6d5bfd3d6aa9988ea73d356d287b5c437c0d5/rapidfuzz-3.11.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3048c6ed29d693fba7d2a7caf165f5e0bb2b9743a0989012a98a47b975355cca", size = 1543944 }, +version = "3.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376 }, + { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903 }, + { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655 }, + { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708 }, + { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106 }, + { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048 }, + { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020 }, + { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958 }, + { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043 }, + { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273 }, + { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875 }, ] [[package]] name = "referencing" -version = "0.36.2" +version = "0.37.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744 } +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775 }, + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766 }, ] [[package]] name = "regex" -version = "2024.11.6" +version = "2025.11.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669 } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674 }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684 }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589 }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511 }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149 }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707 }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702 }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976 }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397 }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726 }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098 }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325 }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277 }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197 }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714 }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042 }, + { url = "https://files.pythonhosted.org/packages/8a/d6/d788d52da01280a30a3f6268aef2aa71043bff359c618fea4c5b536654d5/regex-2025.11.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2b441a4ae2c8049106e8b39973bfbddfb25a179dda2bdb99b0eeb60c40a6a3af", size = 488087 }, + { url = "https://files.pythonhosted.org/packages/69/39/abec3bd688ec9bbea3562de0fd764ff802976185f5ff22807bf0a2697992/regex-2025.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2fa2eed3f76677777345d2f81ee89f5de2f5745910e805f7af7386a920fa7313", size = 290544 }, + { url = "https://files.pythonhosted.org/packages/39/b3/9a231475d5653e60002508f41205c61684bb2ffbf2401351ae2186897fc4/regex-2025.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8b4a27eebd684319bdf473d39f1d79eed36bf2cd34bd4465cdb4618d82b3d56", size = 288408 }, + { url = "https://files.pythonhosted.org/packages/c3/c5/1929a0491bd5ac2d1539a866768b88965fa8c405f3e16a8cef84313098d6/regex-2025.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cf77eac15bd264986c4a2c63353212c095b40f3affb2bc6b4ef80c4776c1a28", size = 781584 }, + { url = "https://files.pythonhosted.org/packages/ce/fd/16aa16cf5d497ef727ec966f74164fbe75d6516d3d58ac9aa989bc9cdaad/regex-2025.11.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b7f9ee819f94c6abfa56ec7b1dbab586f41ebbdc0a57e6524bd5e7f487a878c7", size = 850733 }, + { url = "https://files.pythonhosted.org/packages/e6/49/3294b988855a221cb6565189edf5dc43239957427df2d81d4a6b15244f64/regex-2025.11.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:838441333bc90b829406d4a03cb4b8bf7656231b84358628b0406d803931ef32", size = 898691 }, + { url = "https://files.pythonhosted.org/packages/14/62/b56d29e70b03666193369bdbdedfdc23946dbe9f81dd78ce262c74d988ab/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfe6d3f0c9e3b7e8c0c694b24d25e677776f5ca26dce46fd6b0489f9c8339391", size = 791662 }, + { url = "https://files.pythonhosted.org/packages/15/fc/e4c31d061eced63fbf1ce9d853975f912c61a7d406ea14eda2dd355f48e7/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2ab815eb8a96379a27c3b6157fcb127c8f59c36f043c1678110cea492868f1d5", size = 782587 }, + { url = "https://files.pythonhosted.org/packages/b2/bb/5e30c7394bcf63f0537121c23e796be67b55a8847c3956ae6068f4c70702/regex-2025.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:728a9d2d173a65b62bdc380b7932dd8e74ed4295279a8fe1021204ce210803e7", size = 774709 }, + { url = "https://files.pythonhosted.org/packages/c5/c4/fce773710af81b0cb37cb4ff0947e75d5d17dee304b93d940b87a67fc2f4/regex-2025.11.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:509dc827f89c15c66a0c216331260d777dd6c81e9a4e4f830e662b0bb296c313", size = 845773 }, + { url = "https://files.pythonhosted.org/packages/7b/5e/9466a7ec4b8ec282077095c6eb50a12a389d2e036581134d4919e8ca518c/regex-2025.11.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:849202cd789e5f3cf5dcc7822c34b502181b4824a65ff20ce82da5524e45e8e9", size = 836164 }, + { url = "https://files.pythonhosted.org/packages/95/18/82980a60e8ed1594eb3c89eb814fb276ef51b9af7caeab1340bfd8564af6/regex-2025.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b6f78f98741dcc89607c16b1e9426ee46ce4bf31ac5e6b0d40e81c89f3481ea5", size = 779832 }, + { url = "https://files.pythonhosted.org/packages/03/cc/90ab0fdbe6dce064a42015433f9152710139fb04a8b81b4fb57a1cb63ffa/regex-2025.11.3-cp310-cp310-win32.whl", hash = "sha256:149eb0bba95231fb4f6d37c8f760ec9fa6fabf65bab555e128dde5f2475193ec", size = 265802 }, + { url = "https://files.pythonhosted.org/packages/34/9d/e9e8493a85f3b1ddc4a5014465f5c2b78c3ea1cbf238dcfde78956378041/regex-2025.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:ee3a83ce492074c35a74cc76cf8235d49e77b757193a5365ff86e3f2f93db9fd", size = 277722 }, + { url = "https://files.pythonhosted.org/packages/15/c4/b54b24f553966564506dbf873a3e080aef47b356a3b39b5d5aba992b50db/regex-2025.11.3-cp310-cp310-win_arm64.whl", hash = "sha256:38af559ad934a7b35147716655d4a2f79fcef2d695ddfe06a06ba40ae631fa7e", size = 270289 }, ] [[package]] name = "requests" -version = "2.32.3" +version = "2.32.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, @@ -3433,9 +3770,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, ] [package.optional-dependencies] @@ -3477,116 +3814,154 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, ] +[[package]] +name = "rfc3987-syntax" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lark" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046 }, +] + [[package]] name = "rich" -version = "13.9.4" +version = "14.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, - { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990 } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393 }, ] [[package]] name = "rich-toolkit" -version = "0.13.2" +version = "0.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/8a/71cfbf6bf6257ea785d1f030c22468f763eea1b3e5417620f2ba9abd6dca/rich_toolkit-0.13.2.tar.gz", hash = "sha256:fea92557530de7c28f121cbed572ad93d9e0ddc60c3ca643f1b831f2f56b95d3", size = 72288 } +sdist = { url = "https://files.pythonhosted.org/packages/ad/d0/8f8de36e1abf8339b497ce700dd7251ca465ffca4a1976969b0eaeb596fb/rich_toolkit-0.17.0.tar.gz", hash = "sha256:17ca7a32e613001aa0945ddea27a246f6de01dfc4c12403254c057a8ee542977", size = 187955 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/1b/1c2f43af46456050b27810a7a013af8a7e12bc545a0cdc00eb0df55eb769/rich_toolkit-0.13.2-py3-none-any.whl", hash = "sha256:f3f6c583e5283298a2f7dbd3c65aca18b7f818ad96174113ab5bec0b0e35ed61", size = 13566 }, + { url = "https://files.pythonhosted.org/packages/b2/42/ef2ed40699567661d03b0b511ac46cf6cee736de8f3666819c12d6d20696/rich_toolkit-0.17.0-py3-none-any.whl", hash = "sha256:06fb47a5c5259d6b480287cd38aff5f551b6e1a307f90ed592453dd360e4e71e", size = 31412 }, +] + +[[package]] +name = "rignore" +version = "0.7.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999 }, + { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824 }, + { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121 }, + { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813 }, + { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019 }, + { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822 }, + { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820 }, + { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050 }, + { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164 }, + { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028 }, + { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024 }, + { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531 }, + { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817 }, + { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001 }, + { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462 }, + { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918 }, + { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922 }, + { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987 }, + { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110 }, + { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339 }, + { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680 }, + { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045 }, + { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310 }, + { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998 }, + { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178 }, + { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190 }, ] [[package]] name = "rpds-py" -version = "0.22.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/80/cce854d0921ff2f0a9fa831ba3ad3c65cee3a46711addf39a2af52df2cfd/rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d", size = 26771 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/2a/ead1d09e57449b99dcc190d8d2323e3a167421d8f8fdf0f217c6f6befe47/rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967", size = 359514 }, - { url = "https://files.pythonhosted.org/packages/8f/7e/1254f406b7793b586c68e217a6a24ec79040f85e030fff7e9049069284f4/rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37", size = 349031 }, - { url = "https://files.pythonhosted.org/packages/aa/da/17c6a2c73730d426df53675ff9cc6653ac7a60b6438d03c18e1c822a576a/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24", size = 381485 }, - { url = "https://files.pythonhosted.org/packages/aa/13/2dbacd820466aa2a3c4b747afb18d71209523d353cf865bf8f4796c969ea/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff", size = 386794 }, - { url = "https://files.pythonhosted.org/packages/6d/62/96905d0a35ad4e4bc3c098b2f34b2e7266e211d08635baa690643d2227be/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c", size = 423523 }, - { url = "https://files.pythonhosted.org/packages/eb/1b/d12770f2b6a9fc2c3ec0d810d7d440f6d465ccd8b7f16ae5385952c28b89/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e", size = 446695 }, - { url = "https://files.pythonhosted.org/packages/4d/cf/96f1fd75512a017f8e07408b6d5dbeb492d9ed46bfe0555544294f3681b3/rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec", size = 381959 }, - { url = "https://files.pythonhosted.org/packages/ab/f0/d1c5b501c8aea85aeb938b555bfdf7612110a2f8cdc21ae0482c93dd0c24/rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c", size = 410420 }, - { url = "https://files.pythonhosted.org/packages/33/3b/45b6c58fb6aad5a569ae40fb890fc494c6b02203505a5008ee6dc68e65f7/rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09", size = 557620 }, - { url = "https://files.pythonhosted.org/packages/83/62/3fdd2d3d47bf0bb9b931c4c73036b4ab3ec77b25e016ae26fab0f02be2af/rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00", size = 584202 }, - { url = "https://files.pythonhosted.org/packages/04/f2/5dced98b64874b84ca824292f9cee2e3f30f3bcf231d15a903126684f74d/rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf", size = 552787 }, - { url = "https://files.pythonhosted.org/packages/67/13/2273dea1204eda0aea0ef55145da96a9aa28b3f88bb5c70e994f69eda7c3/rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652", size = 220088 }, - { url = "https://files.pythonhosted.org/packages/4e/80/8c8176b67ad7f4a894967a7a4014ba039626d96f1d4874d53e409b58d69f/rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8", size = 231737 }, - { url = "https://files.pythonhosted.org/packages/8b/63/e29f8ee14fcf383574f73b6bbdcbec0fbc2e5fc36b4de44d1ac389b1de62/rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d", size = 360786 }, - { url = "https://files.pythonhosted.org/packages/d3/e0/771ee28b02a24e81c8c0e645796a371350a2bb6672753144f36ae2d2afc9/rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd", size = 350589 }, - { url = "https://files.pythonhosted.org/packages/cf/49/abad4c4a1e6f3adf04785a99c247bfabe55ed868133e2d1881200aa5d381/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493", size = 381848 }, - { url = "https://files.pythonhosted.org/packages/3a/7d/f4bc6d6fbe6af7a0d2b5f2ee77079efef7c8528712745659ec0026888998/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96", size = 387879 }, - { url = "https://files.pythonhosted.org/packages/13/b0/575c797377fdcd26cedbb00a3324232e4cb2c5d121f6e4b0dbf8468b12ef/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123", size = 423916 }, - { url = "https://files.pythonhosted.org/packages/54/78/87157fa39d58f32a68d3326f8a81ad8fb99f49fe2aa7ad9a1b7d544f9478/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad", size = 448410 }, - { url = "https://files.pythonhosted.org/packages/59/69/860f89996065a88be1b6ff2d60e96a02b920a262d8aadab99e7903986597/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9", size = 382841 }, - { url = "https://files.pythonhosted.org/packages/bd/d7/bc144e10d27e3cb350f98df2492a319edd3caaf52ddfe1293f37a9afbfd7/rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e", size = 409662 }, - { url = "https://files.pythonhosted.org/packages/14/2a/6bed0b05233c291a94c7e89bc76ffa1c619d4e1979fbfe5d96024020c1fb/rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338", size = 558221 }, - { url = "https://files.pythonhosted.org/packages/11/23/cd8f566de444a137bc1ee5795e47069a947e60810ba4152886fe5308e1b7/rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566", size = 583780 }, - { url = "https://files.pythonhosted.org/packages/8d/63/79c3602afd14d501f751e615a74a59040328da5ef29ed5754ae80d236b84/rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe", size = 553619 }, - { url = "https://files.pythonhosted.org/packages/9f/2e/c5c1689e80298d4e94c75b70faada4c25445739d91b94c211244a3ed7ed1/rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d", size = 233338 }, +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490 }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751 }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696 }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136 }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699 }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022 }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522 }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579 }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305 }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503 }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322 }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792 }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901 }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823 }, ] [[package]] name = "rsa" -version = "4.9" +version = "4.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/aa/65/7d973b89c4d2351d7fb232c2e452547ddfa243e93131e7cfa766da627b52/rsa-4.9.tar.gz", hash = "sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21", size = 29711 } +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } wheels = [ - { url = "https://files.pythonhosted.org/packages/49/97/fa78e3d2f65c02c8e1268b9aba606569fe97f6c8f7c2d74394553347c145/rsa-4.9-py3-none-any.whl", hash = "sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7", size = 34315 }, + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, ] [[package]] name = "s3transfer" -version = "0.11.2" +version = "0.16.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/62/45/2323b5928f86fd29f9afdcef4659f68fa73eaa5356912b774227f5cf46b5/s3transfer-0.11.2.tar.gz", hash = "sha256:3b39185cb72f5acc77db1a58b6e25b977f28d20496b6e58d6813d75f464d632f", size = 147885 } +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/ac/e7dc469e49048dc57f62e0c555d2ee3117fa30813d2a1a2962cce3a2a82a/s3transfer-0.11.2-py3-none-any.whl", hash = "sha256:be6ecb39fadd986ef1701097771f87e4d2f821f27f6071c872143884d2950fbc", size = 84151 }, + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830 }, ] [[package]] name = "safetensors" -version = "0.5.2" +version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f4/4f/2ef9ef1766f8c194b01b67a63a444d2e557c8fe1d82faf3ebd85f370a917/safetensors-0.5.2.tar.gz", hash = "sha256:cb4a8d98ba12fa016f4241932b1fc5e702e5143f5374bba0bbcf7ddc1c4cf2b8", size = 66957 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/96/d1/017e31e75e274492a11a456a9e7c171f8f7911fe50735b4ec6ff37221220/safetensors-0.5.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:45b6092997ceb8aa3801693781a71a99909ab9cc776fbc3fa9322d29b1d3bef2", size = 427067 }, - { url = "https://files.pythonhosted.org/packages/24/84/e9d3ff57ae50dd0028f301c9ee064e5087fe8b00e55696677a0413c377a7/safetensors-0.5.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6d0d6a8ee2215a440e1296b843edf44fd377b055ba350eaba74655a2fe2c4bae", size = 408856 }, - { url = "https://files.pythonhosted.org/packages/f1/1d/fe95f5dd73db16757b11915e8a5106337663182d0381811c81993e0014a9/safetensors-0.5.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86016d40bcaa3bcc9a56cd74d97e654b5f4f4abe42b038c71e4f00a089c4526c", size = 450088 }, - { url = "https://files.pythonhosted.org/packages/cf/21/e527961b12d5ab528c6e47b92d5f57f33563c28a972750b238b871924e49/safetensors-0.5.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:990833f70a5f9c7d3fc82c94507f03179930ff7d00941c287f73b6fcbf67f19e", size = 458966 }, - { url = "https://files.pythonhosted.org/packages/a5/8b/1a037d7a57f86837c0b41905040369aea7d8ca1ec4b2a77592372b2ec380/safetensors-0.5.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3dfa7c2f3fe55db34eba90c29df94bcdac4821043fc391cb5d082d9922013869", size = 509915 }, - { url = "https://files.pythonhosted.org/packages/61/3d/03dd5cfd33839df0ee3f4581a20bd09c40246d169c0e4518f20b21d5f077/safetensors-0.5.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:46ff2116150ae70a4e9c490d2ab6b6e1b1b93f25e520e540abe1b81b48560c3a", size = 527664 }, - { url = "https://files.pythonhosted.org/packages/c5/dc/8952caafa9a10a3c0f40fa86bacf3190ae7f55fa5eef87415b97b29cb97f/safetensors-0.5.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab696dfdc060caffb61dbe4066b86419107a24c804a4e373ba59be699ebd8d5", size = 461978 }, - { url = "https://files.pythonhosted.org/packages/60/da/82de1fcf1194e3dbefd4faa92dc98b33c06bed5d67890e0962dd98e18287/safetensors-0.5.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:03c937100f38c9ff4c1507abea9928a6a9b02c9c1c9c3609ed4fb2bf413d4975", size = 491253 }, - { url = "https://files.pythonhosted.org/packages/5a/9a/d90e273c25f90c3ba1b0196a972003786f04c39e302fbd6649325b1272bb/safetensors-0.5.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:a00e737948791b94dad83cf0eafc09a02c4d8c2171a239e8c8572fe04e25960e", size = 628644 }, - { url = "https://files.pythonhosted.org/packages/70/3c/acb23e05aa34b4f5edd2e7f393f8e6480fbccd10601ab42cd03a57d4ab5f/safetensors-0.5.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:d3a06fae62418ec8e5c635b61a8086032c9e281f16c63c3af46a6efbab33156f", size = 721648 }, - { url = "https://files.pythonhosted.org/packages/71/45/eaa3dba5253a7c6931230dc961641455710ab231f8a89cb3c4c2af70f8c8/safetensors-0.5.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:1506e4c2eda1431099cebe9abf6c76853e95d0b7a95addceaa74c6019c65d8cf", size = 659588 }, - { url = "https://files.pythonhosted.org/packages/b0/71/2f9851164f821064d43b481ddbea0149c2d676c4f4e077b178e7eeaa6660/safetensors-0.5.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5c5b5d9da594f638a259fca766046f44c97244cc7ab8bef161b3e80d04becc76", size = 632533 }, - { url = "https://files.pythonhosted.org/packages/00/f1/5680e2ef61d9c61454fad82c344f0e40b8741a9dbd1e31484f0d31a9b1c3/safetensors-0.5.2-cp38-abi3-win32.whl", hash = "sha256:fe55c039d97090d1f85277d402954dd6ad27f63034fa81985a9cc59655ac3ee2", size = 291167 }, - { url = "https://files.pythonhosted.org/packages/86/ca/aa489392ec6fb59223ffce825461e1f811a3affd417121a2088be7a5758b/safetensors-0.5.2-cp38-abi3-win_amd64.whl", hash = "sha256:78abdddd03a406646107f973c7843276e7b64e5e32623529dc17f3d94a20f589", size = 303756 }, +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781 }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058 }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748 }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881 }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463 }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855 }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152 }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856 }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060 }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715 }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377 }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368 }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423 }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380 }, + { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430 }, + { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890 }, + { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885 }, ] [[package]] name = "scikit-learn" -version = "1.5.2" +version = "1.7.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "joblib" }, @@ -3594,13 +3969,13 @@ dependencies = [ { name = "scipy" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/37/59/44985a2bdc95c74e34fef3d10cb5d93ce13b0e2a7baefffe1b53853b502d/scikit_learn-1.5.2.tar.gz", hash = "sha256:b4237ed7b3fdd0a4882792e68ef2545d5baa50aca3bb45aa7df468138ad8f94d", size = 7001680 } +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/89/be41419b4bec629a4691183a5eb1796f91252a13a5ffa243fd958cad7e91/scikit_learn-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:299406827fb9a4f862626d0fe6c122f5f87f8910b86fe5daa4c32dcd742139b6", size = 12106070 }, - { url = "https://files.pythonhosted.org/packages/bf/e0/3b6d777d375f3b685f433c93384cdb724fb078e1dc8f8ff0950467e56c30/scikit_learn-1.5.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:2d4cad1119c77930b235579ad0dc25e65c917e756fe80cab96aa3b9428bd3fb0", size = 10971758 }, - { url = "https://files.pythonhosted.org/packages/7b/31/eb7dd56c371640753953277de11356c46a3149bfeebb3d7dcd90b993715a/scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c412ccc2ad9bf3755915e3908e677b367ebc8d010acbb3f182814524f2e5540", size = 12500080 }, - { url = "https://files.pythonhosted.org/packages/4c/1e/a7c7357e704459c7d56a18df4a0bf08669442d1f8878cc0864beccd6306a/scikit_learn-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a686885a4b3818d9e62904d91b57fa757fc2bed3e465c8b177be652f4dd37c8", size = 13347241 }, - { url = "https://files.pythonhosted.org/packages/48/76/154ebda6794faf0b0f3ccb1b5cd9a19f0a63cb9e1f3d2c61b6114002677b/scikit_learn-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:c15b1ca23d7c5f33cc2cb0a0d6aaacf893792271cddff0edbd6a40e8319bc113", size = 11000477 }, + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221 }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834 }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938 }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818 }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969 }, ] [[package]] @@ -3666,6 +4041,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072 }, ] +[[package]] +name = "sentence-transformers" +version = "5.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "pillow" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "transformers" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/96/f3f3409179d14dbfdbea8622e2e9eaa3c8836ddcaecd2cd5ff0a11731d20/sentence_transformers-5.1.2.tar.gz", hash = "sha256:0f6c8bd916a78dc65b366feb8d22fd885efdb37432e7630020d113233af2b856", size = 375185 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/a6/a607a737dc1a00b7afe267b9bfde101b8cee2529e197e57471d23137d4e5/sentence_transformers-5.1.2-py3-none-any.whl", hash = "sha256:724ce0ea62200f413f1a5059712aff66495bc4e815a1493f7f9bca242414c333", size = 488009 }, +] + [[package]] name = "sentencepiece" version = "0.2.0" @@ -3682,13 +4076,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525 }, ] +[[package]] +name = "sentry-sdk" +version = "2.47.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4a/2a/d225cbf87b6c8ecce5664db7bcecb82c317e448e3b24a2dcdaacb18ca9a7/sentry_sdk-2.47.0.tar.gz", hash = "sha256:8218891d5e41b4ea8d61d2aed62ed10c80e39d9f2959d6f939efbf056857e050", size = 381895 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/ac/d6286ea0d49e7b58847faf67b00e56bb4ba3d525281e2ac306e1f1f353da/sentry_sdk-2.47.0-py2.py3-none-any.whl", hash = "sha256:d72f8c61025b7d1d9e52510d03a6247b280094a327dd900d987717a4fce93412", size = 411088 }, +] + [[package]] name = "setuptools" -version = "75.8.0" +version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/92/ec/089608b791d210aec4e7f97488e67ab0d33add3efccb83a056cbafe3a2a6/setuptools-75.8.0.tar.gz", hash = "sha256:c5afc8f407c626b8313a86e10311dd3f661c6cd9c09d4bf8c15c0e11f9f2b0e6", size = 1343222 } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 }, ] [[package]] @@ -3738,11 +4145,11 @@ wheels = [ [[package]] name = "soupsieve" -version = "2.6" +version = "2.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } +sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, + { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679 }, ] [[package]] @@ -3755,23 +4162,23 @@ wheels = [ [[package]] name = "sqlalchemy" -version = "2.0.37" +version = "2.0.44" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3b/20/93ea2518df4d7a14ebe9ace9ab8bb92aaf7df0072b9007644de74172b06c/sqlalchemy-2.0.37.tar.gz", hash = "sha256:12b28d99a9c14eaf4055810df1001557176716de0167b91026e648e65229bffb", size = 9626249 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830 } wheels = [ - { url = "https://files.pythonhosted.org/packages/80/21/aaf0cd2e7ee56e464af7cba38a54f9c1203570181ec5d847711f33c9f520/SQLAlchemy-2.0.37-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da36c3b0e891808a7542c5c89f224520b9a16c7f5e4d6a1156955605e54aef0e", size = 2102915 }, - { url = "https://files.pythonhosted.org/packages/fd/01/6615256759515f13bb7d7b49981326f1f4e80ff1bd92dccd53f99dab79ea/SQLAlchemy-2.0.37-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e7402ff96e2b073a98ef6d6142796426d705addd27b9d26c3b32dbaa06d7d069", size = 2094095 }, - { url = "https://files.pythonhosted.org/packages/6a/f2/400252bda1bd67da7a35bb2ab84d10a8ad43975d42f15b207a9efb765446/SQLAlchemy-2.0.37-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f5d254a22394847245f411a2956976401e84da4288aa70cbcd5190744062c1", size = 3076482 }, - { url = "https://files.pythonhosted.org/packages/40/c6/e7e8e894c8f065f96ca202cdb00454d60d4962279b3eb5a81b8766dfa836/SQLAlchemy-2.0.37-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:41296bbcaa55ef5fdd32389a35c710133b097f7b2609d8218c0eabded43a1d84", size = 3084750 }, - { url = "https://files.pythonhosted.org/packages/d6/ee/1cdab04b7760e48273f2592037df156afae044e2e6589157673bd2a830c0/SQLAlchemy-2.0.37-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bedee60385c1c0411378cbd4dc486362f5ee88deceea50002772912d798bb00f", size = 3040575 }, - { url = "https://files.pythonhosted.org/packages/4d/af/2dd456bfd8d4b9750792ceedd828bddf83860f2420545e5effbaf722dae5/SQLAlchemy-2.0.37-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:6c67415258f9f3c69867ec02fea1bf6508153709ecbd731a982442a590f2b7e4", size = 3066113 }, - { url = "https://files.pythonhosted.org/packages/dd/d7/ad997559574f94d7bd895a8a63996afef518d07e9eaf5a2a9cbbcb877c16/SQLAlchemy-2.0.37-cp310-cp310-win32.whl", hash = "sha256:650dcb70739957a492ad8acff65d099a9586b9b8920e3507ca61ec3ce650bb72", size = 2075239 }, - { url = "https://files.pythonhosted.org/packages/d0/82/141fbed705a21af2d825068831da1d80d720945df60c2b97ddc5133b3714/SQLAlchemy-2.0.37-cp310-cp310-win_amd64.whl", hash = "sha256:93d1543cd8359040c02b6614421c8e10cd7a788c40047dbc507ed46c29ae5636", size = 2099307 }, - { url = "https://files.pythonhosted.org/packages/3b/36/59cc97c365f2f79ac9f3f51446cae56dfd82c4f2dd98497e6be6de20fb91/SQLAlchemy-2.0.37-py3-none-any.whl", hash = "sha256:a8998bf9f8658bd3839cbc44ddbe982955641863da0c1efe5b00c1ab4f5c16b1", size = 1894113 }, + { url = "https://files.pythonhosted.org/packages/a2/a7/e9ccfa7eecaf34c6f57d8cb0bb7cbdeeff27017cc0f5d0ca90fdde7a7c0d/sqlalchemy-2.0.44-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce", size = 2137282 }, + { url = "https://files.pythonhosted.org/packages/b1/e1/50bc121885bdf10833a4f65ecbe9fe229a3215f4d65a58da8a181734cae3/sqlalchemy-2.0.44-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985", size = 2127322 }, + { url = "https://files.pythonhosted.org/packages/46/f2/a8573b7230a3ce5ee4b961a2d510d71b43872513647398e595b744344664/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0", size = 3214772 }, + { url = "https://files.pythonhosted.org/packages/4a/d8/c63d8adb6a7edaf8dcb6f75a2b1e9f8577960a1e489606859c4d73e7d32b/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e", size = 3214434 }, + { url = "https://files.pythonhosted.org/packages/ee/a6/243d277a4b54fae74d4797957a7320a5c210c293487f931cbe036debb697/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749", size = 3155365 }, + { url = "https://files.pythonhosted.org/packages/5f/f8/6a39516ddd75429fd4ee5a0d72e4c80639fab329b2467c75f363c2ed9751/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2", size = 3178910 }, + { url = "https://files.pythonhosted.org/packages/43/f0/118355d4ad3c39d9a2f5ee4c7304a9665b3571482777357fa9920cd7a6b4/sqlalchemy-2.0.44-cp310-cp310-win32.whl", hash = "sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165", size = 2105624 }, + { url = "https://files.pythonhosted.org/packages/61/83/6ae5f9466f8aa5d0dcebfff8c9c33b98b27ce23292df3b990454b3d434fd/sqlalchemy-2.0.44-cp310-cp310-win_amd64.whl", hash = "sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5", size = 2129240 }, + { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718 }, ] [[package]] @@ -3809,14 +4216,49 @@ wheels = [ [[package]] name = "starlette" -version = "0.45.3" +version = "0.50.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033 }, +] + +[[package]] +name = "streamlit" +version = "1.21.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "altair" }, + { name = "blinker" }, + { name = "cachetools" }, + { name = "click" }, + { name = "gitpython" }, + { name = "importlib-metadata" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pillow" }, + { name = "protobuf" }, + { name = "pyarrow" }, + { name = "pydeck" }, + { name = "pympler" }, + { name = "python-dateutil" }, + { name = "requests" }, + { name = "rich" }, + { name = "toml" }, + { name = "tornado" }, + { name = "typing-extensions" }, + { name = "tzlocal" }, + { name = "validators" }, + { name = "watchdog", marker = "platform_system != 'Darwin'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/fb/2984a686808b89a6781526129a4b51266f678b2d2b97ab2d325e56116df8/starlette-0.45.3.tar.gz", hash = "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f", size = 2574076 } +sdist = { url = "https://files.pythonhosted.org/packages/17/95/89b0f5f51cd006ffb6cc216393793d05029c47e97f140a9bff02f8c291a8/streamlit-1.21.0.tar.gz", hash = "sha256:c72d9639508679c5e411d1f886d213777759501d01975285c049dc30db463c1a", size = 9345809 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/61/f2b52e107b1fc8944b33ef56bf6ac4ebbe16d91b94d2b87ce013bf63fb84/starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d", size = 71507 }, + { url = "https://files.pythonhosted.org/packages/22/fa/5b010610aa136c44a20de6ed9ec0b36867daf7322d0e3c8e626a99fab11a/streamlit-1.21.0-py2.py3-none-any.whl", hash = "sha256:05862598952a9126e16652caa5bc88eeeea7b2773af252e2daccf1c84ceaaef4", size = 9665093 }, ] [[package]] @@ -3876,11 +4318,11 @@ wheels = [ [[package]] name = "tenacity" -version = "9.0.0" +version = "9.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/94/91fccdb4b8110642462e653d5dcb27e7b674742ad68efd146367da7bdb10/tenacity-9.0.0.tar.gz", hash = "sha256:807f37ca97d62aa361264d497b0e31e92b8027044942bfa756160d908320d73b", size = 47421 } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/cb/b86984bed139586d01532a587464b5805f12e397594f19f931c4c2fbfa61/tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539", size = 28169 }, + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 }, ] [[package]] @@ -4005,38 +4447,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f3/48/47b7d25572961a48b1de3729b7a11e835b888e41e0203cca82df95d23b91/tensorflow_io_gcs_filesystem-0.37.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9679b36e3a80921876f31685ab6f7270f3411a4cc51bc2847e80d0e4b5291e27", size = 5085736 }, ] -[[package]] -name = "tensorflow-macos" -version = "2.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "astunparse" }, - { name = "flatbuffers" }, - { name = "gast" }, - { name = "google-pasta" }, - { name = "grpcio" }, - { name = "h5py" }, - { name = "keras" }, - { name = "keras-preprocessing" }, - { name = "libclang" }, - { name = "numpy" }, - { name = "opt-einsum" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "setuptools" }, - { name = "six" }, - { name = "tensorboard" }, - { name = "tensorflow-estimator" }, - { name = "termcolor" }, - { name = "typing-extensions" }, - { name = "wrapt" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/18/d7d06e1c8bf4cafd091d62854b8e6a9e8db176c1b1a5171a586ec17d4b54/tensorflow_macos-2.10.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:dfd1dd478b3ae01e8d578c38083bef68bc838ceaa05a813b6788fe9e6ec19140", size = 211520008 }, - { url = "https://files.pythonhosted.org/packages/6f/a1/3bd220bacb1dcd4eea526c4b5376eddfb0fbb156c9814684dc9be24b7bc8/tensorflow_macos-2.10.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:aa074b5442d3411e5416c5112531d8b78a8c469ca92fa41c0e0cf14428608bf3", size = 245993233 }, -] - [[package]] name = "tensorflow-text" version = "2.10.0" @@ -4044,7 +4454,6 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tensorflow", marker = "platform_machine != 'arm64' or platform_system != 'Darwin'" }, { name = "tensorflow-hub" }, - { name = "tensorflow-macos", marker = "platform_machine == 'arm64' and platform_system == 'Darwin'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/ef/64/489c459f46f678ec4822b815ba9dfb1182c351e2208e98b6e83543254b55/tensorflow_text-2.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84b76847189d0d7bc8d4a130f0617e13bc9b810cf1feeb9c49da2906a2f39785", size = 5621257 }, @@ -4054,11 +4463,11 @@ wheels = [ [[package]] name = "termcolor" -version = "2.5.0" +version = "3.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/72/88311445fd44c455c7d553e61f95412cf89054308a1aa2434ab835075fc5/termcolor-2.5.0.tar.gz", hash = "sha256:998d8d27da6d48442e8e1f016119076b690d962507531df4890fcd2db2ef8a6f", size = 13057 } +sdist = { url = "https://files.pythonhosted.org/packages/87/56/ab275c2b56a5e2342568838f0d5e3e66a32354adcc159b495e374cda43f5/termcolor-3.2.0.tar.gz", hash = "sha256:610e6456feec42c4bcd28934a8c87a06c3fa28b01561d46aa09a9881b8622c58", size = 14423 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/be/df630c387a0a054815d60be6a97eb4e8f17385d5d6fe660e1c02750062b4/termcolor-2.5.0-py3-none-any.whl", hash = "sha256:37b17b5fc1e604945c2642c872a3764b5d547a48009871aea3edd3afa180afb8", size = 7755 }, + { url = "https://files.pythonhosted.org/packages/f9/d5/141f53d7c1eb2a80e6d3e9a390228c3222c27705cbe7f048d3623053f3ca/termcolor-3.2.0-py3-none-any.whl", hash = "sha256:a10343879eba4da819353c55cb8049b0933890c2ebf9ad5d3ecd2bb32ea96ea6", size = 7698 }, ] [[package]] @@ -4107,11 +4516,30 @@ wheels = [ [[package]] name = "threadpoolctl" -version = "3.5.0" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638 }, +] + +[[package]] +name = "tiktoken" +version = "0.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/55/b5148dcbf72f5cde221f8bfe3b6a540da7aa1842f6b491ad979a6c8b84af/threadpoolctl-3.5.0.tar.gz", hash = "sha256:082433502dd922bf738de0d8bcc4fdcbf0979ff44c42bd40f5af8a282f6fa107", size = 41936 } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/2c/ffbf7a134b9ab11a67b0cf0726453cedd9c5043a4fe7a35d1cefa9a1bcfb/threadpoolctl-3.5.0-py3-none-any.whl", hash = "sha256:56c1e26c150397e58c4926da8eeee87533b1e32bef131bd4bf6a2f45f3185467", size = 18414 }, + { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991 }, + { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798 }, + { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865 }, + { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856 }, + { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308 }, + { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697 }, + { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, ] [[package]] @@ -4147,27 +4575,36 @@ wheels = [ [[package]] name = "tokenizers" -version = "0.21.0" +version = "0.21.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/41/c2be10975ca37f6ec40d7abd7e98a5213bb04f284b869c1a24e6504fd94d/tokenizers-0.21.0.tar.gz", hash = "sha256:ee0894bf311b75b0c03079f33859ae4b2334d675d4e93f5a4132e1eae2834fe4", size = 343021 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/2f/402986d0823f8d7ca139d969af2917fefaa9b947d1fb32f6168c509f2492/tokenizers-0.21.4.tar.gz", hash = "sha256:fa23f85fbc9a02ec5c6978da172cdcbac23498c3ca9f3645c5c68740ac007880", size = 351253 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/5c/8b09607b37e996dc47e70d6a7b6f4bdd4e4d5ab22fe49d7374565c7fefaf/tokenizers-0.21.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3c4c93eae637e7d2aaae3d376f06085164e1660f89304c0ab2b1d08a406636b2", size = 2647461 }, - { url = "https://files.pythonhosted.org/packages/22/7a/88e58bb297c22633ed1c9d16029316e5b5ac5ee44012164c2edede599a5e/tokenizers-0.21.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:f53ea537c925422a2e0e92a24cce96f6bc5046bbef24a1652a5edc8ba975f62e", size = 2563639 }, - { url = "https://files.pythonhosted.org/packages/f7/14/83429177c19364df27d22bc096d4c2e431e0ba43e56c525434f1f9b0fd00/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b177fb54c4702ef611de0c069d9169f0004233890e0c4c5bd5508ae05abf193", size = 2903304 }, - { url = "https://files.pythonhosted.org/packages/7e/db/3433eab42347e0dc5452d8fcc8da03f638c9accffefe5a7c78146666964a/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6b43779a269f4629bebb114e19c3fca0223296ae9fea8bb9a7a6c6fb0657ff8e", size = 2804378 }, - { url = "https://files.pythonhosted.org/packages/57/8b/7da5e6f89736c2ade02816b4733983fca1c226b0c42980b1ae9dc8fcf5cc/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aeb255802be90acfd363626753fda0064a8df06031012fe7d52fd9a905eb00e", size = 3095488 }, - { url = "https://files.pythonhosted.org/packages/4d/f6/5ed6711093dc2c04a4e03f6461798b12669bc5a17c8be7cce1240e0b5ce8/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8b09dbeb7a8d73ee204a70f94fc06ea0f17dcf0844f16102b9f414f0b7463ba", size = 3121410 }, - { url = "https://files.pythonhosted.org/packages/81/42/07600892d48950c5e80505b81411044a2d969368cdc0d929b1c847bf6697/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:400832c0904f77ce87c40f1a8a27493071282f785724ae62144324f171377273", size = 3388821 }, - { url = "https://files.pythonhosted.org/packages/22/06/69d7ce374747edaf1695a4f61b83570d91cc8bbfc51ccfecf76f56ab4aac/tokenizers-0.21.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84ca973b3a96894d1707e189c14a774b701596d579ffc7e69debfc036a61a04", size = 3008868 }, - { url = "https://files.pythonhosted.org/packages/c8/69/54a0aee4d576045b49a0eb8bffdc495634309c823bf886042e6f46b80058/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:eb7202d231b273c34ec67767378cd04c767e967fda12d4a9e36208a34e2f137e", size = 8975831 }, - { url = "https://files.pythonhosted.org/packages/f7/f3/b776061e4f3ebf2905ba1a25d90380aafd10c02d406437a8ba22d1724d76/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:089d56db6782a73a27fd8abf3ba21779f5b85d4a9f35e3b493c7bbcbbf0d539b", size = 8920746 }, - { url = "https://files.pythonhosted.org/packages/d8/ee/ce83d5ec8b6844ad4c3ecfe3333d58ecc1adc61f0878b323a15355bcab24/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:c87ca3dc48b9b1222d984b6b7490355a6fdb411a2d810f6f05977258400ddb74", size = 9161814 }, - { url = "https://files.pythonhosted.org/packages/18/07/3e88e65c0ed28fa93aa0c4d264988428eef3df2764c3126dc83e243cb36f/tokenizers-0.21.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4145505a973116f91bc3ac45988a92e618a6f83eb458f49ea0790df94ee243ff", size = 9357138 }, - { url = "https://files.pythonhosted.org/packages/15/b0/dc4572ca61555fc482ebc933f26cb407c6aceb3dc19c301c68184f8cad03/tokenizers-0.21.0-cp39-abi3-win32.whl", hash = "sha256:eb1702c2f27d25d9dd5b389cc1f2f51813e99f8ca30d9e25348db6585a97e24a", size = 2202266 }, - { url = "https://files.pythonhosted.org/packages/44/69/d21eb253fa91622da25585d362a874fa4710be600f0ea9446d8d0217cec1/tokenizers-0.21.0-cp39-abi3-win_amd64.whl", hash = "sha256:87841da5a25a3a5f70c102de371db120f41873b854ba65e52bccd57df5a3780c", size = 2389192 }, + { url = "https://files.pythonhosted.org/packages/98/c6/fdb6f72bf6454f52eb4a2510be7fb0f614e541a2554d6210e370d85efff4/tokenizers-0.21.4-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ccc10a7c3bcefe0f242867dc914fc1226ee44321eb618cfe3019b5df3400133", size = 2863987 }, + { url = "https://files.pythonhosted.org/packages/8d/a6/28975479e35ddc751dc1ddc97b9b69bf7fcf074db31548aab37f8116674c/tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5e2f601a8e0cd5be5cc7506b20a79112370b9b3e9cb5f13f68ab11acd6ca7d60", size = 2732457 }, + { url = "https://files.pythonhosted.org/packages/aa/8f/24f39d7b5c726b7b0be95dca04f344df278a3fe3a4deb15a975d194cbb32/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b376f5a1aee67b4d29032ee85511bbd1b99007ec735f7f35c8a2eb104eade5", size = 3012624 }, + { url = "https://files.pythonhosted.org/packages/58/47/26358925717687a58cb74d7a508de96649544fad5778f0cd9827398dc499/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2107ad649e2cda4488d41dfd031469e9da3fcbfd6183e74e4958fa729ffbf9c6", size = 2939681 }, + { url = "https://files.pythonhosted.org/packages/99/6f/cc300fea5db2ab5ddc2c8aea5757a27b89c84469899710c3aeddc1d39801/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c73012da95afafdf235ba80047699df4384fdc481527448a078ffd00e45a7d9", size = 3247445 }, + { url = "https://files.pythonhosted.org/packages/be/bf/98cb4b9c3c4afd8be89cfa6423704337dc20b73eb4180397a6e0d456c334/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f23186c40395fc390d27f519679a58023f368a0aad234af145e0f39ad1212732", size = 3428014 }, + { url = "https://files.pythonhosted.org/packages/75/c7/96c1cc780e6ca7f01a57c13235dd05b7bc1c0f3588512ebe9d1331b5f5ae/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc88bb34e23a54cc42713d6d98af5f1bf79c07653d24fe984d2d695ba2c922a2", size = 3193197 }, + { url = "https://files.pythonhosted.org/packages/f2/90/273b6c7ec78af547694eddeea9e05de771278bd20476525ab930cecaf7d8/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51b7eabb104f46c1c50b486520555715457ae833d5aee9ff6ae853d1130506ff", size = 3115426 }, + { url = "https://files.pythonhosted.org/packages/91/43/c640d5a07e95f1cf9d2c92501f20a25f179ac53a4f71e1489a3dcfcc67ee/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:714b05b2e1af1288bd1bc56ce496c4cebb64a20d158ee802887757791191e6e2", size = 9089127 }, + { url = "https://files.pythonhosted.org/packages/44/a1/dd23edd6271d4dca788e5200a807b49ec3e6987815cd9d0a07ad9c96c7c2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:1340ff877ceedfa937544b7d79f5b7becf33a4cfb58f89b3b49927004ef66f78", size = 9055243 }, + { url = "https://files.pythonhosted.org/packages/21/2b/b410d6e9021c4b7ddb57248304dc817c4d4970b73b6ee343674914701197/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3c1f4317576e465ac9ef0d165b247825a2a4078bcd01cba6b54b867bdf9fdd8b", size = 9298237 }, + { url = "https://files.pythonhosted.org/packages/b7/0a/42348c995c67e2e6e5c89ffb9cfd68507cbaeb84ff39c49ee6e0a6dd0fd2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c212aa4e45ec0bb5274b16b6f31dd3f1c41944025c2358faaa5782c754e84c24", size = 9461980 }, + { url = "https://files.pythonhosted.org/packages/3d/d3/dacccd834404cd71b5c334882f3ba40331ad2120e69ded32cf5fda9a7436/tokenizers-0.21.4-cp39-abi3-win32.whl", hash = "sha256:6c42a930bc5f4c47f4ea775c91de47d27910881902b0f20e4990ebe045a415d0", size = 2329871 }, + { url = "https://files.pythonhosted.org/packages/41/f2/fd673d979185f5dcbac4be7d09461cbb99751554ffb6718d0013af8604cb/tokenizers-0.21.4-cp39-abi3-win_amd64.whl", hash = "sha256:475d807a5c3eb72c59ad9b5fcdb254f6e17f53dfcbb9903233b0dfa9c943b597", size = 2507568 }, +] + +[[package]] +name = "toml" +version = "0.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, ] [[package]] @@ -4181,11 +4618,20 @@ wheels = [ [[package]] name = "tomli" -version = "2.2.1" +version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408 }, +] + +[[package]] +name = "toolz" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/d6/114b492226588d6ff54579d95847662fc69196bdeec318eb45393b24c192/toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b", size = 52613 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8", size = 58093 }, ] [[package]] @@ -4264,20 +4710,21 @@ wheels = [ [[package]] name = "tornado" -version = "6.4.2" +version = "6.5.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/59/45/a0daf161f7d6f36c3ea5fc0c2de619746cc3dd4c76402e9db545bd920f63/tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b", size = 501135 } +sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821 } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/7e/71f604d8cea1b58f82ba3590290b66da1e72d840aeb37e0d5f7291bd30db/tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1", size = 436299 }, - { url = "https://files.pythonhosted.org/packages/96/44/87543a3b99016d0bf54fdaab30d24bf0af2e848f1d13d34a3a5380aabe16/tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803", size = 434253 }, - { url = "https://files.pythonhosted.org/packages/cb/fb/fdf679b4ce51bcb7210801ef4f11fdac96e9885daa402861751353beea6e/tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec", size = 437602 }, - { url = "https://files.pythonhosted.org/packages/4f/3b/e31aeffffc22b475a64dbeb273026a21b5b566f74dee48742817626c47dc/tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946", size = 436972 }, - { url = "https://files.pythonhosted.org/packages/22/55/b78a464de78051a30599ceb6983b01d8f732e6f69bf37b4ed07f642ac0fc/tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf", size = 437173 }, - { url = "https://files.pythonhosted.org/packages/79/5e/be4fb0d1684eb822c9a62fb18a3e44a06188f78aa466b2ad991d2ee31104/tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634", size = 437892 }, - { url = "https://files.pythonhosted.org/packages/f5/33/4f91fdd94ea36e1d796147003b490fe60a0215ac5737b6f9c65e160d4fe0/tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73", size = 437334 }, - { url = "https://files.pythonhosted.org/packages/2b/ae/c1b22d4524b0e10da2f29a176fb2890386f7bd1f63aacf186444873a88a0/tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c", size = 437261 }, - { url = "https://files.pythonhosted.org/packages/b5/25/36dbd49ab6d179bcfc4c6c093a51795a4f3bed380543a8242ac3517a1751/tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482", size = 438463 }, - { url = "https://files.pythonhosted.org/packages/61/cc/58b1adeb1bb46228442081e746fcdbc4540905c87e8add7c277540934edb/tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38", size = 438907 }, + { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563 }, + { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729 }, + { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295 }, + { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644 }, + { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878 }, + { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549 }, + { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973 }, + { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954 }, + { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023 }, + { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427 }, + { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456 }, ] [[package]] @@ -4303,16 +4750,15 @@ wheels = [ [[package]] name = "transformer-smaller-training-vocab" -version = "0.4.0" +version = "0.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "numpy" }, { name = "torch" }, { name = "transformers", extra = ["sentencepiece", "torch"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/28/5214ff2a93d9cccc55d0679cb8cbc3b9d52f1f07860c92841b16cfeb5026/transformer_smaller_training_vocab-0.4.0.tar.gz", hash = "sha256:d7360ac084786f66f99ef16d621f34acbb0dce6d9a624525d1f7dc8b6c3a49f7", size = 12141 } +sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754 } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/c8/6a02e88256dc48faf3eae5732a94035f4ea0edd91d8224333693111921ba/transformer_smaller_training_vocab-0.4.0-py3-none-any.whl", hash = "sha256:01cb3d8f4818121172e1591a06c3149bf49bc18d6f6f269eb42d2c4ed155cfcc", size = 14120 }, + { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073 }, ] [[package]] @@ -4357,7 +4803,7 @@ wheels = [ [[package]] name = "typer" -version = "0.15.1" +version = "0.20.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -4365,48 +4811,51 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/dca7b219718afd37a0068f4f2530a727c2b74a8b6e8e0c0080a4c0de4fcd/typer-0.15.1.tar.gz", hash = "sha256:a0588c0a7fa68a1978a069818657778f86abe6ff5ea6abf472f940a08bfe4f0a", size = 99789 } +sdist = { url = "https://files.pythonhosted.org/packages/8f/28/7c85c8032b91dbe79725b6f17d2fffc595dff06a35c7a30a37bef73a1ab4/typer-0.20.0.tar.gz", hash = "sha256:1aaf6494031793e4876fb0bacfa6a912b551cf43c1e63c800df8b1a866720c37", size = 106492 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/cc/0a838ba5ca64dc832aa43f727bd586309846b0ffb2ce52422543e6075e8a/typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", size = 44908 }, + { url = "https://files.pythonhosted.org/packages/78/64/7713ffe4b5983314e9d436a90d5bd4f63b6054e2aca783a3cfc44cb95bbf/typer-0.20.0-py3-none-any.whl", hash = "sha256:5b463df6793ec1dca6213a3cf4c0f03bc6e322ac5e16e13ddd622a889489784a", size = 47028 }, ] [[package]] -name = "types-python-dateutil" -version = "2.9.0.20241206" +name = "typing-extensions" +version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802 } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384 }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, ] [[package]] -name = "typing-extensions" -version = "4.12.2" +name = "typing-inspection" +version = "0.4.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, ] [[package]] name = "tzdata" -version = "2025.1" +version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/0f/fa4723f22942480be4ca9527bbde8d43f6c3f2fe8412f00e7f5f6746bc8b/tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694", size = 194950 } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/dd/84f10e23edd882c6f968c21c2434fe67bd4a528967067515feca9e611e5e/tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639", size = 346762 }, + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 }, ] [[package]] name = "tzlocal" -version = "5.2" +version = "5.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "tzdata", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/d3/c19d65ae67636fe63953b20c2e4a8ced4497ea232c43ff8d01db16de8dc0/tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e", size = 30201 } +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761 } wheels = [ - { url = "https://files.pythonhosted.org/packages/97/3f/c4c51c55ff8487f2e6d0e618dba917e3c3ee2caae6cf0fbb59c9b1876f2e/tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8", size = 17859 }, + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026 }, ] [[package]] @@ -4429,25 +4878,25 @@ wheels = [ [[package]] name = "urllib3" -version = "2.3.0" +version = "2.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +sdist = { url = "https://files.pythonhosted.org/packages/1c/43/554c2569b62f49350597348fc3ac70f786e3c32e7f19d266e19817812dd3/urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1", size = 432585 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, + { url = "https://files.pythonhosted.org/packages/56/1a/9ffe814d317c5224166b23e7c47f606d6e473712a2fad0f704ea9b99f246/urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f", size = 131083 }, ] [[package]] name = "uvicorn" -version = "0.34.0" +version = "0.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 } +sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/f06b84e2697fef4688ca63bdb2fdf113ca0a3be33f94488f2cadb690b0cf/uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d", size = 80605 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 }, + { url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109 }, ] [package.optional-dependencies] @@ -4463,16 +4912,25 @@ standard = [ [[package]] name = "uvloop" -version = "0.21.0" +version = "0.22.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335 }, + { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903 }, + { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499 }, + { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133 }, + { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681 }, + { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261 }, +] + +[[package]] +name = "validators" +version = "0.35.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741 } +sdist = { url = "https://files.pythonhosted.org/packages/53/66/a435d9ae49850b2f071f7ebd8119dd4e84872b01630d6736761e6e7fd847/validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a", size = 73399 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019 }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898 }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735 }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126 }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789 }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523 }, + { url = "https://files.pythonhosted.org/packages/fa/6e/3e955517e22cbdd565f2f8b2e73d52528b14b8bcfdb04f62466b071de847/validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd", size = 44712 }, ] [[package]] @@ -4486,16 +4944,35 @@ wheels = [ [[package]] name = "virtualenv" -version = "20.29.1" +version = "20.35.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a7/ca/f23dcb02e161a9bba141b1c08aa50e8da6ea25e6d780528f1d385a3efe25/virtualenv-20.29.1.tar.gz", hash = "sha256:b8b8970138d32fb606192cb97f6cd4bb644fa486be9308fb9b63f81091b5dc35", size = 7658028 } +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799 } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/9b/599bcfc7064fbe5740919e78c5df18e5dceb0887e676256a1061bb5ae232/virtualenv-20.29.1-py3-none-any.whl", hash = "sha256:4e4cb403c0b0da39e13b46b1b2476e505cb0046b25f242bee80f62bf990b2779", size = 4282379 }, + { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095 }, +] + +[[package]] +name = "watchdog" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, ] [[package]] @@ -4518,47 +4995,47 @@ wheels = [ [[package]] name = "watchfiles" -version = "1.0.4" +version = "1.1.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/26/c705fc77d0a9ecdb9b66f1e2976d95b81df3cae518967431e7dbf9b5e219/watchfiles-1.0.4.tar.gz", hash = "sha256:6ba473efd11062d73e4f00c2b730255f9c1bdd73cd5f9fe5b5da8dbd4a717205", size = 94625 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440 } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/02/22fcaed0396730b0d362bc8d1ffb3be2658fd473eecbb2ba84243e157f11/watchfiles-1.0.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ba5bb3073d9db37c64520681dd2650f8bd40902d991e7b4cfaeece3e32561d08", size = 395212 }, - { url = "https://files.pythonhosted.org/packages/e9/3d/ec5a2369a46edf3ebe092c39d9ae48e8cb6dacbde51c4b4f98936c524269/watchfiles-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f25d0ba0fe2b6d2c921cf587b2bf4c451860086534f40c384329fb96e2044d1", size = 384815 }, - { url = "https://files.pythonhosted.org/packages/df/b4/898991cececbe171e67142c31905510203649569d9817848f47c4177ee42/watchfiles-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:47eb32ef8c729dbc4f4273baece89398a4d4b5d21a1493efea77a17059f4df8a", size = 450680 }, - { url = "https://files.pythonhosted.org/packages/58/f7/d4aa3000e812cfb5e5c2c6c0a3ec9d0a46a42489a8727edd160631c4e210/watchfiles-1.0.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:076f293100db3b0b634514aa0d294b941daa85fc777f9c698adb1009e5aca0b1", size = 455923 }, - { url = "https://files.pythonhosted.org/packages/dd/95/7e2e4c6aba1b02fb5c76d2f6a450b85215921ec5f8f7ad5efd075369563f/watchfiles-1.0.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1eacd91daeb5158c598fe22d7ce66d60878b6294a86477a4715154990394c9b3", size = 482339 }, - { url = "https://files.pythonhosted.org/packages/bb/67/4265b0fabcc2ef2c9e3e8802ba7908cf718a357ebfb49c72e53787156a48/watchfiles-1.0.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:13c2ce7b72026cfbca120d652f02c7750f33b4c9395d79c9790b27f014c8a5a2", size = 519908 }, - { url = "https://files.pythonhosted.org/packages/0d/96/b57802d5f8164bdf070befb4fd3dec4edba5a364ec0670965a97eb8098ce/watchfiles-1.0.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:90192cdc15ab7254caa7765a98132a5a41471cf739513cc9bcf7d2ffcc0ec7b2", size = 501410 }, - { url = "https://files.pythonhosted.org/packages/8b/18/6db0de4e8911ba14e31853201b40c0fa9fea5ecf3feb86b0ad58f006dfc3/watchfiles-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278aaa395f405972e9f523bd786ed59dfb61e4b827856be46a42130605fd0899", size = 452876 }, - { url = "https://files.pythonhosted.org/packages/df/df/092a961815edf723a38ba2638c49491365943919c3526cc9cf82c42786a6/watchfiles-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a462490e75e466edbb9fc4cd679b62187153b3ba804868452ef0577ec958f5ff", size = 615353 }, - { url = "https://files.pythonhosted.org/packages/f3/cf/b85fe645de4ff82f3f436c5e9032379fce37c303f6396a18f9726cc34519/watchfiles-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8d0d0630930f5cd5af929040e0778cf676a46775753e442a3f60511f2409f48f", size = 613187 }, - { url = "https://files.pythonhosted.org/packages/f6/d4/a9fea27aef4dd69689bc3556718c1157a7accb72aa035ece87c1fa8483b5/watchfiles-1.0.4-cp310-cp310-win32.whl", hash = "sha256:cc27a65069bcabac4552f34fd2dce923ce3fcde0721a16e4fb1b466d63ec831f", size = 270799 }, - { url = "https://files.pythonhosted.org/packages/df/02/dbe9d4439f15dd4ad0720b6e039bde9d66d1f830331f34c18eb70fa6608e/watchfiles-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:8b1f135238e75d075359cf506b27bf3f4ca12029c47d3e769d8593a2024ce161", size = 284145 }, - { url = "https://files.pythonhosted.org/packages/6f/06/175d5ac6b838fb319008c0cd981d7bf289317c510154d411d3584ca2b67b/watchfiles-1.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cdcc92daeae268de1acf5b7befcd6cfffd9a047098199056c72e4623f531de18", size = 396269 }, - { url = "https://files.pythonhosted.org/packages/86/ee/5db93b0b57dc0587abdbac4149296ee73275f615d790a82cb5598af0557f/watchfiles-1.0.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d8d3d9203705b5797f0af7e7e5baa17c8588030aaadb7f6a86107b7247303817", size = 386010 }, - { url = "https://files.pythonhosted.org/packages/75/61/fe0dc5fedf152bfc085a53711f740701f6bdb8ab6b5c950402b681d4858b/watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bdef5a1be32d0b07dcea3318a0be95d42c98ece24177820226b56276e06b63b0", size = 450913 }, - { url = "https://files.pythonhosted.org/packages/9f/dd/3c7731af3baf1a9957afc643d176f94480921a690ec3237c9f9d11301c08/watchfiles-1.0.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:342622287b5604ddf0ed2d085f3a589099c9ae8b7331df3ae9845571586c4f3d", size = 453474 }, + { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318 }, + { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478 }, + { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894 }, + { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065 }, + { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377 }, + { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837 }, + { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456 }, + { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614 }, + { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690 }, + { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459 }, + { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663 }, + { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453 }, + { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611 }, + { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889 }, + { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616 }, + { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413 }, ] [[package]] name = "wcwidth" -version = "0.2.13" +version = "0.2.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286 }, ] [[package]] name = "webcolors" -version = "24.11.1" +version = "25.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/29/061ec845fb58521848f3739e466efd8250b4b7b98c1b6c5bf4d40b419b7e/webcolors-24.11.1.tar.gz", hash = "sha256:ecb3d768f32202af770477b8b65f318fa4f566c22948673a977b00d589dd80f6", size = 45064 } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/e8/c0e05e4684d13459f93d312077a9a2efbe04d59c393bc2b8802248c908d4/webcolors-24.11.1-py3-none-any.whl", hash = "sha256:515291393b4cdf0eb19c155749a096f779f7d909f7cceea072791cb9095b92e9", size = 14934 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905 }, ] [[package]] @@ -4572,49 +5049,49 @@ wheels = [ [[package]] name = "websocket-client" -version = "1.8.0" +version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 }, + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, ] [[package]] name = "websockets" -version = "14.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/54/8359678c726243d19fae38ca14a334e740782336c9f19700858c4eb64a1e/websockets-14.2.tar.gz", hash = "sha256:5059ed9c54945efb321f097084b4c7e52c246f2c869815876a69d1efc4ad6eb5", size = 164394 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/28/fa/76607eb7dcec27b2d18d63f60a32e60e2b8629780f343bb83a4dbb9f4350/websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885", size = 163089 }, - { url = "https://files.pythonhosted.org/packages/9e/00/ad2246b5030575b79e7af0721810fdaecaf94c4b2625842ef7a756fa06dd/websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397", size = 160741 }, - { url = "https://files.pythonhosted.org/packages/72/f7/60f10924d333a28a1ff3fcdec85acf226281331bdabe9ad74947e1b7fc0a/websockets-14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:714a9b682deb4339d39ffa674f7b674230227d981a37d5d174a4a83e3978a610", size = 160996 }, - { url = "https://files.pythonhosted.org/packages/63/7c/c655789cf78648c01ac6ecbe2d6c18f91b75bdc263ffee4d08ce628d12f0/websockets-14.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2e53c72052f2596fb792a7acd9704cbc549bf70fcde8a99e899311455974ca3", size = 169974 }, - { url = "https://files.pythonhosted.org/packages/fb/5b/013ed8b4611857ac92ac631079c08d9715b388bd1d88ec62e245f87a39df/websockets-14.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3fbd68850c837e57373d95c8fe352203a512b6e49eaae4c2f4088ef8cf21980", size = 168985 }, - { url = "https://files.pythonhosted.org/packages/cd/33/aa3e32fd0df213a5a442310754fe3f89dd87a0b8e5b4e11e0991dd3bcc50/websockets-14.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b27ece32f63150c268593d5fdb82819584831a83a3f5809b7521df0685cd5d8", size = 169297 }, - { url = "https://files.pythonhosted.org/packages/93/17/dae0174883d6399f57853ac44abf5f228eaba86d98d160f390ffabc19b6e/websockets-14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4daa0faea5424d8713142b33825fff03c736f781690d90652d2c8b053345b0e7", size = 169677 }, - { url = "https://files.pythonhosted.org/packages/42/e2/0375af7ac00169b98647c804651c515054b34977b6c1354f1458e4116c1e/websockets-14.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:bc63cee8596a6ec84d9753fd0fcfa0452ee12f317afe4beae6b157f0070c6c7f", size = 169089 }, - { url = "https://files.pythonhosted.org/packages/73/8d/80f71d2a351a44b602859af65261d3dde3a0ce4e76cf9383738a949e0cc3/websockets-14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7a570862c325af2111343cc9b0257b7119b904823c675b22d4ac547163088d0d", size = 169026 }, - { url = "https://files.pythonhosted.org/packages/48/97/173b1fa6052223e52bb4054a141433ad74931d94c575e04b654200b98ca4/websockets-14.2-cp310-cp310-win32.whl", hash = "sha256:75862126b3d2d505e895893e3deac0a9339ce750bd27b4ba515f008b5acf832d", size = 163967 }, - { url = "https://files.pythonhosted.org/packages/c0/5b/2fcf60f38252a4562b28b66077e0d2b48f91fef645d5f78874cd1dec807b/websockets-14.2-cp310-cp310-win_amd64.whl", hash = "sha256:cc45afb9c9b2dc0852d5c8b5321759cf825f82a31bfaf506b65bf4668c96f8b2", size = 164413 }, - { url = "https://files.pythonhosted.org/packages/10/3d/91d3d2bb1325cd83e8e2c02d0262c7d4426dc8fa0831ef1aa4d6bf2041af/websockets-14.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:d7d9cafbccba46e768be8a8ad4635fa3eae1ffac4c6e7cb4eb276ba41297ed29", size = 160773 }, - { url = "https://files.pythonhosted.org/packages/33/7c/cdedadfef7381939577858b1b5718a4ab073adbb584e429dd9d9dc9bfe16/websockets-14.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c76193c1c044bd1e9b3316dcc34b174bbf9664598791e6fb606d8d29000e070c", size = 161007 }, - { url = "https://files.pythonhosted.org/packages/ca/35/7a20a3c450b27c04e50fbbfc3dfb161ed8e827b2a26ae31c4b59b018b8c6/websockets-14.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd475a974d5352390baf865309fe37dec6831aafc3014ffac1eea99e84e83fc2", size = 162264 }, - { url = "https://files.pythonhosted.org/packages/e8/9c/e3f9600564b0c813f2448375cf28b47dc42c514344faed3a05d71fb527f9/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2c6c0097a41968b2e2b54ed3424739aab0b762ca92af2379f152c1aef0187e1c", size = 161873 }, - { url = "https://files.pythonhosted.org/packages/3f/37/260f189b16b2b8290d6ae80c9f96d8b34692cf1bb3475df54c38d3deb57d/websockets-14.2-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d7ff794c8b36bc402f2e07c0b2ceb4a2424147ed4785ff03e2a7af03711d60a", size = 161818 }, - { url = "https://files.pythonhosted.org/packages/ff/1e/e47dedac8bf7140e59aa6a679e850c4df9610ae844d71b6015263ddea37b/websockets-14.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dec254fcabc7bd488dab64846f588fc5b6fe0d78f641180030f8ea27b76d72c3", size = 164465 }, - { url = "https://files.pythonhosted.org/packages/7b/c8/d529f8a32ce40d98309f4470780631e971a5a842b60aec864833b3615786/websockets-14.2-py3-none-any.whl", hash = "sha256:7a6ceec4ea84469f15cf15807a747e9efe57e369c384fa86e022b3bea679b79b", size = 157416 }, +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423 }, + { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080 }, + { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329 }, + { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312 }, + { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319 }, + { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631 }, + { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016 }, + { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426 }, + { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360 }, + { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388 }, + { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830 }, + { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109 }, + { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343 }, + { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599 }, + { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207 }, + { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155 }, + { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884 }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, ] [[package]] name = "werkzeug" -version = "3.1.3" +version = "3.1.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925 } +sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687 } wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498 }, + { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960 }, ] [[package]] @@ -4628,11 +5105,11 @@ wheels = [ [[package]] name = "widgetsnbextension" -version = "4.0.13" +version = "4.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/56/fc/238c424fd7f4ebb25f8b1da9a934a3ad7c848286732ae04263661eb0fc03/widgetsnbextension-4.0.13.tar.gz", hash = "sha256:ffcb67bc9febd10234a362795f643927f4e0c05d9342c727b65d2384f8feacb6", size = 1164730 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402 } wheels = [ - { url = "https://files.pythonhosted.org/packages/21/02/88b65cc394961a60c43c70517066b6b679738caf78506a5da7b88ffcb643/widgetsnbextension-4.0.13-py3-none-any.whl", hash = "sha256:74b2692e8500525cc38c2b877236ba51d34541e6385eeed5aec15a70f88a6c71", size = 2335872 }, + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503 }, ] [[package]] @@ -4646,22 +5123,23 @@ sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581 [[package]] name = "wrapt" -version = "1.17.2" +version = "2.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/fc/e91cc220803d7bc4db93fb02facd8461c37364151b8494762cc88b0fbcef/wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3", size = 55531 } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/d1/1daec934997e8b160040c78d7b31789f19b122110a75eca3d4e8da0049e1/wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984", size = 53307 }, - { url = "https://files.pythonhosted.org/packages/1b/7b/13369d42651b809389c1a7153baa01d9700430576c81a2f5c5e460df0ed9/wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22", size = 38486 }, - { url = "https://files.pythonhosted.org/packages/62/bf/e0105016f907c30b4bd9e377867c48c34dc9c6c0c104556c9c9126bd89ed/wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7", size = 38777 }, - { url = "https://files.pythonhosted.org/packages/27/70/0f6e0679845cbf8b165e027d43402a55494779295c4b08414097b258ac87/wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c", size = 83314 }, - { url = "https://files.pythonhosted.org/packages/0f/77/0576d841bf84af8579124a93d216f55d6f74374e4445264cb378a6ed33eb/wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72", size = 74947 }, - { url = "https://files.pythonhosted.org/packages/90/ec/00759565518f268ed707dcc40f7eeec38637d46b098a1f5143bff488fe97/wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061", size = 82778 }, - { url = "https://files.pythonhosted.org/packages/f8/5a/7cffd26b1c607b0b0c8a9ca9d75757ad7620c9c0a9b4a25d3f8a1480fafc/wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2", size = 81716 }, - { url = "https://files.pythonhosted.org/packages/7e/09/dccf68fa98e862df7e6a60a61d43d644b7d095a5fc36dbb591bbd4a1c7b2/wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c", size = 74548 }, - { url = "https://files.pythonhosted.org/packages/b7/8e/067021fa3c8814952c5e228d916963c1115b983e21393289de15128e867e/wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62", size = 81334 }, - { url = "https://files.pythonhosted.org/packages/4b/0d/9d4b5219ae4393f718699ca1c05f5ebc0c40d076f7e65fd48f5f693294fb/wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563", size = 36427 }, - { url = "https://files.pythonhosted.org/packages/72/6a/c5a83e8f61aec1e1aeef939807602fb880e5872371e95df2137142f5c58e/wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f", size = 38774 }, - { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594 }, + { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481 }, + { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692 }, + { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574 }, + { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688 }, + { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698 }, + { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096 }, + { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878 }, + { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298 }, + { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361 }, + { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035 }, + { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383 }, + { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894 }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046 }, ] [[package]] @@ -4675,11 +5153,11 @@ wheels = [ [[package]] name = "xlsxwriter" -version = "3.2.1" +version = "3.2.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/4f/108b0bada5cfcc47c24ea6181f4c563fbafef50bcc0054089c256b2ae578/XlsxWriter-3.2.1.tar.gz", hash = "sha256:97618759cb264fb6a93397f660cca156ffa9561743b1823dafb60dc4474e1902", size = 202868 } +sdist = { url = "https://files.pythonhosted.org/packages/46/2c/c06ef49dc36e7954e55b802a8b231770d286a9758b3d936bd1e04ce5ba88/xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c", size = 215940 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/30/040af902cb8a9909d320779d8467aa7590bb91477767fd2b7551f4d91bb5/XlsxWriter-3.2.1-py3-none-any.whl", hash = "sha256:7e8f7c60b7a1660ef791d46ab5de78469cb978b991ca841af61f5832d2f9f4fe", size = 162778 }, + { url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315 }, ] [[package]] @@ -4693,60 +5171,64 @@ wheels = [ [[package]] name = "xxhash" -version = "3.5.0" +version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/5e/d6e5258d69df8b4ed8c83b6664f2b47d30d2dec551a29ad72a6c69eafd31/xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f", size = 84241 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/8a/0e9feca390d512d293afd844d31670e25608c4a901e10202aa98785eab09/xxhash-3.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ece616532c499ee9afbb83078b1b952beffef121d989841f7f4b3dc5ac0fd212", size = 31970 }, - { url = "https://files.pythonhosted.org/packages/16/e6/be5aa49580cd064a18200ab78e29b88b1127e1a8c7955eb8ecf81f2626eb/xxhash-3.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3171f693dbc2cef6477054a665dc255d996646b4023fe56cb4db80e26f4cc520", size = 30801 }, - { url = "https://files.pythonhosted.org/packages/20/ee/b8a99ebbc6d1113b3a3f09e747fa318c3cde5b04bd9c197688fadf0eeae8/xxhash-3.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5d3e570ef46adaf93fc81b44aca6002b5a4d8ca11bd0580c07eac537f36680", size = 220927 }, - { url = "https://files.pythonhosted.org/packages/58/62/15d10582ef159283a5c2b47f6d799fc3303fe3911d5bb0bcc820e1ef7ff4/xxhash-3.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cb29a034301e2982df8b1fe6328a84f4b676106a13e9135a0d7e0c3e9f806da", size = 200360 }, - { url = "https://files.pythonhosted.org/packages/23/41/61202663ea9b1bd8e53673b8ec9e2619989353dba8cfb68e59a9cbd9ffe3/xxhash-3.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0d307d27099bb0cbeea7260eb39ed4fdb99c5542e21e94bb6fd29e49c57a23", size = 428528 }, - { url = "https://files.pythonhosted.org/packages/f2/07/d9a3059f702dec5b3b703737afb6dda32f304f6e9da181a229dafd052c29/xxhash-3.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0342aafd421795d740e514bc9858ebddfc705a75a8c5046ac56d85fe97bf196", size = 194149 }, - { url = "https://files.pythonhosted.org/packages/eb/58/27caadf78226ecf1d62dbd0c01d152ed381c14c1ee4ad01f0d460fc40eac/xxhash-3.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dbbd9892c5ebffeca1ed620cf0ade13eb55a0d8c84e0751a6653adc6ac40d0c", size = 207703 }, - { url = "https://files.pythonhosted.org/packages/b1/08/32d558ce23e1e068453c39aed7b3c1cdc690c177873ec0ca3a90d5808765/xxhash-3.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4cc2d67fdb4d057730c75a64c5923abfa17775ae234a71b0200346bfb0a7f482", size = 216255 }, - { url = "https://files.pythonhosted.org/packages/3f/d4/2b971e2d2b0a61045f842b622ef11e94096cf1f12cd448b6fd426e80e0e2/xxhash-3.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ec28adb204b759306a3d64358a5e5c07d7b1dd0ccbce04aa76cb9377b7b70296", size = 202744 }, - { url = "https://files.pythonhosted.org/packages/19/ae/6a6438864a8c4c39915d7b65effd85392ebe22710412902487e51769146d/xxhash-3.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1328f6d8cca2b86acb14104e381225a3d7b42c92c4b86ceae814e5c400dbb415", size = 210115 }, - { url = "https://files.pythonhosted.org/packages/48/7d/b3c27c27d1fc868094d02fe4498ccce8cec9fcc591825c01d6bcb0b4fc49/xxhash-3.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8d47ebd9f5d9607fd039c1fbf4994e3b071ea23eff42f4ecef246ab2b7334198", size = 414247 }, - { url = "https://files.pythonhosted.org/packages/a1/05/918f9e7d2fbbd334b829997045d341d6239b563c44e683b9a7ef8fe50f5d/xxhash-3.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b96d559e0fcddd3343c510a0fe2b127fbff16bf346dd76280b82292567523442", size = 191419 }, - { url = "https://files.pythonhosted.org/packages/08/29/dfe393805b2f86bfc47c290b275f0b7c189dc2f4e136fd4754f32eb18a8d/xxhash-3.5.0-cp310-cp310-win32.whl", hash = "sha256:61c722ed8d49ac9bc26c7071eeaa1f6ff24053d553146d5df031802deffd03da", size = 30114 }, - { url = "https://files.pythonhosted.org/packages/7b/d7/aa0b22c4ebb7c3ccb993d4c565132abc641cd11164f8952d89eb6a501909/xxhash-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9bed5144c6923cc902cd14bb8963f2d5e034def4486ab0bbe1f58f03f042f9a9", size = 30003 }, - { url = "https://files.pythonhosted.org/packages/69/12/f969b81541ee91b55f1ce469d7ab55079593c80d04fd01691b550e535000/xxhash-3.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:893074d651cf25c1cc14e3bea4fceefd67f2921b1bb8e40fcfeba56820de80c6", size = 26773 }, - { url = "https://files.pythonhosted.org/packages/ab/9a/233606bada5bd6f50b2b72c45de3d9868ad551e83893d2ac86dc7bb8553a/xxhash-3.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2014c5b3ff15e64feecb6b713af12093f75b7926049e26a580e94dcad3c73d8c", size = 29732 }, - { url = "https://files.pythonhosted.org/packages/0c/67/f75276ca39e2c6604e3bee6c84e9db8a56a4973fde9bf35989787cf6e8aa/xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fab81ef75003eda96239a23eda4e4543cedc22e34c373edcaf744e721a163986", size = 36214 }, - { url = "https://files.pythonhosted.org/packages/0f/f8/f6c61fd794229cc3848d144f73754a0c107854372d7261419dcbbd286299/xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2febf914ace002132aa09169cc572e0d8959d0f305f93d5828c4836f9bc5a6", size = 32020 }, - { url = "https://files.pythonhosted.org/packages/79/d3/c029c99801526f859e6b38d34ab87c08993bf3dcea34b11275775001638a/xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d3a10609c51da2a1c0ea0293fc3968ca0a18bd73838455b5bca3069d7f8e32b", size = 40515 }, - { url = "https://files.pythonhosted.org/packages/62/e3/bef7b82c1997579c94de9ac5ea7626d01ae5858aa22bf4fcb38bf220cb3e/xxhash-3.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a74f23335b9689b66eb6dbe2a931a88fcd7a4c2cc4b1cb0edba8ce381c7a1da", size = 30064 }, +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845 }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807 }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786 }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830 }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606 }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872 }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217 }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139 }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669 }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018 }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058 }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628 }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577 }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487 }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863 }, ] [[package]] name = "yarl" -version = "1.18.3" +version = "1.22.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b7/9d/4b94a8e6d2b51b599516a5cb88e5bc99b4d8d4583e468057eaa29d5f0918/yarl-1.18.3.tar.gz", hash = "sha256:ac1801c45cbf77b6c99242eeff4fffb5e4e73a800b5c4ad4fc0be5def634d2e1", size = 181062 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/98/e005bc608765a8a5569f58e650961314873c8469c333616eb40bff19ae97/yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34", size = 141458 }, - { url = "https://files.pythonhosted.org/packages/df/5d/f8106b263b8ae8a866b46d9be869ac01f9b3fb7f2325f3ecb3df8003f796/yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7", size = 94365 }, - { url = "https://files.pythonhosted.org/packages/56/3e/d8637ddb9ba69bf851f765a3ee288676f7cf64fb3be13760c18cbc9d10bd/yarl-1.18.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:602d98f2c2d929f8e697ed274fbadc09902c4025c5a9963bf4e9edfc3ab6f7ed", size = 92181 }, - { url = "https://files.pythonhosted.org/packages/76/f9/d616a5c2daae281171de10fba41e1c0e2d8207166fc3547252f7d469b4e1/yarl-1.18.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c654d5207c78e0bd6d749f6dae1dcbbfde3403ad3a4b11f3c5544d9906969dde", size = 315349 }, - { url = "https://files.pythonhosted.org/packages/bb/b4/3ea5e7b6f08f698b3769a06054783e434f6d59857181b5c4e145de83f59b/yarl-1.18.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5094d9206c64181d0f6e76ebd8fb2f8fe274950a63890ee9e0ebfd58bf9d787b", size = 330494 }, - { url = "https://files.pythonhosted.org/packages/55/f1/e0fc810554877b1b67420568afff51b967baed5b53bcc983ab164eebf9c9/yarl-1.18.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35098b24e0327fc4ebdc8ffe336cee0a87a700c24ffed13161af80124b7dc8e5", size = 326927 }, - { url = "https://files.pythonhosted.org/packages/a9/42/b1753949b327b36f210899f2dd0a0947c0c74e42a32de3f8eb5c7d93edca/yarl-1.18.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3236da9272872443f81fedc389bace88408f64f89f75d1bdb2256069a8730ccc", size = 319703 }, - { url = "https://files.pythonhosted.org/packages/f0/6d/e87c62dc9635daefb064b56f5c97df55a2e9cc947a2b3afd4fd2f3b841c7/yarl-1.18.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e2c08cc9b16f4f4bc522771d96734c7901e7ebef70c6c5c35dd0f10845270bcd", size = 310246 }, - { url = "https://files.pythonhosted.org/packages/e3/ef/e2e8d1785cdcbd986f7622d7f0098205f3644546da7919c24b95790ec65a/yarl-1.18.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80316a8bd5109320d38eef8833ccf5f89608c9107d02d2a7f985f98ed6876990", size = 319730 }, - { url = "https://files.pythonhosted.org/packages/fc/15/8723e22345bc160dfde68c4b3ae8b236e868f9963c74015f1bc8a614101c/yarl-1.18.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c1e1cc06da1491e6734f0ea1e6294ce00792193c463350626571c287c9a704db", size = 321681 }, - { url = "https://files.pythonhosted.org/packages/86/09/bf764e974f1516efa0ae2801494a5951e959f1610dd41edbfc07e5e0f978/yarl-1.18.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fea09ca13323376a2fdfb353a5fa2e59f90cd18d7ca4eaa1fd31f0a8b4f91e62", size = 324812 }, - { url = "https://files.pythonhosted.org/packages/f6/4c/20a0187e3b903c97d857cf0272d687c1b08b03438968ae8ffc50fe78b0d6/yarl-1.18.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e3b9fd71836999aad54084906f8663dffcd2a7fb5cdafd6c37713b2e72be1760", size = 337011 }, - { url = "https://files.pythonhosted.org/packages/c9/71/6244599a6e1cc4c9f73254a627234e0dad3883ece40cc33dce6265977461/yarl-1.18.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:757e81cae69244257d125ff31663249b3013b5dc0a8520d73694aed497fb195b", size = 338132 }, - { url = "https://files.pythonhosted.org/packages/af/f5/e0c3efaf74566c4b4a41cb76d27097df424052a064216beccae8d303c90f/yarl-1.18.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b1771de9944d875f1b98a745bc547e684b863abf8f8287da8466cf470ef52690", size = 331849 }, - { url = "https://files.pythonhosted.org/packages/8a/b8/3d16209c2014c2f98a8f658850a57b716efb97930aebf1ca0d9325933731/yarl-1.18.3-cp310-cp310-win32.whl", hash = "sha256:8874027a53e3aea659a6d62751800cf6e63314c160fd607489ba5c2edd753cf6", size = 84309 }, - { url = "https://files.pythonhosted.org/packages/fd/b7/2e9a5b18eb0fe24c3a0e8bae994e812ed9852ab4fd067c0107fadde0d5f0/yarl-1.18.3-cp310-cp310-win_amd64.whl", hash = "sha256:93b2e109287f93db79210f86deb6b9bbb81ac32fc97236b16f7433db7fc437d8", size = 90484 }, - { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 }, +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517 }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495 }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400 }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545 }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598 }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893 }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240 }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965 }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026 }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637 }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082 }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811 }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223 }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118 }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852 }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012 }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, ] [[package]] From f85d7cff909c336d2352d862759a29a87461f224 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 5 Dec 2025 19:21:33 +0000 Subject: [PATCH 020/104] =?UTF-8?q?=E2=8F=AA=20Rollback=20to=20previous=20?= =?UTF-8?q?torch=20and=20torchtext=20versions=20to=20avoid=20conflicts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 4 +- uv.lock | 540 ++----------------------------------------------- 2 files changed, 15 insertions(+), 529 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0086a268..b89395ab 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,8 +74,8 @@ dependencies = [ "cachetools>=5.5.0", "diskcache>=5.6.3", "scipy<1.14.1", - "torch==2.9.0", - "torchtext==0.18.0", + "torch==1.12.1", + "torchtext==0.13.1", "pytorch-lightning==1.8.3.post1", "tensorflow_text==2.10.0; sys_platform == 'linux' or (sys_platform == 'darwin' and platform_machine == 'x86_64') or sys_platform == 'win32'", # no ARM64 macOS wheels "psutil==6.1.0", diff --git a/uv.lock b/uv.lock index 401cc267..f22747ea 100644 --- a/uv.lock +++ b/uv.lock @@ -126,23 +126,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303 }, ] -[[package]] -name = "altair" -version = "4.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "entrypoints" }, - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ec/bf/781b607da4c1a2a7211cd570bd7e22e0accd4deaf1074c32ac7344a09339/altair-4.2.2.tar.gz", hash = "sha256:39399a267c49b30d102c10411e67ab26374156a84b1aeb9fcd15140429ba49c5", size = 740430 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/62/47452306e84d4d2e67f9c559380aeb230f5e6ca84fafb428dd36b96a99ba/altair-4.2.2-py3-none-any.whl", hash = "sha256:8b45ebeaf8557f2d760c5c77b79f02ae12aee7c46c27c06014febab6f849bc87", size = 813630 }, -] - [[package]] name = "annotated-types" version = "0.7.0" @@ -301,7 +284,7 @@ wheels = [ [[package]] name = "aymurai" -version = "1.1.13.dev63" +version = "1.1.13.dev29" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -438,15 +421,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, ] -[[package]] -name = "backoff" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, -] - [[package]] name = "beautifulsoup4" version = "4.8.2" @@ -634,15 +608,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228 }, ] -[[package]] -name = "cloudpickle" -version = "3.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228 }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -833,15 +798,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, ] -[[package]] -name = "distro" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, -] - [[package]] name = "dnspython" version = "2.8.0" @@ -900,40 +856,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/52/56eed4828175f48f712a50a994293065afa7cc98cb112992a0b071179b6c/dspy-3.0.4-py3-none-any.whl", hash = "sha256:c0a88c7936f41f6f613ee6ca8cd92e63746ff2bd780e3896615ade7628eb6a6a", size = 285224 }, ] -[[package]] -name = "dspy" -version = "3.0.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "asyncer" }, - { name = "backoff" }, - { name = "cachetools" }, - { name = "cloudpickle" }, - { name = "diskcache" }, - { name = "gepa" }, - { name = "joblib" }, - { name = "json-repair" }, - { name = "litellm" }, - { name = "magicattr" }, - { name = "numpy" }, - { name = "openai" }, - { name = "optuna" }, - { name = "orjson" }, - { name = "pillow" }, - { name = "pydantic" }, - { name = "regex" }, - { name = "requests" }, - { name = "rich" }, - { name = "tenacity" }, - { name = "tqdm" }, - { name = "xxhash" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8e/18/0042d299cd5e85fdb381568f0cfcc7769122e8f70ea0a2d33e12fd63e705/dspy-3.0.4.tar.gz", hash = "sha256:cb4529df9a91353a16144d9d94ba6ff25f36fc5adfd921f127f4c49d0e309fb8", size = 236376 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/52/56eed4828175f48f712a50a994293065afa7cc98cb112992a0b071179b6c/dspy-3.0.4-py3-none-any.whl", hash = "sha256:c0a88c7936f41f6f613ee6ca8cd92e63746ff2bd780e3896615ade7628eb6a6a", size = 285224 }, -] - [[package]] name = "ebcdic" version = "1.1.1" @@ -964,15 +886,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/35/a8/365059bbcd4572cbc41de17fd5b682be5868b218c3c5479071865cab9078/entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f", size = 5294 }, ] -[[package]] -name = "entrypoints" -version = "0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/8d/a7121ffe5f402dc015277d2d31eb82d2187334503a011c18f2e78ecbb9b2/entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4", size = 13974 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/a8/365059bbcd4572cbc41de17fd5b682be5868b218c3c5479071865cab9078/entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f", size = 5294 }, -] - [[package]] name = "exceptiongroup" version = "1.3.1" @@ -1149,25 +1062,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122 }, ] -[[package]] -name = "fastuuid" -version = "0.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760 }, - { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748 }, - { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537 }, - { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994 }, - { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003 }, - { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583 }, - { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955 }, - { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763 }, - { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613 }, - { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045 }, - { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122 }, -] - [[package]] name = "filelock" version = "3.20.0" @@ -1833,34 +1727,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110 }, ] -[[package]] -name = "jiter" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652 }, - { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829 }, - { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568 }, - { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052 }, - { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585 }, - { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541 }, - { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423 }, - { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958 }, - { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084 }, - { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054 }, - { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368 }, - { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847 }, - { url = "https://files.pythonhosted.org/packages/fe/54/5339ef1ecaa881c6948669956567a64d2670941925f245c434f494ffb0e5/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8", size = 311144 }, - { url = "https://files.pythonhosted.org/packages/27/74/3446c652bffbd5e81ab354e388b1b5fc1d20daac34ee0ed11ff096b1b01a/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3", size = 305877 }, - { url = "https://files.pythonhosted.org/packages/a1/f4/ed76ef9043450f57aac2d4fbeb27175aa0eb9c38f833be6ef6379b3b9a86/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e", size = 340419 }, - { url = "https://files.pythonhosted.org/packages/21/01/857d4608f5edb0664aa791a3d45702e1a5bcfff9934da74035e7b9803846/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d", size = 347212 }, - { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974 }, - { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233 }, - { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537 }, - { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110 }, -] - [[package]] name = "jiwer" version = "3.0.5" @@ -1901,15 +1767,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/53/3a/1b4df9adcd69fee9c9e4b439c13e8c866f2fae520054aede7030b2278be9/json_repair-0.54.2-py3-none-any.whl", hash = "sha256:be51cce5dca97e0c24ebdf61a1ede2449a8a7666012de99467bb7b0afb35179b", size = 29322 }, ] -[[package]] -name = "json-repair" -version = "0.54.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/46/d3a4d9a3dad39bb4a2ad16b8adb9fe2e8611b20b71197fe33daa6768e85d/json_repair-0.54.1.tar.gz", hash = "sha256:d010bc31f1fc66e7c36dc33bff5f8902674498ae5cb8e801ad455a53b455ad1d", size = 38555 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/96/c9aad7ee949cc1bf15df91f347fbc2d3bd10b30b80c7df689ce6fe9332b5/json_repair-0.54.1-py3-none-any.whl", hash = "sha256:016160c5db5d5fe443164927bb58d2dfbba5f43ad85719fa9bc51c713a443ab1", size = 29311 }, -] - [[package]] name = "json5" version = "0.12.1" @@ -2368,14 +2225,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/7e/76b7e0c391bee7e9273725c29c8fe41c4df62a215ce58aa8e3518baee0bb/magicattr-0.1.6-py2.py3-none-any.whl", hash = "sha256:d96b18ee45b5ee83b09c17e15d3459a64de62d538808c2f71182777dd9dbbbdf", size = 4664 }, ] -[[package]] -name = "magicattr" -version = "0.1.6" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/7e/76b7e0c391bee7e9273725c29c8fe41c4df62a215ce58aa8e3518baee0bb/magicattr-0.1.6-py2.py3-none-any.whl", hash = "sha256:d96b18ee45b5ee83b09c17e15d3459a64de62d538808c2f71182777dd9dbbbdf", size = 4664 }, -] - [[package]] name = "mako" version = "1.3.10" @@ -2502,19 +2351,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, ] -[[package]] -name = "ml-collections" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, -] - [[package]] name = "more-itertools" version = "10.8.0" @@ -2537,15 +2373,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, ] -[[package]] -name = "mpmath" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, -] - [[package]] name = "multidict" version = "6.7.0" @@ -2678,15 +2505,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, ] -[[package]] -name = "networkx" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, -] - [[package]] name = "nodeenv" version = "1.9.1" @@ -2740,155 +2558,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, ] -[[package]] -name = "nvidia-cublas-cu12" -version = "12.8.4.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, -] - -[[package]] -name = "nvidia-cuda-cupti-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, -] - -[[package]] -name = "nvidia-cuda-nvrtc-cu12" -version = "12.8.93" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, - { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, -] - -[[package]] -name = "nvidia-cuda-runtime-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, -] - -[[package]] -name = "nvidia-cudnn-cu12" -version = "9.10.2.21" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, -] - -[[package]] -name = "nvidia-cufft-cu12" -version = "11.3.3.83" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, -] - -[[package]] -name = "nvidia-cufile-cu12" -version = "1.13.1.3" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, - { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, -] - -[[package]] -name = "nvidia-curand-cu12" -version = "10.3.9.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, -] - -[[package]] -name = "nvidia-cusolver-cu12" -version = "11.7.3.90" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-cublas-cu12" }, - { name = "nvidia-cusparse-cu12" }, - { name = "nvidia-nvjitlink-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, -] - -[[package]] -name = "nvidia-cusparse-cu12" -version = "12.5.8.93" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "nvidia-nvjitlink-cu12" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, -] - -[[package]] -name = "nvidia-cusparselt-cu12" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, -] - -[[package]] -name = "nvidia-nccl-cu12" -version = "2.27.5" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, -] - -[[package]] -name = "nvidia-nvjitlink-cu12" -version = "12.8.93" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, - { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, -] - -[[package]] -name = "nvidia-nvshmem-cu12" -version = "3.3.20" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/9d/3dd98852568fb845ec1f7902c90a22b240fe1cbabda411ccedf2fd737b7b/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0", size = 124484616 }, - { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145 }, -] - -[[package]] -name = "nvidia-nvtx-cu12" -version = "12.8.90" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, -] - [[package]] name = "oauthlib" version = "3.3.1" @@ -3207,18 +2876,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163 }, ] -[[package]] -name = "proto-plus" -version = "1.26.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163 }, -] - [[package]] name = "protobuf" version = "3.19.6" @@ -3423,19 +3080,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, ] -[[package]] -name = "pydeck" -version = "0.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, -] - [[package]] name = "pygments" version = "2.19.2" @@ -3457,18 +3101,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl", hash = "sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506", size = 165766 }, ] -[[package]] -name = "pympler" -version = "1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dd/37/c384631908029676d8e7213dd956bb686af303a80db7afbc9be36bc49495/pympler-1.1.tar.gz", hash = "sha256:1eaa867cb8992c218430f1708fdaccda53df064144d1c5656b1e6f1ee6000424", size = 179954 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl", hash = "sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506", size = 165766 }, -] - [[package]] name = "pymupdf" version = "1.26.6" @@ -4261,52 +3893,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/fa/5b010610aa136c44a20de6ed9ec0b36867daf7322d0e3c8e626a99fab11a/streamlit-1.21.0-py2.py3-none-any.whl", hash = "sha256:05862598952a9126e16652caa5bc88eeeea7b2773af252e2daccf1c84ceaaef4", size = 9665093 }, ] -[[package]] -name = "streamlit" -version = "1.21.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "altair" }, - { name = "blinker" }, - { name = "cachetools" }, - { name = "click" }, - { name = "gitpython" }, - { name = "importlib-metadata" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "pillow" }, - { name = "protobuf" }, - { name = "pyarrow" }, - { name = "pydeck" }, - { name = "pympler" }, - { name = "python-dateutil" }, - { name = "requests" }, - { name = "rich" }, - { name = "toml" }, - { name = "tornado" }, - { name = "typing-extensions" }, - { name = "tzlocal" }, - { name = "validators" }, - { name = "watchdog", marker = "platform_system != 'Darwin'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/17/95/89b0f5f51cd006ffb6cc216393793d05029c47e97f140a9bff02f8c291a8/streamlit-1.21.0.tar.gz", hash = "sha256:c72d9639508679c5e411d1f886d213777759501d01975285c049dc30db463c1a", size = 9345809 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/fa/5b010610aa136c44a20de6ed9ec0b36867daf7322d0e3c8e626a99fab11a/streamlit-1.21.0-py2.py3-none-any.whl", hash = "sha256:05862598952a9126e16652caa5bc88eeeea7b2773af252e2daccf1c84ceaaef4", size = 9665093 }, -] - -[[package]] -name = "sympy" -version = "1.14.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mpmath" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, -] - [[package]] name = "tabulate" version = "0.9.0" @@ -4542,25 +4128,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, ] -[[package]] -name = "tiktoken" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991 }, - { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798 }, - { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865 }, - { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856 }, - { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308 }, - { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697 }, - { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, -] - [[package]] name = "tinycss2" version = "1.4.0" @@ -4607,15 +4174,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, ] -[[package]] -name = "toml" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, -] - [[package]] name = "tomli" version = "2.3.0" @@ -4634,48 +4192,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8", size = 58093 }, ] -[[package]] -name = "toolz" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/d6/114b492226588d6ff54579d95847662fc69196bdeec318eb45393b24c192/toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b", size = 52613 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8", size = 58093 }, -] - [[package]] name = "torch" -version = "2.9.0" +version = "1.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "filelock" }, - { name = "fsspec" }, - { name = "jinja2" }, - { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/86/245c240d2138c17ed572c943c289056c2721abab70810d772c6bf5495b28/torch-2.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:030bbfe367379ae6a4ae4042b6c44da25383343b8b3c68abaa9c7231efbaf2dd", size = 104213554 }, - { url = "https://files.pythonhosted.org/packages/58/1d/fd1e88ae0948825efcab7dd66d12bec23f05d4d38ed81573c8d453c14c06/torch-2.9.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:51cb63902182a78e90886e8068befd8ea102af4b00e420263591a3d70c7d3c6c", size = 899795167 }, - { url = "https://files.pythonhosted.org/packages/63/5a/496197b45c14982bef4e079b24c61dc108e3ab0d0cc9718dba9f54f45a46/torch-2.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:3f6aad4d2f0ee2248bac25339d74858ff846c3969b27d14ac235821f055af83d", size = 109310314 }, - { url = "https://files.pythonhosted.org/packages/58/b0/2b4e647b0fc706e88eb6c253d05511865578f5f67b55fad639bf3272a4a1/torch-2.9.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:413e1654c9203733138858780e184d9fc59442f0b3b209e16f39354eb893db9b", size = 74452019 }, + { url = "https://files.pythonhosted.org/packages/ca/74/7342c7f21449557a8263c925071a55081edd7e9b641404cfe31d6fb71d3b/torch-1.12.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:9c038662db894a23e49e385df13d47b2a777ffd56d9bcd5b832593fab0a7e286", size = 776338835 }, + { url = "https://files.pythonhosted.org/packages/36/b0/4857929aa28dfe26f7de909ebf002b60499edcd7566441a7433df865f9ba/torch-1.12.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:4e1b9c14cf13fd2ab8d769529050629a0e68a6fc5cb8e84b4a3cc1dd8c4fe541", size = 55712361 }, + { url = "https://files.pythonhosted.org/packages/b9/25/fc2111599a038aa6c1c618a7dc9246aabc95f899008949ade31213255a0c/torch-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:e9c8f4a311ac29fc7e8e955cfb7733deb5dbe1bdaabf5d4af2765695824b7e0d", size = 162235663 }, + { url = "https://files.pythonhosted.org/packages/37/72/ef80d39a371a9b4a8aadfb22b141972cc67a7075dae69a9d5b8116505ec0/torch-1.12.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:976c3f997cea38ee91a0dd3c3a42322785414748d1761ef926b789dfa97c6134", size = 133811424 }, + { url = "https://files.pythonhosted.org/packages/2f/17/8b557dde1cdb5fbe82f90a3f192046c8e508f106456e12f17c87543e6a42/torch-1.12.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:68104e4715a55c4bb29a85c6a8d57d820e0757da363be1ba680fa8cc5be17b52", size = 49099890 }, ] [[package]] @@ -4694,7 +4223,7 @@ wheels = [ [[package]] name = "torchtext" -version = "0.18.0" +version = "0.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, @@ -4703,9 +4232,11 @@ dependencies = [ { name = "tqdm" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/94/1e805ef3ec6541de75e8a86c32e00be471d98cdcef5035ad26457bc388cf/torchtext-0.18.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5826d5bbfe84a3c533e7e97659f72dbff73e1614c00c06709607d17c8446e09c", size = 2137942 }, - { url = "https://files.pythonhosted.org/packages/d7/4f/9953b4d4b79917e03c393484ea8ce8f46a4cc1745f272cc371550fb7fc05/torchtext-0.18.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:3dc446f74aaa9aebab045fbefd102752675258e72ba447982c65e010e1cfd29a", size = 2021446 }, - { url = "https://files.pythonhosted.org/packages/b2/3d/6f18d551b00bf8babaa3a569d5fd62cba2bd7bbdeaf82167a959352ba56b/torchtext-0.18.0-cp310-cp310-win_amd64.whl", hash = "sha256:d4bfe9cb7b08cf7ff3473309d9f24ed243c3a847bfbb2c932925551bf7a05892", size = 1949005 }, + { url = "https://files.pythonhosted.org/packages/10/6f/673e3533a296f135fecfccdf2519ecfba7e16971dca5c3bc7a8cc9cfd064/torchtext-0.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aa59df8f9542674311fc23aca147a34256c936c25840c4b6ee3fee47d511ad17", size = 1775853 }, + { url = "https://files.pythonhosted.org/packages/2f/bd/5f27d604d3dc6421b3c0bd24c28f73eecb091fce9dbdcbe7af314f252cee/torchtext-0.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:492a22727181edf5a33fa18587f3430ffbb366c2ea835e0f4f8a08be8d9e859c", size = 1966034 }, + { url = "https://files.pythonhosted.org/packages/48/4e/56352383c30b75becd5faaff8d404eb86f3a2282d72ae52aaad705bf22bf/torchtext-0.13.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:f56359165eb00ea2ff998b67727f87e7fa32665c1a46610c9b5a2d5d581095e5", size = 1910382 }, + { url = "https://files.pythonhosted.org/packages/3f/fd/e3eef8b5d691cdeb42506fc9fec2a64ab1549039cdf9e7545a171e4a694e/torchtext-0.13.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:b5bf4f9da5326b6e74318b4a5035abfaf166b3abd822565be685f44947adb8d3", size = 1832850 }, + { url = "https://files.pythonhosted.org/packages/b8/9d/7f9b786637d664579b66ae7c6742d662a91b8e6a9f55a34e22c20883d801/torchtext-0.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f8c1b426bda2f22e5bfd118c779c12f8612ed1077e5e3a491242bb4ab7ac4d3", size = 2239348 }, ] [[package]] @@ -4792,15 +4323,6 @@ torch = [ { name = "torch" }, ] -[[package]] -name = "triton" -version = "3.5.0" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/22/507b6f58a35e05e84381630b2dc2a3cee1a7a2a7eaf4cba857c638a18a24/triton-3.5.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6f90de6a6566bb619b4c0adc9855729e1b1b5e26533fca1bf6206e96b6d277a3", size = 159827599 }, - { url = "https://files.pythonhosted.org/packages/0b/eb/09e31d107a5d00eb281aa7e6635ca463e9bca86515944e399480eadb71f8/triton-3.5.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5d3b3d480debf24eaa739623c9a42446b0b77f95593d30eb1f64cd2278cc1f0", size = 170333110 }, -] - [[package]] name = "typer" version = "0.20.0" @@ -4933,15 +4455,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/6e/3e955517e22cbdd565f2f8b2e73d52528b14b8bcfdb04f62466b071de847/validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd", size = 44712 }, ] -[[package]] -name = "validators" -version = "0.35.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/66/a435d9ae49850b2f071f7ebd8119dd4e84872b01630d6736761e6e7fd847/validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a", size = 73399 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/6e/3e955517e22cbdd565f2f8b2e73d52528b14b8bcfdb04f62466b071de847/validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd", size = 44712 }, -] - [[package]] name = "virtualenv" version = "20.35.4" @@ -4975,24 +4488,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, ] -[[package]] -name = "watchdog" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, -] - [[package]] name = "watchfiles" version = "1.1.1" @@ -5230,12 +4725,3 @@ sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50e wheels = [ { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, ] - -[[package]] -name = "zipp" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, -] From 5ac37a0c120e92cffb0d9f7571d752f968c4635a Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 5 Dec 2025 19:22:11 +0000 Subject: [PATCH 021/104] =?UTF-8?q?=F0=9F=A9=B9=20Fix:=20Add=20missing=20e?= =?UTF-8?q?nvironment=20variable=20for=20OLLAMA=5FHOST=20in=20docker-compo?= =?UTF-8?q?se?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index b9f2ab12..9a0b3da7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,6 +12,8 @@ services: env_file: - .env - .env.common + environment: + OLLAMA_HOST: http://ollama:11434 volumes: - ./resources/cache:/resources/cache @@ -26,6 +28,8 @@ services: dockerfile: ./docker/api/Dockerfile target: aymurai-api-full restart: always + environment: + OLLAMA_HOST: http://ollama:11434 deploy: resources: limits: From c1a8a9a279cab2d445e51a42b3df7a855632f1f7 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 5 Dec 2025 19:26:31 +0000 Subject: [PATCH 022/104] =?UTF-8?q?=F0=9F=93=9D=20Add=20anonymization=20pi?= =?UTF-8?q?peline=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/anonymization/README.md | 33 + docs/anonymization/pipeline.excalidraw | 3892 ++++++++++++++++++++++++ 2 files changed, 3925 insertions(+) create mode 100644 docs/anonymization/README.md create mode 100644 docs/anonymization/pipeline.excalidraw diff --git a/docs/anonymization/README.md b/docs/anonymization/README.md new file mode 100644 index 00000000..899a2081 --- /dev/null +++ b/docs/anonymization/README.md @@ -0,0 +1,33 @@ +## Pipeline actual de anonimización + +1. `/misc/document-extract` recibe el DOCX/PDF y devuelve el payload estructurado con `document_id` y la lista de párrafos. +2. `/anonymizer/predict` procesa cada párrafo y retorna las entidades detectadas (`aymurai_label`, texto y offsets) que el frontend reúne sobre el texto completo. Las predicciones originales se persisten en la base de datos. +3. Se validan manualmente las etiquetas consolidadas directamente en la interfaz gráfica. Al confirmar, se persisten las validaciones en la base de datos. +4. `/anonymizer/anonymize-document` aplica los reemplazos según las entidades confirmadas y genera el documento anonimizado listo para descarga. + +## Anonimización con Desambiguación de Entidades Canónicas + +1. `/misc/document-extract` recibe el DOCX/PDF y devuelve el payload estructurado (`document_id`, lista de párrafos) tal como hoy. +2. Se procesa cada párrafo con `/anonymizer/predict`, obteniendo los resultados de NER (`aymurai_label`, texto, offsets, contexto previo y posterior y otros atributos). +3. Se consolida la inferencia: agrupamos todas las menciones detectadas y armamos un paquete enriquecido con contexto circundante (párrafo u oraciones vecinas). +4. Módulo de fuzzy-matching cruza cada mención extraida para sugerir candidatos de `CanonicalEntities` (`canonical_text` y `aliases`). +5. El contexto del paso 3 más las sugerencias del paso 4 son insumo para el servicio de desambiguación (LLM); el modelo se encarga de validar los `CanonicalEntities` sugeridos o proponer nuevos, al tiempo que infiere atributos adicionales (rol procesal), devolviendo una lista refinada de `CanonicalEntities`. +6. Con esa lista se ejecuta el mapeo de `Entity` a `CanonicalEntity`: cada mención NER queda anotada con un `canonical_entity_id` y un `aymurai_label_suffix` y cualquier atributo inferido, generando la desambiguación de entidades. +7. El frontend consume esos outputs y muestra el texto original con dos niveles de revisión: etiquetas NER y asignación canónica. +8. Tras la validación manual, el cliente invoca `/anonymizer/anonymize-document`, que ahora utiliza el `aymurai_label_suffix` para aplicar reemplazos consistentes y generar el documento anonimizado final. +9. El documento anonimizado queda disponible para descarga y se registran en la base de datos las decisiones finales (etiquetas y canónicos). + +## Plan de evaluación incremental + +El objetivo general es optimizar la extracción y desambiguación de entidades. Para avanzar con criterio orientado a métricas mediremos cada capa y el sistema end-to-end. + +- **NER**: aunque el modelo actual cubre el caso de uso, debemos planificar un nuevo ciclo de entrenamiento y finetuning. Será importante consolidar un dataset público anotado con las entidades a detectar, para lo cual podemos aprovechar repositorios públicos de documentos legales de Argentina (e idealmente, del resto de latinoamérica). Para el etiquetado automático, podemos combinar predicciones del NER actual con las extracciones obtenidas usando [`langextract`](/notebooks/experiments/anonymization/05-langextract.ipynb), y conservar solo las coincidencias exactas entre ambos sistemas para minimizar ruido. Luego, se deberán realizar algunas revisiones manuales para asegurar calidad. Este dataset nos permitirá definir un split de evaluación estable y automatizar el cálculo de F1 por etiqueta para comparar versiones de forma consistente. +- **Heurística de agrupación**: vamos a contrastar variantes como Levenshtein normalizada, token fuzzy matching o TF-IDF con coseno. Cada método se ejecutará sobre predicciones reales del NER (para medir robustez ante ruido) y sobre etiquetas existentes (para estimar el techo teórico). La métrica utilizada para evaluar será aquella definida en `/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md`, contra un conjunto de `CanonicalEntities` ya anotados. +- **LLM para desambiguación**: la calidad depende de cómo se promptea y del contexto entregado. Deberíamos experimentar con distintas ventanas de contexto variable (documento completo, párrafos que contienen entidades, oraciones vecinas, metadata, etc.), variantes de prompt (instrucciones directas versus cadenas guiadas) y configuraciones de temperatura/top-p. Cada variante se evaluará con la métrica anteriormente mencionada. + +Finalmente consolidaremos una evaluación integrada combinando el mejor NER disponible, la heurística con mayor cobertura y baja tasa de falsos positivos y la versión de prompt más precisa. El benchmark se ejecutará sobre un conjunto de documentos de validación con etiquetas canónicas revisadas. + +## Consideraciones de integración con frontend + +- Necesitamos habilitar una lista configurable de entidades a excluir de la anonimización. El frontend deberá permitir que la persona usuaria decida, por ejemplo, mantener visibles o no entidades específicas o menciones a funcionariaos públicos según su rol procesal. +- Las exclusiones y la edición manual posterior impactan directamente en el ordenamiento de los `aymurai_label_suffix`. Habrá que recalcular los sufijos luego de aplicar exclusiones y validaciones para evitar huecos o inconsistencias entre el texto mostrado y los reemplazos finales. diff --git a/docs/anonymization/pipeline.excalidraw b/docs/anonymization/pipeline.excalidraw new file mode 100644 index 00000000..358c538e --- /dev/null +++ b/docs/anonymization/pipeline.excalidraw @@ -0,0 +1,3892 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "id": "mprOUEQImobIiF7TwmSu5", + "type": "rectangle", + "x": 323.33333333333337, + "y": 212.14179104477614, + "width": 215.66666666666663, + "height": 280.0447761194029, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a0", + "roundness": { + "type": 3 + }, + "seed": 1252894395, + "version": 114, + "versionNonce": 929231579, + "isDeleted": false, + "boundElements": [ + { + "id": "WOvaiSIhXDUuFwvEHM9bo", + "type": "arrow" + } + ], + "updated": 1764873895187, + "link": null, + "locked": false + }, + { + "id": "j4e8O-DqInLIe6FPmm6uf", + "type": "line", + "x": 366.7885572139304, + "y": 252.37810945273628, + "width": 94.95771144278605, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a1", + "roundness": { + "type": 2 + }, + "seed": 1993017845, + "version": 82, + "versionNonce": 612513819, + "isDeleted": false, + "boundElements": null, + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 94.95771144278605, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "VvUrRcwOayuSCWD_BEIZ-", + "type": "line", + "x": 362.4084692677094, + "y": 279.52565900841427, + "width": 48.28358208955214, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a2", + "roundness": { + "type": 2 + }, + "seed": 1917498107, + "version": 185, + "versionNonce": 1834646715, + "isDeleted": false, + "boundElements": [], + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 48.28358208955214, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "XF0GuSC8OHCflsYFqZIj-", + "type": "line", + "x": 362.95503103842134, + "y": 309.29823770215256, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a3", + "roundness": { + "type": 2 + }, + "seed": 954781173, + "version": 215, + "versionNonce": 1208036699, + "isDeleted": false, + "boundElements": [], + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "ePQ9UG1U9o78Pyz1DIpJG", + "type": "text", + "x": 376.4452736318408, + "y": 538.8606965174129, + "width": 82.85454631444826, + "height": 80.47263681592038, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a4", + "roundness": null, + "seed": 899224181, + "version": 96, + "versionNonce": 1204341243, + "isDeleted": false, + "boundElements": null, + "updated": 1764873895188, + "link": null, + "locked": false, + "text": ".docx\n.pdf", + "fontSize": 32.189054726368155, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": ".docx\n.pdf", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "50Qya96m5ryhBOeNuo5sd", + "type": "line", + "x": 361.96019900497515, + "y": 337.67910447761193, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a5", + "roundness": { + "type": 2 + }, + "seed": 1599168565, + "version": 113, + "versionNonce": 1907610267, + "isDeleted": false, + "boundElements": null, + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "euPm7o0scLf0nKXvH2Mi-", + "type": "line", + "x": 369.12473982912934, + "y": 364.5779783514023, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a6", + "roundness": { + "type": 2 + }, + "seed": 1599660891, + "version": 147, + "versionNonce": 108316475, + "isDeleted": false, + "boundElements": [], + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "RTz0Ti8oU16rW7TBEfaWk", + "type": "line", + "x": 369.4772828409415, + "y": 390.08391000778613, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a7", + "roundness": { + "type": 2 + }, + "seed": 1240160981, + "version": 253, + "versionNonce": 208545755, + "isDeleted": false, + "boundElements": [], + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "ovlQj2YD-86eShmKhZsbR", + "type": "line", + "x": 368.4824508074953, + "y": 418.4647767832455, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a8", + "roundness": { + "type": 2 + }, + "seed": 1975728181, + "version": 151, + "versionNonce": 431125627, + "isDeleted": false, + "boundElements": [], + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "EtWsq0p_WPVrVIpbECqaR", + "type": "line", + "x": 375.6469916316496, + "y": 445.36365065703586, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "6mIBkNFpjb5VS1uhyvbNS" + ], + "frameId": null, + "index": "a9", + "roundness": { + "type": 2 + }, + "seed": 158886293, + "version": 185, + "versionNonce": 1577331995, + "isDeleted": false, + "boundElements": [], + "updated": 1764873895188, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "WOvaiSIhXDUuFwvEHM9bo", + "type": "arrow", + "x": 544.801292623903, + "y": 335.6285710087246, + "width": 276.37331055069967, + "height": 0.9929830550302654, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aA", + "roundness": { + "type": 2 + }, + "seed": 910188603, + "version": 458, + "versionNonce": 376827547, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "2tskJJoi5g4IGXcOp3rfQ" + } + ], + "updated": 1764875808259, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 276.37331055069967, + -0.9929830550302654 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "mprOUEQImobIiF7TwmSu5", + "focus": -0.11485898447026521, + "gap": 5.801292623903009 + }, + "endBinding": { + "elementId": "R8DpmX_gFC_B_zQb3gs_d", + "focus": 0.058585250919652596, + "gap": 26.273809523809632 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "2tskJJoi5g4IGXcOp3rfQ", + "type": "text", + "x": 600.4880623401708, + "y": 310.1320794812094, + "width": 164.99977111816406, + "height": 50, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aB", + "roundness": null, + "seed": 773447163, + "version": 42, + "versionNonce": 491638229, + "isDeleted": false, + "boundElements": null, + "updated": 1764875807159, + "link": null, + "locked": false, + "text": "/misc/document-\nextract", + "fontSize": 20, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "WOvaiSIhXDUuFwvEHM9bo", + "originalText": "/misc/document-extract", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "R8DpmX_gFC_B_zQb3gs_d", + "type": "text", + "x": 847.4484126984123, + "y": 224.08730158730157, + "width": 536.5656565656566, + "height": 232.7272727272728, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aE", + "roundness": null, + "seed": 890582459, + "version": 272, + "versionNonce": 1768355637, + "isDeleted": false, + "boundElements": [ + { + "id": "WOvaiSIhXDUuFwvEHM9bo", + "type": "arrow" + } + ], + "updated": 1764874730850, + "link": null, + "locked": false, + "text": "{\n \"document_id\": ,\n \"document\": [\n \"R., MATIAS EZEQUIEL SOBRE\n128 1 párr\",\n ...\n ]\n}", + "fontSize": 23.27272727272728, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "{\n \"document_id\": ,\n \"document\": [\n \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n ...\n ]\n}", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "9wZT6gadfEtFJsnK6a38y", + "type": "arrow", + "x": 1160.80487286459, + "y": 452.14285714285705, + "width": 348.62970232164366, + "height": 56.216370515816834, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aF", + "roundness": { + "type": 2 + }, + "seed": 1750164379, + "version": 998, + "versionNonce": 411091643, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "1kzq54A47HhfpjGS19GQs" + } + ], + "updated": 1764876692331, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 151.88163507191734, + 49.64285714285717 + ], + [ + 348.62970232164366, + 56.216370515816834 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "elementId": "XNFeqRFFVQOQ2Amv9KiKf", + "focus": -0.20762051337520257, + "gap": 22.16146671210572 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false, + "fixedSegments": [ + { + "index": 2, + "start": [ + 0, + 123.33333333333314 + ], + "end": [ + 111.76666666666688, + 123.33333333333314 + ] + }, + { + "index": 3, + "start": [ + 111.76666666666688, + 123.33333333333314 + ], + "end": [ + 111.76666666666688, + 110.84286406975184 + ] + } + ], + "startIsSpecial": false, + "endIsSpecial": false + }, + { + "id": "1kzq54A47HhfpjGS19GQs", + "type": "text", + "x": 1208.1866528950034, + "y": 489.2857142857142, + "width": 208.9997100830078, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aFV", + "roundness": null, + "seed": 1033291995, + "version": 30, + "versionNonce": 40809307, + "isDeleted": false, + "boundElements": null, + "updated": 1764876692331, + "link": null, + "locked": false, + "text": "/anonymizer/predict", + "fontSize": 20, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "9wZT6gadfEtFJsnK6a38y", + "originalText": "/anonymizer/predict", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "XNFeqRFFVQOQ2Amv9KiKf", + "type": "rectangle", + "x": 1526.4365079365075, + "y": 256.86507936507934, + "width": 521.6666666666664, + "height": 428.88888888888886, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aH", + "roundness": { + "type": 3 + }, + "seed": 477388725, + "version": 215, + "versionNonce": 1294039099, + "isDeleted": false, + "boundElements": [ + { + "id": "dHelCwKVUG5VTmm5vyDz_", + "type": "arrow" + }, + { + "id": "X1lDBhgBqAfbBo2Wh3tA1", + "type": "arrow" + }, + { + "id": "9wZT6gadfEtFJsnK6a38y", + "type": "arrow" + } + ], + "updated": 1764874713403, + "link": null, + "locked": false + }, + { + "id": "DDpm2VgzVTuFYgzzSeDoT", + "type": "text", + "x": 1698.3106526268848, + "y": 697.4206349206348, + "width": 127.13986206054688, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aI", + "roundness": null, + "seed": 781671541, + "version": 183, + "versionNonce": 198505051, + "isDeleted": false, + "boundElements": [ + { + "id": "qJLbJGOfzrt9cwONItkng", + "type": "arrow" + } + ], + "updated": 1764875154944, + "link": null, + "locked": false, + "text": "NER outputs", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "NER outputs", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "qJLbJGOfzrt9cwONItkng", + "type": "arrow", + "x": 1759.2849840986328, + "y": 751.4206349206347, + "width": 5.191199117050928, + "height": 178.5, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aJ", + "roundness": { + "type": 2 + }, + "seed": 1942697813, + "version": 481, + "versionNonce": 1156232859, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "i_EvQstHW-Ge2wvbLPeQ_" + } + ], + "updated": 1764875159518, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 5.191199117050928, + 178.5 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "DDpm2VgzVTuFYgzzSeDoT", + "focus": 0.05947616440110493, + "gap": 14 + }, + "endBinding": { + "elementId": "QMg1bW0iJLThqV1wPLnRu", + "focus": -0.39612694313383184, + "gap": 1 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "i_EvQstHW-Ge2wvbLPeQ_", + "type": "text", + "x": 1654.8938758278896, + "y": 786.9206349206347, + "width": 204.59686279296875, + "height": 70, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aJG", + "roundness": null, + "seed": 1379805179, + "version": 123, + "versionNonce": 1293571995, + "isDeleted": false, + "boundElements": null, + "updated": 1764875154945, + "link": null, + "locked": false, + "text": "fuzzy matching\napproach", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "qJLbJGOfzrt9cwONItkng", + "originalText": "fuzzy matching approach", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "QMg1bW0iJLThqV1wPLnRu", + "type": "text", + "x": 1498.6190476190475, + "y": 929.9206349206347, + "width": 905.5525030525026, + "height": 372.5, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aL", + "roundness": null, + "seed": 101534011, + "version": 624, + "versionNonce": 869890651, + "isDeleted": false, + "boundElements": [ + { + "id": "qJLbJGOfzrt9cwONItkng", + "type": "arrow" + }, + { + "id": "ZMKT-Hy2-Yjk8g0ssbD0q", + "type": "arrow" + } + ], + "updated": 1764876718291, + "link": null, + "locked": false, + "text": "[\n {\n \"aymurai_label\": \"PER\",\n \"canonical_text\": \"MATIAS EZEQUIEL R.\",\n \"aliases\": [\n \"MATIAS EZEQUIEL R.\",\n \"R., MATÍAS EZEQUIEL\",\n \"Matías Ezequiel R.\"\n ],\n \"attributes\": {}\n \n }\n]", + "fontSize": 22.923076923076923, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[\n {\n \"aymurai_label\": \"PER\",\n \"canonical_text\": \"MATIAS EZEQUIEL R.\",\n \"aliases\": [\n \"MATIAS EZEQUIEL R.\",\n \"R., MATÍAS EZEQUIEL\",\n \"Matías Ezequiel R.\"\n ],\n \"attributes\": {}\n \n }\n]", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "ZMKT-Hy2-Yjk8g0ssbD0q", + "type": "arrow", + "x": 1779.442822764371, + "y": 1253.9206349206347, + "width": 1.335206841328045, + "height": 212.22319297821105, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aM", + "roundness": { + "type": 2 + }, + "seed": 1658264629, + "version": 582, + "versionNonce": 1501063611, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "cPRb_-k-P_xgsphynZa-B" + } + ], + "updated": 1764876718291, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -1.335206841328045, + 212.22319297821105 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "QMg1bW0iJLThqV1wPLnRu", + "focus": 0.37688413952517746, + "gap": 14 + }, + "endBinding": { + "elementId": "HT4dCz_WP0No85IzXVlCJ", + "focus": 0.01747376853034287, + "gap": 14 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "cPRb_-k-P_xgsphynZa-B", + "type": "text", + "x": 1680.8807133568653, + "y": 1277.5159805629846, + "width": 186.99974060058594, + "height": 50, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aMV", + "roundness": null, + "seed": 1547919451, + "version": 55, + "versionNonce": 979131387, + "isDeleted": false, + "boundElements": null, + "updated": 1764875143575, + "link": null, + "locked": false, + "text": "CanonicalEntities\n", + "fontSize": 20, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "ZMKT-Hy2-Yjk8g0ssbD0q", + "originalText": "CanonicalEntities\n", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "HT4dCz_WP0No85IzXVlCJ", + "type": "diamond", + "x": 1572.2377265143011, + "y": 1491.9307081807083, + "width": 404.2857142857141, + "height": 299.9999999999999, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aN", + "roundness": { + "type": 2 + }, + "seed": 474391803, + "version": 219, + "versionNonce": 917939349, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "6BbvmS0QuJA92jEgUAM7-" + }, + { + "id": "ZMKT-Hy2-Yjk8g0ssbD0q", + "type": "arrow" + }, + { + "id": "dHelCwKVUG5VTmm5vyDz_", + "type": "arrow" + } + ], + "updated": 1764876727910, + "link": null, + "locked": false + }, + { + "id": "6BbvmS0QuJA92jEgUAM7-", + "type": "text", + "x": 1748.381054499792, + "y": 1624.4307081807083, + "width": 51.856201171875, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aO", + "roundness": null, + "seed": 827091643, + "version": 146, + "versionNonce": 459352021, + "isDeleted": false, + "boundElements": null, + "updated": 1764875170814, + "link": null, + "locked": false, + "text": "LLM", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "HT4dCz_WP0No85IzXVlCJ", + "originalText": "LLM", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "dHelCwKVUG5VTmm5vyDz_", + "type": "arrow", + "x": 2063.285201930389, + "y": 694.3135258107342, + "width": 474.8611910477862, + "height": 844.0773032721003, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aR", + "roundness": { + "type": 2 + }, + "seed": 2016671099, + "version": 642, + "versionNonce": 611520693, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "GTYZaUFv22_vAQroP4Ots" + } + ], + "updated": 1764876728139, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 290.8894012442138, + 434.06705471007433 + ], + [ + -183.9717898035724, + 844.0773032721003 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "XNFeqRFFVQOQ2Amv9KiKf", + "focus": -0.3128704896896401, + "gap": 28.317023962699135 + }, + "endBinding": { + "elementId": "HT4dCz_WP0No85IzXVlCJ", + "focus": -0.07412509117026206, + "gap": 24.87677840035615 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "GTYZaUFv22_vAQroP4Ots", + "type": "text", + "x": 2323.4000670417904, + "y": 1024.213913854142, + "width": 261.549072265625, + "height": 35, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aRV", + "roundness": null, + "seed": 1799358171, + "version": 29, + "versionNonce": 916759547, + "isDeleted": false, + "boundElements": null, + "updated": 1764873079510, + "link": null, + "locked": false, + "text": "Entities in context", + "fontSize": 28, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "dHelCwKVUG5VTmm5vyDz_", + "originalText": "Entities in context", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "fQd08AUXM4h1r1rt1GEYO", + "type": "arrow", + "x": 1531.7321526774883, + "y": 1643.1003241404883, + "width": 262.51194713959944, + "height": 2.3392319195597793, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aT", + "roundness": { + "type": 2 + }, + "seed": 860487771, + "version": 330, + "versionNonce": 363111093, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "NX_RkmyZ4ShoFSsJ4jTLw" + } + ], + "updated": 1764875170815, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -262.51194713959944, + -2.3392319195597793 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "NX_RkmyZ4ShoFSsJ4jTLw", + "type": "text", + "x": 576.9763088073955, + "y": 1091.9307081807083, + "width": 186.99974060058594, + "height": 50, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aU", + "roundness": null, + "seed": 410991867, + "version": 62, + "versionNonce": 810030421, + "isDeleted": false, + "boundElements": [], + "updated": 1764875170815, + "link": null, + "locked": false, + "text": "CanonicalEntities\n", + "fontSize": 20, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "fQd08AUXM4h1r1rt1GEYO", + "originalText": "CanonicalEntities\n", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "IEM1W5vPfKwT3lgRgCi-R", + "type": "text", + "x": 694.7031440781441, + "y": 1395.8730158730161, + "width": 905.5525030525026, + "height": 487.1153846153846, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aW", + "roundness": null, + "seed": 202961365, + "version": 797, + "versionNonce": 518433403, + "isDeleted": false, + "boundElements": [ + { + "id": "ZMKT-Hy2-Yjk8g0ssbD0q", + "type": "arrow" + } + ], + "updated": 1764875186373, + "link": null, + "locked": false, + "text": "[\n {\n \"entity_id\": ,\n \"aymurai_label\": \"PER\",\n \"canonical_text\": \"MATIAS EZEQUIEL R.\",\n \"aliases\": [\n \"MATIAS EZEQUIEL R.\",\n \"R., MATÍAS EZEQUIEL\",\n \"Matías Ezequiel R.\"\n ],\n \"attributes\": {\n \"role\": \"Acusado/a \n }\n \n },\n ...\n]", + "fontSize": 22.923076923076923, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[\n {\n \"entity_id\": ,\n \"aymurai_label\": \"PER\",\n \"canonical_text\": \"MATIAS EZEQUIEL R.\",\n \"aliases\": [\n \"MATIAS EZEQUIEL R.\",\n \"R., MATÍAS EZEQUIEL\",\n \"Matías Ezequiel R.\"\n ],\n \"attributes\": {\n \"role\": \"Acusado/a \n }\n \n },\n ...\n]", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "X1lDBhgBqAfbBo2Wh3tA1", + "type": "arrow", + "x": 1522.927714874569, + "y": 690.6888562602353, + "width": 1016.253111699966, + "height": 1419.4587535518317, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aY", + "roundness": { + "type": 2 + }, + "seed": 1525774261, + "version": 379, + "versionNonce": 916502267, + "isDeleted": false, + "boundElements": null, + "updated": 1764874776673, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -1016.253111699966, + 794.7674929461141 + ], + [ + -678.7729798846242, + 1419.4587535518317 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "XNFeqRFFVQOQ2Amv9KiKf", + "focus": -0.03022916805647842, + "gap": 17.297044401543584 + }, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "bLpxUpm3l_5AdE-wefxGf", + "type": "arrow", + "x": 1033.2850735335269, + "y": 1775.4563492063494, + "width": 0.08162462097448042, + "height": 270.3395345008357, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aZ", + "roundness": { + "type": 2 + }, + "seed": 1621637429, + "version": 264, + "versionNonce": 980985435, + "isDeleted": false, + "boundElements": null, + "updated": 1764876700324, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -0.08162462097448042, + 270.3395345008357 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": { + "elementId": "-PgdE-XG4rOV6rnyozIFX", + "focus": -0.010707089043139571, + "gap": 30.459273173000824 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "-PgdE-XG4rOV6rnyozIFX", + "type": "diamond", + "x": 762.8365384615385, + "y": 2065.4563492063494, + "width": 544.2857142857139, + "height": 342.49999999999994, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "aa", + "roundness": { + "type": 2 + }, + "seed": 987028059, + "version": 397, + "versionNonce": 1724613083, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Xwf273IrzwAMLQrLCkCOu" + }, + { + "id": "3VriZd7FuEOwMpdPbnIiX", + "type": "arrow" + }, + { + "id": "bLpxUpm3l_5AdE-wefxGf", + "type": "arrow" + } + ], + "updated": 1764876697912, + "link": null, + "locked": false + }, + { + "id": "Xwf273IrzwAMLQrLCkCOu", + "type": "text", + "x": 919.4074406047444, + "y": 2184.0813492063494, + "width": 231.0010528564453, + "height": 105, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ab", + "roundness": null, + "seed": 1570690811, + "version": 369, + "versionNonce": 1402964917, + "isDeleted": false, + "boundElements": [], + "updated": 1764875219055, + "link": null, + "locked": false, + "text": "Entity to\nCanonicalEntity\nmapping", + "fontSize": 28, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "-PgdE-XG4rOV6rnyozIFX", + "originalText": "Entity to CanonicalEntity mapping", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "YWHB-Nw2VxgFSkL-pcYdK", + "type": "text", + "x": 1035.5431163075204, + "y": 3213.0399522268453, + "width": 223.87255859375, + "height": 80.21844660194176, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "al", + "roundness": null, + "seed": 1428684437, + "version": 332, + "versionNonce": 1630622267, + "isDeleted": false, + "boundElements": [ + { + "id": "j-ZCuk6tMAZF7uiWTtIk4", + "type": "arrow" + } + ], + "updated": 1764875186373, + "link": null, + "locked": false, + "text": "Disambiguated\nNER outputs", + "fontSize": 32.087378640776706, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "Disambiguated\nNER outputs", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "3VriZd7FuEOwMpdPbnIiX", + "type": "arrow", + "x": 1049.3582234833063, + "y": 2398.7390090918116, + "width": 56.8350216132967, + "height": 206.2823298539638, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "am", + "roundness": { + "type": 2 + }, + "seed": 479819349, + "version": 456, + "versionNonce": 528370965, + "isDeleted": false, + "boundElements": [], + "updated": 1764875219055, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 56.8350216132967, + 206.2823298539638 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "-PgdE-XG4rOV6rnyozIFX", + "focus": 0.11433848854056756, + "gap": 3.6805732632926023 + }, + "endBinding": { + "elementId": "RCTW7-Twmc0vzPbjJZlva", + "focus": 0.012854192325188162, + "gap": 17.9562212017031 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "j-ZCuk6tMAZF7uiWTtIk4", + "type": "arrow", + "x": 1149.7230307134546, + "y": 3304.34173216212, + "width": 0.0530047510710574, + "height": 179.03128371089633, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "an", + "roundness": { + "type": 2 + }, + "seed": 1544894267, + "version": 234, + "versionNonce": 63933787, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 0.0530047510710574, + 179.03128371089633 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "YWHB-Nw2VxgFSkL-pcYdK", + "focus": -0.12996340741750428, + "gap": 11.08333333333303 + }, + "endBinding": { + "elementId": "htYeX7jml0k3AqG6W3Q_x", + "focus": -0.1090092112744266, + "gap": 22.666666666666515 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "htYeX7jml0k3AqG6W3Q_x", + "type": "image", + "x": 635.4793956043954, + "y": 3506.039682539683, + "width": 1024, + "height": 473, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "ao", + "roundness": null, + "seed": 1128147605, + "version": 156, + "versionNonce": 748760533, + "isDeleted": false, + "boundElements": [ + { + "id": "j-ZCuk6tMAZF7uiWTtIk4", + "type": "arrow" + } + ], + "updated": 1764879496527, + "link": null, + "locked": false, + "status": "pending", + "fileId": "7828d57068931cdd86458a8cbc891ed6ee122d38", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "a9YgxexRbVJcxPwYgreZn", + "type": "arrow", + "x": 1147.7941516061107, + "y": 4019.4978280481223, + "width": 2.5974080402759228, + "height": 247.43565838777295, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b01", + "roundness": { + "type": 2 + }, + "seed": 1067879003, + "version": 921, + "versionNonce": 230655093, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "elej2TV9eJ1qTHpBpx-2H" + } + ], + "updated": 1764879496527, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -0.3147560017152955, + 139.37773758213234 + ], + [ + 2.2826520385606273, + 247.43565838777295 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "elej2TV9eJ1qTHpBpx-2H", + "type": "text", + "x": 1036.3792216542001, + "y": 4122.625565630255, + "width": 167.20034790039062, + "height": 40, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b01G", + "roundness": null, + "seed": 553249339, + "version": 35, + "versionNonce": 359281307, + "isDeleted": false, + "boundElements": null, + "updated": 1764875186373, + "link": null, + "locked": false, + "text": "/anonymizer/anonymi\nze-document", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "a9YgxexRbVJcxPwYgreZn", + "originalText": "/anonymizer/anonymize-document", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "h9PsSXNcnOUBkMSzBjg6z", + "type": "rectangle", + "x": 1052.940182148664, + "y": 4308.408197109689, + "width": 215.66666666666663, + "height": 280.0447761194029, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b08", + "roundness": { + "type": 3 + }, + "seed": 1300012667, + "version": 142, + "versionNonce": 1041008603, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false + }, + { + "id": "UieOrbihjMKgv6n7yxaDj", + "type": "line", + "x": 1096.3954060292608, + "y": 4348.64451551765, + "width": 94.95771144278605, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b09", + "roundness": { + "type": 2 + }, + "seed": 720967451, + "version": 110, + "versionNonce": 1216664699, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 94.95771144278605, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "10owweBOlc7qCyP6aRJJV", + "type": "line", + "x": 1092.0153180830398, + "y": 4375.792065073328, + "width": 48.28358208955214, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0A", + "roundness": { + "type": 2 + }, + "seed": 1604156347, + "version": 213, + "versionNonce": 1133153563, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 48.28358208955214, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "BQmhv6TG0JxjRxuwDfSMw", + "type": "line", + "x": 1092.561879853752, + "y": 4405.564643767066, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0B", + "roundness": { + "type": 2 + }, + "seed": 395070555, + "version": 243, + "versionNonce": 311439803, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "4Hm0xXA1DdypSLAR9BoaN", + "type": "text", + "x": 929.1926219227548, + "y": 4635.127102582326, + "width": 436.57354736328125, + "height": 40.2363184079602, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0C", + "roundness": null, + "seed": 1452804347, + "version": 162, + "versionNonce": 112738907, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "text": "documento_anonimizado.odt", + "fontSize": 32.189054726368155, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "documento_anonimizado.odt", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "5LyI3ky8p3RebAfVu1tA_", + "type": "line", + "x": 1091.5670478203056, + "y": 4433.945510542525, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0D", + "roundness": { + "type": 2 + }, + "seed": 37958043, + "version": 141, + "versionNonce": 685063931, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "OSeMl_IH1Pq_pZxGzfw_4", + "type": "line", + "x": 1098.7315886444599, + "y": 4460.844384416316, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0E", + "roundness": { + "type": 2 + }, + "seed": 734021179, + "version": 175, + "versionNonce": 1130997659, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "b4ihNsBPXcvY1lhr6-Ohh", + "type": "line", + "x": 1099.084131656272, + "y": 4486.3503160727, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0F", + "roundness": { + "type": 2 + }, + "seed": 435275483, + "version": 281, + "versionNonce": 749206587, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "mq_eSKsQgMs7MFsq2AJNk", + "type": "line", + "x": 1098.0892996228258, + "y": 4514.731182848159, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0G", + "roundness": { + "type": 2 + }, + "seed": 325727099, + "version": 179, + "versionNonce": 1349696731, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "YN6yT1TNVtadNJ1X5Melr", + "type": "line", + "x": 1105.2538404469801, + "y": 4541.630056721949, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "SQGLLXLdvVhMNPoAROpAt" + ], + "frameId": null, + "index": "b0H", + "roundness": { + "type": 2 + }, + "seed": 1751911451, + "version": 213, + "versionNonce": 2052876667, + "isDeleted": false, + "boundElements": [], + "updated": 1764875186373, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "9G3g0qab8TQWTTo68WKEc", + "type": "text", + "x": 1536.304106606377, + "y": 329.64285714285705, + "width": 476.1529541015625, + "height": 283.3333333333333, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0L", + "roundness": null, + "seed": 915516597, + "version": 11, + "versionNonce": 672956187, + "isDeleted": false, + "boundElements": null, + "updated": 1764875143575, + "link": null, + "locked": false, + "text": "{\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n ...\n }\n }\n ]\n}", + "fontSize": 16.19047619047619, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "{\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n ...\n }\n }\n ]\n}", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "RCTW7-Twmc0vzPbjJZlva", + "type": "rectangle", + "x": 629.1746031746031, + "y": 2613.596856218215, + "width": 1090.833333333333, + "height": 576.5587918015109, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0N", + "roundness": { + "type": 3 + }, + "seed": 2097245493, + "version": 450, + "versionNonce": 492327899, + "isDeleted": false, + "boundElements": [ + { + "id": "3VriZd7FuEOwMpdPbnIiX", + "type": "arrow" + } + ], + "updated": 1764875205688, + "link": null, + "locked": false + }, + { + "id": "Hx_F-eFq9Elf3olyEAh5H", + "type": "text", + "x": 791.7764842274424, + "y": 2644.4357759284935, + "width": 711.4058227539062, + "height": 516.4285714285714, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0O", + "roundness": null, + "seed": 1957523003, + "version": 210, + "versionNonce": 1767565467, + "isDeleted": false, + "boundElements": [ + { + "id": "3VriZd7FuEOwMpdPbnIiX", + "type": "arrow" + } + ], + "updated": 1764875208055, + "link": null, + "locked": false, + "text": "[\n {\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n \"aymurai_label_suffix\": 1,\n \"canonical_entity_id\": ,\n ...\n }\n }\n ]\n }\n]", + "fontSize": 22.952380952380953, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "[\n {\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n \"aymurai_label_suffix\": 1,\n \"canonical_entity_id\": ,\n ...\n }\n }\n ]\n }\n]", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "M3_9cSeevpvgvuGOJmtLu", + "type": "rectangle", + "x": 341.0753968253973, + "y": -946.5918028903099, + "width": 215.66666666666663, + "height": 280.0447761194029, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0P", + "roundness": { + "type": 3 + }, + "seed": 630737269, + "version": 231, + "versionNonce": 857423573, + "isDeleted": false, + "boundElements": [ + { + "id": "EOtxLYz_c5dBLBZTsf6bP", + "type": "arrow" + } + ], + "updated": 1764875361089, + "link": null, + "locked": false + }, + { + "id": "e0VYlO1HBUE6Y61hMmjQS", + "type": "line", + "x": 384.5306207059946, + "y": -906.3554844823498, + "width": 94.95771144278605, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0Q", + "roundness": { + "type": 2 + }, + "seed": 924406485, + "version": 197, + "versionNonce": 1258245525, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 94.95771144278605, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "zz4q6sGFYLSQEGm4_Z_pZ", + "type": "line", + "x": 380.15053275977357, + "y": -879.2079349266717, + "width": 48.28358208955214, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0R", + "roundness": { + "type": 2 + }, + "seed": 2054303797, + "version": 300, + "versionNonce": 2102055669, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 48.28358208955214, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "S9t8FU85SfKbOpC8RR_gM", + "type": "line", + "x": 380.6970945304854, + "y": -849.4353562329334, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0S", + "roundness": { + "type": 2 + }, + "seed": 227041685, + "version": 330, + "versionNonce": 1522445397, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "DL-iPq6d9xxkjVSnghr83", + "type": "text", + "x": 394.1873371239051, + "y": -619.8728974176731, + "width": 82.85454631444826, + "height": 80.47263681592038, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0T", + "roundness": null, + "seed": 898721525, + "version": 211, + "versionNonce": 53500341, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "text": ".docx\n.pdf", + "fontSize": 32.189054726368155, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": ".docx\n.pdf", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "eb7-zegRUYIJqYobn0GTg", + "type": "line", + "x": 379.7022624970393, + "y": -821.0544894574741, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0U", + "roundness": { + "type": 2 + }, + "seed": 1964163157, + "version": 228, + "versionNonce": 2143640341, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "76_13jw7FNEf9CD3vN4K7", + "type": "line", + "x": 386.86680332119363, + "y": -794.1556155836837, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0V", + "roundness": { + "type": 2 + }, + "seed": 1642196405, + "version": 262, + "versionNonce": 418590837, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "7bpvHSILjOEGoxBVuVvmL", + "type": "line", + "x": 387.21934633300566, + "y": -768.6496839272999, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0W", + "roundness": { + "type": 2 + }, + "seed": 992243477, + "version": 368, + "versionNonce": 1820285397, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "hunvhsGsscndVNFWE5PbJ", + "type": "line", + "x": 386.2245142995596, + "y": -740.2688171518405, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0X", + "roundness": { + "type": 2 + }, + "seed": 1062192245, + "version": 266, + "versionNonce": 1132418869, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "T8wwR2IwhMmplgY6InC65", + "type": "line", + "x": 393.3890551237139, + "y": -713.3699432780502, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0Y", + "roundness": { + "type": 2 + }, + "seed": 1110011349, + "version": 300, + "versionNonce": 676898965, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "EOtxLYz_c5dBLBZTsf6bP", + "type": "arrow", + "x": 560.3079384765335, + "y": -801.9441674997673, + "width": 311.1087281901333, + "height": 3.0858479987831515, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0Z", + "roundness": { + "type": 2 + }, + "seed": 46590773, + "version": 818, + "versionNonce": 1436837659, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "AQOsTPNecUVIP5dcYG-CL" + } + ], + "updated": 1764875651472, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 311.1087281901333, + 3.0858479987831515 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "M3_9cSeevpvgvuGOJmtLu", + "focus": 0.024877658056798795, + "gap": 5.80129262390335 + }, + "endBinding": { + "elementId": "vWBP3oXNVHZGwRqV71dye", + "focus": 0.16647678467610177, + "gap": 26.273809523809405 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "AQOsTPNecUVIP5dcYG-CL", + "type": "text", + "x": 617.1124170125182, + "y": -797.1021624155233, + "width": 164.99977111816406, + "height": 50, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0a", + "roundness": null, + "seed": 1099807893, + "version": 47, + "versionNonce": 156055285, + "isDeleted": false, + "boundElements": [], + "updated": 1764875337505, + "link": null, + "locked": false, + "text": "/misc/document-\nextract", + "fontSize": 20, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "EOtxLYz_c5dBLBZTsf6bP", + "originalText": "/misc/document-extract", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "vWBP3oXNVHZGwRqV71dye", + "type": "text", + "x": 897.6904761904764, + "y": -891.8596681096677, + "width": 536.5656565656566, + "height": 232.7272727272728, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0b", + "roundness": null, + "seed": 372466165, + "version": 414, + "versionNonce": 1404522139, + "isDeleted": false, + "boundElements": [ + { + "id": "EOtxLYz_c5dBLBZTsf6bP", + "type": "arrow" + } + ], + "updated": 1764875606006, + "link": null, + "locked": false, + "text": "{\n \"document_id\": ,\n \"document\": [\n \"R., MATIAS EZEQUIEL SOBRE\n128 1 párr\",\n ...\n ]\n}", + "fontSize": 23.27272727272728, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "{\n \"document_id\": ,\n \"document\": [\n \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n ...\n ]\n}", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "AJupGiIgf295eDXNF1NTl", + "type": "rectangle", + "x": 1911.6785714285718, + "y": -959.9404761904758, + "width": 521.6666666666664, + "height": 428.88888888888886, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0e", + "roundness": { + "type": 3 + }, + "seed": 807684629, + "version": 367, + "versionNonce": 1386791739, + "isDeleted": false, + "boundElements": [ + { + "id": "hotXOq7-8juh39kLJem4p", + "type": "arrow" + } + ], + "updated": 1764875606006, + "link": null, + "locked": false + }, + { + "id": "uIFK9kOYNJE4xD48qvRxR", + "type": "text", + "x": 2083.5527161189484, + "y": -757.9960317460313, + "width": 127.13986206054688, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0f", + "roundness": null, + "seed": 1570520949, + "version": 331, + "versionNonce": 2091546331, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "text": "NER outputs", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "NER outputs", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "InHz3D1JmEtzd_JC59uqm", + "type": "text", + "x": 1934.4354277111238, + "y": -887.162698412698, + "width": 476.1529541015625, + "height": 283.3333333333333, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0g", + "roundness": null, + "seed": 1999538389, + "version": 169, + "versionNonce": 660586261, + "isDeleted": false, + "boundElements": [], + "updated": 1764875581978, + "link": null, + "locked": false, + "text": "{\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n ...\n }\n }\n ]\n}", + "fontSize": 16.19047619047619, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "{\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n ...\n }\n }\n ]\n}", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "OKZB0eDL-ABRXZHWhREn2", + "type": "image", + "x": 2663.960317460318, + "y": -976.9960317460313, + "width": 1024, + "height": 473, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0h", + "roundness": null, + "seed": 1317474869, + "version": 341, + "versionNonce": 543979707, + "isDeleted": false, + "boundElements": [ + { + "id": "hotXOq7-8juh39kLJem4p", + "type": "arrow" + } + ], + "updated": 1764875603696, + "link": null, + "locked": false, + "status": "pending", + "fileId": "7828d57068931cdd86458a8cbc891ed6ee122d38", + "scale": [ + 1, + 1 + ], + "crop": null + }, + { + "id": "lhZO6MPRRTWy3V55I0vZM", + "type": "arrow", + "x": 3756.6202534941517, + "y": -758.447755452392, + "width": 403.8000183105464, + "height": 5.908527289127619, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0i", + "roundness": { + "type": 2 + }, + "seed": 280036245, + "version": 1548, + "versionNonce": 1898165275, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "GHolMdYEXJBOSjiLEJF7i" + } + ], + "updated": 1764875603696, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 195.91698365823413, + -2.048276293639333 + ], + [ + 403.8000183105464, + -5.908527289127619 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "GHolMdYEXJBOSjiLEJF7i", + "type": "text", + "x": 3760.5369624941827, + "y": -745.4960317460313, + "width": 264.00054931640625, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0j", + "roundness": null, + "seed": 1331022069, + "version": 47, + "versionNonce": 2111430683, + "isDeleted": false, + "boundElements": [], + "updated": 1764875595533, + "link": null, + "locked": false, + "text": "/anonymizer/anonymize-document", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lhZO6MPRRTWy3V55I0vZM", + "originalText": "/anonymizer/anonymize-document", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "H45OT-nnyrYBIdX_fHnB-", + "type": "rectangle", + "x": 4251.421104004587, + "y": -923.9736436863299, + "width": 215.66666666666663, + "height": 280.0447761194029, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0k", + "roundness": { + "type": 3 + }, + "seed": 1543168597, + "version": 364, + "versionNonce": 1947781947, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false + }, + { + "id": "HkLFBBIeoT2NmdHolQogn", + "type": "line", + "x": 4294.876327885184, + "y": -883.7373252783694, + "width": 94.95771144278605, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0l", + "roundness": { + "type": 2 + }, + "seed": 997576629, + "version": 330, + "versionNonce": 787590107, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 94.95771144278605, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "dP23wQQAJGa8EbTko6TLk", + "type": "line", + "x": 4290.496239938962, + "y": -856.5897757226916, + "width": 48.28358208955214, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0m", + "roundness": { + "type": 2 + }, + "seed": 1005326613, + "version": 433, + "versionNonce": 690321531, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 48.28358208955214, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "AzAxanw4nR0bo9R-OtYUW", + "type": "line", + "x": 4291.042801709675, + "y": -826.8171970289535, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0n", + "roundness": { + "type": 2 + }, + "seed": 1255351925, + "version": 463, + "versionNonce": 276214043, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "cPvNsqjYFBYhf1dvqCfUM", + "type": "text", + "x": 4127.673543778677, + "y": -597.254738213693, + "width": 436.57354736328125, + "height": 40.2363184079602, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0o", + "roundness": null, + "seed": 183537621, + "version": 382, + "versionNonce": 911726011, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "text": "documento_anonimizado.odt", + "fontSize": 32.189054726368155, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "documento_anonimizado.odt", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "FZMsE2ftxJlqlXy5y1Kot", + "type": "line", + "x": 4290.047969676229, + "y": -798.4363302534942, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0p", + "roundness": { + "type": 2 + }, + "seed": 710528309, + "version": 361, + "versionNonce": 434857563, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "c5LayQF2_U6-IqmzQigBO", + "type": "line", + "x": 4297.212510500382, + "y": -771.5374563797035, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0q", + "roundness": { + "type": 2 + }, + "seed": 2020892309, + "version": 395, + "versionNonce": 839115515, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "CZP0a-w2xzB-aIeBIdTfj", + "type": "line", + "x": 4297.565053512195, + "y": -746.0315247233196, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0r", + "roundness": { + "type": 2 + }, + "seed": 1005962229, + "version": 501, + "versionNonce": 1998834587, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "YGpIXuZRgXAXrbeyTS72v", + "type": "line", + "x": 4296.570221478749, + "y": -717.6506579478604, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0s", + "roundness": { + "type": 2 + }, + "seed": 1222868309, + "version": 399, + "versionNonce": 763207739, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "ABZSKgAIt_rm_gemO06m9", + "type": "line", + "x": 4303.734762302903, + "y": -690.7517840740705, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "heHx6O1UXsEtwJkRBikSl" + ], + "frameId": null, + "index": "b0t", + "roundness": { + "type": 2 + }, + "seed": 1452477109, + "version": 433, + "versionNonce": 1861476571, + "isDeleted": false, + "boundElements": [], + "updated": 1764875579057, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "hotXOq7-8juh39kLJem4p", + "type": "arrow", + "x": 2444.591377430666, + "y": -762.2243671485597, + "width": 196.3689400296521, + "height": 3.692569021604527, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0u", + "roundness": { + "type": 2 + }, + "seed": 755633851, + "version": 323, + "versionNonce": 1071716059, + "isDeleted": false, + "boundElements": null, + "updated": 1764875655966, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 196.3689400296521, + -3.692569021604527 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "AJupGiIgf295eDXNF1NTl", + "focus": 0.03289811846175117, + "gap": 14.626683917308128 + }, + "endBinding": { + "elementId": "OKZB0eDL-ABRXZHWhREn2", + "focus": 0.06765961386393643, + "gap": 23 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "gXsFYxTEKv14jMJGLJI8O", + "type": "arrow", + "x": 1452.931012958739, + "y": -762.3018491588567, + "width": 403.8000183105464, + "height": 5.908527289127619, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0v", + "roundness": { + "type": 2 + }, + "seed": 1974610101, + "version": 1579, + "versionNonce": 919034907, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Q4IQFcmT8i1SnTx5DuzTS" + } + ], + "updated": 1764875655966, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 195.91698365823413, + -2.048276293639333 + ], + [ + 403.8000183105464, + -5.908527289127619 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "Q4IQFcmT8i1SnTx5DuzTS", + "type": "text", + "x": 1566.9144893334446, + "y": -809.3501254524961, + "width": 167.20034790039062, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0w", + "roundness": null, + "seed": 2134198805, + "version": 55, + "versionNonce": 1592755067, + "isDeleted": false, + "boundElements": [], + "updated": 1764875655966, + "link": null, + "locked": false, + "text": "/anonymizer/predict", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "gXsFYxTEKv14jMJGLJI8O", + "originalText": "/anonymizer/predict", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "jFnC8PtgWHvjc9weWuFWX", + "type": "text", + "x": 326.69940776522253, + "y": -1119.4404761904757, + "width": 654.3769721137143, + "height": 76.99999999999989, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0z", + "roundness": null, + "seed": 29900859, + "version": 85, + "versionNonce": 988358325, + "isDeleted": false, + "boundElements": null, + "updated": 1764875700204, + "link": null, + "locked": false, + "text": "Anonymization pipeline", + "fontSize": 61.59999999999989, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Anonymization pipeline", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "hdfluh6k2tthpQT1_UP4m", + "type": "text", + "x": 326.69940776522253, + "y": -3.9404761904756924, + "width": 1170.5897216796875, + "height": 76.99999999999986, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b10", + "roundness": null, + "seed": 2091673109, + "version": 149, + "versionNonce": 725184187, + "isDeleted": false, + "boundElements": [], + "updated": 1764875707681, + "link": null, + "locked": false, + "text": "Anonymization + disambiguation pipeline", + "fontSize": 61.59999999999989, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Anonymization + disambiguation pipeline", + "autoResize": true, + "lineHeight": 1.25 + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "7828d57068931cdd86458a8cbc891ed6ee122d38": { + "mimeType": "image/png", + "id": "7828d57068931cdd86458a8cbc891ed6ee122d38", + "dataURL": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAHZCAYAAAAYFEnDAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQd4FcXXxt+9JZUUQhJC6BhaKCqgVAUEQSxIL6KoIKAiKEqRooQiRRAUQSlW9K8IAgICChYEAREsIERASuiQhJDe7r2733cmd8Nm2ZvckISWs8/DE5K7d3fmN7Ozc94554wEPpgAE2ACTIAJMAEmwASYABNgAkyACTCBW56AdMvXkCvIBJgAE2ACTIAJMAEmwASYABNgAkyACYAFAO4ETIAJMAEmwASYABNgAkyACTABJsAESgEBFgBKQSNzFZkAE2ACTIAJMAEmwASYABNgAkyACbAAwH2ACTABJsAEmAATYAJMgAkwASbABJhAKSDAAkApaGSuIhNgAkyACTABJsAEmAATYAJMgAkwARYAuA8wASbABJgAE2ACTIAJMAEmwASYABMoBQRYACgFjcxVZAJMgAkwASbABJgAE2ACTIAJMAEmwAIA9wEmwASYABNgAkyACTABJsAEmAATYAKlgAALAKWgkbmKTIAJMAEmwASYABNgAkyACTABJsAEWADgPsAEmAATYAJMgAkwASbABJgAE2ACTKAUEGABoBQ0MleRCTABJsAEmAATYAJMgAkwASbABJgACwDcB5gAE2ACTIAJMAEmwASYABNgAkyACZQCAiwAlIJG5ioyASbABJgAE2ACTIAJMAEmwASYABNgAYD7ABNgAkyACTABJsAEmAATYAJMgAkwgVJAgAWAUtDIXEUmwASYABNgAkyACTABJsAEmAATYAIsAHAfYAJMgAkwASbABJgAE2ACTIAJMAEmUAoIsABQChqZq8gEmAATYAJMgAkwASbABJgAE2ACTIAFAO4DTIAJMAEmwASYABNgAkyACTABJsAESgEBFgBKQSNzFZkAE2ACTIAJMAEmwASYABNgAkyACbAAwH2ACTABJsAEmAATYAJMgAkwASbABJhAKSDAAkApaGSuIhNgAkyACTABJsAEmAATYAJMgAkwARYAuA8wASbABJgAE2ACTIAJMAEmwASYABMoBQRYACgFjcxVZAJMgAkwASbABJgAE2ACTIAJMAEmcDMIACajZlIUBZJ0ufj0Ox3q3wr6nM7Vf0d/H/UaUVFRmDhx4hXX1t9DvSaVQb32pEmT8nxXf462Dtr7G5WfrkVl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", + "created": 1764873715847, + "lastRetrieved": 1764873715847 + } + } +} \ No newline at end of file From 29b608247b50e7e283a13a789c6badfef05db8f0 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 5 Dec 2025 19:31:33 +0000 Subject: [PATCH 023/104] =?UTF-8?q?=F0=9F=9A=A7=20WIP:=20Add=20Playwright?= =?UTF-8?q?=20PJN=20scraper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + scraper/README.md | 97 +++++ scraper/playwright_scraper.py | 739 ++++++++++++++++++++++++++++++++++ uv.lock | 35 +- 4 files changed, 871 insertions(+), 1 deletion(-) create mode 100644 scraper/README.md create mode 100644 scraper/playwright_scraper.py diff --git a/pyproject.toml b/pyproject.toml index b89395ab..26c99114 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -117,6 +117,7 @@ dev = [ "pip>=24.3.1", "streamlit>=1.21.0", "dspy>=3.0.4", + "playwright==1.56.0" ] [tool.setuptools.packages.find] diff --git a/scraper/README.md b/scraper/README.md new file mode 100644 index 00000000..dc965075 --- /dev/null +++ b/scraper/README.md @@ -0,0 +1,97 @@ +# Scraper Playwright - Gestión Documental PJN + +Este repositorio contiene un script en Python que usa **Playwright** para automatizar la recolección +de documentos PDF publicados en la sección de gestión documental del Poder Judicial de la Nación +(https://www.pjn.gov.ar/gestion-documental). El scraper reproduce las llamadas AJAX que genera el front-end, +mantiene las cookies que requiere el API y descarga los adjuntos desde el servicio oficial. + +## Requisitos + +1. Python 3.8+ +2. Playwright y el navegador Chromium. + +```bash +python -m pip install --upgrade pip +pip install playwright +playwright install chromium +``` + +## Uso básico + +```bash +python playwright_scraper.py --output-dir datos --max-pages 5 --per-page 50 --pdf-template "https://pjn-documento-api.pjn.gov.ar/api/documento/adjunto/{id}" +``` + +El script hará: + +- Abrirá una sesión de Playwright y visitará la página oficial. +- Detectará automáticamente qué llamada REST obtiene los documentos. +- Iterará páginas y descargará los PDFs dentro del directorio `datos`. + +## Aplicar filtros desde la línea de comandos + +La interfaz web permite limitar por dependencia, categorías y rango de fechas. El scraper replica ese comportamiento con los argumentos: + +- `--dependencia "Fueros Federales"` aplica ese texto tanto a `dependencia` como a `dependenciaTexto`. +- `--category` se puede repetir para simular clics en categorías/subcategorías anidadas (por ejemplo `--category Reglamentos --category Normativa`). +- `--desde` y `--hasta` definen los campos `fechaDesde`/`fechaHasta` (o `desde`/`hasta`) que el backend espera. +- `--filter clave=valor` te deja añadir cualquier parámetro extra (por ejemplo `--filter orden=desc`, `--filter tipoDocumento=Resolución`). +- `--simulate-ui` simula los clicks sobre filtros, expande los botones “Mostrar más” y rellena las fechas como lo hace la UI antes de capturar la llamada AJAX. Úsalo si necesitás replicar exactamente la interacción de navegación para los filtros que ves en pantalla. +- `--debug-ui` habilita registros detallados sobre cada intento de clic/expansión para que puedas ver en consola qué filtros se están tocando en tiempo real. + +Los filtros se mezclan automáticamente en la query y en el cuerpo de la petición, así que puedes combinar varios `-f` en el mismo comando. + +## Estructura de almacenamiento guiada por filtros + +Los documentos descargados se organizan siguiendo los filtros aplicados y la metadata del registro: + +- Cada PDF se guarda en `ruta-de-salida///`, usando la dependencia que especifiques o la que entrega el API. +- La categoría se extrae de campos como `rubro`, `categoria` o `tipo` cuando están presentes. +- Si pasás `--category` el scraper usa esa secuencia de categorías/subcategorías como niveles adicionales (en lugar de los valores devueltos por el API), lo que refleja la navegación que aplicaste en los filtros. +- Si falta dependencia o año, se usan nombres como `sin-dependencia` o `sin-anio` para evitar colisiones. +- Los nombres de archivo ahora conservan acentos y caracteres especiales porque la normalización usa Unicode completo (`NFC`) antes de reemplazar espacios; así el título original permanece íntegro para tu pipeline de metadata. + +Esto facilita tener directorios alineados con las dependencias del Poder Judicial y continuar el pipeline de anonimización con una estructura consistente. + +Puedes ajustar el número de páginas, el retraso entre peticiones o el límite de documentos con +`--delay`, `--max-documents`, `--max-pages`. + +## Firma manual del API + +Si lo prefieres, puedes evitar la detección automática y proporcionar un JSON con la firma de las peticiones. +Esto es útil cuando ya sabes qué endpoint se usa o necesitas definir filtros específicos. + +```json +{ + "method": "POST", + "base_url": "https://www.pjn.gov.ar/api/documento/paginado", + "headers": { + "Accept": "application/json", + "Referer": "https://www.pjn.gov.ar/gestion-documental" + }, + "query_params": { + "orden": "desc" + }, + "json_body": { + "pagina": 0, + "size": 25, + "dependencia": "Fueros Federales" + }, + "listing_path": ["data", "registros"], + "page_keys": { + "pagina": 0 + }, + "size_keys": { + "size": 25 + }, + "body_type": "json" +} +``` + +Guarda ese JSON y pásalo al script con `--signature-file firma.json`. + +## Siguientes pasos + +1. Define reglas de nombrado y almacenamiento según tu pipeline de anonimización. +2. Agrega paralelismo/control de errores si necesitas escalar la descarga. +3. Encadena el dump resultante con los módulos de extracción y validación de Aymurai. diff --git a/scraper/playwright_scraper.py b/scraper/playwright_scraper.py new file mode 100644 index 00000000..f108563e --- /dev/null +++ b/scraper/playwright_scraper.py @@ -0,0 +1,739 @@ +#!/usr/bin/env python3 +""" +Playwright scraper para la sección “Gestión Documental” del Poder Judicial de la Nación. + +Este script usa Playwright para capturar las cabeceras y cookies que el frontend genera +y después reproduce las llamadas al API para descargar en lote los PDFs que se enumeran +en la interfaz. Se detecta de forma dinámica el endpoint y los parámetros de paginación, +pero también puede recibir una firma manual si así se prefiere. +""" + +import argparse +import asyncio +import copy +import json +import logging +import re +import unicodedata +import urllib.parse +from dataclasses import dataclass +from datetime import datetime +from pathlib import Path +from typing import Any, Dict, Iterable, List, Optional, Tuple + +from playwright.async_api import APIRequestContext, Page, async_playwright + +logging.basicConfig( + level=logging.INFO, + format="[%(asctime)s] %(levelname)s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", +) +logger = logging.getLogger(__name__) + + +PAGE_KEYWORDS = ( + "pagina", + "page", + "pageindex", + "pagenumber", + "paginaactual", + "numeropagina", + "offset", +) +SIZE_KEYWORDS = ( + "size", + "pagesize", + "tamanio", + "cantidad", + "limit", + "perpage", + "per_page", +) + +MORE_BUTTON_SELECTOR = "text=/Mostrar\\s+m[aá]s/i" + + +def safe_filename(value: str) -> str: + clean = unicodedata.normalize("NFC", value.strip()) + clean = re.sub(r"\s+", "-", clean) + clean = re.sub(r"[^\w\-\.]", "", clean) + return clean[:120] + + +def detect_numeric_fields( + container: Dict[str, Any], keywords: Iterable[str] +) -> Dict[str, int]: + matches: Dict[str, int] = {} + for key, value in container.items(): + lowered = key.lower() + if any(keyword in lowered for keyword in keywords): + try: + matches[key] = int(value) + except (TypeError, ValueError): + continue + return matches + + +def update_values( + container: Dict[str, Any], keys: Iterable[str], new_value: int +) -> None: + for key in keys: + if key in container: + container[key] = new_value + + +def strip_sensitive_headers(headers: Dict[str, str]) -> Dict[str, str]: + blocked = { + "content-length", + "origin", + "connection", + "accept-encoding", + } + return {k: v for k, v in headers.items() if k.lower() not in blocked} + + +def load_signature_from_file(path: Path) -> Dict[str, Any]: + with path.open("r", encoding="utf-8") as fh: + return json.load(fh) + + +def extract_attachment_id(record: Dict[str, Any]) -> Optional[str]: + candidates = ( + "idAdjunto", + "adjunto", + "idDocumento", + "documentoAdjunto", + "id", + "adjuntoId", + ) + for key in candidates: + value = record.get(key) + if isinstance(value, dict): + nested = value.get("id") or value.get("codigo") + if nested: + return str(nested) + elif value: + return str(value) + return None + + +def record_field(record: Dict[str, Any], keys: Iterable[str]) -> Optional[str]: + for key in keys: + if key in record and record[key]: + return str(record[key]) + return None + + +def find_listing_path( + payload: Any, path: Tuple[str, ...] = () +) -> Optional[Tuple[Tuple[str, ...], List[Dict[str, Any]]]]: + if isinstance(payload, dict): + for key, value in payload.items(): + if ( + isinstance(value, list) + and value + and all(isinstance(item, dict) for item in value) + ): + if any( + any( + "id" in field.lower() or "adjunto" in field.lower() + for field in item.keys() + ) + for item in value + ): + return path + (key,), value + child = find_listing_path(value, path + (key,)) + if child: + return child + elif isinstance(payload, list): + if payload and all(isinstance(item, dict) for item in payload): + if any( + any( + "id" in field.lower() or "adjunto" in field.lower() + for field in item.keys() + ) + for item in payload + ): + return path, payload + return None + + +def extract_records_by_path( + payload: Dict[str, Any], path: Tuple[str, ...] +) -> List[Dict[str, Any]]: + current: Any = payload + for key in path: + if not isinstance(current, dict): + return [] + current = current.get(key) + if current is None: + return [] + if isinstance(current, list): + return [item for item in current if isinstance(item, dict)] + return [] + + +def derive_pdf_url(template: str, attachment_id: str) -> str: + if "{id}" in template: + return template.format(id=attachment_id) + return template.rstrip("/") + "/" + attachment_id + + +@dataclass +class SearchSignature: + method: str + base_url: str + headers: Dict[str, str] + query_params: Dict[str, str] + json_body: Optional[Dict[str, Any]] + listing_path: Tuple[str, ...] + example_record: Dict[str, Any] + page_keys: Dict[str, int] + size_keys: Dict[str, int] + body_type: str + + +def build_signature_from_request( + request, + listing_path: Tuple[str, ...], + example_record: Dict[str, Any], + response_payload: Dict[str, Any], +) -> SearchSignature: + parsed = urllib.parse.urlparse(request.url) + base_url = urllib.parse.urlunparse(parsed._replace(query="")) + query_params = dict(urllib.parse.parse_qsl(parsed.query, keep_blank_values=True)) + method = request.method + headers = strip_sensitive_headers(dict(request.headers)) + json_body: Optional[Dict[str, Any]] = None + post_data = request.post_data + content_type = request.headers.get("content-type", "") + if post_data: + if "x-www-form-urlencoded" in content_type: + json_body = dict(urllib.parse.parse_qsl(post_data)) + else: + try: + json_body = json.loads(post_data) + except json.JSONDecodeError: + logger.debug("No se pudo parsear cuerpo JSON de la petición inicial.") + initial_container = {} + initial_container.update(query_params) + if isinstance(json_body, dict): + initial_container.update(json_body) + page_keys = detect_numeric_fields(initial_container, PAGE_KEYWORDS) + size_keys = detect_numeric_fields(initial_container, SIZE_KEYWORDS) + if not listing_path: + found = find_listing_path(response_payload) + if not found: + raise RuntimeError( + "No se pudo determinar la ruta de listado de documentos." + ) + listing_path = found[0] + if post_data: + if "x-www-form-urlencoded" in content_type: + body_type = "form" + else: + body_type = "json" + else: + body_type = "none" + return SearchSignature( + method=method.upper(), + base_url=base_url, + headers=headers, + query_params=query_params, + json_body=json_body, + listing_path=listing_path, + example_record=example_record, + page_keys=page_keys, + size_keys=size_keys, + body_type=body_type, + ) + + +async def capture_signature( + page: Page, args: argparse.Namespace, timeout: float = 20.0 +) -> SearchSignature: + future = asyncio.get_running_loop().create_future() + + async def inspect_response(response): + if future.done(): + return + if response.status != 200: + return + if response.request.resource_type != "xhr": + return + content_type = response.headers.get("content-type", "") + if "application/json" not in content_type: + return + try: + payload = await response.json() + except Exception: + return + found = find_listing_path(payload) + if not found: + return + records = found[1] + if not records: + return + future.set_result((response.request, found[0], records[0], payload)) + + page.on( + "response", + lambda response: asyncio.create_task(inspect_response(response)), + ) + await page.goto( + "https://www.pjn.gov.ar/gestion-documental", wait_until="networkidle" + ) + if args.simulate_ui: + try: + await apply_ui_filters(page, args) + except Exception as exc: # pragma: no cover - best effort + logger.warning("Error al aplicar filtros UI: %s", exc) + try: + await asyncio.wait_for(future, timeout=timeout) + except asyncio.TimeoutError: + logger.warning( + "No se detectó automáticamente la llamada al API. Asegúrate de navegar en la página." + ) + raise + + request, listing_path, sample_record, payload = future.result() + signature = build_signature_from_request( + request, listing_path, sample_record, payload + ) + logger.info("Firma detectada: %s %s", signature.method, signature.base_url) + logger.debug("Campos página: %s", signature.page_keys) + logger.debug("Campos tamaño: %s", signature.size_keys) + return signature + + +def load_signature(source: Dict[str, Any]) -> SearchSignature: + signature = SearchSignature( + method=source["method"].upper(), + base_url=source["base_url"], + headers=source.get("headers", {}), + query_params=source.get("query_params", {}), + json_body=source.get("json_body"), + listing_path=tuple(source["listing_path"]), + example_record=source.get("example_record", {}), + page_keys={k: int(v) for k, v in source.get("page_keys", {}).items()}, + size_keys={k: int(v) for k, v in source.get("size_keys", {}).items()}, + body_type=source.get("body_type", "json"), + ) + return signature + + +def prepare_page_payload( + signature: SearchSignature, + page_value: int, + page_size: int, +) -> Tuple[Dict[str, str], Optional[Dict[str, Any]]]: + query_params = signature.query_params.copy() + if signature.json_body is not None: + body_payload = copy.deepcopy(signature.json_body) + else: + body_payload = None + if signature.page_keys: + update_values(query_params, signature.page_keys.keys(), page_value) + if body_payload is not None: + update_values(body_payload, signature.page_keys.keys(), page_value) + if signature.size_keys: + update_values(query_params, signature.size_keys.keys(), page_size) + if body_payload is not None: + update_values(body_payload, signature.size_keys.keys(), page_size) + return query_params, body_payload + + +def apply_filter_overrides( + query_params: Dict[str, str], + body_payload: Optional[Dict[str, Any]], + overrides: Dict[str, str], +) -> None: + if not overrides: + return + for key, value in overrides.items(): + query_params[key] = value + if body_payload is not None: + body_payload[key] = value + + +def build_filter_overrides( + raw_filters: Iterable[str], + dependencia: Optional[str], + desde: Optional[str], + hasta: Optional[str], +) -> Dict[str, str]: + overrides: Dict[str, str] = {} + for option in raw_filters: + if "=" not in option: + raise ValueError(f"Filtro inválido: {option!r}. Use clave=valor.") + key, value = option.split("=", 1) + overrides[key] = value + if dependencia: + overrides.setdefault("dependencia", dependencia) + overrides.setdefault("dependenciaTexto", dependencia) + if desde: + overrides.setdefault("fechaDesde", desde) + overrides.setdefault("desde", desde) + if hasta: + overrides.setdefault("fechaHasta", hasta) + overrides.setdefault("hasta", hasta) + return overrides + + +def ui_debug(args: argparse.Namespace, message: str) -> None: + if getattr(args, "debug_ui", False): + logger.info("[UI] %s", message) + + +async def expand_more_filters(page: Page, args: argparse.Namespace) -> None: + while True: + locator = page.locator(MORE_BUTTON_SELECTOR) + if not await locator.count(): + break + ui_debug(args, "Expandiendo filtros con 'Mostrar más'") + await locator.first.click() + await page.wait_for_timeout(250) + + +async def click_filter_option(page: Page, args: argparse.Namespace, text: str) -> bool: + text = text.strip() + if not text: + return False + strategies = [ + ("role=button", page.get_by_role("button", name=text, exact=False)), + ("role=link", page.get_by_role("link", name=text, exact=False)), + ("text-match", page.get_by_text(text, exact=False)), + ("button:has-text", page.locator(f'button:has-text("{text}")')), + ("div:has-text", page.locator(f'div:has-text("{text}")')), + ] + ui_debug( + args, + f"Intentando seleccionar filtro '{text}' usando {len(strategies)} estrategias", + ) + for description, locator in strategies: + ui_debug(args, f"Probando estrategia '{description}' para '{text}'") + if await locator.count(): + ui_debug(args, f"Clic en '{text}' usando '{description}'") + await locator.first.click() + await page.wait_for_timeout(400) + return True + ui_debug(args, f"No se encontró '{text}' con '{description}'") + return False + + +def normalize_ui_date(value: str) -> str: + try: + parsed = datetime.fromisoformat(value) + return parsed.strftime("%d/%m/%Y") + except ValueError: + return value + + +async def apply_ui_filters(page: Page, args: argparse.Namespace) -> None: + await expand_more_filters(page, args) + if args.dependencia: + clicked = await click_filter_option(page, args, args.dependencia) + if not clicked: + logger.warning( + "No se encontró la dependencia %s en el filtro UI.", args.dependencia + ) + await expand_more_filters(page, args) + for category in getattr(args, "category_path", []): + await expand_more_filters(page, args) + clicked = await click_filter_option(page, args, category) + if not clicked: + logger.warning("No se encontró la categoría %s en el filtro UI.", category) + await expand_more_filters(page, args) + if args.desde: + desde_input = page.locator("input[placeholder='Desde']") + if await desde_input.count(): + await desde_input.fill(normalize_ui_date(args.desde)) + if args.hasta: + hasta_input = page.locator("input[placeholder='Hasta']") + if await hasta_input.count(): + await hasta_input.fill(normalize_ui_date(args.hasta)) + apply_button = page.locator("button:has-text('Aplicar')") + if not await apply_button.count(): + apply_button = page.locator("button:has-text('Buscar')") + if await apply_button.count(): + ui_debug(args, "Aplicando filtros (botón 'Aplicar'/'Buscar')") + await apply_button.first.click() + else: + await page.keyboard.press("Enter") + await page.wait_for_timeout(1500) + + +def extract_year(value: Optional[str]) -> str: + if not value: + return "sin-anio" + match = re.search(r"(19|20)\d{2}", value) + return match.group(0) if match else "sin-anio" + + +def determine_document_path( + args: argparse.Namespace, record: Dict[str, Any], document: Dict[str, str] +) -> Path: + dependency = ( + args.dependencia + or document.get("dependency") + or record_field(record, ("dependencia", "origen", "tribunal")) + or "sin-dependencia" + ) + category = record_field( + record, ("rubro", "categoria", "tipo", "clasificacion", "subcategoria") + ) + year = extract_year(document.get("date")) + segments = [args.output_dir, safe_filename(dependency)] + if getattr(args, "category_path", None): + segments.extend( + safe_filename(part) for part in args.category_path if part and part.strip() + ) + elif category: + segments.append(safe_filename(category)) + segments.append(year) + return Path(*segments) / document["file_name"] + + +def build_document( + record: Dict[str, Any], pdf_template: str +) -> Optional[Dict[str, str]]: + attachment_id = extract_attachment_id(record) + if not attachment_id: + return None + pdf_url = derive_pdf_url(pdf_template, attachment_id) + document_date = record_field(record, ("fecha", "fechaDocumento", "fechaResolucion")) + title = record_field(record, ("titulo", "descripcion", "tituloDocumento", "nombre")) + dependency = record_field( + record, ("dependencia", "dependenciaTexto", "origen", "tribunal") + ) + parts = [ + document_date or "fecha-desconocida", + title or "sin-titulo", + dependency or "dependencia", + attachment_id, + ] + name = safe_filename("_".join(part for part in parts if part)) + return { + "attachment_id": attachment_id, + "pdf_url": pdf_url, + "file_name": f"{name}.pdf", + "title": title or "", + "date": document_date or "", + "dependency": dependency or "", + } + + +async def download_document( + context: APIRequestContext, destination: Path, document: Dict[str, str] +) -> None: + destination.parent.mkdir(parents=True, exist_ok=True) + if destination.exists(): + logger.info("Salteando %s, ya existe", destination.name) + return + response = await context.get( + document["pdf_url"], headers={"Referer": "https://www.pjn.gov.ar/"} + ) + response_ok = response.ok + if not response_ok: + logger.warning( + "Error al obtener %s (%s)", + document["attachment_id"], + response.status, + ) + return + content = await response.body() + destination.write_bytes(content) + logger.info("Descargado %s (%s)", destination.name, len(content)) + + +async def run_scraping( + args: argparse.Namespace, + signature: SearchSignature, + context_request: APIRequestContext, +) -> None: + documents_downloaded = 0 + page_start = ( + args.page_start + if args.page_start is not None + else next(iter(signature.page_keys.values()), 0) + ) + page_size = ( + args.page_size + if args.page_size is not None + else next(iter(signature.size_keys.values()), args.per_page) + ) + for page_index in range(args.max_pages): + if args.max_documents and documents_downloaded >= args.max_documents: + logger.info("Se alcanzó el límite de documentos solicitado.") + break + page_value = page_start + page_index + query_params, body_payload = prepare_page_payload( + signature, page_value, page_size + ) + apply_filter_overrides(query_params, body_payload, args.filter_overrides) + if signature.method == "GET": + response = await context_request.get( + signature.base_url, + params=query_params, + headers=signature.headers, + ) + else: + if body_payload is not None: + if signature.body_type == "form": + response = await context_request.post( + signature.base_url, + params=query_params, + data=body_payload, + headers=signature.headers, + ) + else: + response = await context_request.post( + signature.base_url, + params=query_params, + json=body_payload, + headers=signature.headers, + ) + else: + response = await context_request.post( + signature.base_url, + params=query_params, + headers=signature.headers, + ) + if not response.ok: + logger.warning("Respuesta %s en página %s", response.status, page_value) + break + payload = await response.json() + records = extract_records_by_path(payload, signature.listing_path) + if not records: + logger.info("No hay registros en la página %s", page_value) + break + logger.info("Procesando página %s (%d registros)", page_value, len(records)) + for record in records: + if args.max_documents and documents_downloaded >= args.max_documents: + break + doc = build_document(record, args.pdf_template) + if not doc: + continue + destination = determine_document_path(args, record, doc) + await download_document(context_request, destination, doc) + documents_downloaded += 1 + await asyncio.sleep(args.delay) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Scraper de gestión documental usando Playwright" + ) + parser.add_argument( + "--output-dir", + type=Path, + default=Path("descargas"), + help="Carpeta donde se guardan los PDFs", + ) + parser.add_argument( + "--pdf-template", + default="https://pjn-documento-api.pjn.gov.ar/api/documento/adjunto/{id}", + ) + parser.add_argument("--max-pages", type=int, default=20) + parser.add_argument("--per-page", type=int, default=25) + parser.add_argument( + "-f", + "--filter", + action="append", + default=[], + help="Filtros adicionales como clave=valor (aplica a query y/o cuerpo).", + ) + parser.add_argument( + "--dependencia", + help="Filtra por dependencia (ej. 'Fueros Federales' o 'Consejo de la Magistratura').", + ) + parser.add_argument( + "--desde", + help="Fecha mínima de publicación en formato ISO o compatible con el backend.", + ) + parser.add_argument( + "--hasta", + help="Fecha máxima de publicación en formato ISO o compatible con el backend.", + ) + parser.add_argument( + "--category", + action="append", + default=[], + help="Secuencia de categorías/subcategorías a seleccionar tras la dependencia.", + ) + parser.add_argument( + "--simulate-ui", + action="store_true", + help="Simula clicks/fechas en la UI antes de detectar la llamada REST.", + ) + parser.add_argument( + "--debug-ui", + action="store_true", + help="Imprime en consola cada intento de interacción con los filtros.", + ) + parser.add_argument( + "--delay", + type=float, + default=1.5, + help="Retraso entre páginas para respetar al servidor", + ) + parser.add_argument( + "--max-documents", + type=int, + default=0, + help="Máximo de PDFs a guardar (0 = infinito)", + ) + parser.add_argument( + "--headless", + action="store_true", + help="Ejecutar Playwright en modo headless", + ) + parser.add_argument( + "--signature-file", + type=Path, + help="Ruta a un JSON con la firma del API", + ) + parser.add_argument( + "--page-start", + type=int, + help="Valor base para el primer número de página", + ) + parser.add_argument( + "--page-size", type=int, help="Cantidad de registros por página" + ) + return parser.parse_args() + + +def main() -> None: + args = parse_args() + if args.max_documents < 0: + raise ValueError("max-documents debe ser positivo o cero.") + args.output_dir.mkdir(parents=True, exist_ok=True) + args.category_path = args.category or [] + args.filter_overrides = build_filter_overrides( + args.filter, args.dependencia, args.desde, args.hasta + ) + + async def run(): + async with async_playwright() as p: + browser = await p.chromium.launch(headless=args.headless) + context = await browser.new_context(viewport={"width": 1400, "height": 900}) + page = await context.new_page() + signature: SearchSignature + if args.signature_file: + signature_data = load_signature_from_file(args.signature_file) + signature = load_signature(signature_data) + await page.goto( + "https://www.pjn.gov.ar/gestion-documental", + wait_until="networkidle", + ) + else: + signature = await capture_signature(page, args) + await run_scraping(args, signature, context.request) + await browser.close() + + asyncio.run(run()) + + +if __name__ == "__main__": + main() diff --git a/uv.lock b/uv.lock index f22747ea..594c7511 100644 --- a/uv.lock +++ b/uv.lock @@ -284,7 +284,7 @@ wheels = [ [[package]] name = "aymurai" -version = "1.1.13.dev29" +version = "1.1.13.dev32" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -337,6 +337,7 @@ dev = [ { name = "matplotlib" }, { name = "nbstripout" }, { name = "pip" }, + { name = "playwright" }, { name = "plotly" }, { name = "pre-commit" }, { name = "rich" }, @@ -396,6 +397,7 @@ dev = [ { name = "matplotlib", specifier = ">=3.10.0" }, { name = "nbstripout", specifier = ">=0.8.0" }, { name = "pip", specifier = ">=24.3.1" }, + { name = "playwright", specifier = "==1.56.0" }, { name = "plotly", specifier = ">=5.24.1" }, { name = "pre-commit", specifier = ">=4.0.1" }, { name = "rich", specifier = ">=13.9.4" }, @@ -2784,6 +2786,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731 }, ] +[[package]] +name = "playwright" +version = "1.56.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet" }, + { name = "pyee" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424 }, + { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228 }, + { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424 }, + { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122 }, + { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645 }, + { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837 }, + { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843 }, + { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959 }, +] + [[package]] name = "plotly" version = "6.5.0" @@ -3080,6 +3101,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, ] +[[package]] +name = "pyee" +version = "13.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730 }, +] + [[package]] name = "pygments" version = "2.19.2" From 0dbc86d93eedf4303b23e511e14e390dd52f7360 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Wed, 10 Dec 2025 21:56:19 +0000 Subject: [PATCH 024/104] =?UTF-8?q?=F0=9F=93=9D=20Add=20Jupyter=20notebook?= =?UTF-8?q?=20for=20entity=20disambiguation=20from=20pre-clustered=20valid?= =?UTF-8?q?ations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ation-from-pre-clustered-validations.ipynb | 899 ++++++++++++++++++ 1 file changed, 899 insertions(+) create mode 100644 notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb diff --git a/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb b/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb new file mode 100644 index 00000000..e0f49b96 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb @@ -0,0 +1,899 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "c8fc128c", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8eeefe8b", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import mimetypes\n", + "import os\n", + "import re\n", + "import sqlite3\n", + "import time\n", + "import unicodedata\n", + "from collections import Counter\n", + "from operator import itemgetter\n", + "from pathlib import Path\n", + "from typing import Iterable\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import requests\n", + "from more_itertools import flatten, unique_everseen\n", + "from rapidfuzz import fuzz, process\n", + "\n", + "from aymurai.llm_providers import OllamaLLMProvider\n", + "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", + "from aymurai.utils.json_data import get_pretty, load_json, save_json" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e0ec450", + "metadata": {}, + "outputs": [], + "source": [ + "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8999\")\n", + "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", + "DATA_ROOT = Path(\n", + " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/disambiguation-eval\")\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b017330", + "metadata": {}, + "outputs": [], + "source": [ + "def call_extraction_api(\n", + " session: requests.Session, file_path: Path\n", + ") -> dict[str, object]:\n", + " \"\"\"\n", + " Calls the document extraction API with the given file.\n", + "\n", + " Args:\n", + " session (requests.Session): The HTTP session to use for the request.\n", + " file_path (Path): The path to the file to be extracted.\n", + " Returns:\n", + " dict[str, object]: The response payload containing status and details.\n", + " \"\"\"\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " ENDPOINT,\n", + " files=files,\n", + " timeout=REQUEST_TIMEOUT_S,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef352767", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "print(f\"Discovered {len(documents)} documents.\")\n", + "documents" + ] + }, + { + "cell_type": "markdown", + "id": "5c1e471d", + "metadata": {}, + "source": [ + "## Fetch data from database" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "281524f4", + "metadata": {}, + "outputs": [], + "source": [ + "# Anonymization document\n", + "conn = sqlite3.connect(\"/workspace/sqlite/database.db\")\n", + "anonymization_document = pd.read_sql_query(\"SELECT * FROM anonymization_document\", conn)\n", + "conn.close()\n", + "\n", + "anonymization_document" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c6db4fc5", + "metadata": {}, + "outputs": [], + "source": [ + "# Anonymization document paragraphs\n", + "conn = sqlite3.connect(\"/workspace/sqlite/database.db\")\n", + "anonymization_document_paragraph = pd.read_sql_query(\n", + " \"SELECT * FROM anonymization_document_paragraph\", conn\n", + ")\n", + "conn.close()\n", + "\n", + "anonymization_document_paragraph" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ee8bf74e", + "metadata": {}, + "outputs": [], + "source": [ + "# Anonymization paragraph\n", + "conn = sqlite3.connect(\"/workspace/sqlite/database.db\")\n", + "anonymization_paragraph = pd.read_sql_query(\n", + " \"SELECT * FROM anonymization_paragraph\", conn\n", + ")\n", + "conn.close()\n", + "\n", + "anonymization_paragraph" + ] + }, + { + "cell_type": "markdown", + "id": "ffd8f27e", + "metadata": {}, + "source": [ + "## Get particular document" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25086b1a", + "metadata": {}, + "outputs": [], + "source": [ + "doc_filename = \"\" # Replace with actual document filename\n", + "\n", + "# Get document ID\n", + "document_id = anonymization_document.loc[\n", + " anonymization_document[\"name\"].str.startswith(doc_filename), \"id\"\n", + "].values[0]\n", + "document_id" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "caa4628c", + "metadata": {}, + "outputs": [], + "source": [ + "# Get paragraph IDs for the document\n", + "paragraph_ids = anonymization_document_paragraph.loc[\n", + " anonymization_document_paragraph[\"document_id\"] == document_id, \"paragraph_id\"\n", + "].tolist()\n", + "\n", + "paragraph_ids" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18307aab", + "metadata": {}, + "outputs": [], + "source": [ + "# Get paragraphs\n", + "doc_paragraphs = anonymization_paragraph.loc[\n", + " anonymization_paragraph[\"id\"].isin(paragraph_ids)\n", + "]\n", + "doc_paragraphs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c7b4ffe", + "metadata": {}, + "outputs": [], + "source": [ + "# Get validations\n", + "validations = doc_paragraphs.loc[:, \"validation\"].map(eval).tolist()\n", + "validations = list(flatten(validations))\n", + "validations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5a262978", + "metadata": {}, + "outputs": [], + "source": [ + "# Parse validations to extract labels and alt texts\n", + "validations = [\n", + " {\n", + " \"aymurai_label\": validation[\"attrs\"][\"aymurai_label\"],\n", + " \"text\": validation[\"attrs\"].get(\"aymurai_alt_text\") or validation[\"text\"],\n", + " }\n", + " for validation in validations\n", + "]\n", + "\n", + "validations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1de8c68f", + "metadata": {}, + "outputs": [], + "source": [ + "# Remove duplicates and sort\n", + "validations = list(unique_everseen(validations))\n", + "validations = sorted(\n", + " validations,\n", + " key=itemgetter(\"aymurai_label\", \"text\"),\n", + ")\n", + "validations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3fb25d74", + "metadata": {}, + "outputs": [], + "source": [ + "# Fix 'TEL' labels\n", + "for validation in validations:\n", + " if validation[\"aymurai_label\"] == \"TEL\":\n", + " validation[\"aymurai_label\"] = \"TELEFONO\"\n", + "\n", + "validations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ea1d64c9", + "metadata": {}, + "outputs": [], + "source": [ + "# Map 'TEXTO_ANONIMIZAR' to 'NOMBRE_ARCHIVO' when applicable\n", + "for validation in validations:\n", + " extension = os.path.splitext(validation[\"text\"])[1].lower()\n", + " if validation[\"aymurai_label\"] == \"TEXTO_ANONIMIZAR\":\n", + " if extension.endswith(\n", + " (\n", + " \"jpg\",\n", + " \"jpeg\",\n", + " \"png\",\n", + " \"pdf\",\n", + " \"docx\",\n", + " \"odt\",\n", + " \"mp4\",\n", + " \"enc\",\n", + " )\n", + " ):\n", + " validation[\"aymurai_label\"] = \"NOMBRE_ARCHIVO\"\n", + "\n", + "validations" + ] + }, + { + "cell_type": "markdown", + "id": "68a55889", + "metadata": {}, + "source": [ + "## Cluster entities based on textual" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7fa3f5b", + "metadata": {}, + "outputs": [], + "source": [ + "def normalize(s: str) -> str:\n", + " \"\"\"\n", + " Normalize string for clustering.\n", + "\n", + " Args:\n", + " s (str): input string\n", + "\n", + " Returns:\n", + " str: normalized string\n", + " \"\"\"\n", + " # strip accents, lowercase, collapse spaces\n", + " s = \"\".join(\n", + " c for c in unicodedata.normalize(\"NFD\", s) if unicodedata.category(c) != \"Mn\"\n", + " )\n", + " s = \" \".join(s.lower().split())\n", + " return s\n", + "\n", + "\n", + "def cluster_with_cdist(\n", + " entities: list[str], threshold: int = 90, scorer: callable = fuzz.token_set_ratio\n", + "):\n", + " \"\"\"\n", + " Cluster entities based on similarity using a distance matrix.\n", + "\n", + " Args:\n", + " entities (list[str]): list of entity strings\n", + " threshold (int): similarity threshold for clustering\n", + " scorer (callable): similarity scoring function\n", + "\n", + " Returns:\n", + " list[list[tuple[str, str]]]: clusters of (original, normalized) entity tuples\n", + " \"\"\"\n", + " # matrix of similarities on normalized strings\n", + " # normalize however you like; here just lower + strip\n", + " normed = [\" \".join(e.lower().split()) for e in entities]\n", + " sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold)\n", + " sim = np.array(sim)\n", + "\n", + " # union-find\n", + " parent = list(range(len(normed)))\n", + "\n", + " def find(i):\n", + " while parent[i] != i:\n", + " parent[i] = parent[parent[i]]\n", + " i = parent[i]\n", + " return i\n", + "\n", + " def union(i, j):\n", + " ri, rj = find(i), find(j)\n", + " if ri != rj:\n", + " parent[rj] = ri\n", + "\n", + " # link pairs above threshold (upper triangle only)\n", + " n = len(normed)\n", + " for i in range(n):\n", + " for j in range(i + 1, n):\n", + " if sim[i, j] >= threshold:\n", + " union(i, j)\n", + "\n", + " # collect clusters\n", + " clusters = {}\n", + " for idx in range(n):\n", + " root = find(idx)\n", + " clusters.setdefault(root, []).append((entities[idx], normed[idx]))\n", + " return list(clusters.values())\n", + "\n", + "\n", + "def pick_canonical(cluster: list[tuple[str, str]]) -> str:\n", + " \"\"\"\n", + " Pick canonical text from a cluster.\n", + "\n", + " Args:\n", + " cluster (list[tuple[str, str]]): cluster of (original, normalized) entity tuples\n", + "\n", + " Returns:\n", + " str: chosen canonical text\n", + " \"\"\"\n", + " # prefer longest original; fall back to first\n", + " return max(cluster, key=lambda x: len(x[0]))[0]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82d57afd", + "metadata": {}, + "outputs": [], + "source": [ + "# Cluster entities\n", + "clusters = cluster_with_cdist(\n", + " [f\"{v['aymurai_label']}:{v['text']}\" for v in validations],\n", + " threshold=95,\n", + ")\n", + "\n", + "for cluster in clusters:\n", + " canonical = pick_canonical(cluster)\n", + " originals = [c[0] for c in cluster]\n", + " print(f\"Canonical: {canonical} -> {originals}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d542a89", + "metadata": {}, + "outputs": [], + "source": [ + "def parse_item(item: tuple[str, ...]) -> tuple[str, str, str]:\n", + " \"\"\"\n", + " Parse an item into (label, orig, norm).\n", + "\n", + " Accepts:\n", + " - (orig, norm, label)\n", + " - (labelled_orig, labelled_norm) with prefix 'LABEL:'\n", + " Args:\n", + " item (tuple[str, ...]): input item\n", + "\n", + " Returns:\n", + " tuple[str, str, str]: (label, orig, norm)\n", + " \"\"\"\n", + " if len(item) == 3:\n", + " orig, norm, label = item\n", + " return label, orig, norm\n", + "\n", + " # len == 2: assume \"LABEL:text\"\n", + " labelled_orig, labelled_norm = item\n", + " label, orig = labelled_orig.split(\":\", 1)\n", + " _, norm = labelled_norm.split(\":\", 1)\n", + " return label, orig, norm\n", + "\n", + "\n", + "def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Pick the most common label from parsed items.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen label\n", + " \"\"\"\n", + " labels = [lbl for lbl, _, _ in parsed_items]\n", + " # majority vote; fallback to first\n", + " return Counter(labels).most_common(1)[0][0]\n", + "\n", + "\n", + "def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Choose the longest original surface form; tweak as needed.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen canonical text\n", + " \"\"\"\n", + " return max(parsed_items, key=lambda x: len(x[1]))[1]\n", + "\n", + "\n", + "def clusters_to_canonical_entities(\n", + " clusters: list[list[tuple[str, str]]],\n", + ") -> list[CanonicalEntity]:\n", + " \"\"\"\n", + " Convert clusters to CanonicalEntity objects.\n", + "\n", + " Args:\n", + " clusters (list[list[tuple[str, str]]]): clusters of (original, normalized) entity tuples\n", + "\n", + " Returns:\n", + " list[CanonicalEntity]: list of CanonicalEntity objects\n", + " \"\"\"\n", + " canonical_entities = []\n", + "\n", + " for cluster in clusters:\n", + " parsed = [parse_item(item) for item in cluster] # [(label, orig, norm), ...]\n", + " label = pick_cluster_label(parsed)\n", + " canonical_text = pick_canonical_text(parsed)\n", + " aliases = sorted({orig for _, orig, _ in parsed})\n", + " ce = CanonicalEntity(\n", + " aymurai_label=label,\n", + " canonical_text=canonical_text,\n", + " aliases=aliases,\n", + " attributes={},\n", + " relations=[],\n", + " )\n", + " canonical_entities.append(ce)\n", + "\n", + " return canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "646a5e41", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = clusters_to_canonical_entities(clusters)\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "edbf9486", + "metadata": {}, + "outputs": [], + "source": [ + "# Sort by label and canonical text\n", + "canonical_entities = sorted(\n", + " canonical_entities,\n", + " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", + ")\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e063eb07", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare target filename\n", + "target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_filename))[0]\n", + ")\n", + "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)\n", + "\n", + "# Save canonical entities to JSON for reviewing\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"/resources/data/restricted/disambiguation-eval/canonical-entities/REVIEWING/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81be5a59", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to load reviewed canonical entities\n", + "reviewed_canonical_entities = load_json(\n", + " \"/resources/data/restricted/disambiguation-eval/canonical-entities/REVIEWING/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", + "]\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "893a6e06", + "metadata": {}, + "outputs": [], + "source": [ + "# Persist reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"/resources/data/restricted/disambiguation-eval/canonical-entities/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "37eb822d", + "metadata": {}, + "source": [ + "## CanonicalEntity extraction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5eed876e", + "metadata": {}, + "outputs": [], + "source": [ + "# Available models\n", + "model = \"phi4:14b\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73400ead", + "metadata": {}, + "outputs": [], + "source": [ + "# Sanity check\n", + "provider = OllamaLLMProvider(model=model)\n", + "provider.generate(\"hola, ¿cómo estás?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b8ac734", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt = \"\"\"\n", + "Eres un asistente especializado en anonimización de sentencias judiciales.\n", + "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", + "Una **entidad canónica** es la representación única de una entidad real.\n", + "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", + "\n", + "# Reglas\n", + "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", + "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", + "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", + "- Cada entidad canónica debe incluir:\n", + " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", + " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", + " - `aliases` (todas las menciones textuales relevantes).\n", + " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", + "\n", + "# Notas\n", + "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", + "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + "\n", + "# Ejemplo\n", + "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", + "A: ```json\n", + "[\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Laura Beatriz Gómez\",\n", + " \"aliases\": [\"Laura Beatriz Gómez\"],\n", + " \"attributes\": {\"role\": \"Denunciante\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"42987654\",\n", + " \"aliases\": [\"42.987.654\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DIRECCION\",\n", + " \"canonical_text\": \"calle Falsa 123\",\n", + " \"aliases\": [\"calle Falsa 123\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", + " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", + " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", + " \"attributes\": {\"role\": \"Denunciado\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"27654321\",\n", + " \"aliases\": [\"27.654.321\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"calle Real 789\",\n", + " \"aliases\": [\"calle Real 789\"]\n", + " }\n", + "]\n", + "```\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50d9cd2d", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template = \"\"\"\n", + "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", + "\n", + "# Documento\n", + "{document_text}\n", + "\n", + "# Menciones de entidades canónicas agrupadas\n", + "{canonical_entities}\n", + "\n", + "# Instrucciones\n", + "1. Evalúa cada entidad canónica listada, poniendo especial atención en las aliases.\n", + "2. Si alguna alias no corresponde a esa entidad, elimínala de la lista de aliases y créala como una nueva entidad canónica.\n", + "3. Las diferencias textuales correctas en los aliases pueden ser variantes ortográficas, abreviaciones, iniciales o errores tipográficos.\n", + "4. Diferencias sutiles que permiten desambiguar entidades distintas (por ejemplo, nombres similares de personas diferentes, fechas próximas pero distintas, números de documentos, códigos de identificación o nombres de archivos con pequeñas variaciones, etc.).\n", + "5. Normaliza canonical_text; mantén los aliases tal como aparecen.\n", + "6. Identifica roles u otros atributos relevantes en el campo attributes (por ejemplo, {{\"role\": \"Denunciante\"}}).\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "81f47270", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "session = requests.Session()\n", + "doc_path = next((doc for doc in documents if doc.name == doc_filename), None)\n", + "document = call_extraction_api(session, Path(doc_path))\n", + "document = document.get(\"detail\", {}).get(\"document\")\n", + "\n", + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f6143dc5", + "metadata": {}, + "outputs": [], + "source": [ + "# Remove empty 'entity_id', 'relations' and 'attributes' fields\n", + "canonical_entities = [\n", + " {\n", + " k: v\n", + " for k, v in ce.items()\n", + " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", + " }\n", + " for ce in canonical_entities\n", + "]\n", + "\n", + "# Prepare user prompt\n", + "user_prompt = user_prompt_template.format(\n", + " document_text=\"\\n\".join(document).strip(),\n", + " canonical_entities=get_pretty(canonical_entities),\n", + ")\n", + "\n", + "print(user_prompt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd772da7", + "metadata": {}, + "outputs": [], + "source": [ + "# Get canonical entities from the model\n", + "provider = OllamaLLMProvider(model=model)\n", + "response = provider.generate(\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options={\"temperature\": 0, \"num_ctx\": 16_384},\n", + " format=CanonicalEntities.model_json_schema(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "adb137aa", + "metadata": {}, + "outputs": [], + "source": [ + "response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "687c02b5", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 26033a8f0566fa0fcfad7b2a7f814ec0e7a1679a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:15:15 -0300 Subject: [PATCH 025/104] Feature/pdf extraction upgrade (#65) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔧 Configure VSCode Python env and Copilot scopes * 🔧 Include resources/llm in .dockerignore * 📌 Update dependencies in pyproject.toml and uv.lock * 🔧 Update Dockerfile and devcontainer.json to install additional PDF tooling * ♻️ Refactor Makefile and docker-compose.yml for improved service configuration and flexibility * 🚧 FIXME: Remove DecisionConv1dBinRegex model from pipeline configuration for dependencies update compatibility * 🔧 Set weights_only=False for torch.load compatibility * ✨ Enhance PDF extraction with marker integration and improved text processing * 🔧 Update run_safe_text_extraction to allow indefinite timeout by default * ✨ Add warm_marker_models function to initialize marker-pdf artifacts at startup * 🔥 Remove unused environment variables and rename TRANSFORMERS_CACHE to HF_HOME * 🔧 Improve service stopping logic for Ollama and API services in Makefile * 🔖 Bump aymurai package version to 2.0.0-alpha.1 * 🔧 Update HF_HOME path and remove HF_DATASETS_CACHE variable in .env.common * 🔧 Update OLLAMA_HOST for GPU-enabled services to point to ollama-gpu * 🔧 Simplify marker model warming logic by removing error handling * ♻️ Refactor text extraction into modular format-specific extractors * ✅ Add unit tests for document extraction and error handling * ➕ Add marker-pdf stack and drop textract * 🔧 Enhance PDF extraction with caching mechanism * 📝 Improve cache utility functions with enhanced docstrings and type hints * 🔧 Enhance cache key generation in PdfExtractor for improved stability and performance * 🔖 Update aymurai package version to 2.0.0a2.dev9 --- .dockerignore | 1 + .env.common | 22 +- .vscode/settings.json | 23 + Makefile | 96 ++- .../routers/misc/document_extract.py | 5 +- aymurai/api/main.py | 10 +- aymurai/api/startup/marker.py | 13 + aymurai/models/decision/tokenizer.py | 2 +- aymurai/text/extraction.py | 292 +------ aymurai/text/extractors/__init__.py | 19 + aymurai/text/extractors/base.py | 112 +++ aymurai/text/extractors/docx.py | 30 + aymurai/text/extractors/odt.py | 26 + aymurai/text/extractors/pdf.py | 74 ++ aymurai/text/extractors/utils.py | 298 +++++++ aymurai/utils/cache.py | 66 +- docker-compose.yml | 111 ++- docker/api/Dockerfile | 3 +- pyproject.toml | 8 +- .../production/full-paragraph/pipeline.json | 10 - test/text/test_extraction.py | 94 +++ test/text/test_extractors.py | 109 +++ uv.lock | 737 +++++++++++------- 23 files changed, 1496 insertions(+), 665 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 aymurai/api/startup/marker.py create mode 100644 aymurai/text/extractors/__init__.py create mode 100644 aymurai/text/extractors/base.py create mode 100644 aymurai/text/extractors/docx.py create mode 100644 aymurai/text/extractors/odt.py create mode 100644 aymurai/text/extractors/pdf.py create mode 100644 aymurai/text/extractors/utils.py create mode 100644 test/text/test_extraction.py create mode 100644 test/text/test_extractors.py diff --git a/.dockerignore b/.dockerignore index 9b91c7d3..e84e738a 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,7 @@ resources/ !resources/api !resources/pipelines +!resources/llm !resources/cache/aymurai !resources/cache/tfhub_modules notebooks/ diff --git a/.env.common b/.env.common index 5b5d5640..5760c797 100644 --- a/.env.common +++ b/.env.common @@ -1,11 +1,7 @@ -DATASETS_BASEPATH=/resources/datasets -MODELS_BASEPATH=/resources/models - +CACHE_PATH=/resources/cache AYMURAI_CACHE_BASEPATH=/resources/cache/aymurai -CACHE_PATH=/resources/cache -HF_DATASETS_CACHE=/resources/cache/huggingface/cache -TRANSFORMERS_CACHE=/resources/cache/huggingface/transformers +HF_HOME=/resources/cache/huggingface TOKENIZERS_PARALLELISM=1 TESSDATA_PREFIX=/usr/local/share/tessdata @@ -15,17 +11,3 @@ AYMURAI_RESTRICTED_DOCUMENT_DOCS_PATH="/resources/data/restricted/ar-juz-pcyf-10 TF_CPP_MIN_LOG_LEVEL=3 TFHUB_CACHE_DIR=/resources/cache/tfhub_modules - -TORCH_VERSION=2.0.1 -CUDA_VERSION=cu118 - -CORE_IMAGE_CUDA=registry.gitlab.com/collective.ai/datagenero-public/aymurai-core -CORE_IMAGE_CPU=registry.gitlab.com/collective.ai/datagenero-public/aymurai-core-cpu -API_IMAGE=registry.gitlab.com/collective.ai/datagenero-public/aymurai-api - -API_HOST=0.0.0.0 -API_PORT=8899 - -SRC_VOLUME_MOUNT=src:/src -RESOURCES_VOLUME_MOUNT=resources:/resources -NOTEBOOKS_VOLUME_MOUNT=notebooks:/notebooks diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..3fa21ad3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,23 @@ +{ + "python-envs.defaultEnvManager": "ms-python.python:system", + "python-envs.pythonProjects": [], + "files.associations": { + ".csv": "csv", + ".env*": "dotenv", + ".json": "json", + ".jsonc": "jsonc", + ".jsonl": "jsonl", + ".md": "markdown" + }, + "github.copilot.enable": { + "*": true, + "dotenv": false, + "csv": false, + "json": false, + "jsonc": false, + "jsonl": false, + "markdown": false, + "plaintext": false, + "scminput": false + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 14e1d527..d828a9e1 100644 --- a/Makefile +++ b/Makefile @@ -2,70 +2,118 @@ include .env export $(shell sed 's/=.*//' .env) include .env.common export $(shell sed 's/=.*//' .env.common) -OLLAMA_CONTAINER := $(shell docker ps -q -f name=^ollama$$) + +# Select which Ollama service to control (ollama or ollama-gpu) +OLLAMA_SERVICE ?= ollama +OLLAMA_CONTAINER := $(shell docker ps -q -f name=^$(OLLAMA_SERVICE)$$) + +# Select which API service to control (override with API_SERVICE=aymurai-api-gpu) +API_SERVICE ?= aymurai-api +# Select which full API service to control (override with API_FULL_SERVICE=aymurai-api-full-gpu) +API_FULL_SERVICE ?= aymurai-api-full api-build: - docker compose build aymurai-api + docker compose build $(API_SERVICE) api-run: - docker compose run --service-ports aymurai-api + @if [ "$(API_SERVICE)" = "aymurai-api-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose run --service-ports $(API_SERVICE) api-up: - docker compose up -d aymurai-api + @if [ "$(API_SERVICE)" = "aymurai-api-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose up -d $(API_SERVICE) api-stop: - docker compose stop aymurai-api + docker compose stop $(API_SERVICE) api-logs: - docker compose logs -f aymurai-api + docker compose logs -f $(API_SERVICE) api-pull: - docker compose pull aymurai-api + docker compose pull $(API_SERVICE) api-full-build: - docker compose build aymurai-api-full + docker compose build $(API_FULL_SERVICE) api-full-run: - docker compose run --service-ports aymurai-api-full + @if [ "$(API_FULL_SERVICE)" = "aymurai-api-full-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose run --service-ports $(API_FULL_SERVICE) api-full-up: - docker compose up -d aymurai-api-full + @if [ "$(API_FULL_SERVICE)" = "aymurai-api-full-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose up -d $(API_FULL_SERVICE) api-full-stop: - docker compose stop aymurai-api-full + docker compose stop $(API_FULL_SERVICE) api-full-logs: - docker compose logs -f aymurai-api-full + docker compose logs -f $(API_FULL_SERVICE) api-full-pull: - docker compose pull aymurai-api-full + docker compose pull $(API_FULL_SERVICE) ollama-up: - docker compose up -d --no-recreate ollama + @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose up -d --no-recreate $(OLLAMA_SERVICE) ollama-stop: - docker compose stop ollama + docker compose stop $(OLLAMA_SERVICE) ollama-restart: - docker compose restart ollama + docker compose restart $(OLLAMA_SERVICE) ollama-pull: ifndef MODEL $(error MODEL variable is required, e.g. make ollama-pull MODEL=llama3) endif ifndef OLLAMA_CONTAINER - $(error Ollama container 'ollama' is not running. Start it first with 'make ollama-up') + $(error Ollama container '$(OLLAMA_SERVICE)' is not running. Start it first with 'make ollama-up OLLAMA_SERVICE=$(OLLAMA_SERVICE)') endif - docker exec ollama ollama pull $(MODEL) + docker exec $(OLLAMA_SERVICE) ollama pull $(MODEL) ollama-run: ifndef MODEL $(error MODEL variable is required, e.g. make ollama-run MODEL=llama3) endif - docker compose up -d --no-recreate ollama - docker compose exec -it ollama ollama run $(MODEL) + @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose up -d --no-recreate $(OLLAMA_SERVICE) + docker compose exec -it $(OLLAMA_SERVICE) ollama run $(MODEL) ollama-list: - docker compose up -d --no-recreate ollama - docker compose exec ollama ollama list + @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose up -d --no-recreate $(OLLAMA_SERVICE) + docker compose exec $(OLLAMA_SERVICE) ollama list ollama-rm: ifndef MODEL $(error MODEL variable is required, e.g. make ollama-rm MODEL=llama3) endif - docker compose up -d --no-recreate ollama - docker compose exec ollama ollama rm $(MODEL) + @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ + docker compose stop ollama || true; \ + else \ + docker compose stop ollama-gpu || true; \ + fi + docker compose up -d --no-recreate $(OLLAMA_SERVICE) + docker compose exec $(OLLAMA_SERVICE) ollama rm $(MODEL) stress-test: locust -f locustfile.py --host http://localhost:8899 diff --git a/aymurai/api/endpoints/routers/misc/document_extract.py b/aymurai/api/endpoints/routers/misc/document_extract.py index be5d4d63..bdbcfc2e 100644 --- a/aymurai/api/endpoints/routers/misc/document_extract.py +++ b/aymurai/api/endpoints/routers/misc/document_extract.py @@ -28,14 +28,15 @@ def extraction(path: str) -> str: return document_normalize(text) if text else "" -def run_safe_text_extraction(path: str, timeout_s: float = 30) -> str: +def run_safe_text_extraction(path: str, timeout_s: float | None = None) -> str: """ Runs the text extraction in a separate process to avoid blocking the main thread. This is useful for long-running tasks or when the extraction might hang. Args: path (str): Path to the file to be processed. - timeout_s (float): Timeout in seconds for the extraction process. Defaults to 30 seconds. + timeout_s (float | None): Timeout in seconds for the extraction process. + If None, waits indefinitely. Defaults to None. Returns: str: Extracted text from the document. diff --git a/aymurai/api/main.py b/aymurai/api/main.py index d814a3f6..fbd5bdad 100644 --- a/aymurai/api/main.py +++ b/aymurai/api/main.py @@ -6,14 +6,15 @@ from alembic import command from alembic.config import Config from fastapi import FastAPI, Request -from fastapi.responses import RedirectResponse from fastapi.middleware.cors import CORSMiddleware +from fastapi.responses import RedirectResponse from aymurai.api import core +from aymurai.api.startup.database import check_db_connection +from aymurai.api.startup.marker import warm_marker_models from aymurai.logger import get_logger -from aymurai.settings import settings from aymurai.pipeline import AymurAIPipeline -from aymurai.api.startup.database import check_db_connection +from aymurai.settings import settings try: from aymurai.version import __version__ @@ -104,10 +105,11 @@ def healthcheck(): if __name__ == "__main__": # download the necessary data - logger.info("Loading pipelines and exit.") + logger.info("Loading pipelines") AymurAIPipeline.load( os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "flair-anonymizer") ) AymurAIPipeline.load( os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "full-paragraph") ) + warm_marker_models() diff --git a/aymurai/api/startup/marker.py b/aymurai/api/startup/marker.py new file mode 100644 index 00000000..208afa43 --- /dev/null +++ b/aymurai/api/startup/marker.py @@ -0,0 +1,13 @@ +from aymurai.logger import get_logger +from aymurai.text.extractors.utils import get_marker_pdf_converter_and_md_renderer + +logger = get_logger(__name__) + + +def warm_marker_models() -> None: + """Download marker-pdf artifacts at startup to avoid first-request latency.""" + try: + get_marker_pdf_converter_and_md_renderer() + logger.info("marker-pdf models are ready") + except Exception as exc: + logger.warning("marker-pdf warmup failed: %s", exc) diff --git a/aymurai/models/decision/tokenizer.py b/aymurai/models/decision/tokenizer.py index bbb21eae..bbd5cae4 100644 --- a/aymurai/models/decision/tokenizer.py +++ b/aymurai/models/decision/tokenizer.py @@ -15,7 +15,7 @@ def save(self, path: str): @classmethod def load(cls, path: str): - vocab = torch.load(path) + vocab = torch.load(path, weights_only=False) return cls(vocab=vocab) def __call__(self, text: str): diff --git a/aymurai/text/extraction.py b/aymurai/text/extraction.py index 66cc76b0..1e2735d2 100644 --- a/aymurai/text/extraction.py +++ b/aymurai/text/extraction.py @@ -1,31 +1,17 @@ import logging import mimetypes import os -import statistics -import unicodedata import zipfile from pathlib import Path -from typing import Any from zipfile import BadZipFile -import numpy as np -import pymupdf -import textract -import xmltodict -from lxml import etree -from more_itertools import flatten -from textract.exceptions import ShellError -from textract.parsers import _get_available_extensions - from aymurai.logger import get_logger -from aymurai.utils.misc import get_element, get_recursively +from aymurai.text.extractors import SUPPORTED_EXTENSIONS, InvalidFile, get_extractor logger = get_logger(__file__) -TEXTRACT_EXTENSIONS = _get_available_extensions() MIMETYPE_EXTENSION_MAPPER = { "application/vnd.openxmlformats-officedocument.wordprocessingml.document": "docx", - "application/msword": "doc", "application/vnd.oasis.opendocument.text": "odt", "application/pdf": "pdf", } @@ -34,12 +20,6 @@ ERRORS = ["ignore", "coerce", "raise"] -class InvalidFile(Exception): - """Invalid File""" - - pass - - def _zip_contains(path: str, member: str) -> bool: """ Check if a zip file contains a specific member. @@ -100,130 +80,6 @@ def get_extension(path: str) -> str: return "unknown" -def _load_xml_from_odt(path: str, xmlfile: str = "styles.xml") -> str: - """ - Load xml file inside an odt. - - Args: - path (str): path to odt file. - xmlfile (str, optional): xml to open. Defaults to 'styles.xml'. - - Returns: - str: xml content. - """ - with zipfile.ZipFile(path, "r") as odt: - if xmlfile not in odt.namelist(): - return "" - with odt.open(xmlfile) as file: - content = file.read().decode("utf-8") - - return content - - -def _load_xml_from_docx(path: str, xmlfile: str = "word/footnotes.xml") -> Any | None: - """Extract XML content from a specific file inside a .docx.""" - with zipfile.ZipFile(path, "r") as docx: - if xmlfile not in docx.namelist(): - return - with docx.open(xmlfile) as f: - return etree.parse(f) - - -def get_header(path: str) -> list[str]: - """ - Extract header from styles.xml inside a ODT file. - - Args: - path (str): path to odt file. - - Returns: - list[str]: header lines. - """ - styles_xml_content = _load_xml_from_odt(path) - styles_dict = xmltodict.parse(styles_xml_content) - - header_root = get_element( - styles_dict, - levels=[ - "office:document-styles", - "office:master-styles", - "style:master-page", - ], - ) - - if not isinstance(header_root, list): - header_root = [header_root] - - style_header = [ - get_recursively(item, "style:header") - for item in header_root - if get_recursively(item, "style:header") - ] - style_header = list(flatten(style_header)) - - texts = [ - get_recursively(item, "#text") - for item in style_header - if get_recursively(item, "#text") - ] - texts = list(flatten(texts)) - - if not texts: - return [] - - return texts - - -def get_footnotes(path: str) -> list[str] | None: - """ - Extract footnotes from footnotes.xml inside a DOCX file. - - Args: - path (str): Path to the DOCX file. - - Returns: - list[str]: Footnote texts. - """ - footnotes_tree = _load_xml_from_docx(path) - if not footnotes_tree: - return - - footnotes_root = footnotes_tree.getroot() - - # Define the namespace map - ns = {"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"} - - # Extract footnote texts in order - footnotes_texts = [] - for footnote in footnotes_root.findall("w:footnote", namespaces=ns): - texts = footnote.xpath(".//w:t/text()", namespaces=ns) - if texts: - footnotes_texts.append("".join(texts)) - - return footnotes_texts - - -def pdf_to_text(filename: str, y_tolerance: float | None = None) -> str: - """ - Extract text from a PDF file. - - Args: - filename (str): Path to the PDF file. - y_tolerance (float, optional): - Maximum vertical gap (in points) to consider blocks part of the same paragraph. - - Returns: - str: Extracted text. - """ - if y_tolerance is None: - y_tolerance = compute_median_margin_between_blocks(filename) - - paragraphs = extract_and_merge_paragraphs(filename, np.ceil(y_tolerance)) - docu = "\n\n".join(paragraphs) - docu = unicodedata.normalize("NFKC", docu) - return docu - - def extract_document( filename: str | Path, errors: str = "ignore", @@ -249,135 +105,41 @@ def extract_document( Returns: str: extracted document text. """ - filename = str(filename) # patch for pathlib + filename = str(filename) if errors not in ERRORS: raise ValueError(f"errors argument must be in {ERRORS}") ext = get_extension(filename) - kwargs["extension"] = kwargs.get("extension", ext) - kwargs["output_encoding"] = kwargs.get("output_encoding", "utf-8") - - logger = get_logger(f"{__file__}.{__name__}") - - if errors == "ignore": - logger.setLevel(logging.ERROR) - - if ( - not isinstance(filename, str) - or not os.path.exists(filename) - or ext not in TEXTRACT_EXTENSIONS - ): + if (not isinstance(filename, str)) or not os.path.exists(filename): if errors == "raise": raise InvalidFile(f"Invalid path: {filename}") - logger.warn(f"skipping (invalid): {filename}") - return - - try: - if ext == "pdf": - return pdf_to_text(filename, y_tolerance=kwargs.get("y_tolerance")) + logger.warning("Skipping (missing): %s", filename) + return None - docu = textract.process(filename, **kwargs).decode("utf-8") - except (BadZipFile, KeyError, ShellError): + if ext not in SUPPORTED_EXTENSIONS: if errors == "raise": - raise - logger.warn(f"skipping (corrupted): {filename}") - return - - # patch header loading in odt files - if ext == "odt": - header = "\n".join(get_header(filename)) - docu = header + "\n\n" + docu - - # patch footnotes loading in docx files - if ext == "docx": - footnotes = get_footnotes(filename) or [] - footnotes = "\n".join(footnotes) - if footnotes.strip(): - docu = docu + "\n\n" + footnotes - - docu = unicodedata.normalize("NFKC", docu) - return docu - - -def compute_median_margin_between_blocks(pdf_path: str) -> float: - """ - Computes the median vertical margin between text blocks in a PDF. - - Args: - pdf_path (str): Path to the PDF file. - - Returns: - float: Median margin between text blocks (in points). - """ - margins = [] - - with pymupdf.open(pdf_path) as doc: - for page in doc: - # Extract all text blocks from the page - blocks = page.get_text("blocks") - - # Sort blocks by their top y-coordinate (y0) - blocks_sorted = sorted(blocks, key=lambda b: b[1]) - - # Compute vertical margins between consecutive blocks - for i in range(1, len(blocks_sorted)): - previous_block = blocks_sorted[i - 1] - current_block = blocks_sorted[i] - - # Calculate the vertical margin - previous_y1 = previous_block[3] # Bottom of the previous block - current_y0 = current_block[1] # Top of the current block - margin = current_y0 - previous_y1 - - if margin > 0: # Ignore overlapping blocks - margins.append(margin) - - # Compute and return the median margin - if margins: - return statistics.median(margins) - else: - return 0.0 # Return 0 if no margins were found + raise InvalidFile(f"Unsupported extension: {ext}") + logger.warning("Skipping (unsupported %s): %s", ext, filename) + return None + extractor = get_extractor(ext) -def extract_and_merge_paragraphs(pdf_path: str, y_tolerance=5) -> list[str]: - """ - Extracts and merges paragraphs from a PDF by grouping close text blocks. - - Args: - pdf_path (str): Path to the PDF file. - y_tolerance (float): Maximum vertical gap (in points) to consider blocks part of the same paragraph. - - Returns: - list[str]: A list of merged paragraphs as strings. - """ - paragraphs = [] - current_paragraph = [] - last_y1 = None - - with pymupdf.open(pdf_path) as doc: - for page in doc: - # Extract all text blocks from the page - blocks = page.get_text("blocks") - - # Sort blocks by their top y-coordinate (y0) - blocks_sorted = sorted(blocks, key=lambda b: b[1]) - - for block in blocks_sorted: - x0, y0, x1, y1, text, *_ = block - - if last_y1 is not None and (y0 - last_y1) > y_tolerance: - # If the gap between blocks is too large, start a new paragraph - if current_paragraph: - paragraphs.append(" ".join(current_paragraph)) - current_paragraph = [] - - current_paragraph.append(text) - last_y1 = y1 - - if current_paragraph: - paragraphs.append(" ".join(current_paragraph)) - current_paragraph = [] - - return paragraphs + try: + return extractor.extract(Path(filename)) + except InvalidFile as exc: + if errors == "raise": + raise + logger.warning("Skipping (corrupted): %s (%s)", filename, exc) + return None + except BadZipFile as exc: + if errors == "raise": + raise + logger.warning("Skipping (corrupted archive): %s (%s)", filename, exc) + return None + except Exception as exc: + if errors == "raise": + raise + logger.warning("Skipping (unexpected): %s (%s)", filename, exc) + return None diff --git a/aymurai/text/extractors/__init__.py b/aymurai/text/extractors/__init__.py new file mode 100644 index 00000000..01919448 --- /dev/null +++ b/aymurai/text/extractors/__init__.py @@ -0,0 +1,19 @@ +# Import concrete extractors so they self-register. +from aymurai.text.extractors import docx, odt, pdf # noqa: F401 +from aymurai.text.extractors.base import ( + BaseExtractor, + InvalidFile, + get_extractor, + register_extractor, + supported_extensions, +) + +SUPPORTED_EXTENSIONS = supported_extensions() + +__all__ = [ + "BaseExtractor", + "InvalidFile", + "SUPPORTED_EXTENSIONS", + "get_extractor", + "register_extractor", +] diff --git a/aymurai/text/extractors/base.py b/aymurai/text/extractors/base.py new file mode 100644 index 00000000..20282b09 --- /dev/null +++ b/aymurai/text/extractors/base.py @@ -0,0 +1,112 @@ +from abc import ABC, abstractmethod +from pathlib import Path + +from aymurai.logger import get_logger + +logger = get_logger(__file__) + + +class InvalidFile(Exception): + """Raised when an extractor receives an invalid or missing file.""" + + +class BaseExtractor(ABC): + """Common interface shared by all document extractors.""" + + # Lowercase file extension handled by the extractor, without dot. + extension: str + + def ensure_file(self, path: Path) -> Path: + """ + Ensure the input file exists before extraction. + + Args: + path (Path): Candidate file path. + + Raises: + InvalidFile: If the file does not exist. + + Returns: + Path: Validated path ready for extraction. + """ + if not path.exists(): + raise InvalidFile(f"Invalid path: {path}") + return path + + @abstractmethod + def extract(self, path: Path) -> str: + """ + Extract normalized text from the source document. + + Args: + path (Path): Input document path. + + Returns: + str: Cleaned textual content. + """ + + +_REGISTRY: dict[str, type[BaseExtractor]] = {} + + +def register_extractor(cls: type[BaseExtractor]) -> type[BaseExtractor]: + """ + Register an extractor class for a specific extension. + + Args: + cls (type[BaseExtractor]): Extractor class to register. + + Returns: + type[BaseExtractor]: Registered class for fluent decorator usage. + """ + extension = getattr(cls, "extension", None) + if not extension: + raise ValueError( + f"Extractor {cls.__name__} must define an 'extension' attribute" + ) + + normalized = extension.lower() + if normalized in _REGISTRY: + logger.warning( + "Overriding extractor for extension '%s' with %s", normalized, cls.__name__ + ) + + _REGISTRY[normalized] = cls + return cls + + +def get_extractor(extension: str) -> BaseExtractor: + """ + Retrieve an extractor instance for the desired extension. + + Args: + extension (str): File extension to resolve. + + Returns: + BaseExtractor: Ready-to-use extractor instance. + """ + normalized = extension.lower() + try: + extractor_cls = _REGISTRY[normalized] + except KeyError as exc: + raise ValueError(f"Unsupported extension: {extension}") from exc + return extractor_cls() + + +def supported_extensions() -> set[str]: + """ + List the registered document extensions. + + Returns: + set[str]: Known extensions handled by the registry. + """ + return set(_REGISTRY.keys()) + + +__all__ = [ + "BaseExtractor", + "InvalidFile", + "get_extractor", + "register_extractor", + "supported_extensions", +] diff --git a/aymurai/text/extractors/docx.py b/aymurai/text/extractors/docx.py new file mode 100644 index 00000000..ae698e20 --- /dev/null +++ b/aymurai/text/extractors/docx.py @@ -0,0 +1,30 @@ +from pathlib import Path +from zipfile import BadZipFile + +import docx2txt + +from aymurai.text.extractors.base import BaseExtractor, InvalidFile, register_extractor +from aymurai.text.extractors.utils import get_footnotes, normalize_text + + +@register_extractor +class DocxExtractor(BaseExtractor): + extension = "docx" + + def extract(self, path: Path) -> str: + file_path = self.ensure_file(path) + + try: + document_text = docx2txt.process(str(file_path)) or "" + except (OSError, BadZipFile, KeyError) as exc: + raise InvalidFile(str(exc)) from exc + except Exception as exc: + raise InvalidFile(str(exc)) from exc + + footnotes = get_footnotes(file_path) or [] + footnotes_text = "\n".join(note for note in footnotes if note.strip()) + + if footnotes_text: + document_text = f"{document_text}\n\n{footnotes_text}" + + return normalize_text(document_text) diff --git a/aymurai/text/extractors/odt.py b/aymurai/text/extractors/odt.py new file mode 100644 index 00000000..7aaf3caa --- /dev/null +++ b/aymurai/text/extractors/odt.py @@ -0,0 +1,26 @@ +from pathlib import Path +from zipfile import BadZipFile + +from xml.etree.ElementTree import ParseError + +from aymurai.text.extractors.base import BaseExtractor, InvalidFile, register_extractor +from aymurai.text.extractors.utils import get_header, normalize_text, odt_to_text + + +@register_extractor +class OdtExtractor(BaseExtractor): + extension = "odt" + + def extract(self, path: Path) -> str: + file_path = self.ensure_file(path) + + try: + document_text = odt_to_text(file_path) + except (OSError, ValueError, BadZipFile, KeyError, ParseError) as exc: + raise InvalidFile(str(exc)) from exc + + header = "\n".join(get_header(file_path)).strip() + if header: + document_text = f"{header}\n\n{document_text}" + + return normalize_text(document_text) diff --git a/aymurai/text/extractors/pdf.py b/aymurai/text/extractors/pdf.py new file mode 100644 index 00000000..7a7e41b3 --- /dev/null +++ b/aymurai/text/extractors/pdf.py @@ -0,0 +1,74 @@ +from hashlib import blake2b +from pathlib import Path + +from aymurai.logger import get_logger +from aymurai.text.extractors.base import BaseExtractor, InvalidFile, register_extractor +from aymurai.text.extractors.utils import pdf_to_text +from aymurai.utils.cache import cache_load, cache_save, get_cache_key + +logger = get_logger(__file__) + + +@register_extractor +class PdfExtractor(BaseExtractor): + extension = "pdf" + + def extract(self, path: Path) -> str: + file_path = self.ensure_file(path) + + # Check cache first + cache_key = self._cache_key(file_path) + if cache_key: + cached_text = cache_load(cache_key) + if cached_text is not None: + logger.debug("PDF cache hit for %s", file_path) + return cached_text + + try: + text = pdf_to_text(file_path) + except (OSError, ValueError) as exc: + raise InvalidFile(str(exc)) from exc + except Exception as exc: + raise InvalidFile(str(exc)) from exc + if cache_key: + cache_save(text, key=cache_key) + logger.debug("PDF cache stored for %s", file_path) + + return text + + @staticmethod + def _cache_key(file_path: Path) -> str | None: + """ + Compute a stable cache key for the PDF payload. + + Args: + file_path (Path): Location of the PDF file to fingerprint. + + Returns: + str | None: Deterministic cache key, or ``None`` when the file is unreadable. + """ + try: + stat = file_path.stat() + except OSError as exc: + logger.warning("Unable to stat PDF %s for caching: %s", file_path, exc) + return None + + try: + hasher = blake2b(digest_size=32) + with file_path.open("rb") as handle: + for chunk in iter(lambda: handle.read(65536), b""): + hasher.update(chunk) + fingerprint = hasher.hexdigest() + except OSError as exc: + logger.warning("Unable to hash PDF %s for caching: %s", file_path, exc) + fingerprint = None + + item = fingerprint or file_path.resolve().as_posix() + context = { + "component": "pdf-extractor", + "size": stat.st_size, + } + if fingerprint is None: + context["mtime_ns"] = stat.st_mtime_ns + + return get_cache_key(item, context=context) diff --git a/aymurai/text/extractors/utils.py b/aymurai/text/extractors/utils.py new file mode 100644 index 00000000..b7c9520b --- /dev/null +++ b/aymurai/text/extractors/utils.py @@ -0,0 +1,298 @@ +import os +import unicodedata +import xml.etree.ElementTree as ET +import zipfile +from functools import cache +from pathlib import Path +from typing import Any + +import markdown2 +import xmltodict +from bs4 import BeautifulSoup +from lxml import etree +from marker.converters.pdf import PdfConverter +from marker.models import create_model_dict +from marker.renderers.markdown import MarkdownRenderer +from more_itertools import flatten + +from aymurai.logger import get_logger +from aymurai.utils.misc import get_element, get_recursively + +logger = get_logger(__file__) + + +BLOCK_TAGS = {"h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "blockquote", "pre"} + +MARKER_PDF_CONFIG = { + "layout_batch_size": 8, + "detection_batch_size": 8, + "table_rec_batch_size": 8, + "recognition_batch_size": 8, + "ocr_error_batch_size": 8, + "force_ocr": True, + "strip_existing_ocr": True, +} + +ODT_NS = {"text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0"} + + +def normalize_text(text: str) -> str: + """ + Normalize Unicode output consistently across extractors. + + Args: + text (str): Raw text extracted from a document. + + Returns: + str: Normalized string in NFKC form. + """ + return unicodedata.normalize("NFKC", text) + + +def markdown_to_text(md: str) -> str: + """ + Convert Markdown content to plain text by extracting relevant blocks. + + Args: + md (str): Markdown content produced by the renderer. + + Returns: + str: Plain text representation stripped of nested blocks. + """ + html = markdown2.markdown(md, extras=["tables"]) + soup = BeautifulSoup(html, "html.parser") + + chunks: list[str] = [] + for block in soup.find_all(BLOCK_TAGS): + if block.find_parent(BLOCK_TAGS): + continue + chunks.append(block.get_text(" ", strip=True)) + + return "\n\n".join(filter(None, chunks)) + + +def _build_marker_pdf_config() -> dict[str, int | str | bool]: + """ + Build marker configuration factoring in environment overrides. + + Returns: + dict[str, int | str | bool]: Effective configuration for marker-pdf. + """ + config = MARKER_PDF_CONFIG.copy() + + torch_device = os.getenv("TORCH_DEVICE") + if torch_device: + config["TORCH_DEVICE"] = torch_device + + log_level = os.getenv("LOG_LEVEL", "").lower() + if log_level == "debug": + config["debug"] = True + + return config + + +@cache +def get_marker_pdf_converter_and_md_renderer() -> tuple[PdfConverter, MarkdownRenderer]: + """ + Provide cached marker PDF converter and Markdown renderer instances. + + Returns: + tuple[PdfConverter, MarkdownRenderer]: Ready-to-use converter and renderer. + """ + pdf_converter = PdfConverter( + artifact_dict=create_model_dict(), + config=_build_marker_pdf_config(), + ) + + markdown_renderer = MarkdownRenderer( + { + "keep_pageheader_in_output": True, + "keep_pagefooter_in_output": True, + } + ) + + return pdf_converter, markdown_renderer + + +def pdf_to_text(file_path: Path) -> str: + """ + Extract text from a PDF file and return normalized plain text. + + Args: + file_path (Path): Path to the PDF document. + + Returns: + str: Cleaned textual content extracted from the PDF. + """ + logger.info("Extracting text from PDF: %s", file_path) + pdf_converter, markdown_renderer = get_marker_pdf_converter_and_md_renderer() + document = pdf_converter.build_document(filepath=file_path.as_posix()) + markdown_output = markdown_renderer(document) + plain_text = markdown_to_text(markdown_output.markdown) + return normalize_text(plain_text) + + +def load_xml_from_docx(path: Path, xmlfile: str = "word/footnotes.xml") -> Any | None: + """ + Extract XML content from a specific file inside a DOCX container. + + Args: + path (Path): DOCX archive path. + xmlfile (str, optional): Internal member name to inspect. Defaults to "word/footnotes.xml". + + Returns: + Any | None: Parsed XML tree or None when the member is missing. + """ + with zipfile.ZipFile(path, "r") as docx: + if xmlfile not in docx.namelist(): + return None + with docx.open(xmlfile) as handle: + return etree.parse(handle) + + +def load_xml_from_odt(path: Path, xmlfile: str = "styles.xml") -> str: + """ + Load XML content from an ODT archive member. + + Args: + path (Path): ODT archive path. + xmlfile (str, optional): Member name to open. Defaults to "styles.xml". + + Returns: + str: UTF-8 decoded XML content or an empty string when absent. + """ + with zipfile.ZipFile(path, "r") as odt: + if xmlfile not in odt.namelist(): + return "" + with odt.open(xmlfile) as file: + return file.read().decode("utf-8") + + +def get_header(path: Path) -> list[str]: + """ + Extract header text defined in an ODT stylesheet. + + Args: + path (Path): ODT document path. + + Returns: + list[str]: Header snippets collected from the stylesheet. + """ + styles_xml_content = load_xml_from_odt(path) + if not styles_xml_content: + return [] + + styles_dict = xmltodict.parse(styles_xml_content) + + header_root = get_element( + styles_dict, + levels=[ + "office:document-styles", + "office:master-styles", + "style:master-page", + ], + ) + + if not isinstance(header_root, list): + header_root = [header_root] + + style_header = [ + get_recursively(item, "style:header") + for item in header_root + if get_recursively(item, "style:header") + ] + style_header = list(flatten(style_header)) + + texts = [ + get_recursively(item, "#text") + for item in style_header + if get_recursively(item, "#text") + ] + texts = list(flatten(texts)) + + return [text for text in texts if isinstance(text, str)] + + +def get_footnotes(path: Path) -> list[str] | None: + """ + Extract footnotes from a DOCX document. + + Args: + path (Path): DOCX document path. + + Returns: + list[str] | None: Ordered footnote texts or None when absent. + """ + footnotes_tree = load_xml_from_docx(path) + if not footnotes_tree: + return None + + footnotes_root = footnotes_tree.getroot() + ns = {"w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main"} + + footnotes_texts: list[str] = [] + for footnote in footnotes_root.findall("w:footnote", namespaces=ns): + texts = footnote.xpath(".//w:t/text()", namespaces=ns) + if texts: + footnotes_texts.append("".join(texts)) + + return footnotes_texts + + +def _odt_qn(name: str) -> str: + """ + Resolve a qualified ODT tag into the ElementTree namespace form. + + Args: + name (str): Namespaced tag in the ``prefix:local`` format. + + Returns: + str: Expanded tag with namespace URI. + """ + prefix, local = name.split(":", 1) + return f"{{{ODT_NS[prefix]}}}{local}" + + +def _odt_text_to_string(elem) -> str: + """ + Flatten an ODT Element into a plain-text string, preserving special tokens. + + Args: + elem (Element): XML element to flatten. + + Returns: + str: Concatenated text content for the element subtree. + """ + out = elem.text or "" + for child in elem: + if child.tag == _odt_qn("text:tab"): + out += "\t" + elif child.tag == _odt_qn("text:s"): + out += " " * int(child.get(_odt_qn("text:c"), 1)) + else: + out += _odt_text_to_string(child) + if child.tail: + out += child.tail + return out + + +def odt_to_text(path: Path) -> str: + """ + Extract text content, preserving paragraphs and headings, from an ODT file. + + Args: + path (Path): ODT document path. + + Returns: + str: Plain text version of the document content. + """ + with zipfile.ZipFile(path, "r") as archive: + content_xml = archive.read("content.xml") + + content = ET.fromstring(content_xml) + + lines = [] + for child in content.iter(): + if child.tag in (_odt_qn("text:p"), _odt_qn("text:h")): + lines.append(_odt_text_to_string(child)) + return "\n".join(lines) diff --git a/aymurai/utils/cache.py b/aymurai/utils/cache.py index 48a4ae75..be653042 100644 --- a/aymurai/utils/cache.py +++ b/aymurai/utils/cache.py @@ -1,13 +1,12 @@ -import os import json +import os import pickle -from typing import Any, Optional +from typing import Any -import joblib import diskcache +import joblib from aymurai.logger import get_logger -from aymurai.meta.types import DataItem from aymurai.utils.json_encoding import EnhancedJSONEncoder logger = get_logger(__name__) @@ -18,15 +17,15 @@ def flatten_dict(current: dict, key: str = "", result: dict = {}) -> dict: """ - Flatten a dict + Flatten nested dictionaries into a dotted-key mapping. Args: - current (dict): dict to be flattened - key (str, optional): key to be used. Defaults to "". - result (dict, optional): result dict. Defaults to {}. + current (dict): Source dictionary to flatten. + key (str): Parent key prefix. Defaults to "". + result (dict, optional): Accumulator reused across recursion. Defaults to {}. Returns: - dict: flattened dict + dict: Mapping of flattened keys to terminal values. """ if type(current) is dict: for k in current: @@ -37,12 +36,12 @@ def flatten_dict(current: dict, key: str = "", result: dict = {}) -> dict: return result -def cache_clear(keys: list[str]): +def cache_clear(keys: list[str]) -> None: """ - Clear cache + Remove the provided keys from the disk-backed cache. Args: - keys (list[str]): keys to be cleared + keys (list[str]): Cache keys to delete. """ for key in keys: cache.pop(key) @@ -50,14 +49,14 @@ def cache_clear(keys: list[str]): def get_cache_key(item: Any, context: Any = "") -> str: """ - Get cache key + Build a stable cache key combining the item payload and context. Args: - item (Any): Data to hash - context (Any): context object to create hash + item (Any): Value to hash into the key namespace. + context (Any): Additional context used to scope the key. Defaults to "". Returns: - str: hash + str: Deterministic hash suitable for cache lookups. """ if type(item) in [dict]: @@ -72,20 +71,29 @@ def get_cache_key(item: Any, context: Any = "") -> str: return cache_key -def is_cached(key: str): +def is_cached(key: str) -> bool: + """ + Determine whether a cache entry exists for the given key. + + Args: + key (str): Cache key to inspect. + + Returns: + bool: True when the key is present, otherwise False. + """ return key in cache -def cache_save( - data_item: DataItem, - key: str, -): +def cache_save(data_item: Any, key: str) -> None: """ - save data on cache + Persist a Python object in the disk-backed cache. Args: - data (Data): data to be cached - key (str): key to store + data_item (Any): Serializable payload to store. + key (str): Cache key under which the payload is saved. + + Returns: + None: This function does not return a value. """ data = pickle.dumps(data_item) @@ -94,18 +102,16 @@ def cache_save( cache.set(key, data) -def cache_load(key: str) -> Optional[DataItem]: +def cache_load(key: str) -> Any | None: """ - load data from cache + Retrieve and deserialize a cached payload when present. Args: - key (str): key to load + key (str): Cache key to resolve. Returns: - Optional[Data]: loaded data - + Any | None: Cached payload on hit, otherwise ``None``. """ - if key in cache: # Retrieve the serialized object from cache data = cache.get(key) diff --git a/docker-compose.yml b/docker-compose.yml index 9a0b3da7..3876bb91 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,56 +1,111 @@ +x-api-lite: &api-lite + image: ghcr.io/aymurai/api:latest + build: + context: . + dockerfile: ./docker/api/Dockerfile + target: aymurai-api + shm_size: "2gb" + ports: + - "8899:8899" + volumes: + - ./resources/cache:/resources/cache + env_file: + - .env + - .env.common + +x-api-full: &api-full + image: ghcr.io/aymurai/api:full + build: + context: . + dockerfile: ./docker/api/Dockerfile + target: aymurai-api-full + shm_size: "2gb" + ports: + - "8899:8899" + restart: always + +x-ollama: &ollama-base + image: ollama/ollama + ports: + - "11434:11434" + volumes: + - ollama:/root/.ollama + restart: always + shm_size: "2gb" + services: + # CPU-friendly API aymurai-api: - image: ghcr.io/aymurai/api:latest - ports: - - "8899:8899" + <<: *api-lite depends_on: - ollama - build: - context: . - dockerfile: ./docker/api/Dockerfile - target: aymurai-api - env_file: - - .env - - .env.common environment: OLLAMA_HOST: http://ollama:11434 - volumes: - - ./resources/cache:/resources/cache + TORCH_DEVICE: cpu + # GPU-enabled API + aymurai-api-gpu: + <<: *api-lite + depends_on: + - ollama-gpu + environment: + OLLAMA_HOST: http://ollama-gpu:11434 + TORCH_DEVICE: cuda + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [ gpu ] + + # CPU-friendly Full API aymurai-api-full: - image: ghcr.io/aymurai/api:full - ports: - - "8899:8899" + <<: *api-full depends_on: - ollama - build: - context: . - dockerfile: ./docker/api/Dockerfile - target: aymurai-api-full - restart: always environment: OLLAMA_HOST: http://ollama:11434 + TORCH_DEVICE: cpu deploy: resources: limits: memory: 4g cpus: "4.0" + # GPU-enabled Full API + aymurai-api-full-gpu: + <<: *api-full + depends_on: + - ollama-gpu + environment: + OLLAMA_HOST: http://ollama-gpu:11434 + TORCH_DEVICE: cuda + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [ gpu ] + limits: + memory: 4g + cpus: "4.0" + + # CPU-only Ollama (default) ollama: - image: ollama/ollama - container_name: ollama + <<: *ollama-base + + # GPU-enabled Ollama (run instead on GPU hosts) + ollama-gpu: + <<: *ollama-base deploy: resources: reservations: devices: - driver: nvidia count: all - capabilities: [gpu] - ports: - - "11434:11434" - volumes: - - ollama:/root/.ollama - restart: always + capabilities: [ gpu ] volumes: ollama: diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 660e5a7e..2462d4ec 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -33,7 +33,6 @@ RUN --mount=type=bind,source=.git,target=.git \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --frozen --no-editable - # ------------------- # Base API Stage # ------------------- @@ -75,6 +74,7 @@ COPY --from=builder --chown=app:app /app/.venv /app/.venv # Copy static resources COPY resources/api/static /resources/api/static COPY resources/pipelines /resources/pipelines +COPY resources/llm /resources/llm # Set working directory WORKDIR /app @@ -96,6 +96,7 @@ ENV TF_CPP_MIN_LOG_LEVEL=3 \ # Copy additional resources COPY ./resources/api resources/api COPY ./resources/pipelines/production resources/pipelines/production +COPY ./resources/llm resources/llm # Initialize application to download models RUN uv run python /app/.venv/lib/python3.10/site-packages/aymurai/api/main.py diff --git a/pyproject.toml b/pyproject.toml index 26c99114..37d72eb0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,13 +57,12 @@ dependencies = [ "odfpy>=1.4.1", "gdown==4.6.0", "joblib>=1.4.2", - "textract==1.6.5", "datetime_matcher @ git+https://github.com/jedzill4/datetime_matcher", "jiwer==3.0.5", "datasets>=3.2.0", "unidecode==1.3.8", "sentencepiece==0.2.0", - "flair==0.14.0", + "flair==0.15.1", "fastapi[standard]>=0.115.6", "uvicorn>=0.34.0", "python-multipart>=0.0.20", @@ -74,8 +73,7 @@ dependencies = [ "cachetools>=5.5.0", "diskcache>=5.6.3", "scipy<1.14.1", - "torch==1.12.1", - "torchtext==0.13.1", + "torch>=1.13.1", "pytorch-lightning==1.8.3.post1", "tensorflow_text==2.10.0; sys_platform == 'linux' or (sys_platform == 'darwin' and platform_machine == 'x86_64') or sys_platform == 'win32'", # no ARM64 macOS wheels "psutil==6.1.0", @@ -92,6 +90,8 @@ dependencies = [ "langextract[openai]==1.1.0", "ollama==0.6.1", "tiktoken==0.12.0", + "marker-pdf==1.10.1", + "docx2txt>=0.9", ] [project.urls] diff --git a/resources/pipelines/production/full-paragraph/pipeline.json b/resources/pipelines/production/full-paragraph/pipeline.json index a60309b5..b3636d2a 100644 --- a/resources/pipelines/production/full-paragraph/pipeline.json +++ b/resources/pipelines/production/full-paragraph/pipeline.json @@ -14,16 +14,6 @@ "device": "cpu", "use_tokenizer": false } - ], - [ - "aymurai.models.decision.binregex.DecisionConv1dBinRegex", - { - "tokenizer_path": "https://drive.google.com/uc?id=1eljQOinpObdfBREIKxVnC5Y2g_sbhPHT&confirm=true", - "model_checkpoint": "https://drive.google.com/uc?id=19_YmBJnO06iS0qW8ak0zl0EIsJYin8kQ&confirm=true", - "device": "cpu", - "threshold": 0.5, - "return_only_with_detalle": true - } ] ], "postprocess": [ diff --git a/test/text/test_extraction.py b/test/text/test_extraction.py new file mode 100644 index 00000000..5e4dba56 --- /dev/null +++ b/test/text/test_extraction.py @@ -0,0 +1,94 @@ +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +from aymurai.text.extraction import ERRORS, InvalidFile, extract_document, get_extension + + +class ExtractionTestCase(unittest.TestCase): + def setUp(self) -> None: + self.tempdir = tempfile.TemporaryDirectory() + self.addCleanup(self.tempdir.cleanup) + self.tmp_path = Path(self.tempdir.name) + + def test_extract_document_dispatches(self): + source = self.tmp_path / "document.docx" + source.write_text("dummy") + + class DummyExtractor: + def __init__(self) -> None: + self.called = False + self.called_path: Path | None = None + + def extract(self, path: Path) -> str: + self.called = True + self.called_path = path + return "ok" + + dummy = DummyExtractor() + + with patch( + "aymurai.text.extraction.get_extractor", + return_value=dummy, + ): + result = extract_document(source) + + self.assertEqual(result, "ok") + self.assertTrue(dummy.called) + self.assertEqual(dummy.called_path, source) + + def test_extract_document_missing_file_raises(self): + missing = Path("/no/such/file.pdf") + with self.assertRaises(InvalidFile): + extract_document(missing, errors="raise") + + def test_extract_document_handles_invalid_file(self): + source = self.tmp_path / "document.pdf" + source.write_text("dummy") + + class BoomExtractor: + def extract(self, _path: Path) -> str: + raise InvalidFile("boom") + + with patch( + "aymurai.text.extraction.get_extractor", + return_value=BoomExtractor(), + ): + result = extract_document(source, errors="ignore") + + self.assertIsNone(result) + + def test_extract_document_raises_unexpected(self): + source = self.tmp_path / "document.odt" + source.write_text("dummy") + + class BoomExtractor: + def extract(self, _path: Path) -> str: + raise RuntimeError("boom") + + with patch( + "aymurai.text.extraction.get_extractor", + return_value=BoomExtractor(), + ): + with self.assertRaises(RuntimeError): + extract_document(source, errors="raise") + + def test_get_extension_basic(self): + cases = [ + ("file.pdf", "pdf"), + ("file.docx", "docx"), + ("file.odt", "odt"), + ("file.unknown", "unknown"), + ] + + for filename, expected in cases: + with self.subTest(filename=filename): + self.assertEqual(get_extension(filename), expected) + + def test_errors_configured(self): + self.assertEqual(set(ERRORS), {"ignore", "coerce", "raise"}) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/text/test_extractors.py b/test/text/test_extractors.py new file mode 100644 index 00000000..8beed5ff --- /dev/null +++ b/test/text/test_extractors.py @@ -0,0 +1,109 @@ +import tempfile +import unittest +from pathlib import Path +from unittest.mock import patch + +from aymurai.text.extractors.base import InvalidFile +from aymurai.text.extractors.docx import DocxExtractor +from aymurai.text.extractors.odt import OdtExtractor +from aymurai.text.extractors.pdf import PdfExtractor + + +class ExtractorTestCase(unittest.TestCase): + def setUp(self) -> None: + self.tempdir = tempfile.TemporaryDirectory() + self.addCleanup(self.tempdir.cleanup) + self.tmp_path = Path(self.tempdir.name) + + def test_docx_extractor_appends_footnotes(self): + file_path = self.tmp_path / "sample.docx" + file_path.write_bytes(b"fake docx content") + + with ( + patch( + "aymurai.text.extractors.docx.docx2txt.process", + return_value="Document body", + ), + patch( + "aymurai.text.extractors.docx.get_footnotes", + return_value=["Footnote one", ""], + ), + ): + extractor = DocxExtractor() + result = extractor.extract(file_path) + + self.assertIn("Document body", result) + self.assertTrue(result.strip().endswith("Footnote one")) + + def test_docx_extractor_raises_invalid_file(self): + file_path = self.tmp_path / "broken.docx" + file_path.write_bytes(b"") + + with patch( + "aymurai.text.extractors.docx.docx2txt.process", + side_effect=OSError("boom"), + ): + extractor = DocxExtractor() + with self.assertRaises(InvalidFile): + extractor.extract(file_path) + + def test_odt_extractor_prepends_header(self): + file_path = self.tmp_path / "sample.odt" + file_path.write_bytes(b"fake odt content") + + with ( + patch( + "aymurai.text.extractors.odt.odt_to_text", + return_value="Paragraph one", + ), + patch( + "aymurai.text.extractors.odt.get_header", + return_value=["Header"], + ), + ): + extractor = OdtExtractor() + result = extractor.extract(file_path) + + self.assertTrue(result.startswith("Header")) + self.assertIn("Paragraph one", result) + + def test_odt_extractor_invalid_file(self): + file_path = self.tmp_path / "broken.odt" + file_path.write_bytes(b"") + + with patch( + "aymurai.text.extractors.odt.odt_to_text", + side_effect=ValueError("bad xml"), + ): + extractor = OdtExtractor() + with self.assertRaises(InvalidFile): + extractor.extract(file_path) + + def test_pdf_extractor_delegates(self): + file_path = self.tmp_path / "sample.pdf" + file_path.write_bytes(b"fake pdf") + + with patch( + "aymurai.text.extractors.pdf.pdf_to_text", + return_value="PDF text", + ): + extractor = PdfExtractor() + result = extractor.extract(file_path) + + self.assertEqual(result, "PDF text") + + def test_pdf_extractor_wraps_errors(self): + file_path = self.tmp_path / "broken.pdf" + file_path.write_bytes(b"") + + with patch( + "aymurai.text.extractors.pdf.pdf_to_text", + side_effect=ValueError("invalid"), + ): + extractor = PdfExtractor() + with self.assertRaises(InvalidFile): + extractor.extract(file_path) + + +if __name__ == "__main__": + unittest.main() diff --git a/uv.lock b/uv.lock index 594c7511..3acc56ea 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,10 @@ version = 1 requires-python = "==3.10.*" +resolution-markers = [ + "platform_system == 'Darwin'", + "platform_machine == 'aarch64' and platform_system == 'Linux'", + "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')", +] [[package]] name = "absl-py" @@ -135,6 +140,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, ] +[[package]] +name = "anthropic" +version = "0.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228 }, +] + [[package]] name = "anyio" version = "4.12.0" @@ -158,15 +181,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, ] -[[package]] -name = "argcomplete" -version = "1.10.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/28/07d2cfe0838f998ea2eafab59f52b0ceb1e70adb1831fa14b958a9fa6c5c/argcomplete-1.10.3.tar.gz", hash = "sha256:a37f522cf3b6a34abddfedb61c4546f60023b3799b22d1cd971eacdc0861530a", size = 50173 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/8e/6b293f883fdbd29b9c8170db44bddff9e7de224d8cf1eb4287f69f1766e5/argcomplete-1.10.3-py2.py3-none-any.whl", hash = "sha256:d8ea63ebaec7f59e56e7b2a386b1d1c7f1a7ae87902c9ee17d377eaa557f06fa", size = 36576 }, -] - [[package]] name = "argon2-cffi" version = "25.1.0" @@ -284,7 +298,7 @@ wheels = [ [[package]] name = "aymurai" -version = "1.1.13.dev32" +version = "2.0.0a2.dev9" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -292,6 +306,7 @@ dependencies = [ { name = "datasets" }, { name = "datetime-matcher" }, { name = "diskcache" }, + { name = "docx2txt" }, { name = "faker" }, { name = "fastapi", extra = ["standard"] }, { name = "flair" }, @@ -299,6 +314,7 @@ dependencies = [ { name = "jiwer" }, { name = "joblib" }, { name = "langextract", extra = ["openai"] }, + { name = "marker-pdf" }, { name = "more-itertools" }, { name = "numpy" }, { name = "odfpy" }, @@ -321,10 +337,8 @@ dependencies = [ { name = "tenacity" }, { name = "tensorflow-hub" }, { name = "tensorflow-text", marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin') or sys_platform == 'linux' or sys_platform == 'win32'" }, - { name = "textract" }, { name = "tiktoken" }, { name = "torch" }, - { name = "torchtext" }, { name = "unidecode" }, { name = "uvicorn" }, { name = "xmltodict" }, @@ -352,13 +366,15 @@ requires-dist = [ { name = "datasets", specifier = ">=3.2.0" }, { name = "datetime-matcher", git = "https://github.com/jedzill4/datetime_matcher" }, { name = "diskcache", specifier = ">=5.6.3" }, + { name = "docx2txt", specifier = ">=0.9" }, { name = "faker", specifier = "==18.11.2" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.115.6" }, - { name = "flair", specifier = "==0.14.0" }, + { name = "flair", specifier = "==0.15.1" }, { name = "gdown", specifier = "==4.6.0" }, { name = "jiwer", specifier = "==3.0.5" }, { name = "joblib", specifier = ">=1.4.2" }, { name = "langextract", extras = ["openai"], specifier = "==1.1.0" }, + { name = "marker-pdf", specifier = "==1.10.1" }, { name = "more-itertools", specifier = ">=10.5.0" }, { name = "numpy", specifier = "<2.0.0" }, { name = "odfpy", specifier = ">=1.4.1" }, @@ -381,10 +397,8 @@ requires-dist = [ { name = "tenacity", specifier = ">=9.0.0" }, { name = "tensorflow-hub", specifier = ">=0.16.1" }, { name = "tensorflow-text", marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin') or sys_platform == 'linux' or sys_platform == 'win32'", specifier = "==2.10.0" }, - { name = "textract", specifier = "==1.6.5" }, { name = "tiktoken", specifier = "==0.12.0" }, - { name = "torch", specifier = "==1.12.1" }, - { name = "torchtext", specifier = "==0.13.1" }, + { name = "torch", specifier = ">=1.13.1" }, { name = "unidecode", specifier = "==1.3.8" }, { name = "uvicorn", specifier = ">=0.34.0" }, { name = "xmltodict", specifier = "==0.14.2" }, @@ -425,14 +439,15 @@ wheels = [ [[package]] name = "beautifulsoup4" -version = "4.8.2" +version = "4.14.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "soupsieve" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/ba/0e121661f529e7f456e903bf5c4d255b8051d8ce2b5e629c5212efe4c3f1/beautifulsoup4-4.8.2.tar.gz", hash = "sha256:05fd825eb01c290877657a56df4c6e4c311b3965bda790c613a3d6fb01a5462a", size = 298650 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a1/c698cf319e9cfed6b17376281bd0efc6bfc8465698f54170ef60a485ab5d/beautifulsoup4-4.8.2-py3-none-any.whl", hash = "sha256:9fbb4d6e48ecd30bcacc5b63b94088192dcda178513b2ae3c394229f8911b887", size = 106874 }, + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 }, ] [[package]] @@ -555,15 +570,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, ] -[[package]] -name = "chardet" -version = "3.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/bb/a5768c230f9ddb03acc9ef3f0d4a3cf93462473795d18e9535498c8f929d/chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae", size = 1868453 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691", size = 133356 }, -] - [[package]] name = "charset-normalizer" version = "3.4.4" @@ -624,7 +630,7 @@ name = "colorlog" version = "6.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162 } wheels = [ @@ -640,15 +646,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, ] -[[package]] -name = "compressed-rtf" -version = "1.0.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/0c/929a4e8ef9d7143f54d77dadb5f370cc7b98534b1bd6e1124d0abe8efb24/compressed_rtf-1.0.7.tar.gz", hash = "sha256:7c30859334839f3cdc7d10796af5b434bb326b9df7cb5a65e95a8eacb2951b0e", size = 8152 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/1d/62f5bf92e12335eb63517f42671ed78512d48bbc69e02a942dd7b90f03f0/compressed_rtf-1.0.7-py3-none-any.whl", hash = "sha256:b7904921d78c67a0a4b7fff9fb361a00ae2b447b6edca010ce321cd98fa0fcc0", size = 7968 }, -] - [[package]] name = "conllu" version = "4.5.3" @@ -859,11 +856,12 @@ wheels = [ ] [[package]] -name = "ebcdic" -version = "1.1.1" +name = "einops" +version = "0.8.1" source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/2f/633031205333bee5f9f93761af8268746aa75f38754823aabb8570eb245b/ebcdic-1.1.1-py2.py3-none-any.whl", hash = "sha256:33b4cb729bc2d0bf46cc1847b0e5946897cb8d3f53520c5b9aa5fa98d7e735f1", size = 128537 }, + { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359 }, ] [[package]] @@ -909,22 +907,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, ] -[[package]] -name = "extract-msg" -version = "0.29.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "compressed-rtf" }, - { name = "ebcdic" }, - { name = "imapclient" }, - { name = "olefile" }, - { name = "tzlocal" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b9/70/60c17682d8b95077c526fe8374061f309fa647836f7783ee14b1277a9d9b/extract_msg-0.29.0.tar.gz", hash = "sha256:ae6ce5f78fddb582350cb49bbf2776eadecdbf3c74b7a305dced42bd187a5401", size = 72891 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/da/dc/511f62860fc076fc4e27bfbb1bc6b1f2b61e694d68007853d983d1877bdf/extract_msg-0.29.0-py2.py3-none-any.whl", hash = "sha256:a8885dc385d0c88c4b87fb2a573727c0115cd2ef5157956cf183878f940eef28", size = 72912 }, -] - [[package]] name = "faker" version = "18.11.2" @@ -1073,6 +1055,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054 }, ] +[[package]] +name = "filetype" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970 }, +] + [[package]] name = "fire" version = "0.7.1" @@ -1087,7 +1078,7 @@ wheels = [ [[package]] name = "flair" -version = "0.14.0" +version = "0.15.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "bioc" }, @@ -1108,7 +1099,6 @@ dependencies = [ { name = "regex" }, { name = "scikit-learn" }, { name = "segtok" }, - { name = "semver" }, { name = "sqlitedict" }, { name = "tabulate" }, { name = "torch" }, @@ -1117,9 +1107,9 @@ dependencies = [ { name = "transformers", extra = ["sentencepiece"] }, { name = "wikipedia-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/3d/81fedb2222c9b9f6b922b69166f53f6244f6e91037ed0a8e121acd16ceef/flair-0.14.0.tar.gz", hash = "sha256:dc14b58e93a52141f204d9995191aa3b7e0463a661a41faa8f8db30745a188a4", size = 371405 } +sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607 } wheels = [ - { url = "https://files.pythonhosted.org/packages/65/f2/29a37585be8e824157d17c6196947b86a7312b0184a5d84f6792082130f5/flair-0.14.0-py3-none-any.whl", hash = "sha256:10735065ff462c05d0ea06ff01bc90e647f822a287858f9a6d0dabc7e402c754", size = 776453 }, + { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, ] [[package]] @@ -1570,18 +1560,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, ] -[[package]] -name = "imapclient" -version = "2.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ea/31/883f78210ed7578f6dd41e4dbc3ad5e7c6127a51e56513b8b7bb7efdf9b3/IMAPClient-2.1.0.zip", hash = "sha256:60ba79758cc9f13ec910d7a3df9acaaf2bb6c458720d9a02ec33a41352fd1b99", size = 248423 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/39/e1c2c2c6e2356ab6ea81fcfc0a74b044b311d6a91a45300811d9a6077ef7/IMAPClient-2.1.0-py2.py3-none-any.whl", hash = "sha256:3eeb97b9aa8faab0caa5024d74bfde59408fbd542781246f6960873c7bf0dd01", size = 73972 }, -] - [[package]] name = "importlib-metadata" version = "8.7.0" @@ -1632,7 +1610,7 @@ name = "ipython" version = "8.37.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "decorator" }, { name = "exceptiongroup" }, { name = "jedi" }, @@ -1952,7 +1930,7 @@ dependencies = [ { name = "overrides" }, { name = "packaging" }, { name = "prometheus-client" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, { name = "pyzmq" }, { name = "send2trash" }, { name = "terminado" }, @@ -1970,7 +1948,7 @@ name = "jupyter-server-terminals" version = "0.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, { name = "terminado" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430 } @@ -2167,13 +2145,12 @@ wheels = [ [[package]] name = "litellm" -version = "1.80.7" +version = "1.80.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "click" }, { name = "fastuuid" }, - { name = "grpcio" }, { name = "httpx" }, { name = "importlib-metadata" }, { name = "jinja2" }, @@ -2184,9 +2161,9 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/3f/af532014449c3931ae6cad2d97d267dd43d0de006060a8cbf0962e004024/litellm-1.80.7.tar.gz", hash = "sha256:3977a8d195aef842d01c18bf9e22984829363c6a4b54daf9a43c9dd9f190b42c", size = 12023127 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/e0/2e60a0c09235fd7b55297390c557923f3c35a9cf001914222c26a7857d2b/litellm-1.80.7-py3-none-any.whl", hash = "sha256:f7d993f78c1e0e4e1202b2a925cc6540b55b6e5fb055dd342d88b145ab3102ed", size = 10848321 }, + { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975 }, ] [[package]] @@ -2260,6 +2237,60 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321 }, ] +[[package]] +name = "markdown2" +version = "2.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954 }, +] + +[[package]] +name = "markdownify" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724 }, +] + +[[package]] +name = "marker-pdf" +version = "1.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anthropic" }, + { name = "click" }, + { name = "filetype" }, + { name = "ftfy" }, + { name = "google-genai" }, + { name = "markdown2" }, + { name = "markdownify" }, + { name = "openai" }, + { name = "pdftext" }, + { name = "pillow" }, + { name = "pre-commit" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-dotenv" }, + { name = "rapidfuzz" }, + { name = "regex" }, + { name = "scikit-learn" }, + { name = "surya-ocr" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "transformers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914 }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -2375,6 +2406,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, ] +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, +] + [[package]] name = "multidict" version = "6.7.0" @@ -2507,6 +2547,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, ] +[[package]] +name = "networkx" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -2560,6 +2609,155 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, ] +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, + { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, + { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, + { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.3.20" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/9d/3dd98852568fb845ec1f7902c90a22b240fe1cbabda411ccedf2fd737b7b/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0", size = 124484616 }, + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145 }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, +] + [[package]] name = "oauthlib" version = "3.3.1" @@ -2578,15 +2776,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045 } -[[package]] -name = "olefile" -version = "0.47" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/1b/077b508e3e500e1629d366249c3ccb32f95e50258b231705c09e3c7a4366/olefile-0.47.zip", hash = "sha256:599383381a0bf3dfbd932ca0ca6515acd174ed48870cbf7fee123d698c192c1c", size = 112240 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/d3/b64c356a907242d719fc668b71befd73324e47ab46c8ebbbede252c154b2/olefile-0.47-py2.py3-none-any.whl", hash = "sha256:543c7da2a7adadf21214938bb79c83ea12b473a4b6ee4ad4bf854e7715e13d1f", size = 114565 }, -] - [[package]] name = "ollama" version = "0.6.1" @@ -2602,7 +2791,7 @@ wheels = [ [[package]] name = "openai" -version = "2.9.0" +version = "1.109.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -2614,9 +2803,26 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/48/516290f38745cc1e72856f50e8afed4a7f9ac396a5a18f39e892ab89dfc2/openai-2.9.0.tar.gz", hash = "sha256:b52ec65727fc8f1eed2fbc86c8eac0998900c7ef63aa2eb5c24b69717c56fa5f", size = 608202 } +sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133 } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/fd/ae2da789cd923dd033c99b8d544071a827c92046b150db01cfa5cea5b3fd/openai-2.9.0-py3-none-any.whl", hash = "sha256:0d168a490fbb45630ad508a6f3022013c155a68fd708069b6a1a01a5e8f0ffad", size = 1030836 }, + { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627 }, +] + +[[package]] +name = "opencv-python-headless" +version = "4.11.0.86" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/53/2c50afa0b1e05ecdb4603818e85f7d174e683d874ef63a6abe3ac92220c8/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca", size = 37326460 }, + { url = "https://files.pythonhosted.org/packages/3b/43/68555327df94bb9b59a1fd645f63fafb0762515344d2046698762fc19d58/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81", size = 56723330 }, + { url = "https://files.pythonhosted.org/packages/45/be/1438ce43ebe65317344a87e4b150865c5585f4c0db880a34cdae5ac46881/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efabcaa9df731f29e5ea9051776715b1bdd1845d7c9530065c7951d2a2899eb", size = 29487060 }, + { url = "https://files.pythonhosted.org/packages/dd/5c/c139a7876099916879609372bfa513b7f1257f7f1a908b0bdc1c2328241b/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0a27c19dd1f40ddff94976cfe43066fbbe9dfbb2ec1907d66c19caef42a57b", size = 49969856 }, + { url = "https://files.pythonhosted.org/packages/95/dd/ed1191c9dc91abcc9f752b499b7928aacabf10567bb2c2535944d848af18/opencv_python_headless-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:f447d8acbb0b6f2808da71fddd29c1cdd448d2bc98f72d9bb78a7a898fc9621b", size = 29324425 }, + { url = "https://files.pythonhosted.org/packages/86/8a/69176a64335aed183529207ba8bc3d329c2999d852b4f3818027203f50e6/opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca", size = 39402386 }, ] [[package]] @@ -2723,18 +2929,18 @@ wheels = [ ] [[package]] -name = "pdfminer-six" -version = "20191110" +name = "pdftext" +version = "0.6.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "chardet" }, - { name = "pycryptodome" }, - { name = "six" }, - { name = "sortedcontainers" }, + { name = "click" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pypdfium2" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e8/31/7acc148333749d6a8ef7cbf25902bdf59a462811a69d040a9a259916b6bd/pdfminer.six-20191110.tar.gz", hash = "sha256:141a53ec491bee6d45bf9b2c7f82601426fb5d32636bcf6b9c8a8f3b6431fea6", size = 10280313 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/83/200b2723bcbf1d1248a8a7d16e6dd6cb970b5331397b11948428d7ebcf37/pdfminer.six-20191110-py2.py3-none-any.whl", hash = "sha256:ca2ca58f3ac66a486bce53a6ddba95dc2b27781612915fa41c444790ba9cd2a8", size = 5606096 }, + { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693 }, ] [[package]] @@ -2751,21 +2957,28 @@ wheels = [ [[package]] name = "pillow" -version = "12.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/08/26e68b6b5da219c2a2cb7b563af008b53bb8e6b6fcb3fa40715fcdb2523a/pillow-12.0.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:3adfb466bbc544b926d50fe8f4a4e6abd8c6bffd28a26177594e6e9b2b76572b", size = 5289809 }, - { url = "https://files.pythonhosted.org/packages/cb/e9/4e58fb097fb74c7b4758a680aacd558810a417d1edaa7000142976ef9d2f/pillow-12.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1ac11e8ea4f611c3c0147424eae514028b5e9077dd99ab91e1bd7bc33ff145e1", size = 4650606 }, - { url = "https://files.pythonhosted.org/packages/4b/e0/1fa492aa9f77b3bc6d471c468e62bfea1823056bf7e5e4f1914d7ab2565e/pillow-12.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d49e2314c373f4c2b39446fb1a45ed333c850e09d0c59ac79b72eb3b95397363", size = 6221023 }, - { url = "https://files.pythonhosted.org/packages/c1/09/4de7cd03e33734ccd0c876f0251401f1314e819cbfd89a0fcb6e77927cc6/pillow-12.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c7b2a63fd6d5246349f3d3f37b14430d73ee7e8173154461785e43036ffa96ca", size = 8024937 }, - { url = "https://files.pythonhosted.org/packages/2e/69/0688e7c1390666592876d9d474f5e135abb4acb39dcb583c4dc5490f1aff/pillow-12.0.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d64317d2587c70324b79861babb9c09f71fbb780bad212018874b2c013d8600e", size = 6334139 }, - { url = "https://files.pythonhosted.org/packages/ed/1c/880921e98f525b9b44ce747ad1ea8f73fd7e992bafe3ca5e5644bf433dea/pillow-12.0.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d77153e14b709fd8b8af6f66a3afbb9ed6e9fc5ccf0b6b7e1ced7b036a228782", size = 7026074 }, - { url = "https://files.pythonhosted.org/packages/28/03/96f718331b19b355610ef4ebdbbde3557c726513030665071fd025745671/pillow-12.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32ed80ea8a90ee3e6fa08c21e2e091bba6eda8eccc83dbc34c95169507a91f10", size = 6448852 }, - { url = "https://files.pythonhosted.org/packages/3a/a0/6a193b3f0cc9437b122978d2c5cbce59510ccf9a5b48825096ed7472da2f/pillow-12.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c828a1ae702fc712978bda0320ba1b9893d99be0badf2647f693cc01cf0f04fa", size = 7117058 }, - { url = "https://files.pythonhosted.org/packages/a7/c4/043192375eaa4463254e8e61f0e2ec9a846b983929a8d0a7122e0a6d6fff/pillow-12.0.0-cp310-cp310-win32.whl", hash = "sha256:bd87e140e45399c818fac4247880b9ce719e4783d767e030a883a970be632275", size = 6295431 }, - { url = "https://files.pythonhosted.org/packages/92/c6/c2f2fc7e56301c21827e689bb8b0b465f1b52878b57471a070678c0c33cd/pillow-12.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:455247ac8a4cfb7b9bc45b7e432d10421aea9fc2e74d285ba4072688a74c2e9d", size = 7000412 }, - { url = "https://files.pythonhosted.org/packages/b2/d2/5f675067ba82da7a1c238a73b32e3fd78d67f9d9f80fbadd33a40b9c0481/pillow-12.0.0-cp310-cp310-win_arm64.whl", hash = "sha256:6ace95230bfb7cd79ef66caa064bbe2f2a1e63d93471c3a2e1f1348d9f22d6b7", size = 2435903 }, +version = "10.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, + { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, + { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, + { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, + { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, + { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, + { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, + { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, + { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, + { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, + { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, + { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, + { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, + { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, + { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, + { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, + { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, + { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, ] [[package]] @@ -2988,32 +3201,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, ] -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627 }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362 }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625 }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954 }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534 }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853 }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465 }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414 }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484 }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636 }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675 }, - { url = "https://files.pythonhosted.org/packages/9f/7c/f5b0556590e7b4e710509105e668adb55aa9470a9f0e4dea9c40a4a11ce1/pycryptodome-3.23.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:350ebc1eba1da729b35ab7627a833a1a355ee4e852d8ba0447fafe7b14504d56", size = 1705791 }, - { url = "https://files.pythonhosted.org/packages/33/38/dcc795578d610ea1aaffef4b148b8cafcfcf4d126b1e58231ddc4e475c70/pycryptodome-3.23.0-pp27-pypy_73-win32.whl", hash = "sha256:93837e379a3e5fd2bb00302a47aee9fdf7940d83595be3915752c74033d17ca7", size = 1780265 }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886 }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151 }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461 }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440 }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005 }, -] - [[package]] name = "pydantic" version = "2.12.5" @@ -3179,6 +3366,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890 }, ] +[[package]] +name = "pypdfium2" +version = "4.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254 }, + { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624 }, + { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126 }, + { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077 }, + { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431 }, + { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008 }, + { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543 }, + { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911 }, + { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430 }, + { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951 }, + { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098 }, + { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118 }, +] + [[package]] name = "pysocks" version = "1.7.1" @@ -3240,20 +3447,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 }, ] -[[package]] -name = "python-pptx" -version = "0.6.23" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "lxml" }, - { name = "pillow" }, - { name = "xlsxwriter" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/20/e7/aeaf794b2d440da609684494075e64cfada248026ecb265807d0668cdd00/python-pptx-0.6.23.tar.gz", hash = "sha256:587497ff28e779ab18dbb074f6d4052893c85dedc95ed75df319364f331fedee", size = 10083771 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/49/6eee83072983473e9905ffddd5c2032b9a0ca4616425560d6d582287b467/python_pptx-0.6.23-py3-none-any.whl", hash = "sha256:dd0527194627a2b7cc05f3ba23ecaa2d9a0d5ac9b6193a28ed1b7a716f4217d4", size = 471575 }, -] - [[package]] name = "pytorch-lightning" version = "1.8.3.post1" @@ -3404,25 +3597,26 @@ wheels = [ [[package]] name = "regex" -version = "2025.11.3" +version = "2024.11.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/a9/546676f25e573a4cf00fe8e119b78a37b6a8fe2dc95cda877b30889c9c45/regex-2025.11.3.tar.gz", hash = "sha256:1fedc720f9bb2494ce31a58a1631f9c82df6a09b49c19517ea5cc280b4541e01", size = 414669 } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/d6/d788d52da01280a30a3f6268aef2aa71043bff359c618fea4c5b536654d5/regex-2025.11.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2b441a4ae2c8049106e8b39973bfbddfb25a179dda2bdb99b0eeb60c40a6a3af", size = 488087 }, - { url = "https://files.pythonhosted.org/packages/69/39/abec3bd688ec9bbea3562de0fd764ff802976185f5ff22807bf0a2697992/regex-2025.11.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2fa2eed3f76677777345d2f81ee89f5de2f5745910e805f7af7386a920fa7313", size = 290544 }, - { url = "https://files.pythonhosted.org/packages/39/b3/9a231475d5653e60002508f41205c61684bb2ffbf2401351ae2186897fc4/regex-2025.11.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d8b4a27eebd684319bdf473d39f1d79eed36bf2cd34bd4465cdb4618d82b3d56", size = 288408 }, - { url = "https://files.pythonhosted.org/packages/c3/c5/1929a0491bd5ac2d1539a866768b88965fa8c405f3e16a8cef84313098d6/regex-2025.11.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5cf77eac15bd264986c4a2c63353212c095b40f3affb2bc6b4ef80c4776c1a28", size = 781584 }, - { url = "https://files.pythonhosted.org/packages/ce/fd/16aa16cf5d497ef727ec966f74164fbe75d6516d3d58ac9aa989bc9cdaad/regex-2025.11.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b7f9ee819f94c6abfa56ec7b1dbab586f41ebbdc0a57e6524bd5e7f487a878c7", size = 850733 }, - { url = "https://files.pythonhosted.org/packages/e6/49/3294b988855a221cb6565189edf5dc43239957427df2d81d4a6b15244f64/regex-2025.11.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:838441333bc90b829406d4a03cb4b8bf7656231b84358628b0406d803931ef32", size = 898691 }, - { url = "https://files.pythonhosted.org/packages/14/62/b56d29e70b03666193369bdbdedfdc23946dbe9f81dd78ce262c74d988ab/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cfe6d3f0c9e3b7e8c0c694b24d25e677776f5ca26dce46fd6b0489f9c8339391", size = 791662 }, - { url = "https://files.pythonhosted.org/packages/15/fc/e4c31d061eced63fbf1ce9d853975f912c61a7d406ea14eda2dd355f48e7/regex-2025.11.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2ab815eb8a96379a27c3b6157fcb127c8f59c36f043c1678110cea492868f1d5", size = 782587 }, - { url = "https://files.pythonhosted.org/packages/b2/bb/5e30c7394bcf63f0537121c23e796be67b55a8847c3956ae6068f4c70702/regex-2025.11.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:728a9d2d173a65b62bdc380b7932dd8e74ed4295279a8fe1021204ce210803e7", size = 774709 }, - { url = "https://files.pythonhosted.org/packages/c5/c4/fce773710af81b0cb37cb4ff0947e75d5d17dee304b93d940b87a67fc2f4/regex-2025.11.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:509dc827f89c15c66a0c216331260d777dd6c81e9a4e4f830e662b0bb296c313", size = 845773 }, - { url = "https://files.pythonhosted.org/packages/7b/5e/9466a7ec4b8ec282077095c6eb50a12a389d2e036581134d4919e8ca518c/regex-2025.11.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:849202cd789e5f3cf5dcc7822c34b502181b4824a65ff20ce82da5524e45e8e9", size = 836164 }, - { url = "https://files.pythonhosted.org/packages/95/18/82980a60e8ed1594eb3c89eb814fb276ef51b9af7caeab1340bfd8564af6/regex-2025.11.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b6f78f98741dcc89607c16b1e9426ee46ce4bf31ac5e6b0d40e81c89f3481ea5", size = 779832 }, - { url = "https://files.pythonhosted.org/packages/03/cc/90ab0fdbe6dce064a42015433f9152710139fb04a8b81b4fb57a1cb63ffa/regex-2025.11.3-cp310-cp310-win32.whl", hash = "sha256:149eb0bba95231fb4f6d37c8f760ec9fa6fabf65bab555e128dde5f2475193ec", size = 265802 }, - { url = "https://files.pythonhosted.org/packages/34/9d/e9e8493a85f3b1ddc4a5014465f5c2b78c3ea1cbf238dcfde78956378041/regex-2025.11.3-cp310-cp310-win_amd64.whl", hash = "sha256:ee3a83ce492074c35a74cc76cf8235d49e77b757193a5365ff86e3f2f93db9fd", size = 277722 }, - { url = "https://files.pythonhosted.org/packages/15/c4/b54b24f553966564506dbf873a3e080aef47b356a3b39b5d5aba992b50db/regex-2025.11.3-cp310-cp310-win_arm64.whl", hash = "sha256:38af559ad934a7b35147716655d4a2f79fcef2d695ddfe06a06ba40ae631fa7e", size = 270289 }, + { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674 }, + { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684 }, + { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589 }, + { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511 }, + { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149 }, + { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707 }, + { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702 }, + { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976 }, + { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397 }, + { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726 }, + { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098 }, + { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325 }, + { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277 }, + { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197 }, + { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714 }, + { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042 }, ] [[package]] @@ -3688,15 +3882,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332 }, ] -[[package]] -name = "semver" -version = "3.0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/d1/d3159231aec234a59dd7d601e9dd9fe96f3afff15efd33c1070019b26132/semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602", size = 269730 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a6/24/4d91e05817e92e3a61c8a21e08fd0f390f5301f1c448b137c57c4bc6e543/semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746", size = 17912 }, -] - [[package]] name = "send2trash" version = "1.8.3" @@ -3774,11 +3959,11 @@ wheels = [ [[package]] name = "six" -version = "1.12.0" +version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/dd/bf/4138e7bfb757de47d1f4b6994648ec67a51efe58fa907c1e11e350cddfca/six-1.12.0.tar.gz", hash = "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73", size = 32725 } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/fb/00a976f728d0d1fecfe898238ce23f502a721c0ac0ecfedb80e0d88c64e9/six-1.12.0-py2.py3-none-any.whl", hash = "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", size = 10586 }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] [[package]] @@ -3817,14 +4002,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679 }, ] -[[package]] -name = "speechrecognition" -version = "3.8.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/e1/7f5678cd94ec1234269d23756dbdaa4c8cfaed973412f88ae8adf7893a50/SpeechRecognition-3.8.1-py2.py3-none-any.whl", hash = "sha256:4d8f73a0c05ec70331c3bacaa89ecc06dfa8d9aba0899276664cda06ab597e8e", size = 32833456 }, -] - [[package]] name = "sqlalchemy" version = "2.0.44" @@ -3926,6 +4103,42 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/fa/5b010610aa136c44a20de6ed9ec0b36867daf7322d0e3c8e626a99fab11a/streamlit-1.21.0-py2.py3-none-any.whl", hash = "sha256:05862598952a9126e16652caa5bc88eeeea7b2773af252e2daccf1c84ceaaef4", size = 9665093 }, ] +[[package]] +name = "surya-ocr" +version = "0.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "einops" }, + { name = "filetype" }, + { name = "opencv-python-headless" }, + { name = "pillow" }, + { name = "platformdirs" }, + { name = "pre-commit" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "pypdfium2" }, + { name = "python-dotenv" }, + { name = "torch" }, + { name = "transformers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395 }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, +] + [[package]] name = "tabulate" version = "0.9.0" @@ -4095,7 +4308,7 @@ version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "os_name == 'nt'" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, { name = "tornado" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } @@ -4103,27 +4316,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, ] -[[package]] -name = "textract" -version = "1.6.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "argcomplete" }, - { name = "beautifulsoup4" }, - { name = "chardet" }, - { name = "docx2txt" }, - { name = "extract-msg" }, - { name = "pdfminer-six" }, - { name = "python-pptx" }, - { name = "six" }, - { name = "speechrecognition" }, - { name = "xlrd" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/81/9f/dd29fcec368f007d44e51f0273489d5172a6d32ed9c796df5054fbb31c9f/textract-1.6.5.tar.gz", hash = "sha256:68f0f09056885821e6c43d8538987518daa94057c306679f2857cc5ee66ad850", size = 17871 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/3e/ac16b6bf28edf78296aea7d0cb416b49ed30282ac8c711662541015ee6f3/textract-1.6.5-py3-none-any.whl", hash = "sha256:0accd78ec42864e3e3827f9ef798ced9aac4727b664303b724a198fed73fa438", size = 23140 }, -] - [[package]] name = "tf-keras" version = "2.15.0" @@ -4175,27 +4367,27 @@ wheels = [ [[package]] name = "tokenizers" -version = "0.21.4" +version = "0.22.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/2f/402986d0823f8d7ca139d969af2917fefaa9b947d1fb32f6168c509f2492/tokenizers-0.21.4.tar.gz", hash = "sha256:fa23f85fbc9a02ec5c6978da172cdcbac23498c3ca9f3645c5c68740ac007880", size = 351253 } +sdist = { url = "https://files.pythonhosted.org/packages/1c/46/fb6854cec3278fbfa4a75b50232c77622bc517ac886156e6afbfa4d8fc6e/tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9", size = 363123 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/c6/fdb6f72bf6454f52eb4a2510be7fb0f614e541a2554d6210e370d85efff4/tokenizers-0.21.4-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ccc10a7c3bcefe0f242867dc914fc1226ee44321eb618cfe3019b5df3400133", size = 2863987 }, - { url = "https://files.pythonhosted.org/packages/8d/a6/28975479e35ddc751dc1ddc97b9b69bf7fcf074db31548aab37f8116674c/tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5e2f601a8e0cd5be5cc7506b20a79112370b9b3e9cb5f13f68ab11acd6ca7d60", size = 2732457 }, - { url = "https://files.pythonhosted.org/packages/aa/8f/24f39d7b5c726b7b0be95dca04f344df278a3fe3a4deb15a975d194cbb32/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b376f5a1aee67b4d29032ee85511bbd1b99007ec735f7f35c8a2eb104eade5", size = 3012624 }, - { url = "https://files.pythonhosted.org/packages/58/47/26358925717687a58cb74d7a508de96649544fad5778f0cd9827398dc499/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2107ad649e2cda4488d41dfd031469e9da3fcbfd6183e74e4958fa729ffbf9c6", size = 2939681 }, - { url = "https://files.pythonhosted.org/packages/99/6f/cc300fea5db2ab5ddc2c8aea5757a27b89c84469899710c3aeddc1d39801/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c73012da95afafdf235ba80047699df4384fdc481527448a078ffd00e45a7d9", size = 3247445 }, - { url = "https://files.pythonhosted.org/packages/be/bf/98cb4b9c3c4afd8be89cfa6423704337dc20b73eb4180397a6e0d456c334/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f23186c40395fc390d27f519679a58023f368a0aad234af145e0f39ad1212732", size = 3428014 }, - { url = "https://files.pythonhosted.org/packages/75/c7/96c1cc780e6ca7f01a57c13235dd05b7bc1c0f3588512ebe9d1331b5f5ae/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc88bb34e23a54cc42713d6d98af5f1bf79c07653d24fe984d2d695ba2c922a2", size = 3193197 }, - { url = "https://files.pythonhosted.org/packages/f2/90/273b6c7ec78af547694eddeea9e05de771278bd20476525ab930cecaf7d8/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51b7eabb104f46c1c50b486520555715457ae833d5aee9ff6ae853d1130506ff", size = 3115426 }, - { url = "https://files.pythonhosted.org/packages/91/43/c640d5a07e95f1cf9d2c92501f20a25f179ac53a4f71e1489a3dcfcc67ee/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:714b05b2e1af1288bd1bc56ce496c4cebb64a20d158ee802887757791191e6e2", size = 9089127 }, - { url = "https://files.pythonhosted.org/packages/44/a1/dd23edd6271d4dca788e5200a807b49ec3e6987815cd9d0a07ad9c96c7c2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:1340ff877ceedfa937544b7d79f5b7becf33a4cfb58f89b3b49927004ef66f78", size = 9055243 }, - { url = "https://files.pythonhosted.org/packages/21/2b/b410d6e9021c4b7ddb57248304dc817c4d4970b73b6ee343674914701197/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3c1f4317576e465ac9ef0d165b247825a2a4078bcd01cba6b54b867bdf9fdd8b", size = 9298237 }, - { url = "https://files.pythonhosted.org/packages/b7/0a/42348c995c67e2e6e5c89ffb9cfd68507cbaeb84ff39c49ee6e0a6dd0fd2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c212aa4e45ec0bb5274b16b6f31dd3f1c41944025c2358faaa5782c754e84c24", size = 9461980 }, - { url = "https://files.pythonhosted.org/packages/3d/d3/dacccd834404cd71b5c334882f3ba40331ad2120e69ded32cf5fda9a7436/tokenizers-0.21.4-cp39-abi3-win32.whl", hash = "sha256:6c42a930bc5f4c47f4ea775c91de47d27910881902b0f20e4990ebe045a415d0", size = 2329871 }, - { url = "https://files.pythonhosted.org/packages/41/f2/fd673d979185f5dcbac4be7d09461cbb99751554ffb6718d0013af8604cb/tokenizers-0.21.4-cp39-abi3-win_amd64.whl", hash = "sha256:475d807a5c3eb72c59ad9b5fcdb254f6e17f53dfcbb9903233b0dfa9c943b597", size = 2507568 }, + { url = "https://files.pythonhosted.org/packages/bf/33/f4b2d94ada7ab297328fc671fed209368ddb82f965ec2224eb1892674c3a/tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73", size = 3069318 }, + { url = "https://files.pythonhosted.org/packages/1c/58/2aa8c874d02b974990e89ff95826a4852a8b2a273c7d1b4411cdd45a4565/tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc", size = 2926478 }, + { url = "https://files.pythonhosted.org/packages/1e/3b/55e64befa1e7bfea963cf4b787b2cea1011362c4193f5477047532ce127e/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a", size = 3256994 }, + { url = "https://files.pythonhosted.org/packages/71/0b/fbfecf42f67d9b7b80fde4aabb2b3110a97fac6585c9470b5bff103a80cb/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7", size = 3153141 }, + { url = "https://files.pythonhosted.org/packages/17/a9/b38f4e74e0817af8f8ef925507c63c6ae8171e3c4cb2d5d4624bf58fca69/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21", size = 3508049 }, + { url = "https://files.pythonhosted.org/packages/d2/48/dd2b3dac46bb9134a88e35d72e1aa4869579eacc1a27238f1577270773ff/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214", size = 3710730 }, + { url = "https://files.pythonhosted.org/packages/93/0e/ccabc8d16ae4ba84a55d41345207c1e2ea88784651a5a487547d80851398/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f", size = 3412560 }, + { url = "https://files.pythonhosted.org/packages/d0/c6/dc3a0db5a6766416c32c034286d7c2d406da1f498e4de04ab1b8959edd00/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4", size = 3250221 }, + { url = "https://files.pythonhosted.org/packages/d7/a6/2c8486eef79671601ff57b093889a345dd3d576713ef047776015dc66de7/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879", size = 9345569 }, + { url = "https://files.pythonhosted.org/packages/6b/16/32ce667f14c35537f5f605fe9bea3e415ea1b0a646389d2295ec348d5657/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446", size = 9271599 }, + { url = "https://files.pythonhosted.org/packages/51/7c/a5f7898a3f6baa3fc2685c705e04c98c1094c523051c805cdd9306b8f87e/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a", size = 9533862 }, + { url = "https://files.pythonhosted.org/packages/36/65/7e75caea90bc73c1dd8d40438adf1a7bc26af3b8d0a6705ea190462506e1/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390", size = 9681250 }, + { url = "https://files.pythonhosted.org/packages/30/2c/959dddef581b46e6209da82df3b78471e96260e2bc463f89d23b1bf0e52a/tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82", size = 2472003 }, + { url = "https://files.pythonhosted.org/packages/b3/46/e33a8c93907b631a99377ef4c5f817ab453d0b34f93529421f42ff559671/tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138", size = 2674684 }, ] [[package]] @@ -4227,17 +4419,37 @@ wheels = [ [[package]] name = "torch" -version = "1.12.1" +version = "2.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/74/7342c7f21449557a8263c925071a55081edd7e9b641404cfe31d6fb71d3b/torch-1.12.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:9c038662db894a23e49e385df13d47b2a777ffd56d9bcd5b832593fab0a7e286", size = 776338835 }, - { url = "https://files.pythonhosted.org/packages/36/b0/4857929aa28dfe26f7de909ebf002b60499edcd7566441a7433df865f9ba/torch-1.12.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:4e1b9c14cf13fd2ab8d769529050629a0e68a6fc5cb8e84b4a3cc1dd8c4fe541", size = 55712361 }, - { url = "https://files.pythonhosted.org/packages/b9/25/fc2111599a038aa6c1c618a7dc9246aabc95f899008949ade31213255a0c/torch-1.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:e9c8f4a311ac29fc7e8e955cfb7733deb5dbe1bdaabf5d4af2765695824b7e0d", size = 162235663 }, - { url = "https://files.pythonhosted.org/packages/37/72/ef80d39a371a9b4a8aadfb22b141972cc67a7075dae69a9d5b8116505ec0/torch-1.12.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:976c3f997cea38ee91a0dd3c3a42322785414748d1761ef926b789dfa97c6134", size = 133811424 }, - { url = "https://files.pythonhosted.org/packages/2f/17/8b557dde1cdb5fbe82f90a3f192046c8e508f106456e12f17c87543e6a42/torch-1.12.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:68104e4715a55c4bb29a85c6a8d57d820e0757da363be1ba680fa8cc5be17b52", size = 49099890 }, + { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681 }, + { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036 }, + { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861 }, + { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222 }, ] [[package]] @@ -4254,24 +4466,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162 }, ] -[[package]] -name = "torchtext" -version = "0.13.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "requests" }, - { name = "torch" }, - { name = "tqdm" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/6f/673e3533a296f135fecfccdf2519ecfba7e16971dca5c3bc7a8cc9cfd064/torchtext-0.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:aa59df8f9542674311fc23aca147a34256c936c25840c4b6ee3fee47d511ad17", size = 1775853 }, - { url = "https://files.pythonhosted.org/packages/2f/bd/5f27d604d3dc6421b3c0bd24c28f73eecb091fce9dbdcbe7af314f252cee/torchtext-0.13.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:492a22727181edf5a33fa18587f3430ffbb366c2ea835e0f4f8a08be8d9e859c", size = 1966034 }, - { url = "https://files.pythonhosted.org/packages/48/4e/56352383c30b75becd5faaff8d404eb86f3a2282d72ae52aaad705bf22bf/torchtext-0.13.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:f56359165eb00ea2ff998b67727f87e7fa32665c1a46610c9b5a2d5d581095e5", size = 1910382 }, - { url = "https://files.pythonhosted.org/packages/3f/fd/e3eef8b5d691cdeb42506fc9fec2a64ab1549039cdf9e7545a171e4a694e/torchtext-0.13.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:b5bf4f9da5326b6e74318b4a5035abfaf166b3abd822565be685f44947adb8d3", size = 1832850 }, - { url = "https://files.pythonhosted.org/packages/b8/9d/7f9b786637d664579b66ae7c6742d662a91b8e6a9f55a34e22c20883d801/torchtext-0.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f8c1b426bda2f22e5bfd118c779c12f8612ed1077e5e3a491242bb4ab7ac4d3", size = 2239348 }, -] - [[package]] name = "tornado" version = "6.5.2" @@ -4327,7 +4521,7 @@ wheels = [ [[package]] name = "transformers" -version = "4.47.1" +version = "4.57.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, @@ -4341,9 +4535,9 @@ dependencies = [ { name = "tokenizers" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/15/1a/936aeb4f88112f670b604f5748034568dbc2b9bbb457a8d4518b1a15510a/transformers-4.47.1.tar.gz", hash = "sha256:6c29c05a5f595e278481166539202bf8641281536df1c42357ee58a45d0a564a", size = 8707421 } +sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f2/3a/8bdab26e09c5a242182b7ba9152e216d5ab4ae2d78c4298eb4872549cd35/transformers-4.47.1-py3-none-any.whl", hash = "sha256:d2f5d19bb6283cd66c893ec7e6d931d6370bbf1cc93633326ff1f41a40046c9c", size = 10133598 }, + { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463 }, ] [package.optional-dependencies] @@ -4356,6 +4550,15 @@ torch = [ { name = "torch" }, ] +[[package]] +name = "triton" +version = "3.5.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/2e/f95e673222afa2c7f0c687d8913e98fcf2589ef0b1405de76894e37fe18f/triton-3.5.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f63e34dcb32d7bd3a1d0195f60f30d2aee8b08a69a0424189b71017e23dfc3d2", size = 159821655 }, + { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692 }, +] + [[package]] name = "typer" version = "0.20.0" @@ -4456,7 +4659,7 @@ wheels = [ [package.optional-dependencies] standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "httptools" }, { name = "python-dotenv" }, { name = "pyyaml" }, @@ -4670,24 +4873,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046 }, ] -[[package]] -name = "xlrd" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/05/ec9d4fcbbb74bbf4da9f622b3b61aec541e4eccf31d3c60c5422ec027ce2/xlrd-1.2.0.tar.gz", hash = "sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2", size = 554079 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/16/63576a1a001752e34bf8ea62e367997530dc553b689356b9879339cf45a4/xlrd-1.2.0-py2.py3-none-any.whl", hash = "sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde", size = 103251 }, -] - -[[package]] -name = "xlsxwriter" -version = "3.2.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/2c/c06ef49dc36e7954e55b802a8b231770d286a9758b3d936bd1e04ce5ba88/xlsxwriter-3.2.9.tar.gz", hash = "sha256:254b1c37a368c444eac6e2f867405cc9e461b0ed97a3233b2ac1e574efb4140c", size = 215940 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/0c/3662f4a66880196a590b202f0db82d919dd2f89e99a27fadef91c4a33d41/xlsxwriter-3.2.9-py3-none-any.whl", hash = "sha256:9a5db42bc5dff014806c58a20b9eae7322a134abb6fce3c92c181bfb275ec5b3", size = 175315 }, -] - [[package]] name = "xmltodict" version = "0.14.2" From 2ec306b9edc041be3fe8e6fd68c5c5903f983702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Mon, 5 Jan 2026 14:42:53 -0300 Subject: [PATCH 026/104] Feature/remove usem tensorflow deps (#68) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🩹 Ensure consistent entity attributes in reformat_entity function and reorder imports * 📝 Update subcategories exploration notebook * ⚗️ Add TensorFlow deprecation experiment notebook * ♻️ Refactor entity subcategorization: Remove USEMSubcategorizer, add SentenceTransformerSubcategorizer - Removed the USEMSubcategorizer implementation from `usem.py`. - Introduced new Jupyter notebooks for testing and evaluating the SentenceTransformerSubcategorizer. - Updated the pipeline configuration to utilize SentenceTransformerSubcategorizer with local embeddings instead of remote URLs. * ♻️ Refactor download function: Replace gdown with requests for improved file downloading * 🔥 Remove empty peft model module * ➖ Remove TensorFlow and gdown dependencies from pyproject.toml * 📌 Update uv.lock * ♻️ Refactor sentence encoder module: Remove unused dependencies and streamline factory functions * 🔖 Update aymurai package version to 2.0.0a3.dev9 --- .../ar_juz_pcyf_10/labelstudio/utils.py | 8 +- aymurai/datasets/ar_juz_pcyf_10/public.py | 16 +- aymurai/models/peft/__init__.py | 0 aymurai/models/sentence_encoder/__init__.py | 45 + .../models/{usem => sentence_encoder}/base.py | 0 aymurai/models/sentence_encoder/factory.py | 102 + .../sentence_transformers_encoder.py | 2 +- aymurai/models/usem/__init__.py | 48 - aymurai/models/usem/core.py | 60 - aymurai/models/usem/factory.py | 107 - aymurai/models/usem/tensorflow_encoder.py | 81 - .../transforms/entity_subcategories/bm25.py | 101 + .../sentence_transformer.py | 270 ++ .../entity_subcategories/subcategories.py | 638 +++++ .../transforms/entity_subcategories/usem.py | 121 - aymurai/utils/download.py | 47 +- .../02-tensorflow-deprecation.ipynb | 2366 +++++++++++++++++ ...nce-transformer-subcategorizer-smoke.ipynb | 104 + ...ence-transformer-subcategorizer-eval.ipynb | 420 +++ .../subcategories/00-exploration.ipynb | 815 ++++-- pyproject.toml | 3 - .../production/full-paragraph/pipeline.json | 28 +- uv.lock | 329 +-- 23 files changed, 4662 insertions(+), 1049 deletions(-) delete mode 100644 aymurai/models/peft/__init__.py create mode 100644 aymurai/models/sentence_encoder/__init__.py rename aymurai/models/{usem => sentence_encoder}/base.py (100%) create mode 100644 aymurai/models/sentence_encoder/factory.py rename aymurai/models/{usem => sentence_encoder}/sentence_transformers_encoder.py (98%) delete mode 100644 aymurai/models/usem/__init__.py delete mode 100644 aymurai/models/usem/core.py delete mode 100644 aymurai/models/usem/factory.py delete mode 100644 aymurai/models/usem/tensorflow_encoder.py create mode 100644 aymurai/transforms/entity_subcategories/bm25.py create mode 100644 aymurai/transforms/entity_subcategories/sentence_transformer.py create mode 100644 aymurai/transforms/entity_subcategories/subcategories.py delete mode 100644 aymurai/transforms/entity_subcategories/usem.py create mode 100755 notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb create mode 100644 notebooks/experiments/sentence-encoders/03-sentence-transformer-subcategorizer-smoke.ipynb create mode 100644 notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb diff --git a/aymurai/datasets/ar_juz_pcyf_10/labelstudio/utils.py b/aymurai/datasets/ar_juz_pcyf_10/labelstudio/utils.py index 94e896db..4cecf591 100644 --- a/aymurai/datasets/ar_juz_pcyf_10/labelstudio/utils.py +++ b/aymurai/datasets/ar_juz_pcyf_10/labelstudio/utils.py @@ -1,13 +1,13 @@ import re -from glob import glob from copy import deepcopy +from glob import glob from itertools import groupby +from more_itertools import collapse, unzip from numpy import cumsum -from more_itertools import unzip, collapse -from aymurai.meta.types import DataItem from aymurai.meta.entities import Entity +from aymurai.meta.types import DataItem from aymurai.utils.json_data import load_json @@ -43,6 +43,8 @@ def reformat_entity(text: str, span: dict) -> dict: end=span["end"], label=span["labels"][0], text=text[span["start"] : span["end"]], + start_char=span["start"], + end_char=span["end"], context_pre=text[soffset : span["start"]], context_post=text[span["end"] : eoffset], attrs={"aymurai_label": span["labels"][0]}, diff --git a/aymurai/datasets/ar_juz_pcyf_10/public.py b/aymurai/datasets/ar_juz_pcyf_10/public.py index 09b9870e..5c7b3cc6 100644 --- a/aymurai/datasets/ar_juz_pcyf_10/public.py +++ b/aymurai/datasets/ar_juz_pcyf_10/public.py @@ -1,17 +1,17 @@ -import sys import logging -import subprocess +import sys +from collections import UserList +from datetime import date, time from pathlib import Path from typing import Any, Union -from collections import UserList -from datetime import date, time, datetime import datasets import pandas as pd -from aymurai.text.extraction import get_extension from aymurai.datasets.ar_juz_pcyf_10.common import BASE, FIELDS +from aymurai.text.extraction import get_extension from aymurai.utils.cache import cache_load, cache_save, get_cache_key +from aymurai.utils.download import download logging.basicConfig(stream=sys.stdout, level=logging.INFO) logger = logging.getLogger(__name__) @@ -38,10 +38,7 @@ def to_datetime(value): @staticmethod def get_file(source: str, dest: str) -> str: - # gdown have to much verbosity and cant be quiet (at least in this version) - # as workaround we use subprocess to get all output (even errors) - cmd = f"gdown --fuzzy -q --continue -O {dest} {source}" - subprocess.getoutput(cmd) + download(source, dest) if not Path(dest).exists(): Path(dest).touch() @@ -118,7 +115,6 @@ def __init__(self, use_cache: Union[str, bool] = True): data = [] GROUPBY_COLUMNS = ["nro_registro", "tomo", "path"] for keys, group in annotations.groupby(GROUPBY_COLUMNS): - data_ = {} data_["path"] = keys[2] data_["metadata"] = { diff --git a/aymurai/models/peft/__init__.py b/aymurai/models/peft/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/aymurai/models/sentence_encoder/__init__.py b/aymurai/models/sentence_encoder/__init__.py new file mode 100644 index 00000000..c3714e12 --- /dev/null +++ b/aymurai/models/sentence_encoder/__init__.py @@ -0,0 +1,45 @@ +"""Sentence encoder module with sentence-transformers backends. + +Implementations are lazily loaded to avoid importing unavailable dependencies. +Use the factory function `create_encoder()` for automatic backend selection, +or import specific implementations directly from their modules: + + from aymurai.models.sentence_encoder.sentence_transformers_encoder import DistilUSEEncoder +""" + +from aymurai.models.sentence_encoder.base import BaseSentenceEncoder +from aymurai.models.sentence_encoder.factory import ( + EncoderType, + create_encoder, +) + + +def __getattr__(name: str): + """Lazy loading of encoder implementations.""" + if name == "DistilUSEEncoder": + from aymurai.models.sentence_encoder.sentence_transformers_encoder import ( + DistilUSEEncoder, + ) + + return DistilUSEEncoder + + if name == "MultilingualMiniLMEncoder": + from aymurai.models.sentence_encoder.sentence_transformers_encoder import ( + MultilingualMiniLMEncoder, + ) + + return MultilingualMiniLMEncoder + + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +__all__ = [ + # Base interface + "BaseSentenceEncoder", + # Factory + "EncoderType", + "create_encoder", + # Implementations (lazy loaded) + "DistilUSEEncoder", + "MultilingualMiniLMEncoder", +] diff --git a/aymurai/models/usem/base.py b/aymurai/models/sentence_encoder/base.py similarity index 100% rename from aymurai/models/usem/base.py rename to aymurai/models/sentence_encoder/base.py diff --git a/aymurai/models/sentence_encoder/factory.py b/aymurai/models/sentence_encoder/factory.py new file mode 100644 index 00000000..a5d5b541 --- /dev/null +++ b/aymurai/models/sentence_encoder/factory.py @@ -0,0 +1,102 @@ +""" +Factory for creating sentence encoder instances based on configuration. +""" + +import os +from enum import Enum +from typing import Optional + +from aymurai.logger import get_logger +from aymurai.models.sentence_encoder.base import BaseSentenceEncoder + +logger = get_logger(__name__) + + +class EncoderType(str, Enum): + """Available encoder implementations.""" + + DISTILUSE = "distiluse" + MINILM = "minilm" + + +def _get_encoder_type_from_env() -> EncoderType: + """Get encoder type from environment variable.""" + env_value = os.getenv("SENTENCE_ENCODER_TYPE", "distiluse").lower() + try: + return EncoderType(env_value) + except ValueError: + logger.warning( + f"Invalid SENTENCE_ENCODER_TYPE '{env_value}', falling back to 'distiluse'" + ) + return EncoderType.DISTILUSE + + +def _coerce_encoder_type(value: EncoderType | str | None) -> EncoderType: + """ + Normalize encoder type values into EncoderType. + + Args: + value: Encoder type as EncoderType, string, or None. If None, reads from env var. + + Returns: + EncoderType: Normalized encoder type. + """ + if value is None: + return _get_encoder_type_from_env() + + if isinstance(value, EncoderType): + return value + + if isinstance(value, str): + try: + return EncoderType(value.lower()) + except ValueError as exc: + raise ValueError(f"Unknown encoder type: {value}") from exc + + raise TypeError(f"Unsupported encoder type value: {type(value)!r}") + + +def create_encoder( + encoder_type: EncoderType | str | None = None, + device: Optional[str] = None, +) -> BaseSentenceEncoder: + """ + Factory function to create the appropriate sentence encoder. + + Args: + encoder_type: Type of encoder to create. Accepts EncoderType or string. + If None, reads from SENTENCE_ENCODER_TYPE env var + (defaults to 'distiluse'). + device: Device for sentence-transformers models. + + Returns: + An instance of BaseSentenceEncoder. + + Environment Variables: + SENTENCE_ENCODER_TYPE: One of 'distiluse', 'minilm'. + - 'distiluse': Use distiluse-base-multilingual-cased-v2 + - 'minilm': Use paraphrase-multilingual-MiniLM-L12-v2 + + Raises: + ImportError: If required dependencies are not available. + ValueError: If an invalid encoder type is specified. + """ + encoder_type = _coerce_encoder_type(encoder_type) + + # Create the appropriate encoder + if encoder_type == EncoderType.DISTILUSE: + from aymurai.models.sentence_encoder.sentence_transformers_encoder import ( + DistilUSEEncoder, + ) + + return DistilUSEEncoder(device=device) + + elif encoder_type == EncoderType.MINILM: + from aymurai.models.sentence_encoder.sentence_transformers_encoder import ( + MultilingualMiniLMEncoder, + ) + + return MultilingualMiniLMEncoder(device=device) + + else: + raise ValueError(f"Unknown encoder type: {encoder_type}") diff --git a/aymurai/models/usem/sentence_transformers_encoder.py b/aymurai/models/sentence_encoder/sentence_transformers_encoder.py similarity index 98% rename from aymurai/models/usem/sentence_transformers_encoder.py rename to aymurai/models/sentence_encoder/sentence_transformers_encoder.py index b7cf81b4..53668f01 100644 --- a/aymurai/models/usem/sentence_transformers_encoder.py +++ b/aymurai/models/sentence_encoder/sentence_transformers_encoder.py @@ -9,7 +9,7 @@ from sentence_transformers import SentenceTransformer from aymurai.logger import get_logger -from aymurai.models.usem.base import BaseSentenceEncoder +from aymurai.models.sentence_encoder.base import BaseSentenceEncoder logger = get_logger(__name__) diff --git a/aymurai/models/usem/__init__.py b/aymurai/models/usem/__init__.py deleted file mode 100644 index ce72ab75..00000000 --- a/aymurai/models/usem/__init__.py +++ /dev/null @@ -1,48 +0,0 @@ -"""Sentence encoder module with multiple backend implementations. - -Implementations are lazily loaded to avoid importing unavailable dependencies. -Use the factory function `create_encoder()` for automatic backend selection, -or import specific implementations directly from their modules: - - from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder - from aymurai.models.usem.sentence_transformers_encoder import DistilUSEEncoder -""" - -from aymurai.models.usem.base import BaseSentenceEncoder -from aymurai.models.usem.factory import EncoderType, create_encoder, get_encoder -from aymurai.models.usem.core import SentenceRetrieval - - -def __getattr__(name: str): - """Lazy loading of encoder implementations.""" - if name == "TensorFlowUSEEncoder" or name == "USEMQA": - from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder - return TensorFlowUSEEncoder - - if name == "DistilUSEEncoder": - from aymurai.models.usem.sentence_transformers_encoder import DistilUSEEncoder - return DistilUSEEncoder - - if name == "MultilingualMiniLMEncoder": - from aymurai.models.usem.sentence_transformers_encoder import MultilingualMiniLMEncoder - return MultilingualMiniLMEncoder - - raise AttributeError(f"module {__name__!r} has no attribute {name!r}") - - -__all__ = [ - # Base interface - "BaseSentenceEncoder", - # Factory - "EncoderType", - "create_encoder", - "get_encoder", - # Implementations (lazy loaded) - "TensorFlowUSEEncoder", - "DistilUSEEncoder", - "MultilingualMiniLMEncoder", - # Backwards compatibility (lazy loaded) - "USEMQA", - # Retrieval - "SentenceRetrieval", -] diff --git a/aymurai/models/usem/core.py b/aymurai/models/usem/core.py deleted file mode 100644 index 5a3e6e27..00000000 --- a/aymurai/models/usem/core.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Sentence encoder implementations and retrieval utilities.""" - -from typing import TYPE_CHECKING, Optional - -import numpy as np - -from aymurai.models.usem.base import BaseSentenceEncoder -from aymurai.models.usem.factory import EncoderType, create_encoder - -# Type hints only - no runtime import -if TYPE_CHECKING: - from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder - from aymurai.models.usem.sentence_transformers_encoder import ( - DistilUSEEncoder, - MultilingualMiniLMEncoder, - ) - - -class SentenceRetrieval: - """Retrieve similar sentences using sentence embeddings.""" - - def __init__( - self, - categories: list[str], - response_embeddings_path: str, - encoder: Optional[BaseSentenceEncoder] = None, - encoder_type: Optional[EncoderType] = None, - ): - """ - Initialize SentenceRetrieval. - - Args: - categories: List of category labels. - response_embeddings_path: Path to pre-computed embeddings (.npy file). - encoder: Pre-configured encoder instance. If None, creates one using factory. - encoder_type: Type of encoder to create if encoder is None. - If None, reads from SENTENCE_ENCODER_TYPE env var. - """ - self.encoder = encoder if encoder is not None else create_encoder(encoder_type) - self.categories = categories - self.usem_vectors = self.load_usem_vectors(response_embeddings_path) - - # Backwards compatibility alias - self.usem = self.encoder - - def load_usem_vectors(self, file_path): - usem_vectors = np.load(file_path) - return usem_vectors - - def retrieve(self, text: str, top_k: int = 10) -> list[str]: - query_vector = self.usem.encode( - [text], - encoder_type="question_encoder", - ) - - products = np.inner(query_vector, self.usem_vectors)[0] - similar_idx = np.flip(products.argsort())[:top_k] - similar_sentences = [self.categories[idx] for idx in similar_idx] - - return similar_sentences diff --git a/aymurai/models/usem/factory.py b/aymurai/models/usem/factory.py deleted file mode 100644 index 7f3ae49a..00000000 --- a/aymurai/models/usem/factory.py +++ /dev/null @@ -1,107 +0,0 @@ -""" -Factory for creating sentence encoder instances based on configuration. -""" - -import os -import platform -from enum import Enum -from typing import Optional - -from aymurai.logger import get_logger -from aymurai.models.usem.base import BaseSentenceEncoder - -logger = get_logger(__name__) - - -class EncoderType(str, Enum): - """Available encoder implementations.""" - - TENSORFLOW_USE = "tensorflow" - DISTILUSE = "distiluse" - MINILM = "minilm" - AUTO = "auto" - - -def _is_apple_silicon() -> bool: - """Check if running on Apple Silicon.""" - return platform.system() == "Darwin" and platform.machine() == "arm64" - - -def _get_encoder_type_from_env() -> EncoderType: - """Get encoder type from environment variable.""" - env_value = os.getenv("SENTENCE_ENCODER_TYPE", "auto").lower() - try: - return EncoderType(env_value) - except ValueError: - logger.warning( - f"Invalid SENTENCE_ENCODER_TYPE '{env_value}', falling back to 'auto'" - ) - return EncoderType.AUTO - - -def create_encoder( - encoder_type: Optional[EncoderType] = None, - device: Optional[str] = None, -) -> BaseSentenceEncoder: - """ - Factory function to create the appropriate sentence encoder. - - Args: - encoder_type: Type of encoder to create. If None, reads from - SENTENCE_ENCODER_TYPE env var (defaults to 'auto'). - device: Device for sentence-transformers models (ignored for TensorFlow). - - Returns: - An instance of BaseSentenceEncoder. - - Environment Variables: - SENTENCE_ENCODER_TYPE: One of 'tensorflow', 'distiluse', 'minilm', 'auto'. - - 'tensorflow': Use TensorFlow Hub USE-QA (not compatible with Apple Silicon) - - 'distiluse': Use distiluse-base-multilingual-cased-v2 - - 'minilm': Use paraphrase-multilingual-MiniLM-L12-v2 - - 'auto': Auto-detect based on platform (Apple Silicon -> distiluse, else tensorflow) - - Raises: - ImportError: If required dependencies are not available. - ValueError: If an invalid encoder type is specified. - """ - if encoder_type is None: - encoder_type = _get_encoder_type_from_env() - - # Auto-detect based on platform - if encoder_type == EncoderType.AUTO: - if _is_apple_silicon(): - logger.info( - "Apple Silicon detected, using DistilUSE encoder for compatibility" - ) - encoder_type = EncoderType.DISTILUSE - else: - logger.info("Using TensorFlow USE encoder") - encoder_type = EncoderType.TENSORFLOW_USE - - # Create the appropriate encoder - if encoder_type == EncoderType.TENSORFLOW_USE: - from aymurai.models.usem.tensorflow_encoder import TensorFlowUSEEncoder - - return TensorFlowUSEEncoder() - - elif encoder_type == EncoderType.DISTILUSE: - from aymurai.models.usem.sentence_transformers_encoder import DistilUSEEncoder - - return DistilUSEEncoder(device=device) - - elif encoder_type == EncoderType.MINILM: - from aymurai.models.usem.sentence_transformers_encoder import ( - MultilingualMiniLMEncoder, - ) - - return MultilingualMiniLMEncoder(device=device) - - else: - raise ValueError(f"Unknown encoder type: {encoder_type}") - - -# Backwards compatibility alias -def get_encoder(**kwargs) -> BaseSentenceEncoder: - """Alias for create_encoder for backwards compatibility.""" - return create_encoder(**kwargs) diff --git a/aymurai/models/usem/tensorflow_encoder.py b/aymurai/models/usem/tensorflow_encoder.py deleted file mode 100644 index 243e948e..00000000 --- a/aymurai/models/usem/tensorflow_encoder.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -TensorFlow Hub Universal Sentence Encoder implementation. -""" - -from multiprocessing import cpu_count -from typing import Iterable, Optional - -import numpy as np -import tensorflow as tf -import tensorflow_hub as hub -import tensorflow_text # noqa -from more_itertools import chunked -from tqdm.auto import tqdm - -from aymurai.logger import get_logger -from aymurai.models.usem.base import BaseSentenceEncoder - -logger = get_logger(__name__) - -N_JOBS = cpu_count() - - -class TensorFlowUSEEncoder(BaseSentenceEncoder): - """ - TensorFlow Hub Universal Sentence Encoder Multilingual QA implementation. - - This implementation requires tensorflow-text which is not available on Apple Silicon. - Use SentenceTransformersEncoder for macOS ARM64 compatibility. - """ - - def __init__( - self, - usem_qa_url: str = "https://tfhub.dev/google/universal-sentence-encoder-multilingual-qa/3", - ): - self.embed = hub.load(usem_qa_url) - - def encode( - self, - text_array: list[str], - encoder_type: str, - context_array: Optional[list[str]] = None, - ) -> np.ndarray: - input_array = [self.normalize_text(text) for text in text_array] - - if encoder_type == "response_encoder": - encoder_params = { - "input": tf.constant(input_array), - "context": tf.constant(context_array), - } - - if encoder_type == "question_encoder": - encoder_params = { - "input": tf.constant(input_array), - } - - encoded = self.embed.signatures[encoder_type](**encoder_params) - encoded = encoded["outputs"] - - return encoded - - def batch_encode( - self, - text_array: Iterable[str], - encoder_type: str, - batch_size: int = 256, - ) -> np.ndarray: - text_list = list(text_array) - text_chunks = chunked(text_list, batch_size) - - encoded = [ - self.encode(list(text_chunk), encoder_type) - for text_chunk in tqdm( - text_chunks, - desc="creating USEM vectors...", - total=len(text_list) // batch_size, - ) - ] - - encoded = np.vstack(encoded) - - return encoded diff --git a/aymurai/transforms/entity_subcategories/bm25.py b/aymurai/transforms/entity_subcategories/bm25.py new file mode 100644 index 00000000..cb88d145 --- /dev/null +++ b/aymurai/transforms/entity_subcategories/bm25.py @@ -0,0 +1,101 @@ +import re +from typing import Callable + +import numpy as np + + +class BM25Scorer: + """Lightweight BM25 scorer over subcategory strings.""" + + def __init__(self, subcategories: list[str], normalize_fn: Callable[[str], str]): + """ + Initialize the BM25Scorer with subcategories and a normalization function. + + Args: + subcategories (list[str]): List of subcategory strings to be scored. + normalize_fn (Callable[[str], str]): Function to normalize text before tokenization. + """ + self.subcategories = subcategories + self.token_pattern = re.compile(r"\w+", re.UNICODE) + self.normalize_fn = normalize_fn + + tokenized = [self._tokenize(sub) for sub in subcategories] + self.doc_len = [len(toks) for toks in tokenized] + self.avgdl = sum(self.doc_len) / len(self.doc_len) if self.doc_len else 0.0 + self.N = len(tokenized) + self.doc_freqs = [self._to_counter(toks) for toks in tokenized] + corpus_tokens = set().union(*self.doc_freqs) if self.doc_freqs else set() + self.df = { + token: sum(1 for doc in self.doc_freqs if token in doc) + for token in corpus_tokens + } + # Using BM25+ style IDF smoothing + self.idf = { + token: np.log(1 + (self.N - freq + 0.5) / (freq + 0.5)) + for token, freq in self.df.items() + } + + def _tokenize(self, text: str) -> list[str]: + """ + Tokenize the input text after normalization. + + Args: + text (str): Input text to tokenize. + + Returns: + list[str]: List of tokens. + """ + normalized = self.normalize_fn(text) + return self.token_pattern.findall(normalized) + + def _to_counter(self, tokens: list[str]) -> dict[str, int]: + """ + Convert a list of tokens into a frequency counter. + + Args: + tokens (list[str]): List of tokens. + + Returns: + dict[str, int]: Frequency counter of tokens. + """ + counts = {} + + for t in tokens: + counts[t] = counts.get(t, 0) + 1 + + return counts + + def score_vector(self, text: str, k1: float = 1.2, b: float = 0.75) -> np.ndarray: + """ + Compute BM25 scores for the input text against all subcategories. + + Args: + text (str): Input text to score. + k1 (float, optional): BM25 k1 parameter. Defaults to 1.2. + b (float, optional): BM25 b parameter. Defaults to 0.75. + + Returns: + np.ndarray: + """ + scores = np.zeros(self.N, dtype=np.float64) + tokens = self._tokenize(text) + + for token in tokens: + idf = self.idf.get(token) + if idf is None: + continue + + for idx, freq_map in enumerate(self.doc_freqs): + freq = freq_map.get(token, 0) + if freq == 0: + continue + + # BM25 scoring formula + denom = freq + k1 * ( + 1 - b + b * self.doc_len[idx] / (self.avgdl + 1e-9) + ) + + # Update score + scores[idx] += idf * freq * (k1 + 1) / denom + + return scores diff --git a/aymurai/transforms/entity_subcategories/sentence_transformer.py b/aymurai/transforms/entity_subcategories/sentence_transformer.py new file mode 100644 index 00000000..f662d043 --- /dev/null +++ b/aymurai/transforms/entity_subcategories/sentence_transformer.py @@ -0,0 +1,270 @@ +import os +from copy import deepcopy +from pathlib import Path +from typing import Iterable + +import numpy as np + +from aymurai.logger import get_logger +from aymurai.meta.pipeline_interfaces import Transform +from aymurai.meta.types import DataItem +from aymurai.models.sentence_encoder.base import BaseSentenceEncoder +from aymurai.models.sentence_encoder.factory import create_encoder +from aymurai.transforms.entity_subcategories.bm25 import BM25Scorer +from aymurai.transforms.entity_subcategories.subcategories import SUBCATEGORIES +from aymurai.transforms.entity_subcategories.utils import filter_by_category +from aymurai.utils.misc import get_element + +logger = get_logger(__name__) + + +class SentenceTransformerSubcategorizer(Transform): + """ + Hybrid sentence-transformer + optional BM25 subcategorizer. + + - When ``bm25_weight > 0`` mixes BM25 and encoder cosine scores. + - When ``bm25_weight <= 0`` it falls back to encoder-only retrieval. + - Subcategories are normalized (underscore -> space, then encoder.normalize_text) before encoding. + """ + + def __init__( + self, + category: str, + embeddings_path: str, + encoder_name: str = "distiluse", + bm25_weight: float = 0.5, + device: str | None = None, + batch_size: int = 256, + rebuild_embeddings: bool = False, + encoder: BaseSentenceEncoder | None = None, + ): + """ + SentenceTransformerSubcategorizer constructor. + + Args: + category (str): Category to subcategorize. + embeddings_path (str): Path to store/load subcategory embeddings. + encoder_name (str, optional): Name of the encoder to use. Defaults to "distiluse". + bm25_weight (float, optional): Weight for BM25 scoring. Defaults to 0.5. + device (str | None, optional): Device to run the encoder on. Defaults to None. + batch_size (int, optional): Batch size for encoding. Defaults to 256. + rebuild_embeddings (bool, optional): Whether to rebuild embeddings even if cached ones exist. Defaults to False. + encoder (BaseSentenceEncoder | None, optional): Encoder instance to use. Defaults to None. + """ + self.category = category + self.bm25_weight = float(bm25_weight) + self.batch_size = batch_size + + cache_root = Path( + os.getenv("AYMURAI_CACHE_BASEPATH", "/resources/cache/aymurai") + ) + self.cache_path = cache_root / self.__class__.__name__ + self.cache_path.mkdir(parents=True, exist_ok=True) + + self.subcategories = self._load_subcategories(category) + + self.encoder_name = encoder_name + self.encoder = encoder or create_encoder( + encoder_type=encoder_name, device=device + ) + + embeddings_path = Path(embeddings_path) + if not embeddings_path.is_absolute(): + embeddings_path = self.cache_path / embeddings_path + embeddings_path.parent.mkdir(parents=True, exist_ok=True) + self.embeddings_path = embeddings_path + + self.response_vectors = self._load_or_build_embeddings(rebuild_embeddings) + self.bm25 = ( + BM25Scorer(self.subcategories, normalize_fn=self._normalize_subcategory) + if self.bm25_weight > 0 + else None + ) + + def _load_subcategories(self, category: str) -> list[str]: + """ + Load subcategories for a given category. + + Args: + category (str): Category name. + + Raises: + ValueError: If no subcategories are found for the given category. + + Returns: + list[str]: List of subcategories. + """ + key = category.lower().replace(" ", "_") + try: + return SUBCATEGORIES[key] + except KeyError as exc: + raise ValueError( + f"No subcategories found for category '{category}'" + ) from exc + + def _load_or_build_embeddings(self, rebuild: bool) -> np.ndarray: + """ + Load or build subcategory response embeddings. + + Args: + rebuild (bool): Whether to rebuild embeddings even if cached ones exist. + + Raises: + ValueError: If the embeddings file is missing expected data. + + Returns: + np.ndarray: Array of subcategory embeddings. + """ + if self.embeddings_path.exists() and not rebuild: + data = np.load(self.embeddings_path, allow_pickle=True) + if isinstance(data, np.lib.npyio.NpzFile): + vectors = data.get("vectors") + subs = data.get("subcategories") + if vectors is None: + raise ValueError("Embeddings file missing 'vectors'") + if subs is not None and len(subs) != len(self.subcategories): + logger.warning("Subcategory count mismatch; rebuilding embeddings") + else: + return vectors + else: + return data + + logger.info("Building response embeddings for subcategories") + + # Apply the same normalization used in notebooks: replace underscores, then encoder normalize. + normalized = [self._normalize_subcategory(sub) for sub in self.subcategories] + vectors = self.encoder.batch_encode( + normalized, + encoder_type="response_encoder", + batch_size=self.batch_size, + ) + + np.savez( + self.embeddings_path, + vectors=vectors, + subcategories=self.subcategories, + ) + logger.info(f"Saved response embeddings to {self.embeddings_path}") + + return vectors + + def _normalize_subcategory(self, name: str) -> str: + """ + Normalize subcategory strings for stable embeddings. + + Args: + name (str): Subcategory name. + + Returns: + str: Normalized subcategory name. + """ + + name = name.replace("_", " ") + + return self.encoder.normalize_text(name) + + def _combine_scores( + self, sim_scores: np.ndarray, bm25_scores: np.ndarray + ) -> np.ndarray: + """ + Combine similarity and BM25 scores. + + Args: + sim_scores (np.ndarray): Similarity scores. + bm25_scores (np.ndarray): BM25 scores. + + Returns: + np.ndarray: Combined scores. + """ + if self.bm25_weight <= 0: + return sim_scores + + bm25_max = bm25_scores.max() if bm25_scores.size else 0.0 + sim_max = sim_scores.max() if sim_scores.size else 0.0 + + bm25_norm = ( + bm25_scores / (bm25_max + 1e-9) + if bm25_max > 0 + else np.zeros_like(bm25_scores) + ) + + sim_norm = ( + sim_scores / (sim_max + 1e-9) if sim_max > 0 else np.zeros_like(sim_scores) + ) + + return self.bm25_weight * bm25_norm + (1 - self.bm25_weight) * sim_norm + + def retrieve(self, text: str, top_k: int = 10) -> list[str]: + """ + Retrieve top-k subcategories for a given text. + + Args: + text (str): Input text. + top_k (int, optional): Number of top subcategories to retrieve. Defaults to 10. + + Returns: + list[str]: List of top-k subcategories. + """ + return self.batch_retrieve([text], top_k=top_k)[0] + + def batch_retrieve(self, texts: Iterable[str], top_k: int = 10) -> list[list[str]]: + """ + Batch retrieve top-k subcategories for given texts. + + Args: + texts (Iterable[str]): Input texts. + top_k (int, optional): Number of top subcategories to retrieve. Defaults to 10. + + Returns: + list[list[str]]: List of lists of top-k subcategories for each input text. + """ + texts = list(texts) + if not texts: + return [] + + query_vectors = self.encoder.batch_encode( + texts, encoder_type="question_encoder", batch_size=self.batch_size + ) + similarity = np.inner(query_vectors, self.response_vectors) + k = min(top_k, similarity.shape[1]) + + results = [] + for idx, text in enumerate(texts): + sim_scores = similarity[idx] + + if self.bm25 and self.bm25_weight > 0: + bm25_scores = self.bm25.score_vector(text) + combined = self._combine_scores(sim_scores, bm25_scores) + else: + combined = sim_scores + + top_indices = np.argsort(-combined)[:k] + results.append([self.subcategories[i] for i in top_indices]) + + return results + + def __call__(self, item: DataItem) -> DataItem: + """ + Apply subcategorization to entities in the data item. + + Args: + item (DataItem): Input data item. + + Returns: + DataItem: Data item with added subclass labels. + """ + item = deepcopy(item) + ents = get_element(item, levels=["predictions", "entities"]) or [] + texts = [ent["text"] for ent in ents] + filtered_ents = filter_by_category(ents, self.category) + retrieved = self.batch_retrieve(texts, top_k=5) + + for ent, retrieved_ in zip(ents, retrieved): + if ent in filtered_ents and not get_element( + ent, levels=["attrs", "aymurai_label_subclass"] + ): + ent.setdefault("attrs", {})["aymurai_label_subclass"] = retrieved_ + + item.setdefault("predictions", {})["entities"] = ents + + return item diff --git a/aymurai/transforms/entity_subcategories/subcategories.py b/aymurai/transforms/entity_subcategories/subcategories.py new file mode 100644 index 00000000..ad4fd5a9 --- /dev/null +++ b/aymurai/transforms/entity_subcategories/subcategories.py @@ -0,0 +1,638 @@ +SUBCATEGORIES = { + "conducta": [ + "abandonar_animal_domestico", + "abandono_de_personas", + "abuso_de_armas", + "abuso_de_autoridad_e_incumplimiento_deberes_funcionario_publico", + "abuso_sexual", + "acceder_a_lugares_distintos_segun_entrada", + "acceder_lugares_distintos_segun_entrada", + "acceso_a_sistema_restringido", + "acoso_sexual_callejero", + "actividades_lucrativas_sin_autorizacion", + "actividades_lucrativas_sin_habilitacion", + "actos_contenido_sexual_con_menores", + "administracion_fraudulenta", + "afectar_desarrollo_espectaculo", + "afectar_el_desarrollo_del_espectaculo", + "afectar_funcionamiento_servicios_publicos", + "afectar_servicios_de_emergencia_o_seguridad", + "afectar_servicios_emergencia", + "afectar_señalizacion", + "allanamiento_autonomo", + "alterar_programa", + "alterar_sepulturas", + "amenazas", + "amparo", + "apariencia_falsa", + "apariencia_falsa_para_entrar_a_domicilio_o_lugar_privado", + "apropiacion_indebida_de_tributos", + "arrojar_cosas_que_puedan_causar_lesiones", + "arrojar_cosas_sustancias", + "arrojar_sustancias_insalubres_en_lugares_publicos", + "asociacion_ilicita", + "asuncion_falsa_de_contravencion", + "atentado_contra_la_autoridad", + "ausencia_de_habilitacion", + "banderas", + "carteles_afiches_volantes", + "cierre_defectuoso", + "circular_por_carriles_exclusivos", + "circular_por_lugar_prohibido", + "cohecho_activo", + "cohecho_pasivo", + "coimas", + "competencia_desleal", + "conducir_con_mayor_cantidad_de_alcohol_en_sangre_del_permitido", + "conducir_con_mayor_grado_de_alcohol_o_bajo_efectos_de_estupefacientes", + "conducir_sin_licencia_que_lo_habilite_por_categoria_de_vehiculo", + "conducir_usando_aparato_electronico", + "connivencia_policial", + "contactar_menor_por_medio_de_tecnologias_para_cometer_delitos_contra_su_integridad_sexual", + "cruce_de_semaforo_en_rojo", + "cuida_coche", + "cuidar_coches_sin_autorizacion", + "daños", + "daños_informaticos", + "defraudacion", + "defraudacion_contra_la_administracion_publica", + "delito_contra_seguridad_transito", + "denegacion_de_justicia", + "derecho_admision", + "desarmado_automotor", + "desinfeccion_y_desratizacion", + "desobediencia_a_cargas_procesales", + "desobediencia_a_la_autoridad", + "difusion_no_autorizada_de_imagenes", + "difusion_no_autorizada_de_imagenes_intimas", + "discriminar", + "documentacion_sanitaria", + "ejecucion_de_multa", + "ejercer_ilegitimamente_actividad", + "ejercicio_ilegal_de_la_medicina", + "elementos_de_prevencion_contra_incendio", + "encubrimiento", + "encubrimiento_actividades_baile", + "ensuciar_bienes", + "entregar_indebidamente_armas_explosivos", + "espantar_animales", + "espejos_retrovisores", + "estacionamiento_prohibido", + "estacionamiento_sobre_senda_peatonal", + "estafa", + "estupefacientes", + "exceso_capacidad_ingreso", + "exceso_de_velocidad", + "exhibicion_de_documentacion_obligatoria", + "exhibiciones_obscenas", + "exhortos_de_otras_jurisdicciones", + "explotacion_trabajo_infantil", + "extorsion", + "fabricar_transportar_artefactos_pirotecnicos", + "falsa_denuncia", + "falsedad_documental_de_certificado_de_aptitud_ambiental", + "falsificacion_certificado_medico", + "falsificacion_de_documento", + "falsificacion_de_marcas_firmas_señas_oficiales", + "falsificacion_de_numeracion_de_objeto_registrada_de_acuerdo_a_ley", + "falta_de_poliza_de_seguros", + "favorecimiento_evasion_persona_detenida", + "frustrar_subasta_publica", + "guardar_artefactos_pirotecnicos", + "guardar_elementos_aptos_violencia", + "habeas_corpus", + "habilitacion_en_infraccion", + "homicidio", + "hostigamiento", + "hostigamiento_digital", + "hurto", + "impedimento_de_contacto_de_menor_con_padre_no_conviviente", + "incendio_explosion_inundacion_con_peligro_para_bienes", + "incendios_y_otros_estragos", + "incitar_al_desorden", + "incitar_desorden", + "incumplimiento_de_plazos", + "incumplimiento_deberes_familiares", + "incumplimiento_deberes_funcionario_publico", + "incumplimiento_medidas_prevencion_sanidad", + "incumplimiento_perimetro_profundidad", + "incumplir_clausura", + "incumplir_obligaciones_legales", + "inducir_menor_a_mendigar", + "infraccion_reglamentos_seguridad", + "ingresar_artefactos_pirotecnicos", + "ingresar_consumir_bebidas_alcoholicas", + "ingresar_contra_derecho_admision", + "ingresar_sin_autorizacion_lugares_reservados", + "ingresar_sin_entrada", + "ingresar_sin_entrada_autorizacion", + "ingreso_a_domicilio_sin_autorizacion", + "inhumar_exhumar_profanar", + "intimidacion", + "juego_sin_autorizacion", + "juegos_de_azar_sin_autorizacion", + "lesiones", + "ley_451", + "licencia_vencida", + "maltrato", + "mantener_animal_domestico_espacios_inadecuados", + "mantenimiento_de_cercas_y_aceras", + "menoscabar_integridad_animal_domestico", + "mesnna_masnna", + "no_realizar_grabado_de_autopartes", + "no_respetar_carriles", + "no_respetar_senda_peatonal", + "obligacion_de_exhibir_cartel", + "obligacion_de_informar_prohibicion_de_fumar", + "obligacion_de_conservar", + "obstaculizar_ingreso_o_salida", + "obstruccion_de_inspeccion", + "obstruccion_de_via", + "obstruccion_de_via_publica", + "obstruccion_via_publica", + "obstruir_salida", + "ocupar_via_publica", + "oferta_demanda_sexo_espacio_publico", + "omitir_cuidados_animal_domestico", + "omitir_recaudos_de_cuidado_animal_domestico", + "omitir_recaudos_de_organizacion", + "omitir_recaudos_espectaculo_masivo", + "omitir_recaudos_organizacion_seguridad", + "organizar_explotar_juego", + "organizar_sin_autorizacion_juego", + "participar_competencias_velocidad_via_publica", + "pelear_en_lugar_publico", + "permiso_y_planos_de_obra", + "persona_no_habilitada", + "perturbar_ceremonias_religiosas_funebres", + "perturbar_filas_ingreso_no_respetar_vallado", + "placas_de_dominio", + "pornografia_infantil", + "portacion_de_arma", + "portar_armas_no_convencionales", + "presencia_menores_lugar_no_autorizado", + "presunta_comision_delito", + "presunta_contravencion", + "privacion_ilegitima_de_la_libertad", + "producir_avalanchas", + "promocion_o_facilitacion_de_prostitucion_de_personas", + "promover_comerciar_ofertar_juego", + "propaganda_discriminatoria", + "proteccion_animal", + "provocar_parcialidad", + "publicidad_en_lugares_no_habilitados_via_publica", + "regentear_o_administrar_casas_de_tolerancia", + "residuos_peligrosos", + "retencion_indebida", + "revender_entradas", + "robo", + "ruidos_molestos", + "ruidos_y_vibraciones", + "sancion_generica", + "servicios_de_seguridad_prohibiciones_incumplidas", + "servicios_de_seguridad_requisitos_incumplidos", + "suministrar_alcohol_menor", + "suministrar_bebidas_alcoholicas", + "suministrar_elementos_aptos_agresion", + "suministrar_material_pornografico", + "suministrar_objetos_peligrosos", + "suministrar_productos_farmaceuticos", + "suministro_de_medicamentos", + "suplantacion_identidad", + "suplantacion_digital_de_identidad", + "taxis_transportes_escolares_remises_sin_autorizacion", + "tenencia_de_arma", + "transporte_de_pasajeros", + "transporte_de_pasajeros_sin_habilitacion", + "transporte_de_pasajeros_sin_habilitacion_o_autorizacion", + "usar_indebidamente_credencial", + "usar_indebidamente_espacio_publico", + "usar_indebidamente_armas", + "uso_de_documento_falso_o_adulterado", + "uso_indebido_del_espacio_publico", + "uso_o_exhibicion_de_franquicias", + "usurpacion", + "vehiculo_abandonado", + "vender_entradas_o_permitir_ingreso_exceso", + "vender_sustancias_medicinales_sin_receta", + "venta_o_consumo_de_bebidas_alcoholicas_fuera_del_horario", + "verificacion_tecnica", + "violacion_de_peaje", + "violacion_de_domicilio", + "violacion_de_secretos_y_de_la_privacidad", + "violar_clausura", + "violar_inhabilitacion_para_conducir", + "violar_reglamentacion_juego", + "zanjas_y_pozos_en_via_publica", + ], + "conducta_descripcion": [ + "agravada", + "agravadas_por_edad", + "agravadas_por_el_uso_de_armas", + "agravadas_por_uso_de_armas", + "agravadas_por_uso_de_armas_impropia", + "agravado", + "agravado_abuso_funcion", + "agravado_alevosia", + "agravado_causar_sufrimiento_otra_persona", + "agravado_concurso", + "agravado_familiar", + "agravado_insertar_datos_en_datos_personales", + "agravado_lugar_publico", + "agravado_mas_personas", + "agravado_medio_idoneo", + "agravado_menor_de_edad", + "agravado_miembro_fuerzas", + "agravado_monumentos", + "agravado_otro_delito", + "agravado_peligro_de_muerte", + "agravado_por_el_vinculo", + "agravado_por_espacio", + "agravado_por_ser_fuerza_de_seguridad", + "agravado_precio", + "agravado_relacion_de_pareja", + "agravado_superior_militar", + "agravado_violar_informacion_banco_de_datos", + "agravado_violar_sistemas_seguridad", + "agravado_violencia_de_genero", + "agravado_violencia_mujer", + "agravados", + "coactivas", + "coactivas_agravadas", + "coactivas_agravadas_por_uso_de_armas", + "comercio_de_plantas_para_producir_estupefacientes", + "con_escalamiento", + "conduccion_imprudente", + "culposas", + "culposo", + "de_fuego_uso_civil", + "de_guerra", + "destinado_a_acreditar_identidad_de_personas_habilitacion_o_titularidad", + "digital", + "digital_agravado_familiar", + "digital_agravado_jefe", + "digital_agravado_mas_de_una_persona", + "digital_agravado_menor_de_edad", + "digital_agravado_relacion_de_pareja", + "durante_espectaculo_deportivo", + "en_grandes_parques_o_espectaculos_masivos", + "en_riña", + "entrega_suministro_facilitacion", + "funcionario_publico", + "ganzua_llave", + "graves", + "graves_tentativa", + "informatica", + "ingreso_a_domicilio_sin_autorizacion", + "intimadacion_o_invocando_orden_superior", + "leves", + "leves_agravadas", + "muebles_transportables", + "no_denuncia_delito", + "ocasion_de_incendio", + "organismo_publico", + "para_produccion_o_tenencia_con_fines_de_comercializacion", + "por_despojo", + "por_obligacion_de_devolver", + "por_turbacion_de_la_posesion", + "productos_separados_suelo", + "publico_o_privado", + "seguido_de_muerte", + "simple", + "simples", + "sin_autorizacion", + "tarjeta_credito_debito", + "tenencia", + "tentativa", + "tentativa_agravado_alevosia", + "transporte_de_pasajeros_sin_habilitacion_o_autorizacion", + "uso_de_tarjeta_o_datos", + "vehiculos", + ], + "detalle": [ + "audiencia_victima_ley26485", + "30_dias", + "45_dias", + "60_dias", + "90_dias", + "180_dias", + "abandono_vehiculo", + "absolucion", + "absolucion_desistimiento_fiscal", + "accesorias_legales", + "acepta_competencia_inhibitoria", + "acepta_cuestion_turno", + "aclaratoria", + "acta_de_comprobacion", + "acta_de_intimacion", + "acuerdo_de_pago_levanta_embargo", + "acumulacion_por_conexidad_y_ampliacion", + "admisibilidad", + "agente_encubierto", + "agente_revelador", + "agotamiento_de_la_pena", + "alimentos_provisorios", + "allanamiento", + "apelacion", + "apertura_extraccion_examen_datos", + "aprehension", + "arma", + "armas", + "arresto_domiciliario_deja_sin_efecto", + "asesor_tutelar", + "atipicidad_sobreseimiento", + "audiencia_acusado_ley26485", + "audiencia_acusado_difiere_sentencia", + "audiencia_preliminar", + "audiencia_victima_11bis_ley24660", + "bloqueo_acceso_al_dominio", + "cadena_de_custodia_de_elementos_secuestrados", + "camara_gesell", + "cambio_domicilio_prision_domiciliaria", + "captura", + "captura_deja_sin_efecto", + "caucion_real", + "cedula_de_notificacion", + "cese_de_actos_de_perturbacion_o_intimidacion", + "cese_de_medidas", + "cese_de_medidas_parcial", + "cierre_de_instancia", + "clausura", + "clausura_deja_sin_efecto", + "competencia_penal_juvenil", + "concede", + "concede_parcialmente", + "conocimiento_personal", + "consigna_policial", + "contienda_negativa", + "control", + "convalida_fallecimiento", + "convalida_inimputabilidad", + "convalidacion_otras_causales", + "copia_forense_celular", + "copias_de_capturas_de_pantalla_mensajes_y_llamados", + "cosa_juzgada_sobreseimiento", + "cuarto_intermedio", + "cuarto_intermedio_para_resolver", + "cumplimiento_de_regla_de_conducta_en_complejo_penitenciario", + "cumplimiento_de_reglas_de_conducta", + "declaracion_testimonial", + "declina_competencia", + "defensa", + "defensa_particular", + "defensa_querella", + "deja_sin_efecto_inhabilitacion_y_devuelve_licencia", + "deja_sin_efecto_revocacion", + "delitos_de_accion_publica", + "desistimiento_accion_instancia_privada_sobreseimiento", + "desistimiento_fiscal", + "destruccion_de_arma", + "detencion", + "detencion_captura_y/o_traslado", + "detencion_captura_y/o_traslado_deja_sin_efecto", + "detencion_secuestro_y_requisa", + "devolucion_acarreo_y_estadia", + "dictamen_fiscal", + "difiere_decision", + "difiere_fundamentos", + "difiere_resolucion", + "dispositivo_de_geoposicionamiento_mantiene_hasta_juicio", + "domiciliaria_con_vigilancia_electronica", + "egreso_del_pais", + "ejecucion_de_honorarios", + "embargo", + "embargo_deja_sin_efecto", + "estimulo_educativo", + "estupefacientes", + "estupefacientes_dinero", + "estupefacientes_telefono_dinero", + "estupefacientes_telefono_dinero_arma", + "estupefacientes_telefono_vehiculo", + "estupefacientes_vehiculo_dinero", + "excarcelacion", + "exclusion_del_hogar", + "exhorto", + "exhorto_diplomatico", + "exime_pago_multa", + "exime_reparacion_del_daño_y_pago_multa", + "eximicion_pago", + "eximicion_pauta_de_conducta", + "expulsion_art_64_a_ley_25871", + "extincion_accion_por_autocomposicion", + "extincion_accion_por_cumplimiento", + "extincion_accion_sobreseimiento", + "extincion_accion_sobreseimiento_por_fallecimiento", + "extincion_de_la_pena", + "extincion_sancion_por_cumplimiento", + "extrañamiento", + "falta_de_accion_sobreseimiento", + "falta_de_legitimacion_pasiva", + "falta_de_participacion", + "falta_de_presentacion", + "falta_de_requisitos_procedencia", + "fija_nueva_audiencia", + "fondo_de_reserva", + "habeas_corpus", + "hasta_agotar_investigacion", + "identidad_objeto_y_sujeto", + "imagenes_videos", + "incompetencia_material", + "incompetencia_por_conexidad", + "incompetencia_por_conexidad_subjetiva", + "incompetencia_territorial", + "indeterminacion_imputacion", + "informacion_y_apertura_de_antenas_llamadas", + "informe_cij", + "informe_mercado_libre", + "informe_ncmec", + "informe_previo", + "informes_llamadas_y_deteccion_de_celdas", + "inhabilitacion_para_conducir", + "inhabilitacion_para_conducir_deja_sin_efecto", + "inmovilizacion", + "interes_en_el_caso", + "internacion_involuntaria", + "interprete", + "interprete_y_defensa", + "interrogatorio_policial", + "intervencion_equipo_especializado", + "intervencion_previa", + "intervencion_red_social", + "intervencion_telefonica", + "intervencion_telefonica_con_ubicacion_de_celda_de_apertura", + "levantamiento_clausura_administrativa", + "levantamiento_secreto_bancario", + "levantamiento_secreto_fiscal", + "liberacion_aves", + "libertad_asistida_incorporacion", + "libertad_condicional_otorga", + "libertad_condicional_revoca", + "litispendencia", + "mantiene", + "mediacion", + "medidas_restrictivas", + "modifica_pauta_de_conducta", + "morigeracion_domiciliaria", + "no_convalida", + "no_homologa_absolucion", + "notificacion_via_mail", + "nulidad_incorporacion_prueba", + "otorga_plazo", + "otras_vias_idoneas", + "pago_de_multa_en_cuotas", + "pago_minimo_multa_sobreseimiento", + "pago_minimo_multa_y_reparacion_daño_64cp", + "paradero", + "paradero_deja_sin_efecto", + "parcial_requerimiento_de_juicio", + "parcial_requerimiento_de_juicio_falta_de_circunscripcion_temporal", + "parcial_requerimiento_de_juicio_falta_de_fundamentacion", + "parcial_requerimiento_de_juicio_por_introduccion_de_agravante", + "pedido_de_informe_banco", + "pedido_de_informe_facebook", + "pedido_de_informe_facebook_google", + "pedido_de_informe_facebook_microsoft", + "pedido_de_informe_google", + "pedido_de_informe_google_microsoft", + "pedido_de_informe_imgur_llc", + "pedido_de_informe_instagram", + "pedido_de_informe_microsoft", + "pedido_de_informe_skype", + "pedido_de_informe_telefonia", + "pedido_de_informe_whatsapp", + "pedido_informe_tiktok", + "pedido_prision_domiciliaria", + "pena_de_arresto_efectivo_cumplimiento", + "pena_de_arresto_efectivo_cumplimiento_compurgada", + "pena_de_arresto_en_suspenso", + "pena_de_inhabilitacion_especial", + "pena_de_multa_efectivo_cumplimiento", + "pena_de_multa_en_suspenso", + "pena_de_multa_sustituida_por_amonestacion", + "pena_de_multa_sustituida_por_clausura_se_tiene_por_cumplida", + "pena_de_multa_sustituida_por_trabajos_comunitarios", + "pena_de_prision_domiciliaria", + "pena_de_prision_efectivo_cumplimiento", + "pena_de_prision_efectivo_cumplimiento_compurgada", + "pena_de_prision_efectivo_cumplimiento_domiciliaria", + "pena_de_prision_en_suspenso", + "pena_de_tareas_comunitarias", + "pena_de_tareas_de_utilidad_publica", + "pericia", + "pericia_arma", + "pericia_examen_veterinario", + "peritaje_de_telefono", + "peritaje_ordenadores_y_o_telefonos", + "peritaje_telefono", + "perito", + "permiso_de_viaje", + "plazo_razonable_sobreseimiento", + "plazo_razonable_sobresimiento", + "pleito_con_una_parte", + "por_quince_dias_hasta_tomar_contacto_con_victima", + "prescripcion_sobreseimiento", + "prision_domiciliaria_mantiene", + "prision_domiciliaria_prorroga", + "procedimiento", + "procedimiento_administrativo_pendiente", + "prohibicion_compra_tenencia_registracion_de_armas", + "prohibicion_de_acercamiento", + "prohibicion_de_acercamiento_y_contacto", + "prohibicion_de_publicar_en_redes", + "prohibicion_de_publicar_en_redes_sobre", + "promocion_a_periodo_de_prueba_art_7_ley_24660", + "prorroga", + "prueba_ofrecida", + "publicacion_de_edictos", + "queja", + "querella", + "quita_puntos_de_licencia_de_conducir", + "realizacion", + "rebeldia", + "rebeldia_deja_sin_efecto", + "rebeldia_y_captura", + "rebeldia_y_paradero", + "rechaza_acuerdo", + "rechaza_competencia", + "regimen_de_comunicacion_provisoria", + "reincidencia", + "reintegra_puntos_de_licencia_de_conducir", + "remate_vehiculo", + "remision_a_justicia_civil", + "remision_camara_para_sorteo", + "reparacion_integral_del_daño_sobreseimiento", + "replica_de_arma_de_plastico", + "reposicion", + "reposicion_apelacion_subsidio", + "reprogramacion", + "requerido_por_infractor", + "requerimiento_de_juicio", + "requerimiento_de_juicio_falta_de_fundamentacion", + "requisa", + "restitucion_de_inmueble", + "revision_psicofisica_capacidad", + "revision_psiquiatrica_y_psicologica", + "revoca", + "revoca_condicionalidad", + "revocacion", + "rueda_de_reconocimiento", + "salidas_extraordinarias", + "salidas_transitorias", + "sancion_sustitutiva_prorroga", + "secuestro", + "sin_indicacion_plazo", + "sobreseimiento", + "solicita", + "solicitud_destruccion_de_estupefacientes", + "tareas_de_investigacion", + "telefono", + "temor_parcialidad_generico", + "tiene_por_desistido", + "tiene_por_no_computado_plazo", + "tiene_presente", + "tiene_presente_acuerdo", + "tobillera_refractaria", + "traslado_por_fuerza_publica", + "unifica_solicita_inhibitoria", + "unificacion_de_pena", + "vehiculo", + "vencimiento_plazo_ipp", + ], + "objeto_de_la_resolucion": [ + "acumulacion_de_caso", + "admisibilidad_amparo", + "admisibilidad_habeas_corpus", + "admisibilidad_prueba", + "apartamiento", + "archivo_fiscal", + "audiencia_de_conciliacion", + "beneficio_litigar_sin_gastos", + "caducidad_de_instancia", + "cuestion_de_competencia", + "decomiso", + "desistimiento_faltas", + "ejecucion_de_la_pena", + "excepcion", + "excusacion", + "extraccion_testimonios", + "juicio_abreviado", + "juicio_oral", + "juzgamiento_faltas", + "mediacion", + "medida_cautelar", + "medida_probatoria", + "mesa_de_dialogo", + "nulidad", + "prision_preventiva", + "prorroga_investigacion_penal_preparatoria", + "recurso", + "recusacion", + "regulacion_de_honorarios", + "remision_controladora", + "restablecimiento_de_contacto", + "restitucion_de_efectos", + "restitucion_de_inmueble", + "restitucion_efectos", + "suspension_del_proceso_a_prueba", + ], +} diff --git a/aymurai/transforms/entity_subcategories/usem.py b/aymurai/transforms/entity_subcategories/usem.py deleted file mode 100644 index 25645aa6..00000000 --- a/aymurai/transforms/entity_subcategories/usem.py +++ /dev/null @@ -1,121 +0,0 @@ -import os -from hashlib import md5 -from copy import deepcopy - -import numpy as np - -from aymurai.logger import get_logger -from aymurai.meta.types import DataItem -from aymurai.models.usem import create_encoder -from aymurai.utils.download import download -from aymurai.utils.misc import is_url, get_element -from aymurai.meta.pipeline_interfaces import Transform - -from .utils import filter_by_category - -logger = get_logger(__name__) - - -class USEMSubcategorizer(Transform): - """ - Use USEM to retrieve subcategories - """ - - usem = create_encoder() - - def __init__( - self, - category: str, - subcategories_path: list[str], - response_embeddings_path: str, - device: str = "/cpu:0", - ): - """ - Sentence Similarity using USEM (Universal Sentence Encoder Multilingual QA) - - Args: - category (str): category to filter - subcategories_path (list[str]): path to subcategories - response_embeddings_path (str): path to response embeddings - device (str, optional): device to use. Defaults to "/cpu:0". - """ - self.category = category - - CACHE_PATH = os.path.join( - os.getenv("AYMURAI_CACHE_BASEPATH", "/resources/cache/aymurai"), - self.__name__, - ) - - logger.info(f"load usem options from {subcategories_path}") - if is_url(url := subcategories_path): - fname = md5(url.encode("utf-8")).hexdigest() - subcategories_path = f"{CACHE_PATH}/{fname}" - logger.info(f"downloading options on {subcategories_path}") - os.makedirs(CACHE_PATH, exist_ok=True) - subcategories_path = download(url, output=subcategories_path) - - with open(subcategories_path, "r") as file: - self.subcategories = file.read().splitlines() - logger.info(f"options head: {self.subcategories[:5]}") - - # download embeddings - if is_url(url := response_embeddings_path): - fname = md5(url.encode("utf-8")).hexdigest() - model_path = f"{CACHE_PATH}/{fname}" - logger.info(f"downloading embeddings on {model_path}") - os.makedirs(CACHE_PATH, exist_ok=True) - response_embeddings_path = download(url, output=model_path) - logger.info(f"load usem embeddings from {response_embeddings_path}") - self.usem_vectors = self.load_usem_vectors(response_embeddings_path) - self.device = device - - def load_usem_vectors(self, file_path): - """ - Load USEM vectors - """ - usem_vectors = np.load(file_path) - return usem_vectors.copy() - - def retrieve(self, text: str, top_k: int = 10) -> list[str]: - """ - Retrieve similar sentences using USEM - """ - query_vector = self.usem.encode( - [text], - encoder_type="question_encoder", - ) - - products = np.inner(query_vector, self.usem_vectors)[0] - similar_idx = np.flip(products.argsort())[:top_k] - similar_sentences = [self.subcategories[idx] for idx in similar_idx] - - return similar_sentences - - def __call__(self, item: DataItem) -> DataItem: - """ - Retrieve subcategories for entities. If the entity is not in the category of interest, - the subcategory is not retrieved. - - Args: - item (DataItem): input data item - - Returns: - DataItem: output data item - """ - item = deepcopy(item) - - ents = get_element(item, levels=["predictions", "entities"]) or [] - - texts = list(map(lambda x: x["text"], ents)) - filtered_ents = filter_by_category(ents, self.category) - retrieved = list(map(self.retrieve, texts)) - - for ent, retrieved_ in zip(ents, retrieved): - if ent in filtered_ents and not get_element( - ent, levels=["attrs", "aymurai_label_subclass"] - ): - ent["attrs"]["aymurai_label_subclass"] = retrieved_ - - item["predictions"]["entities"] = ents - - return item diff --git a/aymurai/utils/download.py b/aymurai/utils/download.py index 17151f32..9ce6ea6a 100644 --- a/aymurai/utils/download.py +++ b/aymurai/utils/download.py @@ -1,6 +1,9 @@ import os +import shutil +import tempfile +from pathlib import Path -import gdown +import requests from aymurai.logger import get_logger @@ -9,30 +12,36 @@ logger = get_logger(__name__) -def download(url, output): +def download(url: str, output: str) -> str: """ - Download file from url - skip if file exists and environment variable NO_DOWNLOAD_IF_EXISTS is set to True + Stream download to a file. + + Skips download when the target exists and NO_DOWNLOAD_IF_EXISTS is truthy. Args: - url (str): url to download - output (str): output path + url: URL to download. + output: Path to save the downloaded file. Returns: - str: output path + str: Path to the downloaded file. """ - if os.path.exists(output) and bool(NO_DOWNLOAD_IF_EXISTS): - logger.warn( + output_path = Path(output) + output_path.parent.mkdir(parents=True, exist_ok=True) + + if output_path.exists() and NO_DOWNLOAD_IF_EXISTS: + logger.warning( "File found and skipping. Set NO_DOWNLOAD_IF_EXISTS environment to false to force download." ) - return output - - gdown.download( - url, - quiet=False, - fuzzy=True, - resume=True, - output=output, - ) - return output + return str(output_path) + + logger.info(f"Downloading {url} -> {output_path}") + with requests.get(url, stream=True, allow_redirects=True, timeout=60) as resp: + resp.raise_for_status() + with tempfile.NamedTemporaryFile(delete=False) as tmp: + for chunk in resp.iter_content(chunk_size=8192): + if chunk: + tmp.write(chunk) + tmp_path = Path(tmp.name) + shutil.move(tmp_path, output_path) + return str(output_path) diff --git a/notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb b/notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb new file mode 100755 index 00000000..d43dae54 --- /dev/null +++ b/notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb @@ -0,0 +1,2366 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "2a8e7308", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n", + "\n", + "%load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "730c04d9", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "import random\n", + "from collections import defaultdict\n", + "from copy import deepcopy\n", + "from pathlib import Path\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "from IPython.display import Markdown\n", + "from rich import print\n", + "\n", + "from aymurai.utils.json_data import load_json\n", + "\n", + "sns.set_theme(style=\"whitegrid\")\n", + "plt.rcParams.update(\n", + " {\"figure.figsize\": (10, 6), \"axes.titlesize\": 14, \"axes.labelsize\": 12}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "211f50a2", + "metadata": {}, + "source": [ + "## Load annotations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f1f76f76", + "metadata": {}, + "outputs": [], + "source": [ + "annotations_path = \"/resources/annotations/label-studio/resos-annotations/30-nov/project-3-at-2022-11-30-16-04-2b43bf39.json\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0e13682", + "metadata": {}, + "outputs": [], + "source": [ + "annotations = load_json(annotations_path)\n", + "print(f\"Loaded {len(annotations)} annotations\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5080fdc6", + "metadata": {}, + "outputs": [], + "source": [ + "def collect_label_annotations(annotations, target_labels):\n", + " \"\"\"Build minimal evaluation buckets keyed by label.\"\"\"\n", + " buckets_by_label = defaultdict(list)\n", + " target_labels = set(target_labels)\n", + "\n", + " for task in annotations:\n", + " for annotation in task.get(\"annotations\", []):\n", + " merged = {}\n", + " for result in annotation.get(\"result\", []):\n", + " result_id = result.get(\"id\")\n", + " value = result.get(\"value\", {})\n", + " slot = merged.setdefault(\n", + " result_id,\n", + " {\n", + " \"text\": value.get(\"text\"),\n", + " \"start\": value.get(\"start\"),\n", + " \"end\": value.get(\"end\"),\n", + " \"labels\": [],\n", + " \"choices\": [],\n", + " },\n", + " )\n", + "\n", + " # Update span info if present in the current result.\n", + " slot[\"text\"] = slot[\"text\"] or value.get(\"text\")\n", + " slot[\"start\"] = (\n", + " slot[\"start\"]\n", + " if slot[\"start\"] is not None\n", + " else value.get(\"start\")\n", + " )\n", + " slot[\"end\"] = (\n", + " slot[\"end\"]\n", + " if slot[\"end\"] is not None\n", + " else value.get(\"end\")\n", + " )\n", + " slot[\"labels\"].extend(value.get(\"labels\", []))\n", + " slot[\"choices\"].extend(value.get(\"choices\", []))\n", + "\n", + " for payload in merged.values():\n", + " labels = [\n", + " label\n", + " for label in payload[\"labels\"]\n", + " if label in target_labels\n", + " ]\n", + " if not labels or payload[\"text\"] is None:\n", + " continue\n", + "\n", + " item = {\n", + " \"text\": payload[\"text\"],\n", + " \"labels\": list(dict.fromkeys(payload[\"labels\"])),\n", + " \"choices\": list(dict.fromkeys(payload[\"choices\"])),\n", + " \"start\": payload[\"start\"],\n", + " \"end\": payload[\"end\"],\n", + " }\n", + "\n", + " for label in labels:\n", + " buckets_by_label[label].append(deepcopy(item))\n", + "\n", + " return {label: buckets_by_label.get(label, []) for label in target_labels}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4e9d0ab", + "metadata": {}, + "outputs": [], + "source": [ + "target_labels = [\n", + " \"CONDUCTA\",\n", + " \"CONDUCTA_DESCRIPCION\",\n", + " \"DETALLE\",\n", + " \"OBJETO_DE_LA_RESOLUCION\",\n", + "]\n", + "samples_by_label = collect_label_annotations(annotations, target_labels)" + ] + }, + { + "cell_type": "markdown", + "id": "ad8f304b", + "metadata": {}, + "source": [ + "## Exploratory data analysis\n", + "\n", + "We consolidate the annotated spans into a tabular view to inspect label and subcategory coverage before running any retrieval experiments.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d99c5871", + "metadata": {}, + "outputs": [], + "source": [ + "def samples_to_dataframe(samples):\n", + " rows = []\n", + " for label, items in samples.items():\n", + " for item in items:\n", + " rows.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"labels\": item[\"labels\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"n_choices\": len(item[\"choices\"]),\n", + " \"char_len\": len(item[\"text\"]),\n", + " }\n", + " )\n", + " return pd.DataFrame(rows)\n", + "\n", + "\n", + "samples_df = samples_to_dataframe(samples_by_label)\n", + "samples_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0eca77e", + "metadata": {}, + "outputs": [], + "source": [ + "samples_df[\"labels\"].map(len).describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbe01d41", + "metadata": {}, + "outputs": [], + "source": [ + "samples_df[\"choices\"].map(len).describe()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b898f23c", + "metadata": {}, + "outputs": [], + "source": [ + "samples_df.loc[samples_df[\"n_choices\"] == 0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fefb83ad", + "metadata": {}, + "outputs": [], + "source": [ + "# Remove samples with zero choices\n", + "samples_df = samples_df[samples_df[\"n_choices\"] > 0].reset_index(drop=True)\n", + "samples_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2aa3550f", + "metadata": {}, + "outputs": [], + "source": [ + "for label, samples in samples_by_label.items():\n", + " print(f\"{label}: {len(samples)} samples before filtering\")\n", + " samples_by_label[label] = [\n", + " sample for sample in samples if len(sample[\"choices\"]) > 0\n", + " ]\n", + " print(f\"{label}: {len(samples_by_label[label])} samples after filtering\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12ff76ac", + "metadata": {}, + "outputs": [], + "source": [ + "samples_df.loc[samples_df[\"n_choices\"] > 1, [\"text\", \"choices\"]].explode(\n", + " \"choices\"\n", + ").drop_duplicates()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1bb2dfec", + "metadata": {}, + "outputs": [], + "source": [ + "label_counts = samples_df.groupby(\"label\").size().sort_values(ascending=False)\n", + "choice_counts = (\n", + " samples_df.explode(\"choices\")\n", + " .groupby([\"label\", \"choices\"])\n", + " .size()\n", + " .rename(\"count\")\n", + ")\n", + "\n", + "summary_table = pd.DataFrame(\n", + " {\n", + " \"samples\": label_counts,\n", + " \"unique_choices\": choice_counts.groupby(\"label\").size(),\n", + " \"avg_text_len\": samples_df.groupby(\"label\")[\"char_len\"]\n", + " .mean()\n", + " .round(1),\n", + " }\n", + ")\n", + "summary_table" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "729dc02e", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "order = label_counts.index\n", + "sns.barplot(\n", + " x=label_counts.values, y=label_counts.index, ax=ax, palette=\"viridis\"\n", + ")\n", + "ax.set_title(\"Samples per label\")\n", + "ax.set_xlabel(\"Number of samples\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "plot_data = (\n", + " choice_counts.reset_index()\n", + " .sort_values(\"count\", ascending=False)\n", + " .groupby(\"label\")\n", + " .head(10)\n", + ")\n", + "\n", + "for label in order:\n", + " subset = plot_data.query(\"label == @label\").sort_values(\n", + " \"count\", ascending=True\n", + " )\n", + " fig, ax = plt.subplots(figsize=(8, 4))\n", + " sns.barplot(data=subset, x=\"count\", y=\"choices\", palette=\"viridis\", ax=ax)\n", + " ax.set_title(f\"Top subcategories for {label}\")\n", + " ax.set_xlabel(\"Frequency\")\n", + " ax.set_ylabel(\"Subcategory\")\n", + " ax.grid(axis=\"x\", alpha=0.2)\n", + " ax.invert_yaxis()\n", + " plt.tight_layout()\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61ef49f8", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "sns.boxplot(data=samples_df, x=\"label\", y=\"char_len\", palette=\"viridis\")\n", + "ax.set_title(\"Entity span length by label\")\n", + "ax.set_xlabel(\"Label\")\n", + "ax.set_ylabel(\"Character length\")\n", + "ax.set_ylim(0, 100)\n", + "plt.xticks(rotation=15)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a402956", + "metadata": {}, + "outputs": [], + "source": [ + "for label in label_counts.index:\n", + " print(f\"=== {label} ===\")\n", + " subset = samples_df.query(\"label == @label\")\n", + " for _, row in subset.sample(n=min(3, len(subset))).iterrows():\n", + " print(f\"- Text: {row['text']}\")\n", + " print(f\" Choices: {row['choices']}\")\n", + " print()" + ] + }, + { + "cell_type": "markdown", + "id": "535f6000", + "metadata": {}, + "source": [ + "## USEM pipeline audit\n", + "\n", + "We validate the existing TensorFlow-based USEM subcategorizer by reloading the cached assets, recomputing embeddings, and measuring retrieval accuracy before swapping in PyTorch alternatives." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51e8f65e", + "metadata": {}, + "outputs": [], + "source": [ + "pipeline_path = Path(\n", + " \"/resources/pipelines/production/full-paragraph/pipeline.json\"\n", + ")\n", + "\n", + "with pipeline_path.open() as f:\n", + " pipeline_config = json.load(f)\n", + "\n", + "usem_configs = {\n", + " config[1][\"category\"]: {\n", + " \"subcategories_path\": config[1][\"subcategories_path\"],\n", + " \"response_embeddings_path\": config[1][\"response_embeddings_path\"],\n", + " }\n", + " for config in pipeline_config[\"postprocess\"]\n", + " if \"USEMSubcategorizer\" in config[0]\n", + "}\n", + "\n", + "usem_configs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8ab1c51f", + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.transforms.entity_subcategories.usem import USEMSubcategorizer\n", + "\n", + "usem_models = {}\n", + "for label, cfg in usem_configs.items():\n", + " print(f\"Loading USEM assets for {label}…\")\n", + " usem_models[label] = USEMSubcategorizer(category=label, **cfg)\n", + "\n", + "list(usem_models.keys())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d28103d8", + "metadata": {}, + "outputs": [], + "source": [ + "model = usem_models[\"CONDUCTA\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f07e07f9", + "metadata": {}, + "outputs": [], + "source": [ + "model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0cd9987", + "metadata": {}, + "outputs": [], + "source": [ + "model.subcategories" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f51be1d", + "metadata": {}, + "outputs": [], + "source": [ + "# Sample encoding of first subcategory\n", + "encoded = model.usem.encode(\n", + " [model.subcategories[0].replace(\"_\", \" \")],\n", + " context_array=[model.subcategories[0].replace(\"_\", \" \")],\n", + " encoder_type=\"response_encoder\",\n", + ")\n", + "encoded" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "caa86d26", + "metadata": {}, + "outputs": [], + "source": [ + "def cosine_similarity(a, b):\n", + " a_norm = a / np.linalg.norm(a, axis=1, keepdims=True)\n", + " b_norm = b / np.linalg.norm(b, axis=1, keepdims=True)\n", + " return np.sum(a_norm * b_norm, axis=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d5dc56a", + "metadata": {}, + "outputs": [], + "source": [ + "# Compute cosine similarity matrix - first value should be 1\n", + "cosine_similarity(encoded, model.usem_vectors)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb470374", + "metadata": {}, + "outputs": [], + "source": [ + "import unicodedata\n", + "\n", + "\n", + "def normalize_text(text: str) -> str:\n", + " \"\"\"Normalize text by lowercasing and removing non-alphanumeric characters.\"\"\"\n", + " text = text.lower()\n", + " text = \"\".join(\n", + " char\n", + " for char in unicodedata.normalize(\"NFKD\", text)\n", + " if char.isalnum() or char.isspace()\n", + " )\n", + " return text\n", + "\n", + "\n", + "def normalize_subcategory(name: str) -> str:\n", + " \"\"\"Mirror the preprocessing applied when the cached embeddings were built.\"\"\"\n", + " # name = normalize_text(name)\n", + " return name.replace(\"_\", \" \")\n", + "\n", + "\n", + "def recompute_response_vectors(model):\n", + " \"\"\"Return normalized subcategory strings and freshly encoded vectors.\"\"\"\n", + " normalized = [\n", + " normalize_subcategory(subcategory)\n", + " for subcategory in model.subcategories\n", + " ]\n", + " fresh_vectors = model.usem.encode(\n", + " normalized,\n", + " context_array=normalized,\n", + " encoder_type=\"response_encoder\",\n", + " )\n", + " return normalized, fresh_vectors.numpy()\n", + "\n", + "\n", + "cached = model.usem_vectors\n", + "normalized_subcategories, fresh = recompute_response_vectors(model)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7362249", + "metadata": {}, + "outputs": [], + "source": [ + "def l2_normalize(matrix: np.ndarray) -> np.ndarray:\n", + " \"\"\"Row-wise L2 normalization to prepare cosine similarity checks.\"\"\"\n", + " return matrix / np.linalg.norm(matrix, axis=1, keepdims=True)\n", + "\n", + "\n", + "cached_norm = l2_normalize(cached)\n", + "fresh_norm = l2_normalize(fresh)\n", + "cosine_matrix = cached_norm @ fresh_norm.T\n", + "cosine_matrix.shape" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a755a678", + "metadata": {}, + "outputs": [], + "source": [ + "row_max_indices = np.argmax(cosine_matrix, axis=1)\n", + "row_max_values = cosine_matrix[\n", + " np.arange(len(row_max_indices)), row_max_indices\n", + "]\n", + "mismatched_rows = np.where(row_max_indices != np.arange(len(row_max_indices)))[\n", + " 0\n", + "]\n", + "diag_values = np.diag(cosine_matrix)\n", + "off_identity_matches = (\n", + " pd.DataFrame(\n", + " {\n", + " \"subcategory\": [\n", + " model.subcategories[idx] for idx in mismatched_rows\n", + " ],\n", + " \"matched_index\": row_max_indices[mismatched_rows],\n", + " \"max_cosine\": row_max_values[mismatched_rows],\n", + " \"diagonal_cosine\": diag_values[mismatched_rows],\n", + " }\n", + " )\n", + " if mismatched_rows.size\n", + " else pd.DataFrame(\n", + " columns=[\n", + " \"subcategory\",\n", + " \"matched_index\",\n", + " \"max_cosine\",\n", + " \"diagonal_cosine\",\n", + " ]\n", + " )\n", + ")\n", + "off_identity_matches # .head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "50f14d8c", + "metadata": {}, + "outputs": [], + "source": [ + "diag_values" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8a42e0a8", + "metadata": {}, + "outputs": [], + "source": [ + "tolerance = 0.99\n", + "near_identity_mask = diag_values >= tolerance\n", + "print(\n", + " f\"Diagonal entries at or above {tolerance:.2f}: {near_identity_mask.sum()} / {len(diag_values)}\"\n", + ")\n", + "diagonal_gaps = (\n", + " pd.DataFrame(\n", + " {\n", + " \"subcategory\": [\n", + " model.subcategories[idx]\n", + " for idx, ok in enumerate(near_identity_mask)\n", + " if not ok\n", + " ],\n", + " \"diagonal_cosine\": diag_values[~near_identity_mask],\n", + " \"shortfall\": 1 - diag_values[~near_identity_mask],\n", + " }\n", + " )\n", + " if (~near_identity_mask).any()\n", + " else pd.DataFrame(columns=[\"subcategory\", \"diagonal_cosine\", \"shortfall\"])\n", + ")\n", + "diagonal_gaps # .head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "129e8489", + "metadata": {}, + "outputs": [], + "source": [ + "embedding_checks = []\n", + "for label, model in usem_models.items():\n", + " cached = model.usem_vectors\n", + " normalized_subcategories, fresh = recompute_response_vectors(model)\n", + " cached_norm = l2_normalize(cached)\n", + " fresh_norm = l2_normalize(fresh)\n", + " delta = cached - fresh\n", + " row_l2 = np.linalg.norm(delta, axis=1)\n", + " cos = np.sum(cached_norm * fresh_norm, axis=1)\n", + " embedding_checks.append(\n", + " {\n", + " \"label\": label,\n", + " \"max_l2\": float(row_l2.max()),\n", + " \"mean_l2\": float(row_l2.mean()),\n", + " \"min_cos\": float(cos.min()),\n", + " \"mean_cos\": float(cos.mean()),\n", + " }\n", + " )\n", + "\n", + "embedding_checks_df = pd.DataFrame(embedding_checks).set_index(\"label\")\n", + "embedding_checks_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a5c521a0", + "metadata": {}, + "outputs": [], + "source": [ + "# Using batch retrieval\n", + "def retrieve_samples(samples, models, top_k=5):\n", + " records = []\n", + " for label, items in samples.items():\n", + " model = models[label]\n", + " texts = [item[\"text\"] for item in items]\n", + " retrieved_lists = model.batch_retrieve(texts, top_k=top_k)\n", + " for item, retrieved in zip(items, retrieved_lists):\n", + " records.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"retrieved\": retrieved,\n", + " }\n", + " )\n", + " return records\n", + "\n", + "\n", + "retrieval_records = retrieve_samples(samples_by_label, usem_models, top_k=5)\n", + "len(retrieval_records)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5278ead4", + "metadata": {}, + "outputs": [], + "source": [ + "# Filter out samples with no annotated choices\n", + "retrieval_records = [\n", + " record for record in retrieval_records if record[\"choices\"]\n", + "]\n", + "len(retrieval_records)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efbe083b", + "metadata": {}, + "outputs": [], + "source": [ + "def compute_topk_accuracy(records, ks=(1, 2, 3, 4, 5)):\n", + " metrics = []\n", + " labels = sorted({record[\"label\"] for record in records})\n", + " for label in labels:\n", + " label_records = [\n", + " record for record in records if record[\"label\"] == label\n", + " ]\n", + " total = len(label_records)\n", + " for k in ks:\n", + " hits = sum(\n", + " any(\n", + " choice in record[\"retrieved\"][:k]\n", + " for choice in record[\"choices\"]\n", + " )\n", + " for record in label_records\n", + " )\n", + " metrics.append(\n", + " {\n", + " \"label\": label,\n", + " \"k\": k,\n", + " \"accuracy\": hits / total if total else np.nan,\n", + " }\n", + " )\n", + "\n", + " overall = []\n", + " for k in ks:\n", + " hits = sum(\n", + " any(\n", + " choice in record[\"retrieved\"][:k]\n", + " for choice in record[\"choices\"]\n", + " )\n", + " for record in records\n", + " )\n", + " overall.append(\n", + " {\"label\": \"OVERALL\", \"k\": k, \"accuracy\": hits / len(records)}\n", + " )\n", + "\n", + " metrics.extend(overall)\n", + " return pd.DataFrame(metrics)\n", + "\n", + "\n", + "baseline_accuracy = compute_topk_accuracy(retrieval_records)\n", + "baseline_accuracy_pivot = baseline_accuracy.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + ").sort_index()\n", + "\n", + "baseline_accuracy_pivot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa531a6c", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "\n", + "sns.heatmap(\n", + " baseline_accuracy_pivot.loc[\n", + " [\n", + " label\n", + " for label in baseline_accuracy_pivot.index\n", + " if label != \"OVERALL\"\n", + " ]\n", + " ],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"USEM baseline top-k accuracy by label\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "baseline_accuracy_pivot.loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f775ee51", + "metadata": {}, + "outputs": [], + "source": [ + "# For each label, show some random success cases where the correct choice was retrieved in top 5\n", + "for label in target_labels:\n", + " print(f\"=== {label} ===\")\n", + " label_records = [\n", + " record\n", + " for record in retrieval_records\n", + " if record[\"label\"] == label\n", + " and any(\n", + " choice in record[\"retrieved\"][:5] for choice in record[\"choices\"]\n", + " )\n", + " ]\n", + " for record in random.sample(label_records, k=min(3, len(label_records))):\n", + " print(f\"- Text: {record['text']}\")\n", + " print(f\" Choices: {record['choices']}\")\n", + " print(f\" Retrieved: {record['retrieved'][:5]}\")\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "441f8b7d", + "metadata": {}, + "outputs": [], + "source": [ + "# For each label, show some random failure cases where the correct choice was not retrieved in top 5\n", + "for label in target_labels:\n", + " print(f\"=== {label} ===\")\n", + " label_records = [\n", + " record\n", + " for record in retrieval_records\n", + " if record[\"label\"] == label\n", + " and not any(\n", + " choice in record[\"retrieved\"][:5] for choice in record[\"choices\"]\n", + " )\n", + " ]\n", + " for record in random.sample(label_records, k=min(3, len(label_records))):\n", + " print(f\"- Text: {record['text']}\")\n", + " print(f\" Choices: {record['choices']}\")\n", + " print(f\" Retrieved: {record['retrieved'][:5]}\")\n", + " print()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ac517e27", + "metadata": {}, + "outputs": [], + "source": [ + "overall = baseline_accuracy_pivot.loc[\"OVERALL\"]\n", + "label_top1 = baseline_accuracy_pivot.loc[\n", + " [label for label in baseline_accuracy_pivot.index if label != \"OVERALL\"], 1\n", + "]\n", + "\n", + "summary_md = f\"\"\"\n", + "### Baseline findings\n", + "\n", + "- Overall top-1 accuracy: {overall[1]:.2%}\n", + "- Overall top-3 accuracy: {overall[3]:.2%}\n", + "- Overall top-5 accuracy: {overall[5]:.2%}\n", + "- Best-performing label (top-1): {label_top1.idxmax()} at {label_top1.max():.2%}\n", + "- Most challenging label (top-1): {label_top1.idxmin()} at {label_top1.min():.2%}\n", + "\n", + "#### Next steps\n", + "1. Replace the TensorFlow encoder with sentence-transformer checkpoints and repeat the evaluation.\n", + "2. Compare latency and memory footprint during retrieval for each contender.\n", + "3. Consolidate the winning model into the pipeline and update deployment assets.\n", + "\"\"\"\n", + "\n", + "Markdown(summary_md)" + ] + }, + { + "cell_type": "markdown", + "id": "4d794421", + "metadata": {}, + "source": [ + "## Random Retriever" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "250cabac", + "metadata": {}, + "outputs": [], + "source": [ + "class RandomRetriever:\n", + " def __init__(self, subcategories: list[str], seed: int = 42):\n", + " self.subcategories = subcategories\n", + " self._rng = random.Random(seed)\n", + "\n", + " def batch_retrieve(\n", + " self, texts: list[str], top_k: int = 5\n", + " ) -> list[list[str]]:\n", + " k = min(top_k, len(self.subcategories))\n", + " if k == 0:\n", + " return [[] for _ in texts]\n", + " return [self._rng.sample(self.subcategories, k) for _ in texts]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f556454", + "metadata": {}, + "outputs": [], + "source": [ + "label_subcategories = {\n", + " label: model.subcategories for label, model in usem_models.items()\n", + "}\n", + "random_models = {\n", + " label: RandomRetriever(subcats, seed=idx * 17)\n", + " for idx, (label, subcats) in enumerate(label_subcategories.items())\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecc98fde", + "metadata": {}, + "outputs": [], + "source": [ + "baseline_variants = {\n", + " \"Random\": random_models,\n", + " # \"USEM\": usem_models,\n", + " # \"BM25\": bm25_models,\n", + " # \"USEM + BM25 hybrid\": hybrid_models,\n", + "}\n", + "\n", + "variant_records = {}\n", + "for variant, models in baseline_variants.items():\n", + " records = retrieve_samples(samples_by_label, models, top_k=5)\n", + " variant_records[variant] = records\n", + "\n", + "variant_accuracy = {\n", + " variant: compute_topk_accuracy(records)\n", + " for variant, records in variant_records.items()\n", + "}\n", + "variant_pivots = {\n", + " variant: df.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + " ).sort_index()\n", + " for variant, df in variant_accuracy.items()\n", + "}\n", + "\n", + "for variant, pivot in variant_pivots.items():\n", + " display(Markdown(f\"**{variant} baseline top-k accuracy**\"))\n", + " display(pivot)\n", + "\n", + "# combined_series = {\n", + "# \"TensorFlow USEM\": baseline_accuracy_pivot.loc[\"OVERALL\"],\n", + "# \"DistilUSE\": distiluse_accuracy_pivot.loc[\"OVERALL\"],\n", + "# \"MiniLM\": minilm_accuracy_pivot.loc[\"OVERALL\"],\n", + "# }\n", + "# combined_series.update(\n", + "# {variant: pivot.loc[\"OVERALL\"] for variant, pivot in variant_pivots.items()}\n", + "# )\n", + "# combined_accuracy = pd.DataFrame.from_dict(combined_series, orient=\"index\")\n", + "# combined_accuracy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "943672c8", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "\n", + "sns.heatmap(\n", + " variant_pivots[\"Random\"].loc[\n", + " [\n", + " label\n", + " for label in baseline_accuracy_pivot.index\n", + " if label != \"OVERALL\"\n", + " ]\n", + " ],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"Random baseline top-k accuracy by label\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "variant_pivots[\"Random\"].loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "markdown", + "id": "f3ead018", + "metadata": {}, + "source": [ + "## BM25 retriever" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7b46e82", + "metadata": {}, + "outputs": [], + "source": [ + "import math\n", + "import re\n", + "from collections import Counter\n", + "\n", + "token_pattern = re.compile(r\"\\w+\", re.UNICODE)\n", + "\n", + "\n", + "def tokenize(text: str) -> list[str]:\n", + " return token_pattern.findall(normalize_text(text))\n", + "\n", + "\n", + "class BM25Retriever:\n", + " def __init__(\n", + " self, subcategories: list[str], k1: float = 1.2, b: float = 0.75\n", + " ):\n", + " self.subcategories = subcategories\n", + " normalized = [normalize_subcategory(sub) for sub in subcategories]\n", + " self.tokenized = [tokenize(text) for text in normalized]\n", + " self.doc_len = [len(tokens) for tokens in self.tokenized]\n", + " self.avgdl = sum(self.doc_len) / len(self.doc_len)\n", + " self.k1 = k1\n", + " self.b = b\n", + " self.N = len(self.tokenized)\n", + " self.doc_freqs = [Counter(tokens) for tokens in self.tokenized]\n", + " corpus_tokens = set().union(*self.doc_freqs)\n", + " self.df = Counter(\n", + " {\n", + " token: sum(1 for doc in self.doc_freqs if token in doc)\n", + " for token in corpus_tokens\n", + " }\n", + " )\n", + " self.idf = {\n", + " token: math.log(1 + (self.N - freq + 0.5) / (freq + 0.5))\n", + " for token, freq in self.df.items()\n", + " }\n", + "\n", + " def _score(self, tokens: list[str]) -> np.ndarray:\n", + " scores = np.zeros(self.N, dtype=np.float64)\n", + " for token in tokens:\n", + " idf = self.idf.get(token)\n", + " if idf is None:\n", + " continue\n", + " for idx, freq_map in enumerate(self.doc_freqs):\n", + " freq = freq_map.get(token, 0)\n", + " if freq == 0:\n", + " continue\n", + " denom = freq + self.k1 * (\n", + " 1 - self.b + self.b * self.doc_len[idx] / self.avgdl\n", + " )\n", + " scores[idx] += idf * freq * (self.k1 + 1) / denom\n", + " return scores\n", + "\n", + " def batch_retrieve(\n", + " self, texts: list[str], top_k: int = 5\n", + " ) -> list[list[str]]:\n", + " return [self._topk(text, top_k) for text in texts]\n", + "\n", + " def _topk(self, text: str, top_k: int) -> list[str]:\n", + " scores = self._score(tokenize(text))\n", + " if top_k <= 0:\n", + " return []\n", + " top_indices = np.argsort(-scores)[:top_k]\n", + " return [self.subcategories[idx] for idx in top_indices]\n", + "\n", + " def score_vector(self, text: str) -> np.ndarray:\n", + " return self._score(tokenize(text))\n", + "\n", + "\n", + "class HybridRetriever:\n", + " def __init__(self, usem_model, bm25_model, bm25_weight: float = 0.5):\n", + " self.usem_model = usem_model\n", + " self.bm25_model = bm25_model\n", + " self.response_vectors = usem_model.usem_vectors\n", + " self.bm25_weight = bm25_weight\n", + "\n", + " def batch_retrieve(\n", + " self, texts: list[str], top_k: int = 5\n", + " ) -> list[list[str]]:\n", + " query_vectors = self.usem_model.usem.batch_encode(\n", + " [normalize_text(text) for text in texts],\n", + " encoder_type=\"question_encoder\",\n", + " )\n", + " similarity = np.inner(query_vectors, self.response_vectors)\n", + " combined_results = []\n", + " for row_idx, text in enumerate(texts):\n", + " bm25_scores = self.bm25_model.score_vector(text)\n", + " bm25_norm = bm25_scores / (bm25_scores.max() + 1e-9)\n", + " sim_scores = similarity[row_idx]\n", + " sim_norm = sim_scores / (sim_scores.max() + 1e-9)\n", + " combined = (\n", + " self.bm25_weight * bm25_norm\n", + " + (1 - self.bm25_weight) * sim_norm\n", + " )\n", + " k = min(top_k, combined.shape[0])\n", + " top_indices = np.argsort(-combined)[:k]\n", + " combined_results.append(\n", + " [self.bm25_model.subcategories[idx] for idx in top_indices]\n", + " )\n", + " return combined_results" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b629aa3", + "metadata": {}, + "outputs": [], + "source": [ + "bm25_models = {\n", + " label: BM25Retriever(subcats)\n", + " for label, subcats in label_subcategories.items()\n", + "}\n", + "hybrid_models = {\n", + " label: HybridRetriever(\n", + " usem_models[label], bm25_models[label], bm25_weight=0.4\n", + " )\n", + " for label in usem_models\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ccfc969e", + "metadata": {}, + "outputs": [], + "source": [ + "baseline_variants = {\n", + " \"Random\": random_models,\n", + " \"BM25\": bm25_models,\n", + " \"USEM + BM25 hybrid\": hybrid_models,\n", + "}\n", + "\n", + "variant_records = {}\n", + "for variant, models in baseline_variants.items():\n", + " records = retrieve_samples(samples_by_label, models, top_k=5)\n", + " variant_records[variant] = records\n", + "\n", + "variant_accuracy = {\n", + " variant: compute_topk_accuracy(records)\n", + " for variant, records in variant_records.items()\n", + "}\n", + "variant_pivots = {\n", + " variant: df.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + " ).sort_index()\n", + " for variant, df in variant_accuracy.items()\n", + "}\n", + "\n", + "for variant, pivot in variant_pivots.items():\n", + " display(Markdown(f\"**{variant} baseline top-k accuracy**\"))\n", + " display(pivot)\n", + "\n", + " fig, ax = plt.subplots()\n", + "\n", + " sns.heatmap(\n", + " pivot.loc[\n", + " [\n", + " label\n", + " for label in baseline_accuracy_pivot.index\n", + " if label != \"OVERALL\"\n", + " ]\n", + " ],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + " )\n", + " ax.set_title(f\"{variant} baseline top-k accuracy by label\")\n", + " ax.set_xlabel(\"k\")\n", + " ax.set_ylabel(\"Label\")\n", + " plt.tight_layout()\n", + " plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "ffbdfc8a", + "metadata": {}, + "source": [ + "## Challenger models: PyTorch sentence-transformers\n", + "\n", + "We now evaluate two PyTorch-based encoders as potential replacements for the TensorFlow USEM model:\n", + "- **DistilUSE**: Knowledge-distilled USE producing 512-dimensional embeddings\n", + "- **MultilingualMiniLM**: Higher-quality MiniLM producing 384-dimensional embeddings\n", + "\n", + "Both models support Apple Silicon (M1/M2/M3) via MPS backend and eliminate the TensorFlow dependency." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f22169f", + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.models.usem.sentence_transformers_encoder import (\n", + " DistilUSEEncoder,\n", + " MultilingualMiniLMEncoder,\n", + ")\n", + "\n", + "# Initialize challenger encoders\n", + "distiluse_encoder = DistilUSEEncoder()\n", + "minilm_encoder = MultilingualMiniLMEncoder()\n", + "\n", + "challenger_encoders = {\n", + " \"DistilUSE\": distiluse_encoder,\n", + " \"MiniLM\": minilm_encoder,\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "016fcb42", + "metadata": {}, + "outputs": [], + "source": [ + "from hashlib import md5\n", + "\n", + "from aymurai.utils.download import download\n", + "from aymurai.utils.misc import is_url\n", + "\n", + "\n", + "class SentenceTransformerRetriever:\n", + " def __init__(\n", + " self,\n", + " label,\n", + " subcategories_path,\n", + " encoder,\n", + " encoder_name=\"challenger\",\n", + " batch_size=256,\n", + " ):\n", + " self.label = label\n", + " self.encoder = encoder\n", + " self.batch_size = batch_size\n", + " self.encoder_name = encoder_name\n", + " self.subcategories = self._load_subcategories(subcategories_path)\n", + " normalized_subcategories = [\n", + " normalize_subcategory(sub) for sub in self.subcategories\n", + " ]\n", + " self.response_vectors = self.encoder.batch_encode(\n", + " normalized_subcategories,\n", + " encoder_type=\"response_encoder\",\n", + " batch_size=batch_size,\n", + " )\n", + "\n", + " def _load_subcategories(self, path):\n", + " resolved_path = Path(path)\n", + " if is_url(path):\n", + " cache_root = Path(\n", + " os.getenv(\"AYMURAI_CACHE_BASEPATH\", \"/resources/cache/aymurai\")\n", + " )\n", + " target_dir = cache_root / \"sentence_transformer_retriever\"\n", + " target_dir.mkdir(parents=True, exist_ok=True)\n", + " target_path = target_dir / md5(path.encode(\"utf-8\")).hexdigest()\n", + " resolved_path = Path(download(path, str(target_path)))\n", + " if not resolved_path.exists():\n", + " raise FileNotFoundError(\n", + " f\"Subcategory file not found for {self.label}: {resolved_path}\"\n", + " )\n", + " with resolved_path.open() as file:\n", + " return [line.strip() for line in file if line.strip()]\n", + "\n", + " def batch_retrieve(self, texts, top_k=5):\n", + " if not texts:\n", + " return []\n", + "\n", + " query_vectors = self.encoder.batch_encode(\n", + " texts,\n", + " encoder_type=\"question_encoder\",\n", + " batch_size=self.batch_size,\n", + " )\n", + " similarity = np.inner(query_vectors, self.response_vectors)\n", + " k = min(top_k, similarity.shape[1])\n", + " top_indices = np.argsort(-similarity, axis=1)[:, :k]\n", + " return [\n", + " [self.subcategories[idx] for idx in row] for row in top_indices\n", + " ]\n", + "\n", + "\n", + "class HybridSentenceTransformerRetriever:\n", + " def __init__(self, base_retriever, bm25_model, bm25_weight: float = 0.4):\n", + " self.base_retriever = base_retriever\n", + " self.bm25_model = bm25_model\n", + " self.bm25_weight = bm25_weight\n", + " self.encoder = base_retriever.encoder\n", + " self.response_vectors = base_retriever.response_vectors\n", + " self.subcategories = base_retriever.subcategories\n", + " self.batch_size = base_retriever.batch_size\n", + "\n", + " def batch_retrieve(self, texts, top_k=5):\n", + " if not texts:\n", + " return []\n", + "\n", + " query_vectors = self.encoder.batch_encode(\n", + " texts,\n", + " encoder_type=\"question_encoder\",\n", + " batch_size=self.batch_size,\n", + " )\n", + " similarity = np.inner(query_vectors, self.response_vectors)\n", + " combined_results = []\n", + " for row_idx, text in enumerate(texts):\n", + " bm25_scores = self.bm25_model.score_vector(text)\n", + " bm25_norm = bm25_scores / (bm25_scores.max() + 1e-9)\n", + " sim_scores = similarity[row_idx]\n", + " sim_norm = sim_scores / (sim_scores.max() + 1e-9)\n", + " combined = (\n", + " self.bm25_weight * bm25_norm\n", + " + (1 - self.bm25_weight) * sim_norm\n", + " )\n", + " k = min(top_k, combined.shape[0])\n", + " top_indices = np.argsort(-combined)[:k]\n", + " combined_results.append(\n", + " [self.subcategories[idx] for idx in top_indices]\n", + " )\n", + " return combined_results\n", + "\n", + "\n", + "def build_challenger_models(\n", + " usem_configs, encoder, encoder_name, batch_size=256\n", + "):\n", + " return {\n", + " label: SentenceTransformerRetriever(\n", + " label=label,\n", + " subcategories_path=cfg[\"subcategories_path\"],\n", + " encoder=encoder,\n", + " encoder_name=encoder_name,\n", + " batch_size=batch_size,\n", + " )\n", + " for label, cfg in usem_configs.items()\n", + " }\n", + "\n", + "\n", + "def build_hybrid_sentence_transformer_models(\n", + " base_models, bm25_models, bm25_weight=0.4\n", + "):\n", + " return {\n", + " label: HybridSentenceTransformerRetriever(\n", + " base_retriever=base_models[label],\n", + " bm25_model=bm25_models[label],\n", + " bm25_weight=bm25_weight,\n", + " )\n", + " for label in base_models\n", + " }\n", + "\n", + "\n", + "def evaluate_sentence_transformers(samples, models, top_k=5):\n", + " records = []\n", + " for label, items in samples.items():\n", + " retriever = models[label]\n", + " texts = [item[\"text\"] for item in items]\n", + " retrieved_lists = retriever.batch_retrieve(texts, top_k=top_k)\n", + " for item, retrieved in zip(items, retrieved_lists):\n", + " records.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"retrieved\": retrieved,\n", + " }\n", + " )\n", + " return records\n", + "\n", + "\n", + "distiluse_models = build_challenger_models(\n", + " usem_configs, distiluse_encoder, \"DistilUSE\"\n", + ")\n", + "minilm_models = build_challenger_models(usem_configs, minilm_encoder, \"MiniLM\")" + ] + }, + { + "cell_type": "markdown", + "id": "4847338b", + "metadata": {}, + "source": [ + "### DistilUSE evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3baaedfb", + "metadata": {}, + "outputs": [], + "source": [ + "distiluse_retrieval_records = evaluate_sentence_transformers(\n", + " samples_by_label,\n", + " distiluse_models,\n", + " top_k=5,\n", + ")\n", + "distiluse_accuracy = compute_topk_accuracy(distiluse_retrieval_records)\n", + "distiluse_accuracy_pivot = distiluse_accuracy.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + ").sort_index()\n", + "\n", + "distiluse_accuracy_pivot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30162b63", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "sns.heatmap(\n", + " distiluse_accuracy_pivot.loc[\n", + " [\n", + " label\n", + " for label in distiluse_accuracy_pivot.index\n", + " if label != \"OVERALL\"\n", + " ]\n", + " ],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"DistilUSE top-k accuracy by label\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "distiluse_accuracy_pivot.loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "markdown", + "id": "a13c5d69", + "metadata": {}, + "source": [ + "### MultilingualMiniLM evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd0e59f1", + "metadata": {}, + "outputs": [], + "source": [ + "minilm_retrieval_records = evaluate_sentence_transformers(\n", + " samples_by_label,\n", + " minilm_models,\n", + " top_k=5,\n", + ")\n", + "minilm_accuracy = compute_topk_accuracy(minilm_retrieval_records)\n", + "minilm_accuracy_pivot = minilm_accuracy.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + ").sort_index()\n", + "\n", + "minilm_accuracy_pivot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e9fe5a7", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "sns.heatmap(\n", + " minilm_accuracy_pivot.loc[\n", + " [label for label in minilm_accuracy_pivot.index if label != \"OVERALL\"]\n", + " ],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"MultilingualMiniLM top-k accuracy by label\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "minilm_accuracy_pivot.loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "markdown", + "id": "4593cd14", + "metadata": {}, + "source": [ + "### Hybrid (BM25 + encoder) evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e58869d", + "metadata": {}, + "outputs": [], + "source": [ + "distiluse_hybrid_models = build_hybrid_sentence_transformer_models(\n", + " distiluse_models,\n", + " bm25_models,\n", + " bm25_weight=0.4,\n", + ")\n", + "minilm_hybrid_models = build_hybrid_sentence_transformer_models(\n", + " minilm_models,\n", + " bm25_models,\n", + " bm25_weight=0.4,\n", + ")\n", + "\n", + "distiluse_hybrid_records = evaluate_sentence_transformers(\n", + " samples_by_label,\n", + " distiluse_hybrid_models,\n", + " top_k=5,\n", + ")\n", + "distiluse_hybrid_accuracy = compute_topk_accuracy(distiluse_hybrid_records)\n", + "distiluse_hybrid_pivot = distiluse_hybrid_accuracy.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + ").sort_index()\n", + "\n", + "distiluse_hybrid_pivot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4c103f8", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "sns.heatmap(\n", + " distiluse_hybrid_pivot.loc[\n", + " [label for label in distiluse_hybrid_pivot.index if label != \"OVERALL\"]\n", + " ],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"DistilUSE + BM25 hybrid top-k accuracy by label\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "distiluse_hybrid_pivot.loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c249abb", + "metadata": {}, + "outputs": [], + "source": [ + "minilm_hybrid_records = evaluate_sentence_transformers(\n", + " samples_by_label,\n", + " minilm_hybrid_models,\n", + " top_k=5,\n", + ")\n", + "minilm_hybrid_accuracy = compute_topk_accuracy(minilm_hybrid_records)\n", + "minilm_hybrid_pivot = minilm_hybrid_accuracy.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + ").sort_index()\n", + "\n", + "minilm_hybrid_pivot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5333bf04", + "metadata": {}, + "outputs": [], + "source": [ + "fig, ax = plt.subplots()\n", + "sns.heatmap(\n", + " minilm_hybrid_pivot.loc[\n", + " [label for label in minilm_hybrid_pivot.index if label != \"OVERALL\"]\n", + " ],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"MiniLM + BM25 hybrid top-k accuracy by label\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "minilm_hybrid_pivot.loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "markdown", + "id": "6e4f967a", + "metadata": {}, + "source": [ + "## Model comparison and champion selection\n", + "\n", + "We compare the three models across all metrics to select the best replacement for the TensorFlow USEM implementation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ef3d532", + "metadata": {}, + "outputs": [], + "source": [ + "# Consolidate OVERALL accuracy across all models\n", + "comparison_df = pd.DataFrame(\n", + " {\n", + " \"TensorFlow USEM\": baseline_accuracy_pivot.loc[\"OVERALL\"],\n", + " \"DistilUSE\": distiluse_accuracy_pivot.loc[\"OVERALL\"],\n", + " \"MiniLM\": minilm_accuracy_pivot.loc[\"OVERALL\"],\n", + " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"].loc[\n", + " \"OVERALL\"\n", + " ],\n", + " \"DistilUSE + BM25\": distiluse_hybrid_pivot.loc[\"OVERALL\"],\n", + " \"MiniLM + BM25\": minilm_hybrid_pivot.loc[\"OVERALL\"],\n", + " }\n", + ").T\n", + "\n", + "comparison_df" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d90c448", + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize comparison across k values as bar chart, sorted by performance at each k\n", + "fig, ax = plt.subplots(figsize=(10, 6))\n", + "melted = comparison_df.reset_index().melt(\n", + " id_vars=\"index\", var_name=\"k\", value_name=\"accuracy\"\n", + ")\n", + "\n", + "sns.barplot(\n", + " data=melted.sort_values(by=\"accuracy\", ascending=False),\n", + " x=\"k\",\n", + " y=\"accuracy\",\n", + " hue=\"index\",\n", + " ax=ax,\n", + ")\n", + "\n", + "ax.set_title(\"Top-k Accuracy Comparison Across Models\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Accuracy\")\n", + "ax.set_ylim(0, 1)\n", + "ax.legend(title=\"Model\", bbox_to_anchor=(1.05, 1), loc=\"upper left\")\n", + "ax.grid(axis=\"y\", alpha=0.3)\n", + "plt.xticks(rotation=0)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3b42a256", + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize comparison across k values as bar chart, sorted by performance at each k\n", + "fig, ax = plt.subplots(figsize=(10, 6))\n", + "melted = comparison_df.reset_index().melt(\n", + " id_vars=\"index\", var_name=\"k\", value_name=\"accuracy\"\n", + ")\n", + "# Drop TF USEM + BM25 variant for clarity\n", + "melted = melted[melted[\"index\"] != \"TensorFlow USEM + BM25\"]\n", + "\n", + "sns.barplot(\n", + " data=melted.sort_values(by=\"accuracy\", ascending=False),\n", + " x=\"k\",\n", + " y=\"accuracy\",\n", + " hue=\"index\",\n", + " ax=ax,\n", + ")\n", + "\n", + "ax.set_title(\"Top-k Accuracy Comparison Across Models\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Accuracy\")\n", + "ax.set_ylim(0, 1)\n", + "ax.legend(title=\"Model\", bbox_to_anchor=(1.05, 1), loc=\"upper left\")\n", + "ax.grid(axis=\"y\", alpha=0.3)\n", + "plt.xticks(rotation=0)\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ff3390f", + "metadata": {}, + "outputs": [], + "source": [ + "# Per-label comparison for top-1 accuracy\n", + "label_index = [l for l in baseline_accuracy_pivot.index if l != \"OVERALL\"]\n", + "label_comparison = pd.DataFrame(\n", + " {\n", + " \"TensorFlow USEM\": baseline_accuracy_pivot.loc[label_index, 1],\n", + " \"DistilUSE\": distiluse_accuracy_pivot.loc[label_index, 1],\n", + " \"MiniLM\": minilm_accuracy_pivot.loc[label_index, 1],\n", + " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"].loc[\n", + " label_index, 1\n", + " ],\n", + " \"DistilUSE + BM25\": distiluse_hybrid_pivot.loc[label_index, 1],\n", + " \"MiniLM + BM25\": minilm_hybrid_pivot.loc[label_index, 1],\n", + " }\n", + ")\n", + "\n", + "label_comparison" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34902f2c", + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize comparison across labels as bar chart, sorted by performance at each label\n", + "fig, ax = plt.subplots(figsize=(10, 6))\n", + "\n", + "melted = label_comparison.reset_index().melt(\n", + " id_vars=\"label\", var_name=\"Model\", value_name=\"accuracy\"\n", + ")\n", + "\n", + "sns.barplot(\n", + " data=melted.sort_values(by=[\"label\", \"accuracy\"], ascending=False),\n", + " x=\"label\",\n", + " y=\"accuracy\",\n", + " hue=\"Model\",\n", + " ax=ax,\n", + ")\n", + "\n", + "ax.set_title(\"Top-1 Accuracy Comparison by Label\")\n", + "ax.set_xlabel(\"Label\")\n", + "ax.set_ylabel(\"Accuracy\")\n", + "ax.set_ylim(0, 1)\n", + "ax.legend(title=\"Model\", bbox_to_anchor=(1.05, 1), loc=\"upper left\")\n", + "ax.grid(axis=\"y\", alpha=0.3)\n", + "plt.xticks(rotation=45, ha=\"right\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "149f195b", + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize comparison across labels as bar chart, sorted by performance at each label\n", + "fig, ax = plt.subplots(figsize=(10, 6))\n", + "\n", + "melted = label_comparison.reset_index().melt(\n", + " id_vars=\"label\", var_name=\"Model\", value_name=\"accuracy\"\n", + ")\n", + "\n", + "for label in melted[\"label\"].unique():\n", + " subset = melted[melted[\"label\"] == label].sort_values(\n", + " by=\"accuracy\", ascending=False\n", + " )\n", + " sns.barplot(\n", + " data=subset,\n", + " x=\"label\",\n", + " y=\"accuracy\",\n", + " hue=\"Model\",\n", + " ax=ax,\n", + " )\n", + "\n", + "# Deduplicate legend entries and draw once after plotting\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "by_label = dict(zip(labels, handles))\n", + "ax.legend(\n", + " by_label.values(),\n", + " by_label.keys(),\n", + " title=\"Model\",\n", + " bbox_to_anchor=(1.05, 1),\n", + " loc=\"upper left\",\n", + ")\n", + "\n", + "ax.set_title(\"Top-1 Accuracy Comparison by Label\")\n", + "ax.set_xlabel(\"Label\")\n", + "ax.set_ylabel(\"Accuracy\")\n", + "ax.set_ylim(0, 1)\n", + "ax.grid(axis=\"y\", alpha=0.3)\n", + "plt.xticks(rotation=45, ha=\"right\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3af7d0a0", + "metadata": {}, + "outputs": [], + "source": [ + "# Visualize comparison across labels as bar chart, sorted by performance at each label\n", + "fig, ax = plt.subplots(figsize=(10, 6))\n", + "\n", + "melted = label_comparison.reset_index().melt(\n", + " id_vars=\"label\", var_name=\"Model\", value_name=\"accuracy\"\n", + ")\n", + "\n", + "# Drop TF USEM + BM25 variant for clarity\n", + "melted = melted[melted[\"Model\"] != \"TensorFlow USEM + BM25\"]\n", + "\n", + "for label in melted[\"label\"].unique():\n", + " subset = melted[melted[\"label\"] == label].sort_values(\n", + " by=\"accuracy\", ascending=False\n", + " )\n", + " sns.barplot(\n", + " data=subset,\n", + " x=\"label\",\n", + " y=\"accuracy\",\n", + " hue=\"Model\",\n", + " ax=ax,\n", + " )\n", + "\n", + "# Deduplicate legend entries and draw once after plotting\n", + "handles, labels = ax.get_legend_handles_labels()\n", + "by_label = dict(zip(labels, handles))\n", + "ax.legend(\n", + " by_label.values(),\n", + " by_label.keys(),\n", + " title=\"Model\",\n", + " bbox_to_anchor=(1.05, 1),\n", + " loc=\"upper left\",\n", + ")\n", + "\n", + "ax.set_title(\"Top-1 Accuracy Comparison by Label\")\n", + "ax.set_xlabel(\"Label\")\n", + "ax.set_ylabel(\"Accuracy\")\n", + "ax.set_ylim(0, 1)\n", + "ax.grid(axis=\"y\", alpha=0.3)\n", + "plt.xticks(rotation=45, ha=\"right\")\n", + "plt.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9aefccac", + "metadata": {}, + "outputs": [], + "source": [ + "# Determine champion model\n", + "top1_scores = comparison_df[1]\n", + "champion_model = top1_scores.idxmax()\n", + "champion_score = top1_scores.max()\n", + "\n", + "# Calculate performance delta vs baseline\n", + "baseline_score = top1_scores[\"TensorFlow USEM\"]\n", + "challengers = top1_scores.drop(\"TensorFlow USEM\")\n", + "\n", + "performance_summary = pd.DataFrame(\n", + " {\n", + " \"Model\": comparison_df.index,\n", + " \"Top-1\": comparison_df[1].values,\n", + " \"Top-3\": comparison_df[3].values,\n", + " \"Top-5\": comparison_df[5].values,\n", + " \"Δ vs Baseline (Top-1)\": [\n", + " 0.0 if model == \"TensorFlow USEM\" else (score - baseline_score)\n", + " for model, score in zip(\n", + " comparison_df.index, comparison_df[1].values\n", + " )\n", + " ],\n", + " }\n", + ").set_index(\"Model\")\n", + "\n", + "performance_summary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f4a72754", + "metadata": {}, + "outputs": [], + "source": [ + "final_summary_md = f\"\"\"\n", + "## Champion Model Selection\n", + "\n", + "### Performance Summary\n", + "\n", + "{performance_summary.to_markdown()}\n", + "\n", + "### Winner: **{champion_model}**\n", + "\n", + "- **Top-1 Accuracy**: {champion_score:.2%}\n", + "- **Performance vs Baseline**: {(champion_score - baseline_score):.2%} ({\"+\" if champion_score >= baseline_score else \"\"}{((champion_score - baseline_score) / baseline_score * 100):.1f}%)\n", + "\n", + "### Key Findings\n", + "\n", + "1. **{champion_model}** achieves the highest top-1 accuracy at {champion_score:.2%}\n", + "2. All PyTorch models eliminate TensorFlow dependency and support Apple Silicon (MPS)\n", + "3. Both challenger models maintain competitive accuracy while offering:\n", + " - Cross-platform compatibility (Linux, macOS, Windows)\n", + " - Apple Silicon acceleration via MPS backend\n", + " - Smaller model footprint and faster inference\n", + "\n", + "### Implementation Recommendations\n", + "\n", + "1. **Replace TensorFlow USEM** with **{champion_model}** in production pipeline\n", + "2. Update `USEMSubcategorizer` to use the selected PyTorch encoder by default\n", + "3. Regenerate cached embeddings using the champion encoder\n", + "4. Update deployment documentation to reflect new dependencies\n", + "5. Verify inference latency and memory footprint in production environment\n", + "\n", + "### Next Steps\n", + "\n", + "- [ ] Implement {champion_model} as default encoder in `aymurai.models.usem`\n", + "- [ ] Regenerate response embeddings for all label categories\n", + "- [ ] Update pipeline configuration files\n", + "- [ ] Run integration tests across all supported platforms\n", + "- [ ] Update deployment scripts and documentation\n", + "\"\"\"\n", + "\n", + "Markdown(final_summary_md)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64638e96", + "metadata": {}, + "outputs": [], + "source": [ + "# Best-performing model per label and k (excluding TensorFlow USEM + BM25)\n", + "label_index = [l for l in baseline_accuracy_pivot.index if l != \"OVERALL\"]\n", + "ks = [k for k in range(1, 6) if k in baseline_accuracy_pivot.columns]\n", + "\n", + "model_pivots = {\n", + " \"TensorFlow USEM\": baseline_accuracy_pivot,\n", + " \"DistilUSE\": distiluse_accuracy_pivot,\n", + " \"MiniLM\": minilm_accuracy_pivot,\n", + " \"DistilUSE + BM25\": distiluse_hybrid_pivot,\n", + " \"MiniLM + BM25\": minilm_hybrid_pivot,\n", + "}\n", + "\n", + "records = []\n", + "for model_name, pivot in model_pivots.items():\n", + " for label in label_index:\n", + " for k in ks:\n", + " records.append(\n", + " {\n", + " \"label\": label,\n", + " \"k\": k,\n", + " \"model\": model_name,\n", + " \"accuracy\": pivot.loc[label, k],\n", + " }\n", + " )\n", + "\n", + "scores = pd.DataFrame(records)\n", + "best_models = scores.loc[scores.groupby([\"label\", \"k\"])[\"accuracy\"].idxmax()]\n", + "model_ranking = (\n", + " best_models[\"model\"]\n", + " .value_counts()\n", + " .rename_axis(\"model\")\n", + " .reset_index(name=\"wins\")\n", + ")\n", + "\n", + "best_models.reset_index(drop=True)\n", + "model_ranking" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fd27e32", + "metadata": {}, + "outputs": [], + "source": [ + "scores.query(\"k == 1\").sort_values(\n", + " [\"label\", \"accuracy\"], ascending=[True, False]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06b5a254", + "metadata": {}, + "outputs": [], + "source": [ + "scores.query(\"k == 3\").sort_values(\n", + " [\"label\", \"accuracy\"], ascending=[True, False]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b20b3ac", + "metadata": {}, + "outputs": [], + "source": [ + "scores.query(\"k == 5\").sort_values(\n", + " [\"label\", \"accuracy\"], ascending=[True, False]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "977f446a", + "metadata": {}, + "outputs": [], + "source": [ + "# Grid search BM25 weights for DistilUSE and MiniLM hybrids\n", + "weight_grid = [round(w, 2) for w in np.linspace(0.0, 0.9, 10)]\n", + "weight_grid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11f9300a", + "metadata": {}, + "outputs": [], + "source": [ + "search_results = []\n", + "pivot_lookup = {}\n", + "\n", + "# Cache texts per label\n", + "label_texts = {\n", + " label: [item[\"text\"] for item in items]\n", + " for label, items in samples_by_label.items()\n", + "}\n", + "\n", + "# Cache BM25 score vectors per label to avoid recomputing across weights\n", + "bm25_cache = {\n", + " label: [bm25_models[label].score_vector(text) for text in texts]\n", + " for label, texts in label_texts.items()\n", + "}\n", + "\n", + "# Cache question embeddings per model and label\n", + "query_cache = {}\n", + "for model_name, base_models in {\n", + " \"DistilUSE\": distiluse_models,\n", + " \"MiniLM\": minilm_models,\n", + "}.items():\n", + " any_model = next(iter(base_models.values()))\n", + " encoder = any_model.encoder\n", + " batch_size = any_model.batch_size\n", + " query_cache[model_name] = {\n", + " label: encoder.batch_encode(\n", + " texts, encoder_type=\"question_encoder\", batch_size=batch_size\n", + " )\n", + " for label, texts in label_texts.items()\n", + " }\n", + "\n", + "\n", + "def hybrid_retrieve_cached(\n", + " base_retriever,\n", + " bm25_model,\n", + " texts,\n", + " query_vectors,\n", + " bm25_scores,\n", + " bm25_weight,\n", + " top_k=5,\n", + "):\n", + " similarity = np.inner(query_vectors, base_retriever.response_vectors)\n", + " combined_results = []\n", + " for idx, text in enumerate(texts):\n", + " bm25_vec = bm25_scores[idx]\n", + " bm25_norm = bm25_vec / (bm25_vec.max() + 1e-9)\n", + " sim_scores = similarity[idx]\n", + " sim_norm = sim_scores / (sim_scores.max() + 1e-9)\n", + " combined = bm25_weight * bm25_norm + (1 - bm25_weight) * sim_norm\n", + " k = min(top_k, combined.shape[0])\n", + " top_indices = np.argsort(-combined)[:k]\n", + " combined_results.append(\n", + " [bm25_model.subcategories[i] for i in top_indices]\n", + " )\n", + " return combined_results\n", + "\n", + "\n", + "for model_name, base_models in {\n", + " \"DistilUSE\": distiluse_models,\n", + " \"MiniLM\": minilm_models,\n", + "}.items():\n", + " for weight in weight_grid:\n", + " records = []\n", + " for label, base_retriever in base_models.items():\n", + " texts = label_texts[label]\n", + " query_vectors = query_cache[model_name][label]\n", + " bm25_scores = bm25_cache[label]\n", + " retrieved_lists = hybrid_retrieve_cached(\n", + " base_retriever=base_retriever,\n", + " bm25_model=bm25_models[label],\n", + " texts=texts,\n", + " query_vectors=query_vectors,\n", + " bm25_scores=bm25_scores,\n", + " bm25_weight=weight,\n", + " top_k=5,\n", + " )\n", + " for item, retrieved in zip(\n", + " samples_by_label[label], retrieved_lists\n", + " ):\n", + " records.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"retrieved\": retrieved,\n", + " }\n", + " )\n", + " accuracy = compute_topk_accuracy(records)\n", + " pivot = accuracy.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + " ).sort_index()\n", + " pivot_lookup[(model_name, weight)] = pivot\n", + " overall = pivot.loc[\"OVERALL\"]\n", + " search_results.append(\n", + " {\n", + " \"model\": model_name,\n", + " \"bm25_weight\": weight,\n", + " \"top1\": overall.get(1, np.nan),\n", + " \"top3\": overall.get(3, np.nan),\n", + " \"top5\": overall.get(5, np.nan),\n", + " }\n", + " )\n", + "\n", + "search_df = pd.DataFrame(search_results)\n", + "\n", + "# Best weight per model by top-1 accuracy\n", + "best_rows = search_df.loc[\n", + " search_df.groupby(\"model\")[\"top1\"].idxmax()\n", + "].reset_index(drop=True)\n", + "best_pivots = {\n", + " row.model: pivot_lookup[(row.model, row.bm25_weight)]\n", + " for _, row in best_rows.iterrows()\n", + "}\n", + "\n", + "best_rows" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c3ade77d", + "metadata": {}, + "outputs": [], + "source": [ + "search_df" + ] + }, + { + "cell_type": "markdown", + "id": "23d4f97e", + "metadata": {}, + "source": [ + "### Hybrid (tuned BM25 + encoder) evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7323a3c", + "metadata": {}, + "outputs": [], + "source": [ + "# Evaluate hybrids at tuned BM25 weights\n", + "\n", + "tuned_records = {}\n", + "tuned_pivots = {}\n", + "\n", + "for row in best_rows.itertuples():\n", + " model_name = row.model\n", + " weight = row.bm25_weight\n", + " base_models = (\n", + " distiluse_models if model_name == \"DistilUSE\" else minilm_models\n", + " )\n", + "\n", + " records = []\n", + " for label, base_retriever in base_models.items():\n", + " texts = label_texts[label]\n", + " query_vectors = query_cache[model_name][label]\n", + " bm25_scores = bm25_cache[label]\n", + " retrieved_lists = hybrid_retrieve_cached(\n", + " base_retriever=base_retriever,\n", + " bm25_model=bm25_models[label],\n", + " texts=texts,\n", + " query_vectors=query_vectors,\n", + " bm25_scores=bm25_scores,\n", + " bm25_weight=weight,\n", + " top_k=5,\n", + " )\n", + " for item, retrieved in zip(samples_by_label[label], retrieved_lists):\n", + " records.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"retrieved\": retrieved,\n", + " }\n", + " )\n", + "\n", + " accuracy = compute_topk_accuracy(records)\n", + " pivot = accuracy.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + " ).sort_index()\n", + " tuned_records[model_name] = records\n", + " tuned_pivots[model_name] = pivot\n", + "\n", + "# Show tuned weights and overall performance\n", + "best_rows_display = best_rows.copy()\n", + "for model_name, pivot in tuned_pivots.items():\n", + " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top1\"] = (\n", + " pivot.loc[\"OVERALL\", 1]\n", + " )\n", + " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top3\"] = (\n", + " pivot.loc[\"OVERALL\", 3]\n", + " )\n", + " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top5\"] = (\n", + " pivot.loc[\"OVERALL\", 5]\n", + " )\n", + "\n", + "best_rows_display" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86348779", + "metadata": {}, + "outputs": [], + "source": [ + "# Full pipeline re-evaluation with evaluate_sentence_transformers at tuned weights\n", + "\n", + "best_weights = best_rows.set_index(\"model\")[\"bm25_weight\"].to_dict()\n", + "\n", + "# Build tuned hybrid retrievers (standard pipeline, no caching shortcuts)\n", + "tuned_hybrid_models = {\n", + " \"DistilUSE + BM25 tuned\": build_hybrid_sentence_transformer_models(\n", + " distiluse_models,\n", + " bm25_models,\n", + " bm25_weight=float(best_weights[\"DistilUSE\"]),\n", + " ),\n", + " \"MiniLM + BM25 tuned\": build_hybrid_sentence_transformer_models(\n", + " minilm_models, bm25_models, bm25_weight=float(best_weights[\"MiniLM\"])\n", + " ),\n", + "}\n", + "\n", + "# Run evaluation pipeline\n", + "attribution = {}\n", + "tuned_hybrid_records = {}\n", + "tuned_hybrid_accuracy = {}\n", + "tuned_hybrid_pivots = {}\n", + "\n", + "for name, models in tuned_hybrid_models.items():\n", + " records = evaluate_sentence_transformers(samples_by_label, models, top_k=5)\n", + " tuned_hybrid_records[name] = records\n", + " df = compute_topk_accuracy(records)\n", + " tuned_hybrid_accuracy[name] = df\n", + " tuned_hybrid_pivots[name] = df.pivot(\n", + " index=\"label\", columns=\"k\", values=\"accuracy\"\n", + " ).sort_index()\n", + "\n", + "# Overall comparison table including tuned hybrids\n", + "comparison_df_tuned = pd.DataFrame(\n", + " {\n", + " \"TensorFlow USEM\": baseline_accuracy_pivot.loc[\"OVERALL\"],\n", + " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"].loc[\n", + " \"OVERALL\"\n", + " ],\n", + " \"DistilUSE\": distiluse_accuracy_pivot.loc[\"OVERALL\"],\n", + " \"MiniLM\": minilm_accuracy_pivot.loc[\"OVERALL\"],\n", + " \"DistilUSE + BM25 tuned\": tuned_hybrid_pivots[\n", + " \"DistilUSE + BM25 tuned\"\n", + " ].loc[\"OVERALL\"],\n", + " \"MiniLM + BM25 tuned\": tuned_hybrid_pivots[\"MiniLM + BM25 tuned\"].loc[\n", + " \"OVERALL\"\n", + " ],\n", + " }\n", + ").T\n", + "\n", + "comparison_df_tuned.sort_values(by=1, ascending=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8bdb7199", + "metadata": {}, + "outputs": [], + "source": [ + "# Heatmaps per label for each model\n", + "pivot_map = {\n", + " \"TensorFlow USEM\": baseline_accuracy_pivot,\n", + " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"],\n", + " \"DistilUSE\": distiluse_accuracy_pivot,\n", + " \"MiniLM\": minilm_accuracy_pivot,\n", + " \"DistilUSE + BM25 tuned\": tuned_hybrid_pivots[\"DistilUSE + BM25 tuned\"],\n", + " \"MiniLM + BM25 tuned\": tuned_hybrid_pivots[\"MiniLM + BM25 tuned\"],\n", + "}\n", + "\n", + "labels_no_overall = [l for l in label_index]\n", + "\n", + "for name, pivot in pivot_map.items():\n", + " fig, ax = plt.subplots(figsize=(6, 4))\n", + " sns.heatmap(\n", + " pivot.loc[labels_no_overall],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " vmin=0,\n", + " vmax=1,\n", + " ax=ax,\n", + " )\n", + " ax.set_title(f\"{name} top-k accuracy by label\")\n", + " ax.set_xlabel(\"k\")\n", + " ax.set_ylabel(\"Label\")\n", + " plt.tight_layout()\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "961d15ad", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/sentence-encoders/03-sentence-transformer-subcategorizer-smoke.ipynb b/notebooks/experiments/sentence-encoders/03-sentence-transformer-subcategorizer-smoke.ipynb new file mode 100644 index 00000000..8b84293e --- /dev/null +++ b/notebooks/experiments/sentence-encoders/03-sentence-transformer-subcategorizer-smoke.ipynb @@ -0,0 +1,104 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "0364d1dd", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9ab7b227", + "metadata": {}, + "outputs": [], + "source": [ + "import tempfile\n", + "from pathlib import Path\n", + "\n", + "import numpy as np\n", + "\n", + "from aymurai.models.sentence_encoder.base import BaseSentenceEncoder\n", + "from aymurai.transforms.entity_subcategories.sentence_transformer import (\n", + " SentenceTransformerSubcategorizer,\n", + ")\n", + "\n", + "\n", + "class FakeEncoder(BaseSentenceEncoder):\n", + " def _vec(self, text: str) -> np.ndarray:\n", + " # Deterministic 8-dim vector from hash\n", + " h = abs(hash(text))\n", + " return np.array([(h >> i) & 0xFF for i in range(0, 64, 8)], dtype=np.float32)\n", + "\n", + " def encode(self, text_array, encoder_type, context_array=None):\n", + " return self.batch_encode(text_array, encoder_type)\n", + "\n", + " def batch_encode(self, text_array, encoder_type, batch_size: int = 256):\n", + " texts = list(text_array)\n", + " return np.vstack([self._vec(self.normalize_text(t)) for t in texts])\n", + "\n", + "\n", + "tmpdir = Path(tempfile.mkdtemp())\n", + "subcats_path = tmpdir / \"subcats.txt\"\n", + "subcats_path.write_text(\"\\n\".join([\"alpha\", \"beta\", \"gamma\"]))\n", + "\n", + "# BM25 + encoder path\n", + "hybrid_embeddings = tmpdir / \"embeddings_hybrid.npz\"\n", + "hybrid = SentenceTransformerSubcategorizer(\n", + " category=\"CONDUCTA\",\n", + " embeddings_path=str(hybrid_embeddings),\n", + " encoder_name=\"distiluse\",\n", + " bm25_weight=0.5,\n", + " encoder=FakeEncoder(),\n", + ")\n", + "print(hybrid.batch_retrieve([\"alpha case\", \"beta story\"], top_k=2))\n", + "\n", + "# Encoder-only path (bm25_weight = 0)\n", + "encoder_only_embeddings = tmpdir / \"embeddings_encoder_only.npz\"\n", + "encoder_only = SentenceTransformerSubcategorizer(\n", + " category=\"CONDUCTA\",\n", + " embeddings_path=str(encoder_only_embeddings),\n", + " encoder_name=\"distiluse\",\n", + " bm25_weight=0.0,\n", + " encoder=FakeEncoder(),\n", + " rebuild_embeddings=True,\n", + ")\n", + "print(encoder_only.batch_retrieve([\"gamma topic\"], top_k=2))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c3bf286", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb b/notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb new file mode 100644 index 00000000..83546815 --- /dev/null +++ b/notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb @@ -0,0 +1,420 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "7071ca80", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aacdfd29", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "from collections import defaultdict\n", + "from pathlib import Path\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "\n", + "from aymurai.transforms.entity_subcategories.sentence_transformer import (\n", + " SentenceTransformerSubcategorizer,\n", + ")\n", + "from aymurai.utils.json_data import load_json\n", + "\n", + "sns.set_theme(style=\"whitegrid\")\n", + "plt.rcParams.update(\n", + " {\"figure.figsize\": (10, 6), \"axes.titlesize\": 14, \"axes.labelsize\": 12}\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b102ccf", + "metadata": {}, + "outputs": [], + "source": [ + "# Config\n", + "pipeline_path = Path(\"/resources/pipelines/production/full-paragraph/pipeline.json\")\n", + "annotations_path = Path(\n", + " \"/resources/annotations/label-studio/resos-annotations/30-nov/project-3-at-2022-11-30-16-04-2b43bf39.json\"\n", + ")\n", + "target_labels = [\n", + " \"CONDUCTA\",\n", + " \"CONDUCTA_DESCRIPCION\",\n", + " \"DETALLE\",\n", + " \"OBJETO_DE_LA_RESOLUCION\",\n", + "]\n", + "encoder_name = \"distiluse\"\n", + "bm25_weight = 0.5 # use tuned default; set 0.0 for encoder-only\n", + "batch_size = 256\n", + "embeddings_dir = Path(\"/resources/cache/aymurai\")\n", + "embeddings_dir.mkdir(parents=True, exist_ok=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe9a836a", + "metadata": {}, + "outputs": [], + "source": [ + "def collect_label_annotations(annotations, target_labels):\n", + " buckets_by_label = defaultdict(list)\n", + " target_labels = set(target_labels)\n", + "\n", + " for task in annotations:\n", + " for annotation in task.get(\"annotations\", []):\n", + " merged = {}\n", + " for result in annotation.get(\"result\", []):\n", + " result_id = result.get(\"id\")\n", + " value = result.get(\"value\", {})\n", + " slot = merged.setdefault(\n", + " result_id,\n", + " {\n", + " \"text\": value.get(\"text\"),\n", + " \"start\": value.get(\"start\"),\n", + " \"end\": value.get(\"end\"),\n", + " \"labels\": [],\n", + " \"choices\": [],\n", + " },\n", + " )\n", + " slot[\"text\"] = slot[\"text\"] or value.get(\"text\")\n", + " slot[\"start\"] = (\n", + " slot[\"start\"] if slot[\"start\"] is not None else value.get(\"start\")\n", + " )\n", + " slot[\"end\"] = (\n", + " slot[\"end\"] if slot[\"end\"] is not None else value.get(\"end\")\n", + " )\n", + " slot[\"labels\"].extend(value.get(\"labels\", []))\n", + " slot[\"choices\"].extend(value.get(\"choices\", []))\n", + "\n", + " for payload in merged.values():\n", + " labels = [\n", + " label for label in payload[\"labels\"] if label in target_labels\n", + " ]\n", + " if not labels or payload[\"text\"] is None:\n", + " continue\n", + " item = {\n", + " \"text\": payload[\"text\"],\n", + " \"labels\": list(dict.fromkeys(payload[\"labels\"])),\n", + " \"choices\": list(dict.fromkeys(payload[\"choices\"])),\n", + " \"start\": payload[\"start\"],\n", + " \"end\": payload[\"end\"],\n", + " }\n", + " for label in labels:\n", + " buckets_by_label[label].append(item)\n", + " return {label: buckets_by_label.get(label, []) for label in target_labels}\n", + "\n", + "\n", + "def compute_topk_accuracy(records, ks=(1, 2, 3, 4, 5)):\n", + " metrics = []\n", + " labels = sorted({record[\"label\"] for record in records})\n", + " for label in labels:\n", + " label_records = [r for r in records if r[\"label\"] == label]\n", + " total = len(label_records)\n", + " for k in ks:\n", + " hits = sum(\n", + " any(choice in r[\"retrieved\"][:k] for choice in r[\"choices\"])\n", + " for r in label_records\n", + " )\n", + " metrics.append(\n", + " {\"label\": label, \"k\": k, \"accuracy\": hits / total if total else np.nan}\n", + " )\n", + " overall = []\n", + " for k in ks:\n", + " hits = sum(\n", + " any(choice in r[\"retrieved\"][:k] for choice in r[\"choices\"])\n", + " for r in records\n", + " )\n", + " overall.append(\n", + " {\n", + " \"label\": \"OVERALL\",\n", + " \"k\": k,\n", + " \"accuracy\": hits / len(records) if records else np.nan,\n", + " }\n", + " )\n", + " metrics.extend(overall)\n", + " return pd.DataFrame(metrics)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64556a79", + "metadata": {}, + "outputs": [], + "source": [ + "# Load annotations and collect samples\n", + "annotations = load_json(str(annotations_path))\n", + "samples_by_label = collect_label_annotations(annotations, target_labels)\n", + "# filter out empty-choice samples\n", + "for label in list(samples_by_label):\n", + " samples_by_label[label] = [s for s in samples_by_label[label] if s.get(\"choices\")]\n", + "\n", + "\n", + "def samples_to_dataframe(samples):\n", + " rows = []\n", + " for label, items in samples.items():\n", + " for item in items:\n", + " rows.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"n_choices\": len(item[\"choices\"]),\n", + " \"char_len\": len(item[\"text\"]),\n", + " }\n", + " )\n", + " return pd.DataFrame(rows)\n", + "\n", + "\n", + "samples_df = samples_to_dataframe(samples_by_label)\n", + "samples_df.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a93a2087", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract sentence-transformer config from pipeline (or fall back to targets)\n", + "with pipeline_path.open() as f:\n", + " pipeline_config = json.load(f)\n", + "\n", + "st_configs = {\n", + " config[1][\"category\"]: {\n", + " \"embeddings_path\": config[1].get(\"embeddings_path\"),\n", + " }\n", + " for config in pipeline_config.get(\"postprocess\", [])\n", + " if \"SentenceTransformerSubcategorizer\" in config[0]\n", + "}\n", + "\n", + "# Fallback: build configs from target_labels when pipeline does not define them\n", + "if not st_configs:\n", + " st_configs = {\n", + " label: {\"embeddings_path\": embeddings_dir / f\"{label.lower()}.npz\"}\n", + " for label in target_labels\n", + " }\n", + "\n", + "st_configs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8fdf84cf", + "metadata": {}, + "outputs": [], + "source": [ + "# Build sentence-transformer subcategorizer models (hybrid by default)\n", + "models = {}\n", + "for label, cfg in st_configs.items():\n", + " emb_path = cfg.get(\"embeddings_path\") or (embeddings_dir / f\"{label.lower()}.npz\")\n", + " models[label] = SentenceTransformerSubcategorizer(\n", + " category=label,\n", + " embeddings_path=str(emb_path),\n", + " encoder_name=encoder_name,\n", + " bm25_weight=bm25_weight,\n", + " batch_size=batch_size,\n", + " rebuild_embeddings=True,\n", + " )\n", + "list(models.keys())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e51e5b92", + "metadata": {}, + "outputs": [], + "source": [ + "# Re run to check loading existing embeddings\n", + "models = {}\n", + "for label, cfg in st_configs.items():\n", + " emb_path = cfg.get(\"embeddings_path\") or (embeddings_dir / f\"{label.lower()}.npz\")\n", + " models[label] = SentenceTransformerSubcategorizer(\n", + " category=label,\n", + " embeddings_path=str(emb_path),\n", + " encoder_name=encoder_name,\n", + " bm25_weight=bm25_weight,\n", + " batch_size=batch_size,\n", + " rebuild_embeddings=False,\n", + " )\n", + "list(models.keys())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a384a261", + "metadata": {}, + "outputs": [], + "source": [ + "# Evaluate\n", + "records = []\n", + "for label, items in samples_by_label.items():\n", + " retriever = models[label]\n", + " texts = [item[\"text\"] for item in items]\n", + " retrieved_lists = retriever.batch_retrieve(texts, top_k=5)\n", + " for item, retrieved in zip(items, retrieved_lists):\n", + " records.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"retrieved\": retrieved,\n", + " }\n", + " )\n", + "\n", + "accuracy_df = compute_topk_accuracy(records)\n", + "pivot = accuracy_df.pivot(index=\"label\", columns=\"k\", values=\"accuracy\").sort_index()\n", + "pivot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fdc73175", + "metadata": {}, + "outputs": [], + "source": [ + "# Heatmap\n", + "fig, ax = plt.subplots()\n", + "sns.heatmap(\n", + " pivot.loc[[l for l in pivot.index if l != \"OVERALL\"]],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"SentenceTransformerSubcategorizer (distiluse) top-k accuracy\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "pivot.loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1a99ad20", + "metadata": {}, + "outputs": [], + "source": [ + "encoder_name = \"minilm\"\n", + "\n", + "# Build sentence-transformer subcategorizer models (hybrid by default)\n", + "models = {}\n", + "for label, cfg in st_configs.items():\n", + " emb_path = cfg.get(\"embeddings_path\") or (embeddings_dir / f\"{label.lower()}.npz\")\n", + " models[label] = SentenceTransformerSubcategorizer(\n", + " category=label,\n", + " embeddings_path=str(emb_path),\n", + " encoder_name=encoder_name,\n", + " bm25_weight=bm25_weight,\n", + " batch_size=batch_size,\n", + " rebuild_embeddings=True,\n", + " )\n", + "list(models.keys())" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5c8bf7e", + "metadata": {}, + "outputs": [], + "source": [ + "# Evaluate\n", + "records = []\n", + "for label, items in samples_by_label.items():\n", + " retriever = models[label]\n", + " texts = [item[\"text\"] for item in items]\n", + " retrieved_lists = retriever.batch_retrieve(texts, top_k=5)\n", + " for item, retrieved in zip(items, retrieved_lists):\n", + " records.append(\n", + " {\n", + " \"label\": label,\n", + " \"text\": item[\"text\"],\n", + " \"choices\": item[\"choices\"],\n", + " \"retrieved\": retrieved,\n", + " }\n", + " )\n", + "\n", + "accuracy_df = compute_topk_accuracy(records)\n", + "pivot = accuracy_df.pivot(index=\"label\", columns=\"k\", values=\"accuracy\").sort_index()\n", + "pivot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e3700072", + "metadata": {}, + "outputs": [], + "source": [ + "# Heatmap\n", + "fig, ax = plt.subplots()\n", + "sns.heatmap(\n", + " pivot.loc[[l for l in pivot.index if l != \"OVERALL\"]],\n", + " annot=True,\n", + " fmt=\".2f\",\n", + " cmap=\"YlGnBu\",\n", + " ax=ax,\n", + ")\n", + "ax.set_title(\"SentenceTransformerSubcategorizer (minilm) top-k accuracy\")\n", + "ax.set_xlabel(\"k\")\n", + "ax.set_ylabel(\"Label\")\n", + "plt.tight_layout()\n", + "plt.show()\n", + "\n", + "pivot.loc[[\"OVERALL\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9c46485", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/subcategories/00-exploration.ipynb b/notebooks/experiments/subcategories/00-exploration.ipynb index f29849cc..348323b0 100644 --- a/notebooks/experiments/subcategories/00-exploration.ipynb +++ b/notebooks/experiments/subcategories/00-exploration.ipynb @@ -31,6 +31,7 @@ "outputs": [], "source": [ "import os\n", + "\n", "os.environ[\"TF_CPP_MIN_LOG_LEVEL\"] = \"3\"" ] }, @@ -77,13 +78,13 @@ "metadata": {}, "outputs": [], "source": [ - "from aymurai.spacy.display import DocRender\n", - "from aymurai.datasets.ar_juz_pcyf_10.docs import ArgentinaJuzgadoPCyF10DocsDataset\n", + "from aymurai.datasets.ar_juz_pcyf_10.docs import (\n", + " ArgentinaJuzgadoPCyF10DocsDataset,\n", + ")\n", "from aymurai.datasets.ar_juz_pcyf_10.annotations import (\n", " ArgentinaJuzgadoPCyF10LabelStudioAnnotations,\n", ")\n", "\n", - "render = DocRender()\n", "docs = ArgentinaJuzgadoPCyF10LabelStudioAnnotations(\n", " \"/resources/data/restricted/annotations/20221130-bis/\"\n", ").data\n", @@ -772,13 +773,13 @@ "metadata": {}, "outputs": [], "source": [ - "with open('./conduct_options.txt', 'r') as file:\n", + "with open(\"./conduct_options.txt\", \"r\") as file:\n", " conduct_categories = file.read().splitlines()\n", - "with open('./conduct_desc_options.txt', 'r') as file:\n", + "with open(\"./conduct_desc_options.txt\", \"r\") as file:\n", " conduct_desc_categories = file.read().splitlines()\n", - "with open('./detail_options.txt', 'r') as file:\n", + "with open(\"./detail_options.txt\", \"r\") as file:\n", " detail_categories = file.read().splitlines()\n", - "with open('./object_options.txt', 'r') as file:\n", + "with open(\"./object_options.txt\", \"r\") as file:\n", " object_categories = file.read().splitlines()" ] }, @@ -801,7 +802,10 @@ "from aymurai.models.flair.core import FlairModel\n", "from aymurai.models.flair.utils import FlairTextNormalize\n", "from aymurai.transforms.entity_subcategories.regex import RegexSubcategorizer\n", - "from aymurai.transforms.entity_subcategories.usem import USEMSubcategorizePipeline, USEMSubcategorizer\n", + "from aymurai.transforms.entity_subcategories.usem import (\n", + " USEMSubcategorizePipeline,\n", + " USEMSubcategorizer,\n", + ")\n", "\n", "config = {\n", " \"preprocess\": [\n", @@ -821,39 +825,39 @@ " (RegexSubcategorizer, {}),\n", " (\n", " USEMSubcategorizer,\n", - " {\n", - " \"category\": \"CONDUCTA\",\n", - " # \"subcategories\": conduct_categories,\n", - " \"subcategories_path\": './conduct_options.txt',\n", - " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/conduct_embeddings.npy\",\n", - " }\n", + " {\n", + " \"category\": \"CONDUCTA\",\n", + " # \"subcategories\": conduct_categories,\n", + " \"subcategories_path\": \"./conduct_options.txt\",\n", + " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/conduct_embeddings.npy\",\n", + " },\n", " ),\n", " (\n", " USEMSubcategorizer,\n", - " {\n", - " \"category\": \"CONDUCTA_DESCRIPCION\",\n", - " # \"subcategories\": conduct_descr_categories,\n", - " \"subcategories_path\": './conduct_desc_options.txt',\n", - " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/conduct_descr_embeddings.npy\",\n", - " }\n", + " {\n", + " \"category\": \"CONDUCTA_DESCRIPCION\",\n", + " # \"subcategories\": conduct_descr_categories,\n", + " \"subcategories_path\": \"./conduct_desc_options.txt\",\n", + " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/conduct_descr_embeddings.npy\",\n", + " },\n", " ),\n", " (\n", " USEMSubcategorizer,\n", - " {\n", - " \"category\": \"DETALLE\",\n", - " # \"subcategories\": detail_categories,\n", - " \"subcategories_path\": './detail_options.txt',\n", - " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/detail_embeddings.npy\",\n", - " }\n", + " {\n", + " \"category\": \"DETALLE\",\n", + " # \"subcategories\": detail_categories,\n", + " \"subcategories_path\": \"./detail_options.txt\",\n", + " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/detail_embeddings.npy\",\n", + " },\n", " ),\n", " (\n", " USEMSubcategorizer,\n", - " {\n", - " \"category\": \"OBJETO_DE_LA_RESOLUCION\",\n", - " \"subcategories_path\": './object_options.txt',\n", - " # \"subcategories\": object_categories,\n", - " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/object_embeddings.npy\",\n", - " }\n", + " {\n", + " \"category\": \"OBJETO_DE_LA_RESOLUCION\",\n", + " \"subcategories_path\": \"./object_options.txt\",\n", + " # \"subcategories\": object_categories,\n", + " \"response_embeddings_path\": \"/resources/pipelines/examples/flair-simple/UsemEmbeddings/object_embeddings.npy\",\n", + " },\n", " ),\n", " ],\n", " # \"multiprocessing\": {},\n", @@ -871,7 +875,7 @@ "source": [ "pipeline = AymurAIPipeline(config)\n", "results = pipeline.preprocess(sample[:1])\n", - "results = pipeline.predict(results)\n" + "results = pipeline.predict(results)" ] }, { @@ -881,7 +885,6 @@ "metadata": {}, "outputs": [], "source": [ - "\n", "pp = pipeline.postprocess(results)" ] }, @@ -948,7 +951,7 @@ "# # \"multiprocessing\": {},\n", "# \"use_cache\": False,\n", "# # 'log_level': 'debug'\n", - "# }\n" + "# }" ] }, { @@ -959,7 +962,7 @@ "outputs": [], "source": [ "# pipeline = AymurAIPipeline(config)\n", - "# " + "#" ] }, { @@ -969,9 +972,8 @@ "metadata": {}, "outputs": [], "source": [ - "\n", "# preprocess = pipeline.preprocess(sample)\n", - "# results = pipeline.predict(preprocess)\n" + "# results = pipeline.predict(preprocess)" ] }, { @@ -981,7 +983,7 @@ "metadata": {}, "outputs": [], "source": [ - "# \n", + "#\n", "postprocess = pipeline.postprocess(results)" ] }, @@ -1029,7 +1031,11 @@ "outputs": [], "source": [ "for label in [\"VIOLENCIA_DE_GENERO\"]:\n", - " __ = [_ for _ in results[idx][\"predictions\"][\"entities\"] if _[\"label\"] == label]\n", + " __ = [\n", + " _\n", + " for _ in results[idx][\"predictions\"][\"entities\"]\n", + " if _[\"label\"] == label\n", + " ]\n", " print(label)\n", " display(__)\n", " print(\"\\n\\n\")" @@ -1044,8 +1050,17 @@ }, "outputs": [], "source": [ - "for label in [\"CONDUCTA\", \"CONDUCTA_DESCRIPCION\", \"DETALLE\", \"OBJETO_DE_LA_RESOLUCION\"]:\n", - " __ = [_ for _ in results[idx][\"predictions\"][\"entities\"] if _[\"label\"] == label]\n", + "for label in [\n", + " \"CONDUCTA\",\n", + " \"CONDUCTA_DESCRIPCION\",\n", + " \"DETALLE\",\n", + " \"OBJETO_DE_LA_RESOLUCION\",\n", + "]:\n", + " __ = [\n", + " _\n", + " for _ in results[idx][\"predictions\"][\"entities\"]\n", + " if _[\"label\"] == label\n", + " ]\n", " print(label)\n", " display(__)\n", " print(\"\\n\\n\")" @@ -1068,8 +1083,9 @@ "source": [ "import re\n", "import pandas as pd\n", + "\n", "pd.set_option(\"display.max_rows\", 500)\n", - "pd.set_option('max_colwidth', 400)" + "pd.set_option(\"max_colwidth\", 400)" ] }, { @@ -1080,7 +1096,7 @@ "outputs": [], "source": [ "path = \"/resources/ner/flair/resos-20221130-no-decision/\"\n", - "df = pd.read_csv(path+\"train.txt\", sep=\"\\s\", header=None)\n", + "df = pd.read_csv(path + \"train.txt\", sep=\"\\s\", header=None)\n", "df.columns = [\"token\", \"label\"]\n", "df.head()" ] @@ -1127,7 +1143,7 @@ "\n", "def normalize_text(text: str) -> str:\n", " text = unidecode.unidecode(text.lower())\n", - " text = re.sub(r'[_\\-,.;:]+', '', text)\n", + " text = re.sub(r\"[_\\-,.;:]+\", \"\", text)\n", " return text" ] }, @@ -1167,7 +1183,7 @@ "\n", " if len(output_dict[\"choices\"]) == 1:\n", " output_dict[\"choices\"] = output_dict[\"choices\"][0]\n", - " \n", + "\n", " return output_dict" ] }, @@ -1190,8 +1206,10 @@ "outputs": [], "source": [ "viol_gen = [\n", - " pred_ent for pred_ent in pred_ents if pred_ent[\"label\"] == \"VIOLENCIA_DE_GENERO\"\n", - "]\n" + " pred_ent\n", + " for pred_ent in pred_ents\n", + " if pred_ent[\"label\"] == \"VIOLENCIA_DE_GENERO\"\n", + "]" ] }, { @@ -1240,8 +1258,8 @@ " for violence_type, pattern in violence_type_patterns.items():\n", " if re.search(pattern, normalized_pred):\n", " found_types.add(violence_type)\n", - " \n", - " return list(found_types)\n" + "\n", + " return list(found_types)" ] }, { @@ -1455,7 +1473,7 @@ " if re.search(pattern, normalized_pred):\n", " found_modalities.add(modality)\n", "\n", - " return list(found_modalities)\n" + " return list(found_modalities)" ] }, { @@ -1582,7 +1600,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"RELACION_Y_TIPO_ENTRE_ACUSADO/A_Y_DENUNCIANTE\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -1596,7 +1614,9 @@ "source": [ "relationship_choices = []\n", "for sample in annots:\n", - " relationship = list(filter(filter_relationship_choices, sample[\"annotations\"][0][\"result\"]))\n", + " relationship = list(\n", + " filter(filter_relationship_choices, sample[\"annotations\"][0][\"result\"])\n", + " )\n", " relationship_choices.extend(relationship)" ] }, @@ -1718,7 +1738,7 @@ "source": [ "def find_relationship_type(pred: str) -> list:\n", " normalized_pred = normalize_text(pred)\n", - " \n", + "\n", " relationship_type_patterns = {\n", " \"familiar\": r\"(?:familiar?|hij[ao]s?|[mp]adres?|herman[ao]s?)\",\n", " \"pareja\": r\"(? list:\n", " normalized_pred = normalize_text(pred)\n", - " \n", + "\n", " resolution_type_patterns = {\n", " \"interlocutoria\": r\"interlocut[oa]ria\",\n", " \"definitiva\": r\"definitiv[ao]\",\n", " }\n", - " \n", + "\n", " found_types = set()\n", - " \n", + "\n", " for res_type, pattern in resolution_type_patterns.items():\n", " if re.search(pattern, normalized_pred):\n", " found_types.add(res_type)\n", - " \n", + "\n", " return list(found_types)" ] }, @@ -2058,7 +2080,9 @@ }, "outputs": [], "source": [ - "resolution_texts.loc[(resolution_texts[\"types\"].map(len) == 0)].sort_values(\"text\")" + "resolution_texts.loc[(resolution_texts[\"types\"].map(len) == 0)].sort_values(\n", + " \"text\"\n", + ")" ] }, { @@ -2149,7 +2173,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"NIVEL_INSTRUCCION_CAT\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -2163,7 +2187,9 @@ "source": [ "education_choices = []\n", "for sample in annots:\n", - " education = list(filter(filter_education_choices, sample[\"annotations\"][0][\"result\"]))\n", + " education = list(\n", + " filter(filter_education_choices, sample[\"annotations\"][0][\"result\"])\n", + " )\n", " education_choices.extend(education)" ] }, @@ -2273,7 +2299,7 @@ "source": [ "def find_education_level(pred: str) -> list:\n", " normalized_pred = normalize_text(pred)\n", - " \n", + "\n", " education_level_patterns = {\n", " # \"sin_instruccion\": r\"\",\n", " \"sin_escolarizar\": r\"(?:no (?:posee|termino)|sin).+estudios?\",\n", @@ -2290,13 +2316,13 @@ " \"universitario_completo\": r\"(?:universitari[ao]s? (?!in)complet[ao]s?|(? 0)].drop_duplicates(\"text\")" + "education_texts.loc[(education_texts[\"types\"].map(len) > 0)].drop_duplicates(\n", + " \"text\"\n", + ")" ] }, { @@ -2348,7 +2376,9 @@ }, "outputs": [], "source": [ - "education_texts.loc[(education_texts[\"types\"].map(len) == 0)].sort_values(\"text\")" + "education_texts.loc[(education_texts[\"types\"].map(len) == 0)].sort_values(\n", + " \"text\"\n", + ")" ] }, { @@ -2360,7 +2390,9 @@ }, "outputs": [], "source": [ - "education_texts.loc[(education_texts[\"types\"].map(len) > 1)].sort_values(\"text\")" + "education_texts.loc[(education_texts[\"types\"].map(len) > 1)].sort_values(\n", + " \"text\"\n", + ")" ] }, { @@ -2450,7 +2482,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"GENERO_CAT\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -2464,7 +2496,9 @@ "source": [ "gender_choices = []\n", "for sample in annots:\n", - " gender = list(filter(filter_gender_choices, sample[\"annotations\"][0][\"result\"]))\n", + " gender = list(\n", + " filter(filter_gender_choices, sample[\"annotations\"][0][\"result\"])\n", + " )\n", " gender_choices.extend(gender)" ] }, @@ -2574,7 +2608,7 @@ "source": [ "def find_gender(pred: str) -> list:\n", " normalized_pred = normalize_text(pred)\n", - " \n", + "\n", " gender_patterns = {\n", " \"varon_cis\": r\"varon(?:es)? cis\",\n", " \"mujer_cis\": r\"mujer(?:es)? cis\",\n", @@ -2583,13 +2617,13 @@ " \"travesti\": r\"travesti\",\n", " \"no_binaria\": r\"no ?binari[aoex]\",\n", " }\n", - " \n", + "\n", " found_gender = set()\n", - " \n", + "\n", " for gender, pattern in gender_patterns.items():\n", " if re.search(pattern, normalized_pred):\n", " found_gender.add(gender)\n", - " \n", + "\n", " return list(found_gender)" ] }, @@ -2695,7 +2729,9 @@ "metadata": {}, "outputs": [], "source": [ - "not_determined[\"beginning\"] = not_determined[\"label\"].str.startswith(\"B\").astype(int)\n", + "not_determined[\"beginning\"] = (\n", + " not_determined[\"label\"].str.startswith(\"B\").astype(int)\n", + ")\n", "not_determined.head(10)" ] }, @@ -2743,7 +2779,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"PERSONA_ACUSADA_NO_DETERMINADA\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -2757,7 +2793,11 @@ "source": [ "not_determined_choices = []\n", "for sample in annots:\n", - " not_determined = list(filter(filter_not_determined_choices, sample[\"annotations\"][0][\"result\"]))\n", + " not_determined = list(\n", + " filter(\n", + " filter_not_determined_choices, sample[\"annotations\"][0][\"result\"]\n", + " )\n", + " )\n", " not_determined_choices.extend(not_determined)" ] }, @@ -2869,7 +2909,7 @@ "source": [ "def find_gender(pred: str) -> list:\n", " normalized_pred = normalize_text(pred)\n", - " \n", + "\n", " gender_patterns = {\n", " \"varon_cis\": r\"varon(?:es)? cis\",\n", " \"mujer_cis\": r\"mujer(?:es)? cis\",\n", @@ -2878,13 +2918,13 @@ " \"travesti\": r\"travesti\",\n", " \"no_binaria\": r\"no ?binari[aoex]\",\n", " }\n", - " \n", + "\n", " found_gender = set()\n", - " \n", + "\n", " for gender, pattern in gender_patterns.items():\n", " if re.search(pattern, normalized_pred):\n", " found_gender.add(gender)\n", - " \n", + "\n", " return list(found_gender)" ] }, @@ -3038,7 +3078,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"CONDUCTA\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -3052,7 +3092,9 @@ "source": [ "conduct_choices = []\n", "for sample in annots:\n", - " conduct = list(filter(filter_conduct_choices, sample[\"annotations\"][0][\"result\"]))\n", + " conduct = list(\n", + " filter(filter_conduct_choices, sample[\"annotations\"][0][\"result\"])\n", + " )\n", " conduct_choices.extend(conduct)" ] }, @@ -3091,7 +3133,7 @@ " group_key=\"choices\",\n", " sort_key=\"choices\",\n", " )\n", - ")\n" + ")" ] }, { @@ -3389,7 +3431,7 @@ " \"violar_inhabilitacion_para_conducir\",\n", " \"violar_reglamentacion_juego\",\n", " \"zanjas_y_pozos_en_via_publica\",\n", - "]\n" + "]" ] }, { @@ -3425,7 +3467,7 @@ "# categories_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(categories))\n", "\n", "categories_embeddings = usem_qa.signatures[\"response_encoder\"](\n", - " input=tf.constant(categories), context=tf.constant(categories)\n", + " input=tf.constant(categories), context=tf.constant(categories)\n", ")\n", "\n", "# categories_embeddings = usem(categories)" @@ -3480,7 +3522,7 @@ "metadata": {}, "outputs": [], "source": [ - "#texts_embeddings = usem(texts)\n", + "# texts_embeddings = usem(texts)\n", "# texts_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(texts))" ] }, @@ -3543,7 +3585,7 @@ " top_3_similar = similarities.loc[text].sort_values(ascending=False)[:3]\n", " print(text)\n", " display(top_3_similar)\n", - " print(\"=\"*100)" + " print(\"=\" * 100)" ] }, { @@ -3553,13 +3595,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -3610,8 +3662,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -3653,8 +3709,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -3686,8 +3746,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -3729,13 +3793,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -3786,8 +3860,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -3829,8 +3907,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -3862,8 +3944,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -3905,13 +3991,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -3962,8 +4058,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -4005,8 +4105,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -4038,8 +4142,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -4081,13 +4189,21 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", " text_embeddings = usem([normalized_text])\n", - " similarities = np.inner(text_embeddings.numpy(), conduct_embeddings.numpy())\n", + " similarities = np.inner(\n", + " text_embeddings.numpy(), conduct_embeddings.numpy()\n", + " )\n", " top_k = np.ravel(np.argsort(-similarities))[:k]\n", - " \n", - " return np.array([categories])[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array([categories])[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -4128,8 +4244,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -4415,7 +4535,7 @@ " if re.search(pattern, normalized_pred):\n", " found_types.add(modality)\n", "\n", - " return list(found_types)\n" + " return list(found_types)" ] }, { @@ -4490,7 +4610,9 @@ "metadata": {}, "outputs": [], "source": [ - "conduct_desc[\"beginning\"] = conduct_desc[\"label\"].str.startswith(\"B\").astype(int)\n", + "conduct_desc[\"beginning\"] = (\n", + " conduct_desc[\"label\"].str.startswith(\"B\").astype(int)\n", + ")\n", "conduct_desc.head(10)" ] }, @@ -4538,7 +4660,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"CONDUCTA_DESCRIPCION\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -4552,7 +4674,9 @@ "source": [ "conduct_desc_choices = []\n", "for sample in annots:\n", - " conduct_desc = list(filter(filter_conduct_desc_choices, sample[\"annotations\"][0][\"result\"]))\n", + " conduct_desc = list(\n", + " filter(filter_conduct_desc_choices, sample[\"annotations\"][0][\"result\"])\n", + " )\n", " conduct_desc_choices.extend(conduct_desc)" ] }, @@ -4591,7 +4715,7 @@ " group_key=\"choices\",\n", " sort_key=\"choices\",\n", " )\n", - ")\n" + ")" ] }, { @@ -4789,7 +4913,7 @@ "# categories_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(categories))\n", "\n", "categories_embeddings = usem_qa.signatures[\"response_encoder\"](\n", - " input=tf.constant(categories) , context=tf.constant(categories)\n", + " input=tf.constant(categories), context=tf.constant(categories)\n", ")\n", "\n", "# categories_embeddings = usem(categories)" @@ -4802,7 +4926,9 @@ "metadata": {}, "outputs": [], "source": [ - "np.save(\"conduct_descr_embeddings.npy\", categories_embeddings[\"outputs\"].numpy())" + "np.save(\n", + " \"conduct_descr_embeddings.npy\", categories_embeddings[\"outputs\"].numpy()\n", + ")" ] }, { @@ -4854,8 +4980,10 @@ "metadata": {}, "outputs": [], "source": [ - "#texts_embeddings = usem(texts)\n", - "texts_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(texts))" + "# texts_embeddings = usem(texts)\n", + "texts_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(texts)\n", + ")" ] }, { @@ -4867,7 +4995,9 @@ }, "outputs": [], "source": [ - "similarities = np.inner(texts_embeddings[\"outputs\"], categories_embeddings[\"outputs\"])\n", + "similarities = np.inner(\n", + " texts_embeddings[\"outputs\"], categories_embeddings[\"outputs\"]\n", + ")\n", "similarities = pd.DataFrame(similarities, index=texts, columns=categories)\n", "similarities" ] @@ -4885,7 +5015,7 @@ " top_3_similar = similarities.loc[text].sort_values(ascending=False)[:3]\n", " print(text)\n", " display(top_3_similar)\n", - " print(\"=\"*100)" + " print(\"=\" * 100)" ] }, { @@ -4895,13 +5025,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -4952,8 +5092,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -4995,8 +5139,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -5028,8 +5176,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -5071,7 +5223,9 @@ "metadata": {}, "outputs": [], "source": [ - "categories_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(categories))" + "categories_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(categories)\n", + ")" ] }, { @@ -5081,13 +5235,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -5138,8 +5302,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -5181,8 +5349,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -5214,8 +5386,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -5257,13 +5433,21 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", " text_embeddings = usem([normalized_text])\n", - " similarities = np.inner(text_embeddings.numpy(), conduct_embeddings.numpy())\n", + " similarities = np.inner(\n", + " text_embeddings.numpy(), conduct_embeddings.numpy()\n", + " )\n", " top_k = np.ravel(np.argsort(-similarities))[:k]\n", - " \n", - " return np.array([categories])[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array([categories])[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -5304,8 +5488,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -5591,7 +5779,7 @@ " if re.search(pattern, normalized_pred):\n", " found_types.add(modality)\n", "\n", - " return list(found_types)\n" + " return list(found_types)" ] }, { @@ -5714,7 +5902,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"DETALLE\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -5728,7 +5916,9 @@ "source": [ "detail_choices = []\n", "for sample in annots:\n", - " detail = list(filter(filter_detail_choices, sample[\"annotations\"][0][\"result\"]))\n", + " detail = list(\n", + " filter(filter_detail_choices, sample[\"annotations\"][0][\"result\"])\n", + " )\n", " detail_choices.extend(detail)" ] }, @@ -6170,7 +6360,7 @@ "# categories_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(categories))\n", "\n", "categories_embeddings = usem_qa.signatures[\"response_encoder\"](\n", - " input=tf.constant(categories) , context=tf.constant(categories)\n", + " input=tf.constant(categories), context=tf.constant(categories)\n", ")\n", "\n", "# categories_embeddings = usem(categories)" @@ -6235,8 +6425,10 @@ "metadata": {}, "outputs": [], "source": [ - "#texts_embeddings = usem(texts)\n", - "texts_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(texts))" + "# texts_embeddings = usem(texts)\n", + "texts_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(texts)\n", + ")" ] }, { @@ -6248,7 +6440,9 @@ }, "outputs": [], "source": [ - "similarities = np.inner(texts_embeddings[\"outputs\"], categories_embeddings[\"outputs\"])\n", + "similarities = np.inner(\n", + " texts_embeddings[\"outputs\"], categories_embeddings[\"outputs\"]\n", + ")\n", "similarities = pd.DataFrame(similarities, index=texts, columns=categories)\n", "similarities" ] @@ -6266,7 +6460,7 @@ " top_3_similar = similarities.loc[text].sort_values(ascending=False)[:3]\n", " print(text)\n", " display(top_3_similar)\n", - " print(\"=\"*100)" + " print(\"=\" * 100)" ] }, { @@ -6276,13 +6470,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -6333,8 +6537,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -6376,8 +6584,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -6409,8 +6621,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -6452,7 +6668,9 @@ "metadata": {}, "outputs": [], "source": [ - "categories_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(categories))" + "categories_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(categories)\n", + ")" ] }, { @@ -6462,13 +6680,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -6519,8 +6747,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -6562,8 +6794,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -6595,8 +6831,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -6638,13 +6878,21 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", " text_embeddings = usem([normalized_text])\n", - " similarities = np.inner(text_embeddings.numpy(), conduct_embeddings.numpy())\n", + " similarities = np.inner(\n", + " text_embeddings.numpy(), conduct_embeddings.numpy()\n", + " )\n", " top_k = np.ravel(np.argsort(-similarities))[:k]\n", - " \n", - " return np.array([categories])[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array([categories])[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -6685,8 +6933,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -6808,7 +7060,7 @@ " from_name = annot[\"from_name\"]\n", " if from_name == \"OBJETO_DE_LA_RESOLUCION\":\n", " return True\n", - " \n", + "\n", " except:\n", " return False" ] @@ -6822,7 +7074,9 @@ "source": [ "res_object_choices = []\n", "for sample in annots:\n", - " res_object = list(filter(filter_res_object_choices, sample[\"annotations\"][0][\"result\"]))\n", + " res_object = list(\n", + " filter(filter_res_object_choices, sample[\"annotations\"][0][\"result\"])\n", + " )\n", " res_object_choices.extend(res_object)" ] }, @@ -7012,7 +7266,7 @@ "# categories_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(categories))\n", "\n", "categories_embeddings = usem_qa.signatures[\"response_encoder\"](\n", - " input=tf.constant(categories) , context=tf.constant(categories)\n", + " input=tf.constant(categories), context=tf.constant(categories)\n", ")\n", "\n", "# categories_embeddings = usem(categories)" @@ -7077,8 +7331,10 @@ "metadata": {}, "outputs": [], "source": [ - "#texts_embeddings = usem(texts)\n", - "texts_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(texts))" + "# texts_embeddings = usem(texts)\n", + "texts_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(texts)\n", + ")" ] }, { @@ -7090,7 +7346,9 @@ }, "outputs": [], "source": [ - "similarities = np.inner(texts_embeddings[\"outputs\"], categories_embeddings[\"outputs\"])\n", + "similarities = np.inner(\n", + " texts_embeddings[\"outputs\"], categories_embeddings[\"outputs\"]\n", + ")\n", "similarities = pd.DataFrame(similarities, index=texts, columns=categories)\n", "similarities" ] @@ -7108,7 +7366,7 @@ " top_3_similar = similarities.loc[text].sort_values(ascending=False)[:3]\n", " print(text)\n", " display(top_3_similar)\n", - " print(\"=\"*100)" + " print(\"=\" * 100)" ] }, { @@ -7118,13 +7376,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -7165,8 +7433,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -7208,8 +7480,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -7241,8 +7517,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -7284,7 +7564,9 @@ "metadata": {}, "outputs": [], "source": [ - "categories_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(categories))" + "categories_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(categories)\n", + ")" ] }, { @@ -7294,13 +7576,23 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", - " text_embeddings = usem_qa.signatures[\"question_encoder\"](input=tf.constant(normalized_text))\n", - " similarities = np.inner(text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"])\n", + " text_embeddings = usem_qa.signatures[\"question_encoder\"](\n", + " input=tf.constant(normalized_text)\n", + " )\n", + " similarities = np.inner(\n", + " text_embeddings[\"outputs\"], conduct_embeddings[\"outputs\"]\n", + " )\n", " top_k = np.argsort(np.ravel(-similarities))[:k]\n", - " \n", - " return np.array(categories)[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array(categories)[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -7351,8 +7643,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=2))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=2)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -7394,8 +7690,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -7427,8 +7727,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=5))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=5)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -7470,13 +7774,21 @@ "metadata": {}, "outputs": [], "source": [ - "def find_top_k_similar(text, conduct_embeddings=categories_embeddings, categories=categories, k=1):\n", + "def find_top_k_similar(\n", + " text, conduct_embeddings=categories_embeddings, categories=categories, k=1\n", + "):\n", " normalized_text = normalize_text(text)\n", " text_embeddings = usem([normalized_text])\n", - " similarities = np.inner(text_embeddings.numpy(), conduct_embeddings.numpy())\n", + " similarities = np.inner(\n", + " text_embeddings.numpy(), conduct_embeddings.numpy()\n", + " )\n", " top_k = np.ravel(np.argsort(-similarities))[:k]\n", - " \n", - " return np.array([categories])[top_k][0] if k == 1 else np.array(categories)[top_k]" + "\n", + " return (\n", + " np.array([categories])[top_k][0]\n", + " if k == 1\n", + " else np.array(categories)[top_k]\n", + " )" ] }, { @@ -7517,8 +7829,12 @@ "metadata": {}, "outputs": [], "source": [ - "grouped[\"pred_choices\"] = grouped[\"text\"].map(lambda x: find_top_k_similar(x, k=3))\n", - "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(lambda x: [string.replace(\" \", \"_\") for string in x])" + "grouped[\"pred_choices\"] = grouped[\"text\"].map(\n", + " lambda x: find_top_k_similar(x, k=3)\n", + ")\n", + "grouped[\"pred_choices\"] = grouped[\"pred_choices\"].map(\n", + " lambda x: [string.replace(\" \", \"_\") for string in x]\n", + ")" ] }, { @@ -7580,7 +7896,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "aymurai (3.10.19)", "language": "python", "name": "python3" }, @@ -7594,12 +7910,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8 (main, Oct 12 2022, 19:14:26) [GCC 9.4.0]" - }, - "vscode": { - "interpreter": { - "hash": "e7370f93d1d0cde622a1f8e1c04877d8463912d04d973331ad4851f04de6915a" - } + "version": "3.10.19" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index 37d72eb0..94e817e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,7 +55,6 @@ dependencies = [ "numpy<2.0.0", "more-itertools>=10.5.0", "odfpy>=1.4.1", - "gdown==4.6.0", "joblib>=1.4.2", "datetime_matcher @ git+https://github.com/jedzill4/datetime_matcher", "jiwer==3.0.5", @@ -75,13 +74,11 @@ dependencies = [ "scipy<1.14.1", "torch>=1.13.1", "pytorch-lightning==1.8.3.post1", - "tensorflow_text==2.10.0; sys_platform == 'linux' or (sys_platform == 'darwin' and platform_machine == 'x86_64') or sys_platform == 'win32'", # no ARM64 macOS wheels "psutil==6.1.0", "sqlmodel==0.0.22", "alembic>=1.13.3", "tenacity>=9.0.0", "python-dotenv>=1.0.1", - "tensorflow-hub>=0.16.1", "sentence-transformers>=2.2.0", "pymupdf>=1.25.2", "pymupdf4llm>=0.0.17", diff --git a/resources/pipelines/production/full-paragraph/pipeline.json b/resources/pipelines/production/full-paragraph/pipeline.json index b3636d2a..b5da2f9e 100644 --- a/resources/pipelines/production/full-paragraph/pipeline.json +++ b/resources/pipelines/production/full-paragraph/pipeline.json @@ -26,39 +26,35 @@ {} ], [ - "aymurai.transforms.entity_subcategories.usem.USEMSubcategorizer", + "aymurai.transforms.entity_subcategories.sentence_transformer.SentenceTransformerSubcategorizer", { "category": "CONDUCTA", - "subcategories_path": "https://drive.google.com/uc?id=1Vj5BxyeHzDnR1T8jYjLuteM3YwzE7fTW&confirm=true", - "response_embeddings_path": "https://drive.google.com/uc?id=1zvBHGf1MeFyyG_I0TukJl1eaM-7TsbPF&confirm=true", - "device": "/cpu:0" + "embeddings_path": "conducta.npz", + "device": "cpu" } ], [ - "aymurai.transforms.entity_subcategories.usem.USEMSubcategorizer", + "aymurai.transforms.entity_subcategories.sentence_transformer.SentenceTransformerSubcategorizer", { "category": "CONDUCTA_DESCRIPCION", - "subcategories_path": "https://drive.google.com/uc?id=1A1I9xwzvynwxSv1I0SDHhN216Z3Yvoqj&confirm=true", - "response_embeddings_path": "https://drive.google.com/uc?id=1c3nYVDIq23kYqgMIIKGtDbIz6zDORpYK&confirm=true", - "device": "/cpu:0" + "embeddings_path": "conducta_descripcion.npz", + "device": "cpu" } ], [ - "aymurai.transforms.entity_subcategories.usem.USEMSubcategorizer", + "aymurai.transforms.entity_subcategories.sentence_transformer.SentenceTransformerSubcategorizer", { "category": "DETALLE", - "subcategories_path": "https://drive.google.com/uc?id=1o1Z4fhGTtNzUIL2m3WOfDr_f0KXHu_Ms&confirm=true", - "response_embeddings_path": "https://drive.google.com/uc?id=1OumPgnnM9ffjHjObnb5NL96e3hnlt7Ik&confirm=true", - "device": "/cpu:0" + "embeddings_path": "detalle.npz", + "device": "cpu" } ], [ - "aymurai.transforms.entity_subcategories.usem.USEMSubcategorizer", + "aymurai.transforms.entity_subcategories.sentence_transformer.SentenceTransformerSubcategorizer", { "category": "OBJETO_DE_LA_RESOLUCION", - "subcategories_path": "https://drive.google.com/uc?id=1ksmfX_AJaE-OFEEGzj2N2mZgg5HZWB_4&confirm=true", - "response_embeddings_path": "https://drive.google.com/uc?id=18wOgqzNDsqF13nrvX2XscE0JS_xrgqBU&confirm=true", - "device": "/cpu:0" + "embeddings_path": "objeto_de_la_resolucion.npz", + "device": "cpu" } ], [ diff --git a/uv.lock b/uv.lock index 3acc56ea..e8a103b2 100644 --- a/uv.lock +++ b/uv.lock @@ -241,19 +241,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, ] -[[package]] -name = "astunparse" -version = "1.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, - { name = "wheel" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/af/4182184d3c338792894f34a62672919db7ca008c89abee9b564dd34d8029/astunparse-1.6.3.tar.gz", hash = "sha256:5ad93a8456f0d084c3456d059fd9a92cce667963232cbf763eac3bc5b7940872", size = 18290 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/03/13dde6512ad7b4557eb792fbcf0c653af6076b81e5941d36ec61f7ce6028/astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8", size = 12732 }, -] - [[package]] name = "async-lru" version = "2.0.5" @@ -298,7 +285,7 @@ wheels = [ [[package]] name = "aymurai" -version = "2.0.0a2.dev9" +version = "2.0.0a3.dev9" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -310,7 +297,6 @@ dependencies = [ { name = "faker" }, { name = "fastapi", extra = ["standard"] }, { name = "flair" }, - { name = "gdown" }, { name = "jiwer" }, { name = "joblib" }, { name = "langextract", extra = ["openai"] }, @@ -335,8 +321,6 @@ dependencies = [ { name = "sentencepiece" }, { name = "sqlmodel" }, { name = "tenacity" }, - { name = "tensorflow-hub" }, - { name = "tensorflow-text", marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin') or sys_platform == 'linux' or sys_platform == 'win32'" }, { name = "tiktoken" }, { name = "torch" }, { name = "unidecode" }, @@ -370,7 +354,6 @@ requires-dist = [ { name = "faker", specifier = "==18.11.2" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.115.6" }, { name = "flair", specifier = "==0.15.1" }, - { name = "gdown", specifier = "==4.6.0" }, { name = "jiwer", specifier = "==3.0.5" }, { name = "joblib", specifier = ">=1.4.2" }, { name = "langextract", extras = ["openai"], specifier = "==1.1.0" }, @@ -395,8 +378,6 @@ requires-dist = [ { name = "sentencepiece", specifier = "==0.2.0" }, { name = "sqlmodel", specifier = "==0.0.22" }, { name = "tenacity", specifier = ">=9.0.0" }, - { name = "tensorflow-hub", specifier = ">=0.16.1" }, - { name = "tensorflow-text", marker = "(platform_machine == 'x86_64' and sys_platform == 'darwin') or sys_platform == 'linux' or sys_platform == 'win32'", specifier = "==2.10.0" }, { name = "tiktoken", specifier = "==0.12.0" }, { name = "torch", specifier = ">=1.13.1" }, { name = "unidecode", specifier = "==1.3.8" }, @@ -1112,15 +1093,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, ] -[[package]] -name = "flatbuffers" -version = "25.9.23" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9d/1f/3ee70b0a55137442038f2a33469cc5fddd7e0ad2abf83d7497c18a2b6923/flatbuffers-25.9.23.tar.gz", hash = "sha256:676f9fa62750bb50cf531b42a0a2a118ad8f7f797a511eda12881c016f093b12", size = 22067 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/1b/00a78aa2e8fbd63f9af08c9c19e6deb3d5d66b4dda677a0f61654680ee89/flatbuffers-25.9.23-py2.py3-none-any.whl", hash = "sha256:255538574d6cb6d0a79a17ec8bc0d30985913b87513a01cce8bcdb6b4c44d0e2", size = 30869 }, -] - [[package]] name = "fonttools" version = "4.61.0" @@ -1198,15 +1170,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821 }, ] -[[package]] -name = "gast" -version = "0.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/4a/07c7e59cef23fb147454663c3271c21da68ba2ab141427c20548ae5a8a4d/gast-0.4.0.tar.gz", hash = "sha256:40feb7b8b8434785585ab224d1568b857edb18297e5a3047f1ba012bc83b42c1", size = 13804 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/48/583c032b79ae5b3daa02225a675aeb673e58d2cb698e78510feceb11958c/gast-0.4.0-py3-none-any.whl", hash = "sha256:b7adcdd5adbebf1adf17378da5ba3f543684dbec47b1cda1f3997e573cd542c4", size = 9824 }, -] - [[package]] name = "gdown" version = "4.6.0" @@ -1291,19 +1254,6 @@ requests = [ { name = "requests" }, ] -[[package]] -name = "google-auth-oauthlib" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-auth" }, - { name = "requests-oauthlib" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/30/21/b84fa7ef834d4b126faad13da6e582c8f888e196326b9d6aab1ae303df4f/google-auth-oauthlib-0.4.6.tar.gz", hash = "sha256:a90a072f6993f2c327067bf65270046384cda5a8ecb20b94ea9a687f1f233a7a", size = 19516 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/0e/0636cc1448a7abc444fb1b3a63655e294e0d2d49092dc3de05241be6d43c/google_auth_oauthlib-0.4.6-py2.py3-none-any.whl", hash = "sha256:3f2a6e802eebbb6fb736a370fbf3b055edcb6b52878bf2f26330b5e041316c73", size = 18306 }, -] - [[package]] name = "google-cloud-core" version = "2.5.0" @@ -1369,18 +1319,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/40/f2/97fefdd1ad1f3428321bac819ae7a83ccc59f6439616054736b7819fa56c/google_genai-1.53.0-py3-none-any.whl", hash = "sha256:65a3f99e5c03c372d872cda7419f5940e723374bb12a2f3ffd5e3e56e8eb2094", size = 262015 }, ] -[[package]] -name = "google-pasta" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/4a/0bd53b36ff0323d10d5f24ebd67af2de10a1117f5cf4d7add90df92756f1/google-pasta-0.2.0.tar.gz", hash = "sha256:c9f2c8dfc8f96d0d5808299920721be30c9eec37f2389f28904f454565c8a16e", size = 40430 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/de/c648ef6835192e6e2cc03f40b19eeda4382c49b5bafb43d88b931c4c74ac/google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed", size = 57471 }, -] - [[package]] name = "google-resumable-media" version = "2.8.0" @@ -1421,23 +1359,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740 }, ] -[[package]] -name = "grpcio" -version = "1.67.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/53/d9282a66a5db45981499190b77790570617a604a38f3d103d0400974aeb5/grpcio-1.67.1.tar.gz", hash = "sha256:3dc2ed4cabea4dc14d5e708c2b426205956077cc5de419b4d4079315017e9732", size = 12580022 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/cd/f6ca5c49aa0ae7bc6d0757f7dae6f789569e9490a635eaabe02bc02de7dc/grpcio-1.67.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:8b0341d66a57f8a3119b77ab32207072be60c9bf79760fa609c5609f2deb1f3f", size = 5112450 }, - { url = "https://files.pythonhosted.org/packages/d4/f0/d9bbb4a83cbee22f738ee7a74aa41e09ccfb2dcea2cc30ebe8dab5b21771/grpcio-1.67.1-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:f5a27dddefe0e2357d3e617b9079b4bfdc91341a91565111a21ed6ebbc51b22d", size = 10937518 }, - { url = "https://files.pythonhosted.org/packages/5b/17/0c5dbae3af548eb76669887642b5f24b232b021afe77eb42e22bc8951d9c/grpcio-1.67.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:43112046864317498a33bdc4797ae6a268c36345a910de9b9c17159d8346602f", size = 5633610 }, - { url = "https://files.pythonhosted.org/packages/17/48/e000614e00153d7b2760dcd9526b95d72f5cfe473b988e78f0ff3b472f6c/grpcio-1.67.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9b929f13677b10f63124c1a410994a401cdd85214ad83ab67cc077fc7e480f0", size = 6240678 }, - { url = "https://files.pythonhosted.org/packages/64/19/a16762a70eeb8ddfe43283ce434d1499c1c409ceec0c646f783883084478/grpcio-1.67.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7d1797a8a3845437d327145959a2c0c47c05947c9eef5ff1a4c80e499dcc6fa", size = 5884528 }, - { url = "https://files.pythonhosted.org/packages/6b/dc/bd016aa3684914acd2c0c7fa4953b2a11583c2b844f3d7bae91fa9b98fbb/grpcio-1.67.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:0489063974d1452436139501bf6b180f63d4977223ee87488fe36858c5725292", size = 6583680 }, - { url = "https://files.pythonhosted.org/packages/1a/93/1441cb14c874f11aa798a816d582f9da82194b6677f0f134ea53d2d5dbeb/grpcio-1.67.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9fd042de4a82e3e7aca44008ee2fb5da01b3e5adb316348c21980f7f58adc311", size = 6162967 }, - { url = "https://files.pythonhosted.org/packages/29/e9/9295090380fb4339b7e935b9d005fa9936dd573a22d147c9e5bb2df1b8d4/grpcio-1.67.1-cp310-cp310-win32.whl", hash = "sha256:638354e698fd0c6c76b04540a850bf1db27b4d2515a19fcd5cf645c48d3eb1ed", size = 3616336 }, - { url = "https://files.pythonhosted.org/packages/ce/de/7c783b8cb8f02c667ca075c49680c4aeb8b054bc69784bcb3e7c1bbf4985/grpcio-1.67.1-cp310-cp310-win_amd64.whl", hash = "sha256:608d87d1bdabf9e2868b12338cd38a79969eaf920c89d698ead08f48de9c0f9e", size = 4352071 }, -] - [[package]] name = "h11" version = "0.16.0" @@ -1447,24 +1368,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, ] -[[package]] -name = "h5py" -version = "3.15.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4d/6a/0d79de0b025aa85dc8864de8e97659c94cf3d23148394a954dc5ca52f8c8/h5py-3.15.1.tar.gz", hash = "sha256:c86e3ed45c4473564de55aa83b6fc9e5ead86578773dfbd93047380042e26b69", size = 426236 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/30/8fa61698b438dd751fa46a359792e801191dadab560d0a5f1c709443ef8e/h5py-3.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:67e59f6c2f19a32973a40f43d9a088ae324fe228c8366e25ebc57ceebf093a6b", size = 3414477 }, - { url = "https://files.pythonhosted.org/packages/16/16/db2f63302937337c4e9e51d97a5984b769bdb7488e3d37632a6ac297f8ef/h5py-3.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e2f471688402c3404fa4e13466e373e622fd4b74b47b56cfdff7cc688209422", size = 2850298 }, - { url = "https://files.pythonhosted.org/packages/fc/2e/f1bb7de9b05112bfd14d5206090f0f92f1e75bbb412fbec5d4653c3d44dd/h5py-3.15.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c45802bcb711e128a6839cb6c01e9ac648dc55df045c9542a675c771f15c8d5", size = 4523605 }, - { url = "https://files.pythonhosted.org/packages/05/8a/63f4b08f3628171ce8da1a04681a65ee7ac338fde3cb3e9e3c9f7818e4da/h5py-3.15.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:64ce3f6470adb87c06e3a8dd1b90e973699f1759ad79bfa70c230939bff356c9", size = 4735346 }, - { url = "https://files.pythonhosted.org/packages/74/48/f16d12d9de22277605bcc11c0dcab5e35f06a54be4798faa2636b5d44b3c/h5py-3.15.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4411c1867b9899a25e983fff56d820a66f52ac326bbe10c7cdf7d832c9dcd883", size = 4175305 }, - { url = "https://files.pythonhosted.org/packages/d6/2f/47cdbff65b2ce53c27458c6df63a232d7bb1644b97df37b2342442342c84/h5py-3.15.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2cbc4104d3d4aca9d6db8c0c694555e255805bfeacf9eb1349bda871e26cacbe", size = 4653602 }, - { url = "https://files.pythonhosted.org/packages/c3/28/dc08de359c2f43a67baa529cb70d7f9599848750031975eed92d6ae78e1d/h5py-3.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:01f55111ca516f5568ae7a7fc8247dfce607de331b4467ee8a9a6ed14e5422c7", size = 2873601 }, -] - [[package]] name = "hf-xet" version = "1.2.0" @@ -2017,27 +1920,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, ] -[[package]] -name = "keras" -version = "2.10.0" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/4d/dc255a437c9616b155e5bd55e325e092b7cdcb4652361d733ae051d40853/keras-2.10.0-py2.py3-none-any.whl", hash = "sha256:26a6e2c2522e7468ddea22710a99b3290493768fc08a39e75d1173a0e3452fdf", size = 1684294 }, -] - -[[package]] -name = "keras-preprocessing" -version = "1.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/f1/b44337faca48874333769a29398fe4666686733c8880aa160b9fd5dfe600/Keras_Preprocessing-1.1.2.tar.gz", hash = "sha256:add82567c50c8bc648c14195bf544a5ce7c1f76761536956c3d2978970179ef3", size = 163598 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/4c/7c3275a01e12ef9368a892926ab932b33bb13d55794881e3573482b378a7/Keras_Preprocessing-1.1.2-py2.py3-none-any.whl", hash = "sha256:7b82029b130ff61cc99b55f3bd27427df4838576838c5b2f65940e4fcec99a7b", size = 42581 }, -] - [[package]] name = "kiwisolver" version = "1.4.9" @@ -2114,23 +1996,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, ] -[[package]] -name = "libclang" -version = "18.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6e/5c/ca35e19a4f142adffa27e3d652196b7362fa612243e2b916845d801454fc/libclang-18.1.1.tar.gz", hash = "sha256:a1214966d08d73d971287fc3ead8dfaf82eb07fb197680d8b3859dbbbbf78250", size = 39612 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/49/f5e3e7e1419872b69f6f5e82ba56e33955a74bd537d8a1f5f1eff2f3668a/libclang-18.1.1-1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:0b2e143f0fac830156feb56f9231ff8338c20aecfe72b4ffe96f19e5a1dbb69a", size = 25836045 }, - { url = "https://files.pythonhosted.org/packages/e2/e5/fc61bbded91a8830ccce94c5294ecd6e88e496cc85f6704bf350c0634b70/libclang-18.1.1-py2.py3-none-macosx_10_9_x86_64.whl", hash = "sha256:6f14c3f194704e5d09769108f03185fce7acaf1d1ae4bbb2f30a72c2400cb7c5", size = 26502641 }, - { url = "https://files.pythonhosted.org/packages/db/ed/1df62b44db2583375f6a8a5e2ca5432bbdc3edb477942b9b7c848c720055/libclang-18.1.1-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:83ce5045d101b669ac38e6da8e58765f12da2d3aafb3b9b98d88b286a60964d8", size = 26420207 }, - { url = "https://files.pythonhosted.org/packages/1d/fc/716c1e62e512ef1c160e7984a73a5fc7df45166f2ff3f254e71c58076f7c/libclang-18.1.1-py2.py3-none-manylinux2010_x86_64.whl", hash = "sha256:c533091d8a3bbf7460a00cb6c1a71da93bffe148f172c7d03b1c31fbf8aa2a0b", size = 24515943 }, - { url = "https://files.pythonhosted.org/packages/3c/3d/f0ac1150280d8d20d059608cf2d5ff61b7c3b7f7bcf9c0f425ab92df769a/libclang-18.1.1-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:54dda940a4a0491a9d1532bf071ea3ef26e6dbaf03b5000ed94dd7174e8f9592", size = 23784972 }, - { url = "https://files.pythonhosted.org/packages/fe/2f/d920822c2b1ce9326a4c78c0c2b4aa3fde610c7ee9f631b600acb5376c26/libclang-18.1.1-py2.py3-none-manylinux2014_armv7l.whl", hash = "sha256:cf4a99b05376513717ab5d82a0db832c56ccea4fd61a69dbb7bccf2dfb207dbe", size = 20259606 }, - { url = "https://files.pythonhosted.org/packages/2d/c2/de1db8c6d413597076a4259cea409b83459b2db997c003578affdd32bf66/libclang-18.1.1-py2.py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:69f8eb8f65c279e765ffd28aaa7e9e364c776c17618af8bff22a8df58677ff4f", size = 24921494 }, - { url = "https://files.pythonhosted.org/packages/0b/2d/3f480b1e1d31eb3d6de5e3ef641954e5c67430d5ac93b7fa7e07589576c7/libclang-18.1.1-py2.py3-none-win_amd64.whl", hash = "sha256:4dd2d3b82fab35e2bf9ca717d7b63ac990a3519c7e312f19fa8e86dcc712f7fb", size = 26415083 }, - { url = "https://files.pythonhosted.org/packages/71/cf/e01dc4cc79779cd82d77888a88ae2fa424d93b445ad4f6c02bfc18335b70/libclang-18.1.1-py2.py3-none-win_arm64.whl", hash = "sha256:3f0e1f49f04d3cd198985fea0511576b0aee16f9ff0e0f0cad7f9c57ec3c20e8", size = 22361112 }, -] - [[package]] name = "lightning-utilities" version = "0.3.0" @@ -2216,15 +2081,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509 }, ] -[[package]] -name = "markdown" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/7dd27d9d863b3376fcf23a5a13cb5d024aed1db46f963f1b5735ae43b3be/markdown-3.10.tar.gz", hash = "sha256:37062d4f2aa4b2b6b32aefb80faa300f82cc790cb949a35b8caede34f2b68c0e", size = 364931 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/70/81/54e3ce63502cd085a0c556652a4e1b919c45a446bd1e5300e10c44c8c521/markdown-3.10-py3-none-any.whl", hash = "sha256:b5b99d6951e2e4948d939255596523444c0e677c669700b1d17aa4a8a464cb7c", size = 107678 }, -] - [[package]] name = "markdown-it-py" version = "4.0.0" @@ -2758,15 +2614,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, ] -[[package]] -name = "oauthlib" -version = "3.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065 }, -] - [[package]] name = "odfpy" version = "1.4.1" @@ -2825,15 +2672,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/86/8a/69176a64335aed183529207ba8bc3d329c2999d852b4f3818027203f50e6/opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca", size = 39402386 }, ] -[[package]] -name = "opt-einsum" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/b9/2ac072041e899a52f20cf9510850ff58295003aa75525e58343591b0cbfb/opt_einsum-3.4.0.tar.gz", hash = "sha256:96ca72f1b886d148241348783498194c577fa30a8faac108586b14f1ba4473ac", size = 63004 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/23/cd/066e86230ae37ed0be70aae89aabf03ca8d9f39c8aea0dec8029455b5540/opt_einsum-3.4.0-py3-none-any.whl", hash = "sha256:69bb92469f86a1565195ece4ac0323943e83477171b91d24c35afe028a90d7cd", size = 71932 }, -] - [[package]] name = "optuna" version = "4.6.0" @@ -3639,19 +3477,6 @@ socks = [ { name = "pysocks" }, ] -[[package]] -name = "requests-oauthlib" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "oauthlib" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179 }, -] - [[package]] name = "rfc3339-validator" version = "0.1.4" @@ -4157,47 +3982,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 }, ] -[[package]] -name = "tensorboard" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "google-auth" }, - { name = "google-auth-oauthlib" }, - { name = "grpcio" }, - { name = "markdown" }, - { name = "numpy" }, - { name = "protobuf" }, - { name = "requests" }, - { name = "setuptools" }, - { name = "tensorboard-data-server" }, - { name = "tensorboard-plugin-wit" }, - { name = "werkzeug" }, - { name = "wheel" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/80/49/a5ec29886ef823718c8ae54ed0b3ad7e19066b5bf21cec5038427e6a04c4/tensorboard-2.10.1-py3-none-any.whl", hash = "sha256:fb9222c1750e2fa35ef170d998a1e229f626eeced3004494a8849c88c15d8c1c", size = 5873392 }, -] - -[[package]] -name = "tensorboard-data-server" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/74/69/5747a957f95e2e1d252ca41476ae40ce79d70d38151d2e494feb7722860c/tensorboard_data_server-0.6.1-py3-none-any.whl", hash = "sha256:809fe9887682d35c1f7d1f54f0f40f98bb1f771b14265b453ca051e2ce58fca7", size = 2350 }, - { url = "https://files.pythonhosted.org/packages/3e/48/dd135dbb3cf16bfb923720163493cab70e7336db4b5f3103d49efa730404/tensorboard_data_server-0.6.1-py3-none-macosx_10_9_x86_64.whl", hash = "sha256:fa8cef9be4fcae2f2363c88176638baf2da19c5ec90addb49b1cde05c95c88ee", size = 3546350 }, - { url = "https://files.pythonhosted.org/packages/60/f9/802efd84988bffd9f644c03b6e66fde8e76c3aa33db4279ddd11c5d61f4b/tensorboard_data_server-0.6.1-py3-none-manylinux2010_x86_64.whl", hash = "sha256:d8237580755e58eff68d1f3abefb5b1e39ae5c8b127cc40920f9c4fb33f4b98a", size = 4910134 }, -] - -[[package]] -name = "tensorboard-plugin-wit" -version = "1.8.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/68/e8ecfac5dd594b676c23a7f07ea34c197d7d69b3313afdf8ac1b0a9905a2/tensorboard_plugin_wit-1.8.1-py3-none-any.whl", hash = "sha256:ff26bdd583d155aa951ee3b152b3d0cffae8005dc697f72b44a8e8c2a77a8cbe", size = 781327 }, -] - [[package]] name = "tensorboardx" version = "2.6" @@ -4212,87 +3996,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/9f/d532d37f10ac7af136d4c2ba71e1fe7af0f3cc0cc076dfc05826171e9737/tensorboardX-2.6-py2.py3-none-any.whl", hash = "sha256:24a7cd076488de1e9d15ef25371b8ebf90c4f8f622af2477c611198f03f4a606", size = 114480 }, ] -[[package]] -name = "tensorflow" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "astunparse" }, - { name = "flatbuffers" }, - { name = "gast" }, - { name = "google-pasta" }, - { name = "grpcio" }, - { name = "h5py" }, - { name = "keras" }, - { name = "keras-preprocessing" }, - { name = "libclang" }, - { name = "numpy" }, - { name = "opt-einsum" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "setuptools" }, - { name = "six" }, - { name = "tensorboard" }, - { name = "tensorflow-estimator" }, - { name = "tensorflow-io-gcs-filesystem" }, - { name = "termcolor" }, - { name = "typing-extensions" }, - { name = "wrapt" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/73/84/92f4f4c017ef2071412745034a98108106347478c56475c65d275bd2a792/tensorflow-2.10.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:dc3587dfa714be711d2681d5e2fb59037b18e83e692f084db49bce31b6268d15", size = 241225350 }, - { url = "https://files.pythonhosted.org/packages/27/35/50f68ad5c082836045b2b068d095b0ed5bb6fdee4dfcb9af76058df4ed66/tensorflow-2.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3cab933757eb0c204dc4cf34d031939e33cae8f97a7aaef00a12678129b17f", size = 1937 }, - { url = "https://files.pythonhosted.org/packages/b2/c3/668c91cc7074eed672691f130562c0f02d89aebf01f6e14f1741f7fb900b/tensorflow-2.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20f1d579b849afaea7b10f7693dc43b1d07321d279a016f01e2ddfe971d0d8af", size = 578143480 }, - { url = "https://files.pythonhosted.org/packages/ad/87/f484e0b86687c97d2dfb081e03e948b796561fc8608b409a9366e3b4a663/tensorflow-2.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a6049664f9a0d14b0a4a7e6f058be87b2d8c27be826d7dd9a870ff03683fbc0b", size = 455948187 }, -] - -[[package]] -name = "tensorflow-estimator" -version = "2.10.0" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/05/9d7f3a6c783669cba36a6eb4555d0c73a516eee935dde6176dfb8512f94e/tensorflow_estimator-2.10.0-py2.py3-none-any.whl", hash = "sha256:f324ea17cd57f16e33bf188711d5077e6b2e5f5a12c328d6e01a07b23888edcd", size = 438698 }, -] - -[[package]] -name = "tensorflow-hub" -version = "0.16.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "protobuf" }, - { name = "tf-keras" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/50/00dba77925bf2a0a1e45d7bcf8a69a1d2534fb4bb277d9010bd148d2235e/tensorflow_hub-0.16.1-py2.py3-none-any.whl", hash = "sha256:e10c184b3d08daeafada11ffea2dd46781725b6bef01fad1f74d6634ad05311f", size = 30771 }, -] - -[[package]] -name = "tensorflow-io-gcs-filesystem" -version = "0.37.1" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/a3/12d7e7326a707919b321e2d6e4c88eb61596457940fd2b8ff3e9b7fac8a7/tensorflow_io_gcs_filesystem-0.37.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:249c12b830165841411ba71e08215d0e94277a49c551e6dd5d72aab54fe5491b", size = 2470224 }, - { url = "https://files.pythonhosted.org/packages/1c/55/3849a188cc15e58fefde20e9524d124a629a67a06b4dc0f6c881cb3c6e39/tensorflow_io_gcs_filesystem-0.37.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:257aab23470a0796978efc9c2bcf8b0bc80f22e6298612a4c0a50d3f4e88060c", size = 3479613 }, - { url = "https://files.pythonhosted.org/packages/e2/19/9095c69e22c879cb3896321e676c69273a549a3148c4f62aa4bc5ebdb20f/tensorflow_io_gcs_filesystem-0.37.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8febbfcc67c61e542a5ac1a98c7c20a91a5e1afc2e14b1ef0cb7c28bc3b6aa70", size = 4842078 }, - { url = "https://files.pythonhosted.org/packages/f3/48/47b7d25572961a48b1de3729b7a11e835b888e41e0203cca82df95d23b91/tensorflow_io_gcs_filesystem-0.37.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9679b36e3a80921876f31685ab6f7270f3411a4cc51bc2847e80d0e4b5291e27", size = 5085736 }, -] - -[[package]] -name = "tensorflow-text" -version = "2.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tensorflow", marker = "platform_machine != 'arm64' or platform_system != 'Darwin'" }, - { name = "tensorflow-hub" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/64/489c459f46f678ec4822b815ba9dfb1182c351e2208e98b6e83543254b55/tensorflow_text-2.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84b76847189d0d7bc8d4a130f0617e13bc9b810cf1feeb9c49da2906a2f39785", size = 5621257 }, - { url = "https://files.pythonhosted.org/packages/37/a5/bf11fb427226283b2abefcad355030effdb1a0c45978b80c63a38556bdd2/tensorflow_text-2.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:554f05956922afe0269dfb1e2fd73f5e049fa5746c47fd34d92ff7e447d746d4", size = 5889598 }, - { url = "https://files.pythonhosted.org/packages/88/a2/8d2ee50c8e5e355bf23975a0b7fa49ddd9c9b0ecb48b8c77d78ff4b3bcc0/tensorflow_text-2.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:269a3d7c3bd34e069e5d4ccaece902fc46aad65220301ee3bdb70d4ab031a60d", size = 5004273 }, -] - [[package]] name = "termcolor" version = "3.2.0" @@ -4316,15 +4019,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, ] -[[package]] -name = "tf-keras" -version = "2.15.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ce/0c/36054828137226dc3a559b525640f296a99ee8eb38beca32b36d29bb303b/tf_keras-2.15.0.tar.gz", hash = "sha256:d7559c2ba40667679fcb2105d3e4b68bbc07ecafbf1037462ce7b3974c3c6798", size = 1250420 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/26/ca8a6cca61f2a44f1e7ee71ebdb9c8dfbc4371f418db811cdca4641f6daa/tf_keras-2.15.0-py3-none-any.whl", hash = "sha256:48607ee60a4d1fa7c09d6a44293a803faf3136e7a43f92df089ac094117547d2", size = 1714973 }, -] - [[package]] name = "threadpoolctl" version = "3.6.0" @@ -4813,27 +4507,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, ] -[[package]] -name = "werkzeug" -version = "3.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960 }, -] - -[[package]] -name = "wheel" -version = "0.45.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/98/2d9906746cdc6a6ef809ae6338005b3f21bb568bea3165cfc6a243fdc25c/wheel-0.45.1.tar.gz", hash = "sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729", size = 107545 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/2c/87f3254fd8ffd29e4c02732eee68a83a1d3c346ae39bc6822dcbcb697f2b/wheel-0.45.1-py3-none-any.whl", hash = "sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248", size = 72494 }, -] - [[package]] name = "widgetsnbextension" version = "4.0.15" From 0a35efe9c22e668989ef1fb00a274be2dcac1f8f Mon Sep 17 00:00:00 2001 From: jed Date: Mon, 5 Jan 2026 17:47:24 -0300 Subject: [PATCH 027/104] =?UTF-8?q?WIP:=20feat(decision):=20=E2=9C=A8=20in?= =?UTF-8?q?tegrate=20TinyEmbeddingBagClassifier=20for=20decision=20detecti?= =?UTF-8?q?on=20(#67)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(decision): ✨ integrate TinyEmbeddingBagClassifier for decision detection - Introduced a new model class `DecisionEmbeddingBagBinRegex` using `TinyEmbeddingBagClassifier`. - Updated model loading and saving mechanisms to support safetensors format. - Added a new training notebook for the embedding bag classifier. - Modified the pipeline configuration to include the new model. * ⚡️ Remove unidecode usage to avoid double normalization in model_input_from_text * 📝 Add type hints and docstrings for clarity in DecisionEmbeddingBagBinRegex and TinyEmbeddingBagClassifier * 🔧 Refactor import statements for safetensors to remove try-except block * 🔥 Remove Conv1dTextClassifier, Tokenizer and SpanishTokenizer implementations * 🐛 Fix gen_aymurai_entity call by removing unused category parameter * 🔖 Update aymurai package version to 2.0.0a4.dev1 --- aymurai/models/decision/binregex.py | 197 ++++-- aymurai/models/decision/conv1d.py | 138 ----- aymurai/models/decision/embeddingbag.py | 267 +++++++++ aymurai/models/decision/tokenizer.py | 36 -- aymurai/text/tokenizers/__init__.py | 0 aymurai/text/tokenizers/spanish.py | 372 ------------ .../01-training-2class-embeddingbag.ipynb | 561 ++++++++++++++++++ .../production/full-paragraph/pipeline.json | 9 + uv.lock | 2 +- 9 files changed, 980 insertions(+), 602 deletions(-) delete mode 100644 aymurai/models/decision/conv1d.py create mode 100644 aymurai/models/decision/embeddingbag.py delete mode 100644 aymurai/models/decision/tokenizer.py delete mode 100644 aymurai/text/tokenizers/__init__.py delete mode 100644 aymurai/text/tokenizers/spanish.py create mode 100644 notebooks/experiments/decision/01-training-2class-embeddingbag.ipynb diff --git a/aymurai/models/decision/binregex.py b/aymurai/models/decision/binregex.py index a3b77a01..9c6b0a61 100644 --- a/aymurai/models/decision/binregex.py +++ b/aymurai/models/decision/binregex.py @@ -1,96 +1,113 @@ +from __future__ import annotations + import os -import shutil from copy import deepcopy import regex import torch -from unidecode import unidecode from aymurai.logger import get_logger from aymurai.meta.api_interfaces import DocLabel, EntityAttributes from aymurai.meta.pipeline_interfaces import TrainModule from aymurai.meta.types import DataBlock, DataItem -from aymurai.models.decision.conv1d import Conv1dTextClassifier -from aymurai.models.decision.tokenizer import Tokenizer +from aymurai.models.decision.embeddingbag import ( + TinyEmbeddingBagClassifier, + encode_text, + make_offsets, +) from aymurai.utils.download import download from aymurai.utils.misc import get_element, is_url logger = get_logger(__name__) -class DecisionConv1dBinRegex(TrainModule): +class DecisionEmbeddingBagBinRegex(TrainModule): def __init__( self, - tokenizer_path: str, model_checkpoint: str, device: str = "cpu", threshold: float = 0.88, return_only_with_detalle: bool = True, ): self._device = device - self._tokenizer_path = tokenizer_path self._model_path = model_checkpoint self.threshold = threshold self.return_only_with_detalle = return_only_with_detalle - # download if needed - # tokenizer basepath = os.getenv("AYMURAI_CACHE_BASEPATH", "/resources/cache/aymurai") - if is_url(url := self._tokenizer_path): - output = f"{basepath}/{self.__name__}/tokenizer.pth" - logger.info(f"downloading tokenizer on {output}") - os.makedirs(os.path.dirname(output), exist_ok=True) - self._tokenizer_path = download(url, output=output) - # model if is_url(url := self._model_path): - output = f"{basepath}/{self.__name__}/model.ckpt" + # Determine file extension from URL or default to safetensors + if url.endswith(".pt"): + ext = ".pt" + else: + ext = ".safetensors" + output = f"{basepath}/{self.__class__.__name__}/model{ext}" logger.info(f"downloading model on {output}") os.makedirs(os.path.dirname(output), exist_ok=True) self._model_path = download(url, output=output) - - self.tokenizer = Tokenizer.load(self._tokenizer_path) - self.model = Conv1dTextClassifier.load_from_checkpoint( + # If downloading safetensors, also try to download config + if ext == ".safetensors": + config_url = url.rsplit(".safetensors", 1)[0] + ".json" + config_output = output.rsplit(".safetensors", 1)[0] + ".json" + try: + download(config_url, output=config_output) + except Exception as e: + logger.warning(f"Could not download config file: {e}") + + self.model, self.cfg = TinyEmbeddingBagClassifier.from_checkpoint( self._model_path, - map_location=self._device, + device=self._device, ) self.model = self.model.eval() - def save(self, basepath: str) -> dict | None: - # save tokenizer - os.makedirs(basepath, exist_ok=True) - self._tokenizer_path = f"{basepath}/tokenizer.pth" - self.tokenizer.save(self._tokenizer_path) - logger.info(f"tokenizer saved on: {self._tokenizer_path}") - - # save model - new_model_path = f"{basepath}/model.ckpt" - shutil.copy(self._model_path, new_model_path) - self._model_path = new_model_path - logger.info(f"model saved on: {self._model_path}") - return { - "tokenizer_path": self._tokenizer_path, - "model_checkpoint": self._model_path, - "device": self._device, - } - - @classmethod - def load(cls, path: str, **kwargs): - return cls( - tokenizer_path=f"{path}/tokenizer.pth", - model_checkpoint=f"{path}/model.ckpt", - **kwargs, - ) + def fit(self, train: DataBlock, val: DataBlock) -> None: + """ + Fit the model on training data. Currently not implemented. - def fit(self, train: DataBlock, val: DataBlock): + Args: + train (DataBlock): Training data block. + val (DataBlock): Validation data block. + """ logger.warning("fit routine not implemented") pass def predict(self, data: DataBlock) -> DataBlock: + """ + Predict on a data block. + + Args: + data (DataBlock): Input data block. + + Returns: + DataBlock: Predicted data block. + """ # FIXME: optimize - logger.warn("predict not optimized") + logger.warning("predict not optimized") return [self.predict_single(item) for item in data] - def get_subcategory(self, text): + def model_input_from_text(self, text: str) -> tuple[torch.Tensor, torch.Tensor]: + """ + Convert text to model input tensors. + + Args: + text (str): Input text. + + Returns: + tuple[torch.Tensor, torch.Tensor]: (flat_tokens, offsets) for model input. + """ + token_ids = encode_text(text, self.cfg).to(self._device) + return make_offsets([token_ids]) + + def get_subcategory(self, text: str) -> list[str]: + """ + Determine the subcategory of a decision based on its text. + + Args: + text (str): Text of the decision. + + Returns: + list[str]: List of subcategories for the decision. + """ pattern_no_hace_lugar = regex.compile( r"(?i)(no hacer? lugar|rechaz[ao]r?|no admitir|no convalidar|no autorizar|declarar inadmisible)" ) @@ -100,8 +117,19 @@ def get_subcategory(self, text): else: return ["hace_lugar"] - def gen_aymurai_entity(self, text: str, category: int, score: float): + def gen_aymurai_entity(self, text: str, score: float) -> dict: + """ + Generate an Aymurai entity dictionary for a decision. + + Args: + text (str): Text of the decision. + score (float): Confidence score of the decision. + + Returns: + dict: Aymurai entity dictionary. + """ subcategory = self.get_subcategory(text) + attrs = EntityAttributes( aymurai_label="DECISION", aymurai_label_subclass=subcategory, @@ -119,18 +147,27 @@ def gen_aymurai_entity(self, text: str, category: int, score: float): ent["label"] = "DECISION" ent["context_pre"] = "" ent["context_post"] = "" + return ent def predict_single(self, item: DataItem) -> DataItem: + """ + Predict a single data item. + + Args: + item (DataItem): The data item to predict. + + Returns: + DataItem: The predicted data item with added entities if applicable. + """ item = deepcopy(item) text = item["data"]["doc.text"] - text = unidecode(text) - input_ids = self.tokenizer.encode_batch([text]).to(self.model.device) + flat_tokens, offsets = self.model_input_from_text(text) with torch.no_grad(): - log_prob = self.model(input_ids).exp() - # using category 1 as global score (binary) - prob = log_prob.detach().numpy()[0, 1] + logits = self.model(flat_tokens, offsets) + probs = logits.softmax(dim=1).cpu() + prob = float(probs[0, 1]) category = int(prob > self.threshold) score = prob @@ -143,7 +180,7 @@ def predict_single(self, item: DataItem) -> DataItem: if self.return_only_with_detalle and not detalles: return item - ent = self.gen_aymurai_entity(text=text, category=category, score=score) + ent = self.gen_aymurai_entity(text=text, score=score) ents.append(ent) if "predictions" not in item: @@ -152,3 +189,53 @@ def predict_single(self, item: DataItem) -> DataItem: item["predictions"]["entities"] = ents return item + + def save(self, basepath: str) -> dict: + """ + Save the model to a directory. + + Args: + basepath (str): Directory path to save the model. + + Returns: + dict: A dictionary containing metadata about the saved model. + """ + os.makedirs(basepath, exist_ok=True) + + # Use safetensors as the main format + new_model_path = f"{basepath}/model.safetensors" + self.model.save_checkpoint(new_model_path, use_safetensors=True) + self._model_path = new_model_path + logger.info(f"model saved on: {self._model_path}") + + return { + "model_checkpoint": self._model_path, + "device": self._device, + "threshold": self.threshold, + "return_only_with_detalle": self.return_only_with_detalle, + } + + @classmethod + def load(cls, path: str, **kwargs) -> DecisionEmbeddingBagBinRegex: + """ + Load a DecisionEmbeddingBagBinRegex model from a directory. + + Args: + path (str): Path to the directory containing the model files. + + Returns: + DecisionEmbeddingBagBinRegex: The loaded model instance. + """ + # Try safetensors first, then .pt + safetensors_path = f"{path}/model.safetensors" + pt_path = f"{path}/model.pt" + + if os.path.exists(safetensors_path): + model_checkpoint = safetensors_path + elif os.path.exists(pt_path): + model_checkpoint = pt_path + else: + # Fallback to .pt for backward compatibility + model_checkpoint = pt_path + + return cls(model_checkpoint=model_checkpoint, **kwargs) diff --git a/aymurai/models/decision/conv1d.py b/aymurai/models/decision/conv1d.py deleted file mode 100644 index 9c93dfad..00000000 --- a/aymurai/models/decision/conv1d.py +++ /dev/null @@ -1,138 +0,0 @@ -import pytorch_lightning as pl -import torch -import torch.nn.functional as F -import torchmetrics -from torch import nn -from torch.optim.lr_scheduler import ReduceLROnPlateau - - -class Conv1dTextClassifier(pl.LightningModule): - def __init__( - self, - vocab_size: int, - max_tokens: int = 128, - embed_len: int = 128, - nfeatures: int = 64, - num_classes: int = 2, - lr_scheduler_patience: int = 2, - class_weights: list = [], - ): - self.vocab_size = vocab_size - self.max_tokens = max_tokens - self.embed_len = embed_len - self.nfeatures = nfeatures - self.num_classes = num_classes - self.lr = 1e-3 - self.lr_scheduler_patience = lr_scheduler_patience - self.class_weights = class_weights - - super().__init__() - self.save_hyperparameters() - - # layers - self.embedding_layer = nn.Embedding( - num_embeddings=self.vocab_size, - embedding_dim=self.embed_len, - ) - self.conv1 = nn.Conv1d(self.embed_len, 64, kernel_size=7, padding="same") - self.conv2 = nn.Conv1d(64, 32, kernel_size=7, padding="same") - self.pooling = nn.MaxPool1d(2) - - self.linear1 = nn.Linear(32, 32) - self.linear2 = nn.Linear(32, self.num_classes) - # self.linear = nn.Linear(self.nfeatures, self.num_classes) - - if len(self.class_weights): - self.class_weights = torch.tensor(class_weights, dtype=torch.float32) - - self.logsoftmax = nn.LogSoftmax(dim=1) - self.loss = nn.NLLLoss(weight=self.class_weights) - - # metrics - self.accuracy = torchmetrics.Accuracy( - task="multiclass", - num_classes=self.num_classes, - ) - self.f1score = torchmetrics.F1Score( - task="multiclass", - num_classes=self.num_classes, - ) - - def forward(self, X_batch): - x = self.embedding_layer(X_batch) - x = x.reshape( - len(x), self.embed_len, self.max_tokens - ) ## Embedding Length needs to be treated as channel dimension - x = F.relu(self.conv1(x)) - x = self.pooling(x) - # x = F.dropout(x, 0.5) - x = F.relu(self.conv2(x)) - x, _ = x.max(dim=-1) - - x = self.linear2(x) - x = self.logsoftmax(x) - - return x - - def predict_step(self, batch, batch_idx): - return self(batch) - - def training_step(self, batch, batch_idx): - # training_step defines the train loop. - x, y = batch - - y_pred = self.forward(x) - - loss = self.loss(y_pred, y) - acc = self.accuracy(y_pred, y) - f1score = self.f1score(y_pred, y) - - self.log("loss", loss, on_epoch=True, prog_bar=True, logger=True) - self.log("acc", acc, on_epoch=True, prog_bar=True, logger=True) - self.log("f1score", f1score, on_epoch=True, prog_bar=True, logger=True) - return loss - - def validation_step(self, batch, batch_idx): - x, y = batch - - y_pred = self.forward(x) - - # loss = F.cross_entropy(y_pred, y) - loss = self.loss(y_pred, y) - acc = self.accuracy(y_pred, y) - f1score = self.f1score(y_pred, y) - - self.log("val_loss", loss, on_epoch=True, prog_bar=True, logger=True) - self.log("val_acc", acc, on_epoch=True, prog_bar=True, logger=True) - self.log("val_f1score", f1score, on_epoch=True, prog_bar=True, logger=True) - - def test_step(self, batch, batch_idx): - x, y = batch - - y_pred = self.forward(x) - - # loss = F.cross_entropy(y_pred, y) - loss = self.loss(y_pred, y) - acc = self.accuracy(y_pred, y) - f1score = self.f1score(y_pred, y) - - self.log("test_loss", loss, on_epoch=True, prog_bar=True, logger=True) - self.log("test_acc", acc, on_epoch=True, prog_bar=True, logger=True) - self.log("test_f1score", f1score, on_epoch=True, prog_bar=True, logger=True) - - def configure_optimizers(self): - # optimizer = torch.optim.Adam(self.parameters(), lr=1e-3) - optimizer = torch.optim.AdamW(self.parameters(), lr=self.lr) - return { - "optimizer": optimizer, - "lr_scheduler": { - "scheduler": ReduceLROnPlateau( - optimizer, - patience=self.lr_scheduler_patience, - ), - "monitor": "val_loss", - "frequency": 1, - # If "monitor" references validation metrics, then "frequency" should be set to a - # multiple of "trainer.check_val_every_n_epoch". - }, - } diff --git a/aymurai/models/decision/embeddingbag.py b/aymurai/models/decision/embeddingbag.py new file mode 100644 index 00000000..19e29d46 --- /dev/null +++ b/aymurai/models/decision/embeddingbag.py @@ -0,0 +1,267 @@ +from __future__ import annotations + +import hashlib +import json +import os +import re +from dataclasses import dataclass, field + +import torch +from safetensors.torch import load_file as safe_load_file +from safetensors.torch import save_file as safe_save_file +from torch import nn +from unidecode import unidecode + + +def _normalize_text(text: str) -> str: + """ + Normalize text by removing accents, converting to lowercase, and collapsing whitespace. + + Args: + text (str): The input text to normalize. + + Returns: + str: The normalized text. + """ + text = unidecode(str(text)).lower() + text = re.sub(r"\s+", " ", text).strip() + return text + + +def _tokenize(text: str) -> list[str]: + """ + Tokenize text by splitting on spaces after normalization. + + Args: + text (str): The input text to tokenize. + + Returns: + list[str]: The list of tokens. + """ + text = _normalize_text(text) + return [token for token in text.split(" ") if token] + + +def _hash_token(token: str, vocab_size: int) -> int: + """ + Hash a token string into an integer in the range [0, vocab_size). + + Args: + token (str): The token string to hash. + vocab_size (int): The size of the vocabulary. + + Returns: + int: The hashed token id. + """ + digest = hashlib.blake2b(token.encode("utf-8"), digest_size=4).digest() + return int.from_bytes(digest, "little") % vocab_size + + +@dataclass +class EmbeddingBagConfig: + vocab_size: int = 20000 + embed_dim: int = 64 + max_tokens: int = 128 + dropout: float = 0.1 + num_classes: int = 2 + # allow passthrough of unknown config keys when loading from checkpoints + extra: dict = field(default_factory=dict) + + +def _merge_config(ckpt_cfg: dict | None) -> EmbeddingBagConfig: + """ + Merge checkpoint config with defaults, stashing unknown keys in extra. + + Args: + ckpt_cfg (dict | None): The config dictionary from checkpoint. + + Returns: + EmbeddingBagConfig: The merged configuration object. + """ + ckpt_cfg = ckpt_cfg or {} + cfg_defaults = EmbeddingBagConfig().__dict__ + merged = {**cfg_defaults} + extra = {} + + for k, v in ckpt_cfg.items(): + if k in cfg_defaults: + merged[k] = v + else: + extra[k] = v + + merged["extra"] = extra + + return EmbeddingBagConfig(**merged) + + +def encode_text(text: str, cfg: EmbeddingBagConfig) -> torch.Tensor: + """ + Encode text into token ids using hashing; truncates to cfg.max_tokens. + + Args: + text (str): The input text to encode. + cfg (EmbeddingBagConfig): The configuration with vocab size and max tokens. + + Returns: + torch.Tensor: The tensor of token ids. + """ + tokens = _tokenize(text) + token_ids = [_hash_token(tok, cfg.vocab_size) for tok in tokens[: cfg.max_tokens]] + + if not token_ids: + token_ids = [0] + + return torch.tensor(token_ids, dtype=torch.long) + + +def make_offsets(token_seqs: list[torch.Tensor]) -> tuple[torch.Tensor, torch.Tensor]: + """ + Flatten variable-length token sequences for EmbeddingBag. + + Args: + token_seqs (list[torch.Tensor]): List of 1D tensors of token ids. + + Returns: + tuple[torch.Tensor, torch.Tensor]: (flat_tokens, offsets) where flat_tokens is a 1D tensor of concatenated tokens, + and offsets is a 1D tensor indicating start indices of each sequence. + """ + device = token_seqs[0].device if token_seqs else None + offsets = torch.zeros(len(token_seqs), dtype=torch.long, device=device) + flat = [] + total = 0 + + for i, seq in enumerate(token_seqs): + offsets[i] = total + flat.append(seq) + total += len(seq) + flat_tokens = torch.cat(flat) if flat else torch.tensor([], device=device) + + return flat_tokens, offsets + + +class TinyEmbeddingBagClassifier(nn.Module): + def __init__(self, cfg: EmbeddingBagConfig): + super().__init__() + self.cfg = cfg + self.embedding = nn.EmbeddingBag(cfg.vocab_size, cfg.embed_dim, mode="mean") + self.dropout = nn.Dropout(cfg.dropout) + self.head = nn.Linear(cfg.embed_dim, cfg.num_classes) + + def forward(self, tokens: torch.Tensor, offsets: torch.Tensor) -> torch.Tensor: + """ + Forward pass of the TinyEmbeddingBagClassifier. + + Args: + tokens (torch.Tensor): Tensor of token ids. + offsets (torch.Tensor): Tensor of offsets for EmbeddingBag. + + Returns: + torch.Tensor: The output logits for each class. + """ + x = self.embedding(tokens, offsets) + x = self.dropout(x) + return self.head(x) + + @classmethod + def from_checkpoint( + cls, checkpoint_path: str, device: str = "cpu" + ) -> tuple[TinyEmbeddingBagClassifier, EmbeddingBagConfig]: + """ + Load a TinyEmbeddingBagClassifier from a checkpoint file. + + Raises: + ImportError: If safetensors is required but not installed. + + Returns: + tuple[TinyEmbeddingBagClassifier, EmbeddingBagConfig]: The loaded model and its configuration. + """ + if checkpoint_path.endswith(".safetensors"): + if safe_load_file is None: + raise ImportError( + "safetensors is not installed; cannot load .safetensors checkpoint" + ) + state = safe_load_file(checkpoint_path, device=device) + cfg_path = os.path.splitext(checkpoint_path)[0] + ".json" + cfg_data = {} + if os.path.exists(cfg_path): + with open(cfg_path, "r") as f: + cfg_data = json.load(f) + cfg = _merge_config(cfg_data) + else: + checkpoint = torch.load(checkpoint_path, map_location=device) + cfg = _merge_config(checkpoint.get("config", {})) + state = checkpoint.get("state_dict", checkpoint) + + model = cls(cfg) + model.load_state_dict(state) + model.to(device) + model.eval() + return model, cfg + + def save_checkpoint( + self, + save_path: str, + use_safetensors: bool = True, + ) -> str: + """ + Save model checkpoint. + + Args: + save_path (str): Path to save checkpoint. Extension determines format. + If no extension, .safetensors or .pt will be added based on use_safetensors. + use_safetensors (bool): If True and no extension provided, save as .safetensors. + If False, save as .pt format. Defaults to True. + + Returns: + str: The actual path where the checkpoint was saved. + """ + # Determine save format based on extension or flag + if not save_path.endswith((".safetensors", ".pt")): + ext = ".safetensors" if use_safetensors else ".pt" + save_path = save_path + ext + + os.makedirs(os.path.dirname(save_path) or ".", exist_ok=True) + + if save_path.endswith(".safetensors"): + if safe_save_file is None: + raise ImportError( + "safetensors is not installed; cannot save .safetensors checkpoint. " + "Install with: pip install safetensors" + ) + # Save model weights as safetensors + safe_save_file(self.state_dict(), save_path) + + # Save config as JSON + cfg_path = os.path.splitext(save_path)[0] + ".json" + + with open(cfg_path, "w") as f: + json.dump( + { + "vocab_size": self.cfg.vocab_size, + "embed_dim": self.cfg.embed_dim, + "max_tokens": self.cfg.max_tokens, + "dropout": self.cfg.dropout, + "num_classes": self.cfg.num_classes, + **self.cfg.extra, + }, + f, + indent=2, + ) + else: + # Save as PyTorch checkpoint with config embedded + torch.save( + { + "state_dict": self.state_dict(), + "config": { + "vocab_size": self.cfg.vocab_size, + "embed_dim": self.cfg.embed_dim, + "max_tokens": self.cfg.max_tokens, + "dropout": self.cfg.dropout, + "num_classes": self.cfg.num_classes, + **self.cfg.extra, + }, + }, + save_path, + ) + + return save_path diff --git a/aymurai/models/decision/tokenizer.py b/aymurai/models/decision/tokenizer.py deleted file mode 100644 index bbd5cae4..00000000 --- a/aymurai/models/decision/tokenizer.py +++ /dev/null @@ -1,36 +0,0 @@ -import torch -from unidecode import unidecode - -from aymurai.text.tokenizers.spanish import SpanishTokenizer - - -class Tokenizer(object): - def __init__(self, vocab): - self.max_len = 128 - self.tokenizer = SpanishTokenizer() - self.vocab = vocab - - def save(self, path: str): - torch.save(self.vocab, path) - - @classmethod - def load(cls, path: str): - vocab = torch.load(path, weights_only=False) - return cls(vocab=vocab) - - def __call__(self, text: str): - text = text.lower() - text = unidecode(text) - return self.tokenizer(text) - - def encode(self, text: int): - tokens = self(text)[: self.max_len] - indices = self.vocab(tokens) - indices = torch.tensor(indices, dtype=torch.int64) - indices = torch.nn.functional.pad(indices, (0, self.max_len - len(indices))) - return indices - - def encode_batch(self, texts): - indices = [self.encode(text) for text in texts] - indices = torch.stack(indices) - return indices diff --git a/aymurai/text/tokenizers/__init__.py b/aymurai/text/tokenizers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/aymurai/text/tokenizers/spanish.py b/aymurai/text/tokenizers/spanish.py deleted file mode 100644 index fa11b0b4..00000000 --- a/aymurai/text/tokenizers/spanish.py +++ /dev/null @@ -1,372 +0,0 @@ -""" -A simplified clone of spaCy’s Spanish tokenizer (and related components) -without any dependency on spaCy. This module provides: - • TOKENIZER_EXCEPTIONS – a mapping for known exceptions. - • STOP_WORDS – Spanish stop words. - • TOKENIZER_SUFFIXES and TOKENIZER_INFIXES – basic regex rules. - • Lexical attribute getter for “like_num”. - • SpanishTokenizer – a class that tokenizes text using the above rules. - -Note: This is a “simple but close” clone. spaCy’s internal rules are very -comprehensive; here we implement only some of the core ideas. -""" - -import re - -# --- Definitions used in spaCy’s internals, simplified --- -ORTH = "ORTH" -NORM = "NORM" - - -def update_exc(base, new_exc): - base.update(new_exc) - return base - - -# A base (empty) exceptions dict -BASE_EXCEPTIONS = {} - -# --- Tokenizer Exceptions (from spacy.lang.es.tokenizer_exceptions) --- -_exc = { - "pal": [{ORTH: "pa"}, {ORTH: "l", NORM: "el"}], -} - -for exc_data in [ - {ORTH: "n°"}, - {ORTH: "°C"}, - {ORTH: "aprox."}, - {ORTH: "dna."}, - {ORTH: "dpto."}, - {ORTH: "ej."}, - {ORTH: "esq."}, - {ORTH: "pág."}, - {ORTH: "p.ej."}, - {ORTH: "Ud.", NORM: "usted"}, - {ORTH: "Vd.", NORM: "usted"}, - {ORTH: "Uds.", NORM: "ustedes"}, - {ORTH: "Vds.", NORM: "ustedes"}, - {ORTH: "vol.", NORM: "volúmen"}, -]: - _exc[exc_data[ORTH]] = [exc_data] - -# Times exceptions: “12m.” splits into “12” and “m.”, and also the h+a.m./p.m. forms. -_exc["12m."] = [{ORTH: "12"}, {ORTH: "m."}] - -for h in range(1, 13): - for period in ["a.m.", "am"]: - _exc[f"{h}{period}"] = [{ORTH: f"{h}"}, {ORTH: period}] - for period in ["p.m.", "pm"]: - _exc[f"{h}{period}"] = [{ORTH: f"{h}"}, {ORTH: period}] - -for orth in [ - "a.C.", - "a.J.C.", - "d.C.", - "d.J.C.", - "apdo.", - "Av.", - "Avda.", - "Cía.", - "Dr.", - "Dra.", - "EE.UU.", - "Ee.Uu.", - "EE. UU.", - "Ee. Uu.", - "etc.", - "fig.", - "Gob.", - "Gral.", - "Ing.", - "J.C.", - "km/h", - "Lic.", - "m.n.", - "núm.", - "P.D.", - "Prof.", - "Profa.", - "q.e.p.d.", - "Q.E.P.D.", - "S.A.", - "S.L.", - "S.R.L.", - "s.s.s.", - "Sr.", - "Sra.", - "Srta.", -]: - _exc[orth] = [{ORTH: orth}] - -TOKENIZER_EXCEPTIONS = update_exc(BASE_EXCEPTIONS.copy(), _exc) - -# --- Stop words (from spacy.lang.es.stop_words) --- -STOP_WORDS = set( - """ -a acuerdo adelante ademas además afirmó agregó ahi ahora ahí al algo alguna -algunas alguno algunos algún alli allí alrededor ambos ante anterior antes -apenas aproximadamente aquel aquella aquellas aquello aquellos aqui aquél -aquélla aquéllas aquéllos aquí arriba aseguró asi así atras aun aunque añadió -aún - -bajo bastante bien breve buen buena buenas bueno buenos - -cada casi cierta ciertas cierto ciertos cinco claro comentó como con conmigo -conocer conseguimos conseguir considera consideró consigo consigue consiguen -consigues contigo contra creo cual cuales cualquier cuando cuanta cuantas -cuanto cuantos cuatro cuenta cuál cuáles cuándo cuánta cuántas cuánto cuántos -cómo - -da dado dan dar de debajo debe deben debido decir dejó del delante demasiado -demás dentro deprisa desde despacio despues después detras detrás dia dias dice -dicen dicho dieron diez diferente diferentes dijeron dijo dio doce donde dos -durante día días dónde - -e el ella ellas ello ellos embargo en encima encuentra enfrente enseguida -entonces entre era eramos eran eras eres es esa esas ese eso esos esta estaba -estaban estado estados estais estamos estan estar estará estas este esto estos -estoy estuvo está están excepto existe existen explicó expresó él ésa ésas ése -ésos ésta éstas éste éstos - -fin final fue fuera fueron fui fuimos - -gran grande grandes - -ha haber habia habla hablan habrá había habían hace haceis hacemos hacen hacer -hacerlo haces hacia haciendo hago han hasta hay haya he hecho hemos hicieron -hizo hoy hubo - -igual incluso indicó informo informó ir - -junto - -la lado largo las le les llegó lleva llevar lo los luego - -mal manera manifestó mas mayor me mediante medio mejor mencionó menos menudo mi -mia mias mientras mio mios mis misma mismas mismo mismos modo mucha muchas -mucho muchos muy más mí mía mías mío míos - -nada nadie ni ninguna ningunas ninguno ningunos ningún no nos nosotras nosotros -nuestra nuestras nuestro nuestros nueva nuevas nueve nuevo nuevos nunca - -o ocho once os otra otras otro otros - -para parece parte partir pasada pasado paìs peor pero pesar poca pocas poco -pocos podeis podemos poder podria podriais podriamos podrian podrias podrá -podrán podría podrían poner por porque posible primer primera primero primeros -pronto propia propias propio propios proximo próximo próximos pudo pueda puede -pueden puedo pues - -qeu que quedó queremos quien quienes quiere quiza quizas quizá quizás quién -quiénes qué - -realizado realizar realizó repente respecto - -sabe sabeis sabemos saben saber sabes salvo se sea sean segun segunda segundo -según seis ser sera será serán sería señaló si sido siempre siendo siete sigue -siguiente sin sino sobre sois sola solamente solas solo solos somos son soy su -supuesto sus suya suyas suyo suyos sé sí sólo - -tal tambien también tampoco tan tanto tarde te temprano tendrá tendrán teneis -tenemos tener tenga tengo tenido tenía tercera tercero ti tiene tienen toda -todas todavia todavía todo todos total tras trata través tres tu tus tuvo tuya -tuyas tuyo tuyos tú - -u ultimo un una unas uno unos usa usais usamos usan usar usas uso usted ustedes -última últimas último últimos - -va vais vamos van varias varios vaya veces ver verdad verdadera verdadero vez -vosotras vosotros voy vuestra vuestras vuestro vuestros - -y ya yo -""".split() -) - -# --- Punctuation-related rules (a simplified version of spacy.lang.es.punctuation) --- -# Here we provide basic suffix and infix patterns. -TOKENIZER_SUFFIXES = [ - r"[—–]", # dashes - r"[.,!?;:%]", # common punctuation - r"['\"“”‘’]", # quotes -] -# Infixes that split on, for example, hyphens between digits. -TOKENIZER_INFIXES = [ - r"(?<=[0-9])[-/](?=[0-9])", -] - -# --- Lexical attribute getter (from spacy.lang.es.lex_attrs) --- -_num_words = { - "cero", - "uno", - "dos", - "tres", - "cuatro", - "cinco", - "seis", - "siete", - "ocho", - "nueve", - "diez", - "once", - "doce", - "trece", - "catorce", - "quince", - "dieciséis", - "diecisiete", - "dieciocho", - "diecinueve", - "veinte", - "veintiuno", - "veintidós", - "veintitrés", - "veinticuatro", - "veinticinco", - "veintiséis", - "veintisiete", - "veintiocho", - "veintinueve", - "treinta", - "cuarenta", - "cincuenta", - "sesenta", - "setenta", - "ochenta", - "noventa", - "cien", - "mil", - "millón", - "billón", - "trillón", -} -_ordinal_words = { - "primero", - "segundo", - "tercero", - "cuarto", - "quinto", - "sexto", - "séptimo", - "octavo", - "noveno", - "décimo", - "undécimo", - "duodécimo", - "decimotercero", - "decimocuarto", - "decimoquinto", - "decimosexto", - "decimoséptimo", - "decimoctavo", - "decimonoveno", - "vigésimo", - "trigésimo", - "cuadragésimo", - "quincuagésimo", - "sexagésimo", - "septuagésimo", - "octogésima", - "nonagésima", - "centésima", - "milésima", - "millonésima", - "billonésima", -} - - -def like_num(text): - # Remove a leading +, -, ±, or ~ if present. - if text.startswith(("+", "-", "±", "~")): - text = text[1:] - # Remove commas and periods for a digit check. - text_clean = text.replace(",", "").replace(".", "") - if text_clean.isdigit(): - return True - if text.count("/") == 1: - num, denom = text.split("/") - if num.isdigit() and denom.isdigit(): - return True - text_lower = text.lower() - if text_lower in _num_words: - return True - if text_lower in _ordinal_words: - return True - return False - - -LEX_ATTRS = {"LIKE_NUM": like_num} - - -# --- Spanish Tokenizer Implementation --- -class SpanishTokenizer: - """ - Spacy spanish tokenizer clone - Source: https://github.com/explosion/spaCy/tree/b3c46c315eb16ce644bddd106d31c3dd349f6bb2/spacy/lang/es - """ - - def __init__(self): - # A basic regex for “words” and “non-space” characters. - self.word_re = re.compile(r"\w+|[^\w\s]", re.UNICODE) - # Combine infix patterns into one regex. - self.infix_re = re.compile("|".join(TOKENIZER_INFIXES)) - - def apply_exceptions(self, text: str): - """ - If the given text exactly matches a tokenizer exception, - return the corresponding token list. - """ - if text in TOKENIZER_EXCEPTIONS: - # For each exception item (a dict), return the ORTH value, - # falling back to NORM if available. - return [ - item.get(ORTH, item.get(NORM, item)) - for item in TOKENIZER_EXCEPTIONS[text] - ] - return None - - def tokenize(self, text: str): - """ - Tokenizes the input text into a list of tokens. - The algorithm first splits on whitespace, checks for exceptions, - and otherwise applies regex-based splitting and infix splitting. - """ - tokens = [] - for word in text.split(): - exc = self.apply_exceptions(word) - if exc is not None: - tokens.extend(exc) - else: - # First, use regex to split word into basic tokens. - sub_tokens = self.word_re.findall(word) - final_tokens = [] - for token in sub_tokens: - # Apply infix splitting if applicable. - splits = self.infix_re.split(token) - if len(splits) > 1: - last_end = 0 - # Re-find infix matches to capture separators. - for m in self.infix_re.finditer(token): - pre = token[last_end : m.start()] - sep = token[m.start() : m.end()] - if pre: - final_tokens.append(pre) - final_tokens.append(sep) - last_end = m.end() - remainder = token[last_end:] - if remainder: - final_tokens.append(remainder) - else: - final_tokens.append(token) - tokens.extend(final_tokens) - return tokens - - def __call__(self, text: str): - return self.tokenize(text) - - -# --- Example Usage --- -if __name__ == "__main__": - sample_text = "El Sr. habló con 12a.m. y 3pm en la reunión. ¡Increíble, verdad?" - tokenizer = SpanishTokenizer() - tokens = tokenizer(sample_text) - print("Tokens:", tokens) diff --git a/notebooks/experiments/decision/01-training-2class-embeddingbag.ipynb b/notebooks/experiments/decision/01-training-2class-embeddingbag.ipynb new file mode 100644 index 00000000..7870bdb7 --- /dev/null +++ b/notebooks/experiments/decision/01-training-2class-embeddingbag.ipynb @@ -0,0 +1,561 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "44b15c4f", + "metadata": {}, + "source": [ + "# Tiny decision classifier (EmbeddingBag, no torchtext)\n", + "\n", + "A fastText-style baseline for the decision detection task. It uses a hashed bag of words with `nn.EmbeddingBag` pooling and a single linear head to stay extremely small. No `torchtext` dependencies.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e40eb3f5", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload\n", + "%autoreload 2\n" + ] + }, + { + "cell_type": "markdown", + "id": "ce1f616a", + "metadata": {}, + "source": [ + "## Imports and config\n", + "\n", + "- Uses deterministic hashing for tokens to keep a fixed vocab size without building a vocab file.\n", + "- Model size is controlled by `vocab_size` and `embed_dim` (for example, 20k vocab and 64-dim embeddings is roughly 1.3M parameters).\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "461aa6da", + "metadata": {}, + "outputs": [], + "source": [ + "import hashlib\n", + "import os\n", + "import random\n", + "import re\n", + "from dataclasses import dataclass\n", + "from pathlib import Path\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import torch\n", + "from sklearn.model_selection import train_test_split\n", + "from sklearn.utils.class_weight import compute_class_weight\n", + "from torch import nn\n", + "from torch.cuda.amp import autocast, GradScaler\n", + "from torch.utils.data import DataLoader, Dataset\n", + "from unidecode import unidecode\n", + "\n", + "SEED = 42\n", + "random.seed(SEED)\n", + "np.random.seed(SEED)\n", + "torch.manual_seed(SEED)\n", + "torch.cuda.manual_seed_all(SEED)\n", + "torch.backends.cudnn.deterministic = True\n", + "\n", + "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", + "\n", + "\n", + "@dataclass\n", + "class Config:\n", + " data_path: str = \"sentences-decision-manual.csv\"\n", + " vocab_size: int = 20000\n", + " embed_dim: int = 64\n", + " max_tokens: int = 128\n", + " batch_size: int = 512\n", + " lr: float = 5e-3\n", + " weight_decay: float = 1e-3\n", + " epochs: int = 50\n", + " dropout: float = 0.1\n", + " num_workers: int = 2\n", + " checkpoint_path: str = \"checkpoints/tiny-embeddingbag.pt\"\n", + "\n", + "\n", + "cfg = Config()\n", + "\n", + "print(f\"device: {device}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "69fbe089", + "metadata": {}, + "source": [ + "## Load data\n", + "\n", + "Input columns: `path`, `nro_registro`, `tomo`, `sentence`, `decision`, `hace_lugar`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5574c092", + "metadata": {}, + "outputs": [], + "source": [ + "data = pd.read_csv(\n", + " cfg.data_path,\n", + " usecols=[\"path\", \"nro_registro\", \"tomo\", \"sentence\", \"decision\", \"hace_lugar\"],\n", + ")\n", + "print(data.head())\n", + "print(f\"Loaded {len(data)} rows\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "3bc71145", + "metadata": {}, + "source": [ + "## Preprocess labels\n", + "\n", + "- Drop null rows and duplicate sentences.\n", + "- Collapse labels to a binary target: `0 = not decision`, `1 = decision` (regardless of `hace_lugar`).\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cafdac5c", + "metadata": {}, + "outputs": [], + "source": [ + "data.dropna(inplace=True)\n", + "\n", + "\n", + "def force_bool(value):\n", + " return True if value in [\"True\", True, 1, \"1\"] else False\n", + "\n", + "\n", + "def get_category(row):\n", + " decision, hace_lugar = row\n", + " if not decision:\n", + " return 0\n", + " if decision and not hace_lugar:\n", + " return 1\n", + " if decision and hace_lugar:\n", + " return 1\n", + " raise ValueError(\"unexpected label combo\")\n", + "\n", + "\n", + "data[\"decision\"] = data[\"decision\"].apply(force_bool).astype(bool)\n", + "data[\"hace_lugar\"] = data[\"hace_lugar\"].apply(force_bool).astype(bool)\n", + "data[\"category\"] = data[[\"decision\", \"hace_lugar\"]].apply(get_category, axis=1)\n", + "\n", + "data.dropna(subset=[\"category\"], inplace=True)\n", + "data.drop_duplicates(subset=\"sentence\", inplace=True)\n", + "\n", + "print(f\"After cleaning: {len(data)} rows\")\n", + "print(data[[\"category\"]].value_counts(normalize=True) * 100)\n" + ] + }, + { + "cell_type": "markdown", + "id": "cae1826b", + "metadata": {}, + "source": [ + "## Train/val/test split\n", + "\n", + "80/10/10 with stratification on the binary label.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52cb5244", + "metadata": {}, + "outputs": [], + "source": [ + "train_df, test_df = train_test_split(\n", + " data, test_size=0.2, random_state=SEED, stratify=data[\"category\"]\n", + ")\n", + "test_df, val_df = train_test_split(\n", + " test_df, test_size=0.5, random_state=SEED, stratify=test_df[\"category\"]\n", + ")\n", + "\n", + "for name, df_ in {\"train\": train_df, \"val\": val_df, \"test\": test_df}.items():\n", + " print(\n", + " f\"{name}: {len(df_)} rows | class balance: {df_['category'].value_counts(normalize=True).to_dict()}\"\n", + " )\n" + ] + }, + { + "cell_type": "markdown", + "id": "07ae169f", + "metadata": {}, + "source": [ + "## Tokenization and dataset\n", + "\n", + "- Simple normalize → whitespace split.\n", + "- Deterministic 32-bit Blake2 hash per token to map into `[0, vocab_size)`.\n", + "- Truncate to `max_tokens` to bound memory.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1332f587", + "metadata": {}, + "outputs": [], + "source": [ + "def normalize_text(text: str) -> str:\n", + " text = unidecode(str(text)).lower()\n", + " text = re.sub(r\"\\s+\", \" \", text).strip()\n", + " return text\n", + "\n", + "\n", + "def tokenize(text: str) -> list[str]:\n", + " text = normalize_text(text)\n", + " return [tok for tok in text.split(\" \") if tok]\n", + "\n", + "\n", + "def hash_token(token: str, vocab_size: int) -> int:\n", + " digest = hashlib.blake2b(token.encode(\"utf-8\"), digest_size=4).digest()\n", + " return int.from_bytes(digest, \"little\") % vocab_size\n", + "\n", + "\n", + "def encode_text(text: str, cfg: Config) -> torch.Tensor:\n", + " tokens = tokenize(text)\n", + " token_ids = [hash_token(tok, cfg.vocab_size) for tok in tokens[: cfg.max_tokens]]\n", + " if not token_ids:\n", + " token_ids = [0]\n", + " return torch.tensor(token_ids, dtype=torch.long)\n", + "\n", + "\n", + "class HashedTextDataset(Dataset):\n", + " def __init__(self, frame: pd.DataFrame, cfg: Config):\n", + " self.texts = frame[\"sentence\"].tolist()\n", + " self.labels = frame[\"category\"].astype(int).tolist()\n", + " self.cfg = cfg\n", + "\n", + " def __len__(self):\n", + " return len(self.labels)\n", + "\n", + " def __getitem__(self, idx: int):\n", + " token_ids = encode_text(self.texts[idx], self.cfg)\n", + " label = self.labels[idx]\n", + " return token_ids, label\n", + "\n", + "\n", + "def collate_batch(batch):\n", + " token_seqs, labels = zip(*batch)\n", + " offsets = torch.zeros(len(batch), dtype=torch.long)\n", + " total = 0\n", + " flat_tokens = []\n", + " for i, tokens in enumerate(token_seqs):\n", + " offsets[i] = total\n", + " flat_tokens.append(tokens)\n", + " total += len(tokens)\n", + " flat_tokens = torch.cat(flat_tokens)\n", + " labels = torch.tensor(labels, dtype=torch.long)\n", + " return flat_tokens, offsets, labels\n", + "\n", + "\n", + "train_ds = HashedTextDataset(train_df, cfg)\n", + "val_ds = HashedTextDataset(val_df, cfg)\n", + "test_ds = HashedTextDataset(test_df, cfg)\n", + "\n", + "train_loader = DataLoader(\n", + " train_ds,\n", + " batch_size=cfg.batch_size,\n", + " shuffle=True,\n", + " collate_fn=collate_batch,\n", + " num_workers=cfg.num_workers,\n", + ")\n", + "val_loader = DataLoader(\n", + " val_ds,\n", + " batch_size=cfg.batch_size,\n", + " shuffle=False,\n", + " collate_fn=collate_batch,\n", + " num_workers=cfg.num_workers,\n", + ")\n", + "test_loader = DataLoader(\n", + " test_ds,\n", + " batch_size=cfg.batch_size,\n", + " shuffle=False,\n", + " collate_fn=collate_batch,\n", + " num_workers=cfg.num_workers,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "bc80c8af", + "metadata": {}, + "source": [ + "## Model: EmbeddingBag + Linear\n", + "\n", + "Tiny architecture with mean pooling. Dropout is optional for slight regularization.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2605dcc2", + "metadata": {}, + "outputs": [], + "source": [ + "class TinyEmbeddingBagClassifier(nn.Module):\n", + " def __init__(self, cfg: Config, num_classes: int = 2):\n", + " super().__init__()\n", + " self.embedding = nn.EmbeddingBag(cfg.vocab_size, cfg.embed_dim, mode=\"mean\")\n", + " self.dropout = nn.Dropout(cfg.dropout)\n", + " self.head = nn.Linear(cfg.embed_dim, num_classes)\n", + "\n", + " def forward(self, tokens, offsets):\n", + " x = self.embedding(tokens, offsets)\n", + " x = self.dropout(x)\n", + " return self.head(x)\n", + "\n", + "\n", + "model = TinyEmbeddingBagClassifier(cfg).to(device)\n", + "param_count = sum(p.numel() for p in model.parameters())\n", + "print(model)\n", + "print(f\"Parameter count: {param_count:,}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "1a029057", + "metadata": {}, + "source": [ + "## Training utilities\n", + "\n", + "- Class-weighted cross entropy to compensate imbalance.\n", + "- Simple train/val loop with best-model tracking.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8d02447", + "metadata": {}, + "outputs": [], + "source": [ + "class_weights = compute_class_weight(\n", + " class_weight=\"balanced\",\n", + " classes=np.unique(train_df[\"category\"]),\n", + " y=train_df[\"category\"],\n", + ")\n", + "class_weights = torch.tensor(class_weights, dtype=torch.float, device=device)\n", + "\n", + "criterion = nn.CrossEntropyLoss(weight=class_weights)\n", + "optimizer = torch.optim.AdamW(\n", + " model.parameters(), lr=cfg.lr, weight_decay=cfg.weight_decay\n", + ")\n", + "scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(\n", + " optimizer,\n", + " mode=\"min\",\n", + " factor=0.5,\n", + " patience=1,\n", + " threshold=1e-3,\n", + " min_lr=1e-5,\n", + ")\n", + "scaler = GradScaler(enabled=(device == \"cuda\"))\n", + "\n", + "\n", + "def run_epoch(model, loader, optimizer=None, scaler=None):\n", + " train_mode = optimizer is not None\n", + " model.train() if train_mode else model.eval()\n", + "\n", + " total_loss = 0.0\n", + " total_correct = 0\n", + " total_examples = 0\n", + "\n", + " for tokens, offsets, labels in loader:\n", + " tokens = tokens.to(device)\n", + " offsets = offsets.to(device)\n", + " labels = labels.to(device)\n", + "\n", + " if train_mode:\n", + " optimizer.zero_grad(set_to_none=True)\n", + " with autocast(enabled=device == \"cuda\"):\n", + " logits = model(tokens, offsets)\n", + " loss = criterion(logits, labels)\n", + " scaler.scale(loss).backward()\n", + " scaler.step(optimizer)\n", + " scaler.update()\n", + " else:\n", + " with torch.no_grad(), autocast(enabled=device == \"cuda\"):\n", + " logits = model(tokens, offsets)\n", + " loss = criterion(logits, labels)\n", + "\n", + " preds = logits.argmax(dim=1)\n", + " total_correct += (preds == labels).sum().item()\n", + " total_loss += loss.item() * labels.size(0)\n", + " total_examples += labels.size(0)\n", + "\n", + " avg_loss = total_loss / total_examples\n", + " acc = total_correct / total_examples\n", + " return avg_loss, acc\n", + "\n", + "\n", + "best_state = None\n", + "best_val_loss = float(\"inf\")\n", + "\n", + "for epoch in range(cfg.epochs):\n", + " train_loss, train_acc = run_epoch(model, train_loader, optimizer, scaler=scaler)\n", + " val_loss, val_acc = run_epoch(model, val_loader, optimizer=None, scaler=None)\n", + "\n", + " lr_before = optimizer.param_groups[0][\"lr\"]\n", + " scheduler.step(val_loss)\n", + " lr_after = optimizer.param_groups[0][\"lr\"]\n", + "\n", + " if val_loss < best_val_loss:\n", + " best_val_loss = val_loss\n", + " best_state = {k: v.cpu() for k, v in model.state_dict().items()}\n", + "\n", + " if lr_after < lr_before and best_state is not None:\n", + " # resume from best snapshot whenever LR is reduced\n", + " model.load_state_dict(best_state)\n", + "\n", + " cur_lr = optimizer.param_groups[0][\"lr\"]\n", + " print(\n", + " f\"Epoch {epoch + 1:02d} | lr {cur_lr:.2e} | train loss {train_loss:.4f} acc {train_acc:.3f} | \"\n", + " f\"val loss {val_loss:.4f} acc {val_acc:.3f}\"\n", + " )\n", + "\n", + "if best_state is not None:\n", + " model.load_state_dict(best_state)\n", + " print(f\"Loaded best state with val loss={best_val_loss:.4f}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "fb768bda", + "metadata": {}, + "source": [ + "## Evaluation\n", + "\n", + "Compute accuracy and a quick classification report on the held-out splits.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf65d689", + "metadata": {}, + "outputs": [], + "source": [ + "from sklearn.metrics import classification_report, confusion_matrix\n", + "\n", + "\n", + "def collect_predictions(model, loader):\n", + " model.eval()\n", + " all_preds, all_labels = [], []\n", + " with torch.no_grad():\n", + " for tokens, offsets, labels in loader:\n", + " tokens = tokens.to(device)\n", + " offsets = offsets.to(device)\n", + " logits = model(tokens, offsets)\n", + " preds = logits.argmax(dim=1).cpu().tolist()\n", + " all_preds.extend(preds)\n", + " all_labels.extend(labels.tolist())\n", + " return all_labels, all_preds\n", + "\n", + "\n", + "for split_name, loader in [(\"val\", val_loader), (\"test\", test_loader)]:\n", + " y_true, y_pred = collect_predictions(model, loader)\n", + " print(f\"=== {split_name.upper()} ===\")\n", + " print(classification_report(y_true, y_pred, digits=3))\n", + " print(\"Confusion matrix:\")\n", + " print(confusion_matrix(y_true, y_pred))\n" + ] + }, + { + "cell_type": "markdown", + "id": "97811900", + "metadata": {}, + "source": [ + "## Save checkpoint\n", + "\n", + "Saves a lightweight `state_dict` for later reuse.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "57af7004", + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "\n", + "\n", + "ckpt_path = Path(cfg.checkpoint_path)\n", + "ckpt_path.parent.mkdir(parents=True, exist_ok=True)\n", + "torch.save({\"config\": cfg.__dict__, \"state_dict\": model.state_dict()}, ckpt_path)\n", + "print(f\"Saved to {ckpt_path}\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "3c93782b", + "metadata": {}, + "source": [ + "## Save as safetensors\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7dc23b22", + "metadata": {}, + "outputs": [], + "source": [ + "from safetensors.torch import save_file\n", + "import json\n", + "\n", + "# Save model weights as safetensors\n", + "safetensor_path = ckpt_path.with_suffix(\".safetensors\")\n", + "save_file(model.state_dict(), safetensor_path)\n", + "\n", + "# Save config separately as JSON\n", + "config_path = ckpt_path.with_suffix(\".json\")\n", + "with open(config_path, \"w\") as f:\n", + " json.dump(cfg.__dict__, f, indent=2)\n", + "\n", + "print(f\"Saved model to {safetensor_path}\")\n", + "print(f\"Saved config to {config_path}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdbfa386", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/resources/pipelines/production/full-paragraph/pipeline.json b/resources/pipelines/production/full-paragraph/pipeline.json index b5da2f9e..bfba7682 100644 --- a/resources/pipelines/production/full-paragraph/pipeline.json +++ b/resources/pipelines/production/full-paragraph/pipeline.json @@ -14,6 +14,15 @@ "device": "cpu", "use_tokenizer": false } + ], + [ + "aymurai.models.decision.binregex.DecisionEmbeddingBagBinRegex", + { + "model_checkpoint": "https://github.com/AymurAI/backend/releases/download/v2.0.0-alpha.1/tiny-embeddingbag.safetensors", + "device": "cpu", + "threshold": 0.5, + "return_only_with_detalle": true + } ] ], "postprocess": [ diff --git a/uv.lock b/uv.lock index e8a103b2..78db5ef7 100644 --- a/uv.lock +++ b/uv.lock @@ -285,7 +285,7 @@ wheels = [ [[package]] name = "aymurai" -version = "2.0.0a3.dev9" +version = "2.0.0a4.dev1" source = { editable = "." } dependencies = [ { name = "alembic" }, From 90f73690be89c501e181f27786bc9fe3e3f72ab8 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Wed, 7 Jan 2026 14:40:22 +0000 Subject: [PATCH 028/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20TensorFlow=20en?= =?UTF-8?q?vironment=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.common | 3 --- 1 file changed, 3 deletions(-) diff --git a/.env.common b/.env.common index 5760c797..1eec416e 100644 --- a/.env.common +++ b/.env.common @@ -8,6 +8,3 @@ TESSDATA_PREFIX=/usr/local/share/tessdata AYMURAI_RESTRICTED_DOCUMENT_PDFS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO-pdf" AYMURAI_RESTRICTED_DOCUMENT_DOCS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO" - -TF_CPP_MIN_LOG_LEVEL=3 -TFHUB_CACHE_DIR=/resources/cache/tfhub_modules From 0070916454f445029dabc8d65c9b54fe0c9e4743 Mon Sep 17 00:00:00 2001 From: Paolo Donizetti Date: Thu, 8 Jan 2026 12:08:08 -0300 Subject: [PATCH 029/104] Feature/mlfow integration (#66) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add mlflow-based experiments and services (wip) * feat: finalize mlflow experiment runner and artifact logging * feat: add OpenAI ChatGPT extension and update postStartCommand in devcontainer * 📝 Unify disambiguation evaluation notebooks * 📝 Enhance documentation and add type hints across multiple modules * 📌 Update uv.lock * 🔧 Update devcontainer GPU device configuration * 🔧 Change default Python environment manager to venv * 🔧 Add container names for all services in docker-compose.yml * ➖ Remove commented optional dependencies for GPU support in pyproject.toml * 🔧 Increase document request timeout from 30 to 300 seconds in .env.common * 🚚 Changed environment variable names from DOCUMENT_API_BASE_URL and DOCUMENT_REQUEST_TIMEOUT to API_BASE_URL and REQUEST_TIMEOUT * 🔧 Update dependency installation to include 'mlops' group in entrypoint.sh * 🔖 Update aymurai package version to 2.0.0a5.dev8 --- .devcontainer/devcontainer.json | 9 +- .devcontainer/docker-compose.yml | 4 +- .devcontainer/entrypoint.sh | 2 +- .env.common | 9 + .vscode/settings.json | 2 +- Makefile | 16 +- aymurai/evaluation/metrics.py | 8 +- aymurai/experiments/__init__.py | 1 + .../entity_disambiguation/__init__.py | 1 + .../entity_disambiguation/config.py | 176 +++ .../entity_disambiguation/manifest.py | 51 + .../entity_disambiguation/mlflow_logging.py | 111 ++ .../entity_disambiguation/runner.py | 468 ++++++++ aymurai/utils/paths.py | 40 + docker-compose.yml | 85 ++ docs/experiments/README.md | 90 ++ docs/experiments/base.yaml | 50 + .../metrics}/Desarrollo metrica.md | 4 +- .../01-entity-disambiguation.ipynb | 20 +- .../03-disambiguation-evaluation.ipynb | 6 +- ...ation-from-pre-clustered-validations.ipynb | 8 +- .../01-summarization-benchmark.ipynb | 8 +- .../04-dspy-prompt-optimization.ipynb | 8 +- pyproject.toml | 10 +- uv.lock | 1032 +++++++++++------ 25 files changed, 1802 insertions(+), 417 deletions(-) create mode 100644 aymurai/experiments/__init__.py create mode 100644 aymurai/experiments/entity_disambiguation/__init__.py create mode 100644 aymurai/experiments/entity_disambiguation/config.py create mode 100644 aymurai/experiments/entity_disambiguation/manifest.py create mode 100644 aymurai/experiments/entity_disambiguation/mlflow_logging.py create mode 100644 aymurai/experiments/entity_disambiguation/runner.py create mode 100644 aymurai/utils/paths.py create mode 100644 docs/experiments/README.md create mode 100644 docs/experiments/base.yaml rename {notebooks/experiments/entity-disambiguation => docs/metrics}/Desarrollo metrica.md (98%) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2ead9957..5aa72ad5 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,6 +9,9 @@ "aymurai-devcontainer-gpu" ], "workspaceFolder": "/workspace", + "mounts": [ + "source=codex-data,target=/home/ubuntu/.codex,type=volume" + ], "customizations": { "vscode": { "settings": { @@ -47,9 +50,11 @@ "cweijan.vscode-database-client2", "christian-kohler.path-intellisense", "github.vscode-github-actions", - "seatonjiang.gitmoji-vscode" + "seatonjiang.gitmoji-vscode", + "openai.chatgpt" ] } }, - "postCreateCommand": "bash /home/ubuntu/entrypoint.sh" + "postCreateCommand": "bash /home/ubuntu/entrypoint.sh", + "postStartCommand": "sudo chown -R ubuntu:ubuntu /home/ubuntu/.codex && sudo chmod -R u+rwX /home/ubuntu/.codex" } \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 5e12b20d..9477b892 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -27,7 +27,9 @@ services: resources: reservations: devices: - - capabilities: [ gpu ] + - driver: nvidia + count: all + capabilities: [ gpu ] aymurai-devcontainer: <<: *template diff --git a/.devcontainer/entrypoint.sh b/.devcontainer/entrypoint.sh index 000c3360..214ac9f6 100644 --- a/.devcontainer/entrypoint.sh +++ b/.devcontainer/entrypoint.sh @@ -1,7 +1,7 @@ #!/bin/sh # install dependencies -uv sync --frozen --all-extras +uv sync --frozen --all-extras --group mlops # configure precommit uv run pre-commit install diff --git a/.env.common b/.env.common index 1eec416e..38601115 100644 --- a/.env.common +++ b/.env.common @@ -8,3 +8,12 @@ TESSDATA_PREFIX=/usr/local/share/tessdata AYMURAI_RESTRICTED_DOCUMENT_PDFS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO-pdf" AYMURAI_RESTRICTED_DOCUMENT_DOCS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO" + +API_BASE_URL=http://localhost:8899 +REQUEST_TIMEOUT=300 + +MLFLOW_TRACKING_URI=http://localhost:5000 +MLFLOW_S3_ENDPOINT_URL=http://localhost:9002 +MLFLOW_S3_IGNORE_TLS=true +MLFLOW_EXPERIMENT_NAME=entity-disambiguation +MLFLOW_ARTIFACT_ROOT=s3://mlflow/artifacts diff --git a/.vscode/settings.json b/.vscode/settings.json index 3fa21ad3..dc48662f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "python-envs.defaultEnvManager": "ms-python.python:system", + "python-envs.defaultEnvManager": "ms-python.python:venv", "python-envs.pythonProjects": [], "files.associations": { ".csv": "csv", diff --git a/Makefile b/Makefile index d828a9e1..b49053fd 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,6 @@ API_SERVICE ?= aymurai-api # Select which full API service to control (override with API_FULL_SERVICE=aymurai-api-full-gpu) API_FULL_SERVICE ?= aymurai-api-full - api-build: docker compose build $(API_SERVICE) api-run: @@ -115,6 +114,21 @@ endif docker compose up -d --no-recreate $(OLLAMA_SERVICE) docker compose exec $(OLLAMA_SERVICE) ollama rm $(MODEL) +mlops-up: + docker compose up -d postgres minio minio-mc mlflow + +mlops-stop: + docker compose stop mlflow minio minio-mc postgres + +mlops-logs: + docker compose logs -f mlflow + +exp-run: +ifndef CONFIG + $(error CONFIG variable is required, e.g. make exp-run CONFIG=resources/experiments/entity-disambiguation/exp-gemma3-pv1.yaml) +endif + uv run --group mlops -- python -m aymurai.experiments.entity_disambiguation.runner --config $(CONFIG) + stress-test: locust -f locustfile.py --host http://localhost:8899 diff --git a/aymurai/evaluation/metrics.py b/aymurai/evaluation/metrics.py index 30bceca5..e9b2058a 100644 --- a/aymurai/evaluation/metrics.py +++ b/aymurai/evaluation/metrics.py @@ -7,6 +7,7 @@ from aymurai.logger import get_logger from aymurai.utils.json_data import load_json +from aymurai.utils.paths import prediction_filename_for_test, test_id_from_filename logger = get_logger(__name__) @@ -44,6 +45,7 @@ def get_alias_set(entity: dict[str, Any], normalize: bool = True) -> set[str]: optional 'aliases' (list of strings) and 'canonical_text' (string) keys. normalize (bool, optional): If True, normalizes the alias texts using normalize_text function. Defaults to True. + Returns: set[str]: A set of alias strings (normalized if normalize=True) including both explicit aliases and the canonical text. @@ -339,8 +341,8 @@ def evaluate_prediction_directories( results = [] for test_path in sorted(test_dir.glob("*.json")): - prefix = test_path.name[: -len(".json")] - pred_path = preds_dir / f"{prefix}.json" + doc_id = test_id_from_filename(test_path) + pred_path = preds_dir / prediction_filename_for_test(test_path) if not pred_path.exists(): logger.warning(f"Prediction for {test_path.name} was not found; skipping.") @@ -355,7 +357,7 @@ def evaluate_prediction_directories( sim_threshold=sim_threshold, normalize=normalize, ) - results.append((prefix, score, metrics)) + results.append((doc_id, score, metrics)) average_score = ( sum(score for _, score, _ in results) / len(results) diff --git a/aymurai/experiments/__init__.py b/aymurai/experiments/__init__.py new file mode 100644 index 00000000..78e64a4b --- /dev/null +++ b/aymurai/experiments/__init__.py @@ -0,0 +1 @@ +"""Experiment modules and helpers.""" diff --git a/aymurai/experiments/entity_disambiguation/__init__.py b/aymurai/experiments/entity_disambiguation/__init__.py new file mode 100644 index 00000000..17dc9d09 --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/__init__.py @@ -0,0 +1 @@ +"""Entity disambiguation experiment helpers.""" diff --git a/aymurai/experiments/entity_disambiguation/config.py b/aymurai/experiments/entity_disambiguation/config.py new file mode 100644 index 00000000..68f54534 --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/config.py @@ -0,0 +1,176 @@ +import os +from datetime import datetime, timezone +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field + +from aymurai.utils.yaml_data import load_yaml + + +class ExperimentConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + name: str + run_name: str + + +class ModelConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + provider: str + name: str + temperature: float | None = None + max_tokens: int | None = None + + +class PromptSpec(BaseModel): + model_config = ConfigDict(extra="forbid") + + id: str + text: str | None = None + + +class PromptsConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + system: PromptSpec + user: PromptSpec + + +class DataManifestConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + enabled: bool = True + mode: Literal["metadata_only"] = "metadata_only" + + +class DataConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + ground_truth_dir: str + input_dir: str + dataset_id: str | None = None + manifest: DataManifestConfig = DataManifestConfig() + + +class PredictionsConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + output_base_dir: str + dir_name_template: str + + +class MLflowConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + tracking_uri: str + experiment_name: str + + +class LoggingPrivacyConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + log_prompt_text: bool = True + log_data_manifest: bool = False + log_per_doc_scores: bool = True + + +class PerDocScoresConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + id_strategy: str = "anon_filename" + + +class LoggingConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + mlflow: MLflowConfig + privacy: LoggingPrivacyConfig = LoggingPrivacyConfig() + per_doc_scores: PerDocScoresConfig = PerDocScoresConfig() + + +class EvaluationConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + function: str = "evaluate_disambiguation" + weights: dict[str, float] = Field( + default_factory=lambda: { + "w_ent": 0.4, + "w_alias": 0.35, + "w_label": 0.2, + "w_role": 0.05, + } + ) + per_doc_scores: bool = True + sim_threshold: float | None = None + normalize: bool = True + + +class ExperimentRunConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + experiment: ExperimentConfig + model: ModelConfig + prompts: PromptsConfig + data: DataConfig + predictions: PredictionsConfig + logging: LoggingConfig + evaluation: EvaluationConfig + + +def load_experiment_config(path: str) -> ExperimentRunConfig: + """ + Load an experiment configuration from a YAML file. + + Args: + path (str): Path to the YAML configuration file. + + Raises: + ValueError: If the MLflow tracking URI is not set in the environment or configuration. + + Returns: + ExperimentRunConfig: The loaded experiment configuration. + """ + data = load_yaml(path) + tracking_uri = os.getenv("MLFLOW_TRACKING_URI") + if tracking_uri: + logging_cfg = data.setdefault("logging", {}) + mlflow_cfg = logging_cfg.setdefault("mlflow", {}) + mlflow_cfg["tracking_uri"] = tracking_uri + else: + mlflow_cfg = data.get("logging", {}).get("mlflow", {}) + if "tracking_uri" not in mlflow_cfg: + raise ValueError( + "MLFLOW_TRACKING_URI is required but was not set in the environment." + ) + return ExperimentRunConfig.model_validate(data) + + +def render_run_name( + template: str, + model_name: str, + system_id: str, + user_id: str, + *, + timestamp: str | None = None, +) -> str: + """ + Render a run name based on a template and provided identifiers. + + Args: + template (str): The template string for the run name. + model_name (str): The name of the model. + system_id (str): The system identifier. + user_id (str): The user identifier. + timestamp (str | None, optional): The timestamp string. Defaults to None. + + Returns: + str: The rendered run name. + """ + timestamp = timestamp or datetime.now(timezone.utc).strftime("%y%m%d_%H%M") + return template.format( + model=model_name, + system_id=system_id, + user_id=user_id, + timestamp=timestamp, + ) diff --git a/aymurai/experiments/entity_disambiguation/manifest.py b/aymurai/experiments/entity_disambiguation/manifest.py new file mode 100644 index 00000000..2e2c37fa --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/manifest.py @@ -0,0 +1,51 @@ +import hashlib +import json +from dataclasses import dataclass +from pathlib import Path + + +@dataclass(frozen=True) +class DatasetInfo: + dataset_hash: str + dataset_count: int + dataset_bytes_total: int + manifest: dict | None = None + + +def build_metadata_manifest(root_dir: Path) -> DatasetInfo: + """ + Build a metadata manifest for the dataset located at the given root directory. + + Args: + root_dir (Path): The root directory of the dataset. + + Returns: + DatasetInfo: An object containing dataset hash, count, total bytes, and manifest. + """ + files = [] + total_bytes = 0 + + for path in sorted(root_dir.rglob("*")): + if not path.is_file(): + continue + stat = path.stat() + rel_path = path.relative_to(root_dir).as_posix() + files.append( + { + "path": rel_path, + "size_bytes": stat.st_size, + "mtime": int(stat.st_mtime), + } + ) + total_bytes += stat.st_size + + manifest = {"files": files, "summary": {"count": len(files), "bytes": total_bytes}} + manifest_bytes = json.dumps(files, sort_keys=True).encode("utf-8") + dataset_hash = hashlib.sha256(manifest_bytes).hexdigest() + + return DatasetInfo( + dataset_hash=dataset_hash, + dataset_count=len(files), + dataset_bytes_total=total_bytes, + manifest=manifest, + ) diff --git a/aymurai/experiments/entity_disambiguation/mlflow_logging.py b/aymurai/experiments/entity_disambiguation/mlflow_logging.py new file mode 100644 index 00000000..b9e0a799 --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/mlflow_logging.py @@ -0,0 +1,111 @@ +import json +import tempfile +from pathlib import Path + +import mlflow + +from aymurai.experiments.entity_disambiguation.config import ExperimentRunConfig +from aymurai.experiments.entity_disambiguation.manifest import DatasetInfo +from aymurai.utils.yaml_data import save_yaml + + +def configure_mlflow(config: ExperimentRunConfig) -> None: + """ + Configure MLflow tracking URI and experiment name. + + Args: + config (ExperimentRunConfig): Experiment run configuration. + """ + mlflow.set_tracking_uri(config.logging.mlflow.tracking_uri) + mlflow.set_experiment(config.logging.mlflow.experiment_name) + + +def log_run_metadata( + config: ExperimentRunConfig, + *, + run_name: str | None = None, + preds_dir_name: str | None = None, + dataset_info: DatasetInfo | None = None, + metrics: dict[str, float] | None = None, + per_doc_scores: dict[str, object] | None = None, +) -> None: + """ + Log run metadata to MLflow. + + Args: + config (ExperimentRunConfig): Experiment run configuration. + run_name (str | None, optional): Run name. Defaults to None. + preds_dir_name (str | None, optional): Predictions directory name. Defaults to None. + dataset_info (DatasetInfo | None, optional): Dataset information. Defaults to None. + metrics (dict[str, float] | None, optional): Metrics to log. Defaults to None. + per_doc_scores (dict[str, object] | None, optional): Per-document scores to log. Defaults to None. + """ + params = { + "model_provider": config.model.provider, + "model_name": config.model.name, + "system_prompt_id": config.prompts.system.id, + "user_prompt_id": config.prompts.user.id, + "preds_dir_template": config.predictions.dir_name_template, + } + if run_name: + params["run_name"] = run_name + if preds_dir_name: + params["preds_dir_name"] = preds_dir_name + if config.model.temperature is not None: + params["temperature"] = config.model.temperature + if config.model.max_tokens is not None: + params["max_tokens"] = config.model.max_tokens + if config.data.dataset_id: + params["dataset_id"] = config.data.dataset_id + + if dataset_info: + params.update( + { + "dataset_hash": dataset_info.dataset_hash, + "dataset_count": dataset_info.dataset_count, + "dataset_bytes_total": dataset_info.dataset_bytes_total, + } + ) + + mlflow.log_params(params) + + if metrics: + mlflow.log_metrics(metrics) + + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_path = Path(tmp_dir) + config_payload = config.model_dump(mode="json") + if not config.logging.privacy.log_prompt_text: + config_payload["prompts"]["system"]["text"] = "" + config_payload["prompts"]["user"]["text"] = "" + config_path = tmp_path / "config.yaml" + save_yaml(config_payload, str(config_path)) + mlflow.log_artifact(str(config_path), artifact_path="config") + + if config.logging.privacy.log_prompt_text: + system_path = tmp_path / "system_prompt.txt" + user_path = tmp_path / "user_prompt.txt" + system_path.write_text(config.prompts.system.text or "", encoding="utf-8") + user_path.write_text(config.prompts.user.text or "", encoding="utf-8") + mlflow.log_artifact(str(system_path), artifact_path="prompts") + mlflow.log_artifact(str(user_path), artifact_path="prompts") + + if ( + config.logging.privacy.log_data_manifest + and dataset_info + and dataset_info.manifest + ): + manifest_path = tmp_path / "manifest.json" + manifest_path.write_text( + json.dumps(dataset_info.manifest, indent=2, sort_keys=True), + encoding="utf-8", + ) + mlflow.log_artifact(str(manifest_path), artifact_path="data") + + if config.logging.privacy.log_per_doc_scores and per_doc_scores: + scores_path = tmp_path / "per_doc_scores.json" + scores_path.write_text( + json.dumps(per_doc_scores, indent=2, sort_keys=True), + encoding="utf-8", + ) + mlflow.log_artifact(str(scores_path), artifact_path="metrics") diff --git a/aymurai/experiments/entity_disambiguation/runner.py b/aymurai/experiments/entity_disambiguation/runner.py new file mode 100644 index 00000000..2cc372ce --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/runner.py @@ -0,0 +1,468 @@ +import argparse +import json +import mimetypes +import os +import re +import time +from pathlib import Path +from typing import Any, Iterable + +import mlflow +import requests +from more_itertools import unique_everseen +from tqdm import tqdm + +from aymurai.evaluation.metrics import evaluate_disambiguation +from aymurai.experiments.entity_disambiguation.config import ( + load_experiment_config, + render_run_name, +) +from aymurai.experiments.entity_disambiguation.manifest import build_metadata_manifest +from aymurai.experiments.entity_disambiguation.mlflow_logging import ( + configure_mlflow, + log_run_metadata, +) +from aymurai.llm_providers import OllamaLLMProvider +from aymurai.logger import get_logger +from aymurai.meta.entities import CanonicalEntities, CanonicalEntity +from aymurai.utils.json_data import get_pretty, load_json, save_json +from aymurai.utils.paths import prediction_filename_for_test, test_id_from_filename + +logger = get_logger(__name__) + +DOC_EXTENSIONS = {".pdf", ".docx"} + + +def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]: + """ + Discover documents in a directory with given extensions. + + Args: + root (Path): Root directory to search for documents. + extensions (Iterable[str]): File extensions to include. + + Returns: + list[Path]: List of discovered document paths with the specified extensions. + """ + extensions = {ext.lower() for ext in extensions} + return sorted( + path + for path in root.rglob("*") + if path.is_file() and path.suffix.lower() in extensions + ) + + +def call_extraction_api( + session: requests.Session, endpoint: str, file_path: Path, timeout_s: float +) -> dict[str, object]: + """ + Call the extraction API with a document file. + + Args: + session (requests.Session): HTTP session for making requests. + endpoint (str): URL of the extraction API endpoint. + file_path (Path): Path to the document file to be processed. + timeout_s (float): Request timeout in seconds. + + Returns: + dict[str, object]: Payload containing the response details. + """ + payload: dict[str, object] = { + "path": str(file_path), + "status": "failure", + "status_code": None, + "elapsed_s": None, + "detail": None, + } + + if not file_path.exists(): + payload["detail"] = "File does not exist" + return payload + + mime_type = mimetypes.guess_type(file_path.name)[0] or "application/octet-stream" + files = { + "file": (file_path.name, file_path.open("rb"), mime_type), + } + + try: + start = time.perf_counter() + response = session.post( + endpoint, + files=files, + timeout=timeout_s, + ) + elapsed = time.perf_counter() - start + except requests.RequestException as exc: + payload["detail"] = f"Request failed: {exc}" + return payload + finally: + files["file"][1].close() + + payload["status_code"] = response.status_code + payload["elapsed_s"] = elapsed + + try: + response_body = response.json() + except ValueError: + response_body = {"raw": response.text[:500]} + + if response.ok: + payload["status"] = "success" + payload["detail"] = { + "document_id": response_body.get("document_id"), + "document": response_body.get("document", []), + } + else: + payload["detail"] = response_body + + return payload + + +def get_predictions( + session: requests.Session, endpoint: str, sample: str, timeout_s: float +) -> dict: + """ + Get predictions from the prediction API for a given text sample. + + Args: + session (requests.Session): HTTP session for making requests. + endpoint (str): URL of the prediction API endpoint. + sample (str): Text sample to be predicted. + timeout_s (float): Request timeout in seconds. + + Returns: + dict: Prediction response as a dictionary. + """ + response = session.post(url=endpoint, json={"text": sample}, timeout=timeout_s) + response.raise_for_status() + return response.json() + + +def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]: + """ + Parse prediction labels to extract unique aymurai labels and their alternative texts. + + Args: + predictions (list[dict[str, Any]]): List of prediction dictionaries. + + Returns: + list[dict[str, str]]: List of dictionaries containing unique aymurai labels and their alternative texts. + """ + attrs_stream = ( + label.get("attrs") or {} + for label in (label for pred in predictions for label in pred.get("labels", ())) + ) + + unique_pairs = unique_everseen( + ( + attrs.get("aymurai_label"), + attrs.get("aymurai_alt_text"), + ) + for attrs in attrs_stream + if attrs.get("aymurai_label") and attrs.get("aymurai_alt_text") + ) + + return sorted( + ({"aymurai_label": label, "text": text} for label, text in unique_pairs), + key=lambda item: (item["aymurai_label"], item["text"]), + ) + + +def sanitize_filename(path: Path) -> str: + """ + Sanitize a filename by replacing spaces and underscores with hyphens and collapsing multiple hyphens. + + Args: + path (Path): Path object representing the file. + + Returns: + str: Sanitized filename as a string. + """ + base = os.path.splitext(path.name)[0] + target = re.sub(r"\s+|_", "-", base) + target = re.sub(r"-{2,}", "-", target) + return target + + +def extract_canonical_entities( + *, + session: requests.Session, + doc_path: Path, + extract_endpoint: str, + predict_endpoint: str, + timeout_s: float, + model_name: str, + system_prompt: str, + user_prompt_template: str, + temperature: float | None, + max_tokens: int | None, +) -> list[CanonicalEntity]: + """ + Extract canonical entities from a document using extraction and prediction APIs. + + Args: + session (requests.Session): HTTP session for making requests. + doc_path (Path): Path to the document file. + extract_endpoint (str): URL of the extraction API endpoint. + predict_endpoint (str): URL of the prediction API endpoint. + timeout_s (float): Request timeout in seconds. + model_name (str): Name of the LLM model to use. + system_prompt (str): System prompt text. + user_prompt_template (str): User prompt template text. + temperature (float | None): Temperature setting for the LLM. + max_tokens (int | None): Maximum tokens setting for the LLM. + + Raises: + ValueError: If the document text is empty or not found. + + Returns: + list[CanonicalEntity]: List of extracted canonical entities. + """ + document_payload = call_extraction_api( + session, + extract_endpoint, + doc_path, + timeout_s, + ) + document = document_payload.get("detail", {}).get("document") + + if not document: + raise ValueError("Document text is empty or not found.") + + ner_predictions = [ + get_predictions(session, predict_endpoint, paragraph, timeout_s) + for paragraph in tqdm(document, desc=f"NER {doc_path.name}") + ] + parsed_ner_labels = parse_prediction_labels(ner_predictions) + ner_output_json = get_pretty(parsed_ner_labels) + + user_prompt = user_prompt_template.format( + document_text="\n".join(document).strip(), + ner_output_json=ner_output_json, + ) + + provider = OllamaLLMProvider(model=model_name) + options: dict[str, object] = {} + if temperature is not None: + options["temperature"] = temperature + if max_tokens is not None: + options["num_predict"] = max_tokens + + generate_kwargs: dict[str, object] = { + "messages": [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt}, + ], + "format": CanonicalEntities.model_json_schema(), + } + if options: + generate_kwargs["options"] = options + + response = provider.generate(**generate_kwargs) + + payload = json.loads(response.text) + canonical_entities = [ + CanonicalEntity.model_validate(output) + for output in payload.get("canonical_entities", []) + ] + + return canonical_entities + + +def run_experiment(config_path: str) -> None: + """ + Run the entity disambiguation experiment based on the provided configuration. + + Args: + config_path (str): Path to the experiment configuration file. + + Raises: + FileNotFoundError: If the input directory is not found. + FileNotFoundError: If the ground truth directory is not found. + RuntimeError: If no documents are found in the input directory. + ValueError: If there is an error in processing the documents. + """ + config = load_experiment_config(config_path) + + input_dir = Path(config.data.input_dir) + ground_truth_dir = Path(config.data.ground_truth_dir) + + if not input_dir.exists(): + raise FileNotFoundError(f"Input directory not found: {input_dir}") + if not ground_truth_dir.exists(): + raise FileNotFoundError(f"Ground truth directory not found: {ground_truth_dir}") + + documents = discover_documents(input_dir, DOC_EXTENSIONS) + if not documents: + raise RuntimeError(f"No documents found under {input_dir}") + + timestamp = time.strftime("%y%m%d_%H%M") + run_name = render_run_name( + config.experiment.run_name, + config.model.name, + config.prompts.system.id, + config.prompts.user.id, + timestamp=timestamp, + ) + preds_dir_name = render_run_name( + config.predictions.dir_name_template, + config.model.name, + config.prompts.system.id, + config.prompts.user.id, + timestamp=timestamp, + ) + output_dir = Path(config.predictions.output_base_dir) / preds_dir_name + output_dir.mkdir(parents=True, exist_ok=False) + + dataset_info = ( + build_metadata_manifest(ground_truth_dir) + if config.data.manifest.enabled + else None + ) + + api_base_url = os.getenv("API_BASE_URL", "http://localhost:8899") + extract_endpoint = f"{api_base_url}/misc/document-extract" + predict_endpoint = f"{api_base_url}/anonymizer/predict" + timeout_s = float(os.getenv("REQUEST_TIMEOUT", "30")) + + logger.info(f"Processing {len(documents)} documents from {input_dir}") + logger.info(f"Predictions will be stored in {output_dir}") + + configure_mlflow(config) + + per_doc_scores: dict[str, object] = {} + metrics_summary: dict[str, float] = {} + + with mlflow.start_run(run_name=run_name): + session = requests.Session() + + processed = 0 + failed = 0 + + for doc_path in documents: + logger.info(f"Processing document: {doc_path.name}") + try: + canonical_entities = extract_canonical_entities( + session=session, + doc_path=doc_path, + extract_endpoint=extract_endpoint, + predict_endpoint=predict_endpoint, + timeout_s=timeout_s, + model_name=config.model.name, + system_prompt=config.prompts.system.text or "", + user_prompt_template=config.prompts.user.text or "", + temperature=config.model.temperature, + max_tokens=config.model.max_tokens, + ) + target_filename = sanitize_filename(doc_path) + target_path = output_dir / f"{target_filename}.json" + save_json( + [ + entity.model_dump() + | { + "entity_id": entity.entity_id.hex + if entity.entity_id + else None + } + for entity in canonical_entities + ], + str(target_path), + ) + processed += 1 + except Exception as exc: + failed += 1 + logger.warning(f"Error processing {doc_path.name}: {exc}") + + if config.evaluation.function != "evaluate_disambiguation": + raise ValueError( + f"Unsupported evaluation function: {config.evaluation.function}" + ) + + results = [] + if output_dir.exists(): + for test_path in sorted(ground_truth_dir.glob("*.json")): + doc_id = test_id_from_filename(test_path) + pred_path = output_dir / prediction_filename_for_test(test_path) + + if not pred_path.exists(): + logger.warning( + f"Prediction for {test_path.name} was not found; skipping." + ) + continue + + gold_data = load_json(str(test_path)) + pred_data = load_json(str(pred_path)) + + score, metrics = evaluate_disambiguation( + gold_data, + pred_data, + w_ent=config.evaluation.weights.get("w_ent", 0.4), + w_alias=config.evaluation.weights.get("w_alias", 0.35), + w_label=config.evaluation.weights.get("w_label", 0.2), + w_role=config.evaluation.weights.get("w_role", 0.05), + sim_threshold=config.evaluation.sim_threshold or 0.3, + normalize=config.evaluation.normalize, + ) + results.append((doc_id, score, metrics)) + + average = ( + sum(score for _, score, _ in results) / len(results) + if results + else float("nan") + ) + + if results: + metrics_summary["score_avg"] = average + metrics_summary["doc_count"] = float(len(results)) + + metric_names = set(results[0][2].keys()) + for metric_name in metric_names: + metrics_summary[f"{metric_name}_avg"] = sum( + metrics.get(metric_name, 0.0) for _, _, metrics in results + ) / len(results) + + for doc_id, score, metrics in results: + per_doc_scores[doc_id] = {"score": score, **metrics} + + metrics_summary["docs_processed"] = float(processed) + metrics_summary["docs_failed"] = float(failed) + + log_run_metadata( + config, + run_name=run_name, + preds_dir_name=preds_dir_name, + dataset_info=dataset_info, + metrics=metrics_summary if metrics_summary else None, + per_doc_scores=per_doc_scores if per_doc_scores else None, + ) + + +def build_arg_parser() -> argparse.ArgumentParser: + """ + Build the argument parser for the entity disambiguation experiment. + + Returns: + argparse.ArgumentParser: The configured argument parser. + """ + parser = argparse.ArgumentParser( + description="Run entity disambiguation experiment from a YAML config.", + ) + parser.add_argument( + "--config", + required=True, + help="Path to the experiment YAML config.", + ) + return parser + + +def main() -> None: + """ + Main entry point for the entity disambiguation experiment script. + Parses command-line arguments and runs the experiment. + """ + args = build_arg_parser().parse_args() + run_experiment(args.config) + + +if __name__ == "__main__": + main() diff --git a/aymurai/utils/paths.py b/aymurai/utils/paths.py new file mode 100644 index 00000000..0677c72e --- /dev/null +++ b/aymurai/utils/paths.py @@ -0,0 +1,40 @@ +from pathlib import Path + +TEST_SUFFIX = "-test" + + +def test_id_from_filename(test_path: Path, *, test_suffix: str = TEST_SUFFIX) -> str: + """ + Convert a test filename like "document-1-test.json" into "document-1". + Falls back to stripping ".json" when the suffix is not present. + + Args: + test_path (Path): Path to the test file. + test_suffix (str, optional): Suffix indicating test files. Defaults to "-test". + + Returns: + str: The test identifier extracted from the filename. + """ + name = Path(test_path).name + suffix_with_ext = f"{test_suffix}.json" + if name.endswith(suffix_with_ext): + return name[: -len(suffix_with_ext)] + if name.endswith(".json"): + return name[: -len(".json")] + return name + + +def prediction_filename_for_test( + test_path: Path, *, test_suffix: str = TEST_SUFFIX +) -> str: + """ + Return the prediction filename that should correspond to the test file. + + Args: + test_path (Path): Path to the test file. + test_suffix (str, optional): Suffix indicating test files. Defaults to "-test". + + Returns: + str: The prediction filename corresponding to the test file. + """ + return f"{test_id_from_filename(test_path, test_suffix=test_suffix)}.json" diff --git a/docker-compose.yml b/docker-compose.yml index 3876bb91..eb8d8fe0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,9 +34,87 @@ x-ollama: &ollama-base shm_size: "2gb" services: + mlflow: + image: ghcr.io/mlflow/mlflow:latest + container_name: mlflow + ports: + - "5000:5000" + environment: + AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} + AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} + MLFLOW_S3_ENDPOINT_URL: http://minio:9000 + MLFLOW_S3_IGNORE_TLS: ${MLFLOW_S3_IGNORE_TLS} + command: + [ + "/bin/sh", + "-c", + "pip install --no-cache-dir psycopg2-binary boto3 && mlflow server --host 0.0.0.0 --port 5000 --backend-store-uri postgresql://mlflow:mlflow@postgres:5432/mlflow --default-artifact-root ${MLFLOW_ARTIFACT_ROOT}", + ] + depends_on: + postgres: + condition: service_healthy + minio: + condition: service_started + healthcheck: + test: + [ + "CMD", + "python", + "-c", + "import urllib.request; urllib.request.urlopen('http://localhost:5000')", + ] + interval: 10s + timeout: 5s + retries: 6 + + postgres: + image: postgres:16 + container_name: postgres + ports: + - "5432:5432" + environment: + POSTGRES_USER: mlflow + POSTGRES_PASSWORD: mlflow + POSTGRES_DB: mlflow + volumes: + - postgres-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U mlflow"] + interval: 10s + timeout: 5s + retries: 6 + + minio: + image: minio/minio:latest + container_name: minio + ports: + - "9002:9000" + - "9001:9001" + environment: + MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID} + MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY} + command: ["server", "/data", "--console-address", ":9001"] + volumes: + - minio-data:/data + # Healthcheck removed; minio image lacks wget and minio-mc already waits for readiness. + + minio-mc: + image: minio/mc:latest + container_name: minio-mc + depends_on: + minio: + condition: service_started + entrypoint: + [ + "/bin/sh", + "-c", + "until (/usr/bin/mc alias set local http://minio:9000 ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}) do sleep 1; done; /usr/bin/mc mb -p local/mlflow; /usr/bin/mc anonymous set none local/mlflow; exit 0;", + ] + # CPU-friendly API aymurai-api: <<: *api-lite + container_name: aymurai-api depends_on: - ollama environment: @@ -46,6 +124,7 @@ services: # GPU-enabled API aymurai-api-gpu: <<: *api-lite + container_name: aymurai-api-gpu depends_on: - ollama-gpu environment: @@ -62,6 +141,7 @@ services: # CPU-friendly Full API aymurai-api-full: <<: *api-full + container_name: aymurai-api-full depends_on: - ollama environment: @@ -76,6 +156,7 @@ services: # GPU-enabled Full API aymurai-api-full-gpu: <<: *api-full + container_name: aymurai-api-full-gpu depends_on: - ollama-gpu environment: @@ -95,10 +176,12 @@ services: # CPU-only Ollama (default) ollama: <<: *ollama-base + container_name: ollama # GPU-enabled Ollama (run instead on GPU hosts) ollama-gpu: <<: *ollama-base + container_name: ollama-gpu deploy: resources: reservations: @@ -109,3 +192,5 @@ services: volumes: ollama: + postgres-data: + minio-data: diff --git a/docs/experiments/README.md b/docs/experiments/README.md new file mode 100644 index 00000000..87c1f771 --- /dev/null +++ b/docs/experiments/README.md @@ -0,0 +1,90 @@ +# Experiments Setup + +This guide walks through running the entity-disambiguation experiments with MLflow +tracking and MinIO artifacts. + +## 1) Update the devcontainer + +The devcontainer installs base dependencies via `uv`. The MLflow client lives in the +`mlops` dependency group, so install it after rebuilding the container: + +```bash +uv sync --frozen --all-extras --group mlops +``` + +If you use VS Code, run "Dev Containers: Rebuild and Reopen in Container" first. + +## 2) Configure environment + +- Set MinIO credentials in `.env`: + - `AWS_ACCESS_KEY_ID` + - `AWS_SECRET_ACCESS_KEY` +- Verify MLflow settings in `.env.common`: + - `MLFLOW_TRACKING_URI` + - `MLFLOW_S3_ENDPOINT_URL` + - `MLFLOW_ARTIFACT_ROOT` + +The experiment runner also uses: +- `API_BASE_URL` (defaults to `http://localhost:8899`) +- `REQUEST_TIMEOUT` (defaults to `300`) + +## 3) Start services + +```bash +make mlops-up +make ollama-up +make api-up +``` + +If you need the GPU services, set: +```bash +make ollama-up OLLAMA_SERVICE=ollama-gpu +make api-up API_SERVICE=aymurai-api-gpu +``` + +## 4) Pull the model + +```bash +make ollama-pull MODEL=gemma3:270m +``` + +## 5) Run the experiment + +```bash +make exp-run CONFIG=resources/experiments/entity-disambiguation/exp-gemma3-pv1.yaml +``` + +## Predictions vs. ground truth filenames + +Ground-truth files are expected to end with `-test.json`, while predictions use +the same base name without the suffix. + +Example: +- `document-1-test.json` (ground truth) +- `document-1.json` (prediction) + +Predictions are written to disk (not logged as artifacts). MLflow logs: +- Run params (model, prompt IDs, dataset hash, etc.) +- Aggregate metrics and per-document scores (as an artifact) +- Prompt text (if enabled in config) + +## 6) Access MLflow UI + +If running remotely, forward the MLflow port: +```bash +ssh -L 5000:127.0.0.1:5000 user@remote-host +``` + +Then open `http://localhost:5000`. + +## Config location + +Experiment configs live under: +- `resources/experiments/entity-disambiguation/` + +Use the template at `docs/experiments/base.yaml` when creating new experiment +configs. Copy it into `resources/experiments/entity-disambiguation/` and adjust +the model, prompts, and data paths as needed. + +The main runner is: +- `aymurai/experiments/entity_disambiguation/runner.py` diff --git a/docs/experiments/base.yaml b/docs/experiments/base.yaml new file mode 100644 index 00000000..a3fb6adc --- /dev/null +++ b/docs/experiments/base.yaml @@ -0,0 +1,50 @@ +experiment: + name: "entity-disambiguation" + run_name: "{model}-{system_id}-{user_id}-{timestamp}" + +model: + provider: "ollama" + name: "llama3:8b" + temperature: 0.2 + max_tokens: 512 + +prompts: + system: + id: "sys-001" + text: "" + user: + id: "user-001" + text: "" + + +data: + ground_truth_dir: "/data/gt" + input_dir: "/data/input" + dataset_id: "gt-v1" + manifest: + enabled: true + mode: "metadata_only" + +predictions: + output_base_dir: "/data/preds" + dir_name_template: "preds-{model}-{system_id}-{user_id}-{timestamp}" + +logging: + mlflow: + experiment_name: "entity-disambiguation" + privacy: + log_prompt_text: true + log_data_manifest: false + log_per_doc_scores: true + per_doc_scores: + id_strategy: "anon_filename" + +evaluation: + function: "evaluate_disambiguation" + weights: + w_ent: 0.4 + w_alias: 0.35 + w_label: 0.2 + w_role: 0.05 + per_doc_scores: true + normalize: true diff --git a/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md b/docs/metrics/Desarrollo metrica.md similarity index 98% rename from notebooks/experiments/entity-disambiguation/Desarrollo metrica.md rename to docs/metrics/Desarrollo metrica.md index 5f02a5f2..13fab9b7 100644 --- a/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md +++ b/docs/metrics/Desarrollo metrica.md @@ -349,8 +349,8 @@ def compute_metrics_components( gold_labels = [e.get("aymurai_label") for e in gold_entities] pred_labels = [e.get("aymurai_label") for e in pred_entities] - gold_roles = [e.get("attributes", {}).get("rol") for e in gold_entities] - pred_roles = [e.get("attributes", {}).get("rol") for e in pred_entities] + gold_roles = [e.get("attributes", {}).get("role") for e in gold_entities] + pred_roles = [e.get("attributes", {}).get("role") for e in pred_entities] sim_matrix = [ [alias_jaccard(g_gold, g_pred) for g_pred in pred_aliases] diff --git a/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb index 65318651..d8ff91eb 100644 --- a/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb +++ b/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb @@ -53,13 +53,13 @@ "metadata": {}, "outputs": [], "source": [ - "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", - "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", + "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8899\")\n", + "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", "DATA_ROOT = Path(\n", " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/disambiguation-eval\")\n", ")\n", "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", "\n", "print(f\"Target endpoint: {ENDPOINT}\")\n", "print(f\"Data root: {DATA_ROOT.resolve()}\")" @@ -123,7 +123,7 @@ " response = session.post(\n", " ENDPOINT,\n", " files=files,\n", - " timeout=REQUEST_TIMEOUT_S,\n", + " timeout=REQUEST_TIMEOUT,\n", " )\n", " elapsed = time.perf_counter() - start\n", " except requests.RequestException as exc:\n", @@ -169,7 +169,9 @@ "source": [ "# Function to make inference using the API\n", "def get_predictions(sample: str) -> dict:\n", - " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample})\n", + " response = requests.post(\n", + " url=f\"{API_BASE_URL}/anonymizer/predict\", json={\"text\": sample}\n", + " )\n", " response.raise_for_status()\n", " return response.json()" ] @@ -236,9 +238,9 @@ "# Available models\n", "# model = \"gpt-oss:20b\"\n", "# model = \"llama3\"\n", - "# model = \"phi4:14b\"\n", + "model = \"phi4:14b\"\n", "# model = \"llama3.1:8b\"\n", - "model = \"gemma3:270m\"" + "# model = \"gemma3:270m\"" ] }, { @@ -482,7 +484,7 @@ ], "metadata": { "kernelspec": { - "display_name": "aymurai", + "display_name": "aymurai (3.10.19)", "language": "python", "name": "python3" }, @@ -496,7 +498,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.18" + "version": "3.10.19" } }, "nbformat": 4, diff --git a/notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb b/notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb index 05c54a17..0797844a 100644 --- a/notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb +++ b/notebooks/experiments/entity-disambiguation/03-disambiguation-evaluation.ipynb @@ -27,8 +27,8 @@ "# Ajusta estas rutas antes de ejecutar\n", "TEST_DIR = Path(\"/resources/data/restricted/disambiguation-eval/test\")\n", "PREDS_DIR = Path(\n", - " \"/resources/data/restricted/disambiguation-eval/preds/preds_phi4:14b_pv1_251125_1716\"\n", - ")" + " \"/resources/data/restricted/disambiguation-eval/preds/preds-phi4:14b-sys-001-user-001-251228_0159\"\n", + ")\n" ] }, { @@ -88,7 +88,7 @@ ], "metadata": { "kernelspec": { - "display_name": ".venv", + "display_name": "aymurai (3.10.19)", "language": "python", "name": "python3" }, diff --git a/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb b/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb index e0f49b96..e907c3fc 100644 --- a/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb +++ b/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb @@ -51,13 +51,13 @@ "metadata": {}, "outputs": [], "source": [ - "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8999\")\n", - "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", + "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8999\")\n", + "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", "DATA_ROOT = Path(\n", " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/disambiguation-eval\")\n", ")\n", "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", "\n", "print(f\"Target endpoint: {ENDPOINT}\")\n", "print(f\"Data root: {DATA_ROOT.resolve()}\")" @@ -104,7 +104,7 @@ " response = session.post(\n", " ENDPOINT,\n", " files=files,\n", - " timeout=REQUEST_TIMEOUT_S,\n", + " timeout=REQUEST_TIMEOUT,\n", " )\n", " elapsed = time.perf_counter() - start\n", " except requests.RequestException as exc:\n", diff --git a/notebooks/experiments/summarization/01-summarization-benchmark.ipynb b/notebooks/experiments/summarization/01-summarization-benchmark.ipynb index 1178ac62..e2a6558a 100644 --- a/notebooks/experiments/summarization/01-summarization-benchmark.ipynb +++ b/notebooks/experiments/summarization/01-summarization-benchmark.ipynb @@ -63,13 +63,13 @@ "metadata": {}, "outputs": [], "source": [ - "BASE_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", - "ENDPOINT = f\"{BASE_URL}/misc/document-extract\"\n", + "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8899\")\n", + "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", "DATA_ROOT = Path(\n", " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", ")\n", "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", "\n", "print(f\"Target endpoint: {ENDPOINT}\")\n", "print(f\"Data root: {DATA_ROOT.resolve()}\")" @@ -133,7 +133,7 @@ " response = session.post(\n", " ENDPOINT,\n", " files=files,\n", - " timeout=REQUEST_TIMEOUT_S,\n", + " timeout=REQUEST_TIMEOUT,\n", " )\n", " elapsed = time.perf_counter() - start\n", " except requests.RequestException as exc:\n", diff --git a/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb b/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb index b40fb1a2..f54a1005 100644 --- a/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb +++ b/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb @@ -105,13 +105,13 @@ "metadata": {}, "outputs": [], "source": [ - "BASE_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://localhost:8899\")\n", - "ENDPOINT = f\"{BASE_URL}/misc/document-extract\"\n", + "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8899\")\n", + "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", "DATA_ROOT = Path(\n", " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", ")\n", "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", "\n", "print(f\"Target endpoint: {ENDPOINT}\")\n", "print(f\"Data root: {DATA_ROOT.resolve()}\")" @@ -175,7 +175,7 @@ " response = session.post(\n", " ENDPOINT,\n", " files=files,\n", - " timeout=REQUEST_TIMEOUT_S,\n", + " timeout=REQUEST_TIMEOUT,\n", " )\n", " elapsed = time.perf_counter() - start\n", " except requests.RequestException as exc:\n", diff --git a/pyproject.toml b/pyproject.toml index 94e817e0..51e6aa24 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -96,13 +96,11 @@ Homepage = "https://www.aymurai.info/" Repository = "https://github.com/aymurAI/backend" Issues = "https://github.com/AymurAI/backend/issues" -# [project.optional-dependencies] -# gpu = [ -# "torch @ https://download.pytorch.org/whl/cu113/torch-1.12.1%2Bcu113-cp310-cp310-linux_x86_64.whl", -# "spacy[cuda113]==3.8.3", -# ] - [dependency-groups] +mlops = [ + "mlflow>=2.12.1", + "boto3>=1.34.0", +] dev = [ "matplotlib>=3.10.0", "seaborn>=0.13.2", diff --git a/uv.lock b/uv.lock index 78db5ef7..dabb9fdc 100644 --- a/uv.lock +++ b/uv.lock @@ -17,7 +17,7 @@ wheels = [ [[package]] name = "accelerate" -version = "1.2.1" +version = "1.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, @@ -28,9 +28,9 @@ dependencies = [ { name = "safetensors" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/09/7947691b7d44bfc739da4a44cc47d6a6d75e6fe9adf047c5234d7cb6be64/accelerate-1.2.1.tar.gz", hash = "sha256:03e161fc69d495daf2b9b5c8d5b43d06e2145520c04727b5bda56d49f1a43ab5", size = 341652 } +sdist = { url = "https://files.pythonhosted.org/packages/4a/8e/ac2a9566747a93f8be36ee08532eb0160558b07630a081a6056a9f89bf1d/accelerate-1.12.0.tar.gz", hash = "sha256:70988c352feb481887077d2ab845125024b2a137a5090d6d7a32b57d03a45df6", size = 398399 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/60/a585c806d6c0ec5f8149d44eb202714792802f484e6e2b1bf96b23bd2b00/accelerate-1.2.1-py3-none-any.whl", hash = "sha256:be1cbb958cf837e7cdfbde46b812964b1b8ae94c9c7d94d921540beafcee8ddf", size = 336355 }, + { url = "https://files.pythonhosted.org/packages/9f/d2/c581486aa6c4fbd7394c23c47b83fa1a919d34194e16944241daf9e762dd/accelerate-1.12.0-py3-none-any.whl", hash = "sha256:3e2091cd341423207e2f084a6654b1efcd250dc326f2a37d6dde446e07cabb11", size = 380935 }, ] [[package]] @@ -44,7 +44,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.13.2" +version = "3.13.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -56,25 +56,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1c/ce/3b83ebba6b3207a7135e5fcaba49706f8a4b6008153b4e30540c982fae26/aiohttp-3.13.2.tar.gz", hash = "sha256:40176a52c186aefef6eb3cad2cdd30cd06e3afbe88fe8ab2af9c0b90f228daca", size = 7837994 } +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/34/939730e66b716b76046dedfe0842995842fa906ccc4964bba414ff69e429/aiohttp-3.13.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2372b15a5f62ed37789a6b383ff7344fc5b9f243999b0cd9b629d8bc5f5b4155", size = 736471 }, - { url = "https://files.pythonhosted.org/packages/fd/cf/dcbdf2df7f6ca72b0bb4c0b4509701f2d8942cf54e29ca197389c214c07f/aiohttp-3.13.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7f8659a48995edee7229522984bd1009c1213929c769c2daa80b40fe49a180c", size = 493985 }, - { url = "https://files.pythonhosted.org/packages/9d/87/71c8867e0a1d0882dcbc94af767784c3cb381c1c4db0943ab4aae4fed65e/aiohttp-3.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:939ced4a7add92296b0ad38892ce62b98c619288a081170695c6babe4f50e636", size = 489274 }, - { url = "https://files.pythonhosted.org/packages/38/0f/46c24e8dae237295eaadd113edd56dee96ef6462adf19b88592d44891dc5/aiohttp-3.13.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6315fb6977f1d0dd41a107c527fee2ed5ab0550b7d885bc15fee20ccb17891da", size = 1668171 }, - { url = "https://files.pythonhosted.org/packages/eb/c6/4cdfb4440d0e28483681a48f69841fa5e39366347d66ef808cbdadddb20e/aiohttp-3.13.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6e7352512f763f760baaed2637055c49134fd1d35b37c2dedfac35bfe5cf8725", size = 1636036 }, - { url = "https://files.pythonhosted.org/packages/84/37/8708cf678628216fb678ab327a4e1711c576d6673998f4f43e86e9ae90dd/aiohttp-3.13.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e09a0a06348a2dd73e7213353c90d709502d9786219f69b731f6caa0efeb46f5", size = 1727975 }, - { url = "https://files.pythonhosted.org/packages/e6/2e/3ebfe12fdcb9b5f66e8a0a42dffcd7636844c8a018f261efb2419f68220b/aiohttp-3.13.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a09a6d073fb5789456545bdee2474d14395792faa0527887f2f4ec1a486a59d3", size = 1815823 }, - { url = "https://files.pythonhosted.org/packages/a1/4f/ca2ef819488cbb41844c6cf92ca6dd15b9441e6207c58e5ae0e0fc8d70ad/aiohttp-3.13.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b59d13c443f8e049d9e94099c7e412e34610f1f49be0f230ec656a10692a5802", size = 1669374 }, - { url = "https://files.pythonhosted.org/packages/f8/fe/1fe2e1179a0d91ce09c99069684aab619bf2ccde9b20bd6ca44f8837203e/aiohttp-3.13.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:20db2d67985d71ca033443a1ba2001c4b5693fe09b0e29f6d9358a99d4d62a8a", size = 1555315 }, - { url = "https://files.pythonhosted.org/packages/5a/2b/f3781899b81c45d7cbc7140cddb8a3481c195e7cbff8e36374759d2ab5a5/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:960c2fc686ba27b535f9fd2b52d87ecd7e4fd1cf877f6a5cba8afb5b4a8bd204", size = 1639140 }, - { url = "https://files.pythonhosted.org/packages/72/27/c37e85cd3ece6f6c772e549bd5a253d0c122557b25855fb274224811e4f2/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6c00dbcf5f0d88796151e264a8eab23de2997c9303dd7c0bf622e23b24d3ce22", size = 1645496 }, - { url = "https://files.pythonhosted.org/packages/66/20/3af1ab663151bd3780b123e907761cdb86ec2c4e44b2d9b195ebc91fbe37/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fed38a5edb7945f4d1bcabe2fcd05db4f6ec7e0e82560088b754f7e08d93772d", size = 1697625 }, - { url = "https://files.pythonhosted.org/packages/95/eb/ae5cab15efa365e13d56b31b0d085a62600298bf398a7986f8388f73b598/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:b395bbca716c38bef3c764f187860e88c724b342c26275bc03e906142fc5964f", size = 1542025 }, - { url = "https://files.pythonhosted.org/packages/e9/2d/1683e8d67ec72d911397fe4e575688d2a9b8f6a6e03c8fdc9f3fd3d4c03f/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:204ffff2426c25dfda401ba08da85f9c59525cdc42bda26660463dd1cbcfec6f", size = 1714918 }, - { url = "https://files.pythonhosted.org/packages/99/a2/ffe8e0e1c57c5e542d47ffa1fcf95ef2b3ea573bf7c4d2ee877252431efc/aiohttp-3.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:05c4dd3c48fb5f15db31f57eb35374cb0c09afdde532e7fb70a75aede0ed30f6", size = 1656113 }, - { url = "https://files.pythonhosted.org/packages/0d/42/d511aff5c3a2b06c09d7d214f508a4ad8ac7799817f7c3d23e7336b5e896/aiohttp-3.13.2-cp310-cp310-win32.whl", hash = "sha256:e574a7d61cf10351d734bcddabbe15ede0eaa8a02070d85446875dc11189a251", size = 432290 }, - { url = "https://files.pythonhosted.org/packages/8b/ea/1c2eb7098b5bad4532994f2b7a8228d27674035c9b3234fe02c37469ef14/aiohttp-3.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:364f55663085d658b8462a1c3f17b2b84a5c2e1ba858e1b79bff7b2e24ad1514", size = 455075 }, + { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950 }, + { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099 }, + { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072 }, + { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588 }, + { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334 }, + { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656 }, + { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625 }, + { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604 }, + { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370 }, + { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023 }, + { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680 }, + { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407 }, + { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047 }, + { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264 }, + { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275 }, + { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053 }, + { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687 }, ] [[package]] @@ -107,19 +107,18 @@ wheels = [ [[package]] name = "altair" -version = "4.2.2" +version = "6.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "entrypoints" }, { name = "jinja2" }, { name = "jsonschema" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "toolz" }, + { name = "narwhals" }, + { name = "packaging" }, + { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ec/bf/781b607da4c1a2a7211cd570bd7e22e0accd4deaf1074c32ac7344a09339/altair-4.2.2.tar.gz", hash = "sha256:39399a267c49b30d102c10411e67ab26374156a84b1aeb9fcd15140429ba49c5", size = 740430 } +sdist = { url = "https://files.pythonhosted.org/packages/f7/c0/184a89bd5feba14ff3c41cfaf1dd8a82c05f5ceedbc92145e17042eb08a4/altair-6.0.0.tar.gz", hash = "sha256:614bf5ecbe2337347b590afb111929aa9c16c9527c4887d96c9bc7f6640756b4", size = 763834 } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/62/47452306e84d4d2e67f9c559380aeb230f5e6ca84fafb428dd36b96a99ba/altair-4.2.2-py3-none-any.whl", hash = "sha256:8b45ebeaf8557f2d760c5c77b79f02ae12aee7c46c27c06014febab6f849bc87", size = 813630 }, + { url = "https://files.pythonhosted.org/packages/db/33/ef2f2409450ef6daa61459d5de5c08128e7d3edb773fefd0a324d1310238/altair-6.0.0-py3-none-any.whl", hash = "sha256:09ae95b53d5fe5b16987dccc785a7af8588f2dca50de1e7a156efa8a461515f8", size = 795410 }, ] [[package]] @@ -160,16 +159,16 @@ wheels = [ [[package]] name = "anyio" -version = "4.12.0" +version = "4.12.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup" }, { name = "idna" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/16/ce/8a777047513153587e5434fd752e89334ac33e379aa3497db860eeb60377/anyio-4.12.0.tar.gz", hash = "sha256:73c693b567b0c55130c104d0b43a9baf3aa6a31fc6110116509f27bf75e21ec0", size = 228266 } +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/9c/36c5c37947ebfb8c7f22e0eb6e4d188ee2d53aa3880f3f2744fb894f0cb1/anyio-4.12.0-py3-none-any.whl", hash = "sha256:dad2376a628f98eeca4881fc56cd06affd18f659b17a747d3ff0307ced94b1bb", size = 113362 }, + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592 }, ] [[package]] @@ -285,7 +284,7 @@ wheels = [ [[package]] name = "aymurai" -version = "2.0.0a4.dev1" +version = "2.0.0a5.dev8" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -342,6 +341,10 @@ dev = [ { name = "seaborn" }, { name = "streamlit" }, ] +mlops = [ + { name = "boto3" }, + { name = "mlflow" }, +] [package.metadata] requires-dist = [ @@ -399,6 +402,10 @@ dev = [ { name = "seaborn", specifier = ">=0.13.2" }, { name = "streamlit", specifier = ">=1.21.0" }, ] +mlops = [ + { name = "boto3", specifier = ">=1.34.0" }, + { name = "mlflow", specifier = ">=2.12.1" }, +] [[package]] name = "babel" @@ -409,15 +416,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, ] -[[package]] -name = "backoff" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, -] - [[package]] name = "beautifulsoup4" version = "4.14.3" @@ -475,48 +473,48 @@ wheels = [ [[package]] name = "boto3" -version = "1.42.3" +version = "1.42.23" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/4e/b1add2d248d7120ee59df1ca1781a0d5fabdb9e45a477ef50c7598908e80/boto3-1.42.3.tar.gz", hash = "sha256:f7fe002c39806d5efe9105f0d74e836f001230e9520b4502c752dd4951f60041", size = 112797 } +sdist = { url = "https://files.pythonhosted.org/packages/0d/df/17828670134e56ffca8cf8b017477f16d1a9df7ecfc3870d02aa6d4d2e20/boto3-1.42.23.tar.gz", hash = "sha256:f681a8d43b46b3d8acf0be4f3894eb85e40e75945431d0dfe0542edda7025512", size = 112845 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/ac/81fb1f37bef7f29f7d0d4b71eb64c6425917cb230da437b42a2a58335ddf/boto3-1.42.3-py3-none-any.whl", hash = "sha256:163df55a774402fa940e95a152c308a33fb0f49cbcb5ec1725936e48635512f7", size = 140619 }, + { url = "https://files.pythonhosted.org/packages/98/8b/8e028dbf6c4bf36defe899882a00c11a8d22fcb7348e88058900c13b72a0/boto3-1.42.23-py3-none-any.whl", hash = "sha256:2ed797bdb394b08550f6269babf0a31bbeb853684bb2cb67116620df0ed632dc", size = 140574 }, ] [[package]] name = "botocore" -version = "1.42.3" +version = "1.42.23" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/e1/8238fbbab5c45def1b4f75d486a95d1d838e8e21a348563d075a2b09f74b/botocore-1.42.3.tar.gz", hash = "sha256:6bad2e512ab85926bbfb391a9486bb3120f4be71419e2f70b556d99783dcb1ce", size = 14842884 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/2c/db33716f86b67c514f895c60694a25cd7428d2137b574b59d09d626b0e2e/botocore-1.42.23.tar.gz", hash = "sha256:453ce449bd1021acd67e75c814aae1b132b1ab3ee0ecff248de863bf19e58be8", size = 14878387 } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/7f/69721ba9d89b4053ac243016428cdd2ea1a1f1c7217572a965aab9f57a20/botocore-1.42.3-py3-none-any.whl", hash = "sha256:fa174f53224ab2adc3a01bb3215b41d314df2f6578381a4a0051bd60d5c718d9", size = 14517527 }, + { url = "https://files.pythonhosted.org/packages/8d/e6/114d66f81fc4b77a8c1e45e6fcf0021018d1f4eefca0905b3da8023c9a47/botocore-1.42.23-py3-none-any.whl", hash = "sha256:d5042e0252b81f25ca1152fff9ed25463bab2438fbc4530ba53d5390d00ca1b1", size = 14551561 }, ] [[package]] name = "cachetools" -version = "6.2.2" +version = "6.2.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/44/ca1675be2a83aeee1886ab745b28cda92093066590233cc501890eb8417a/cachetools-6.2.2.tar.gz", hash = "sha256:8e6d266b25e539df852251cfd6f990b4bc3a141db73b939058d809ebd2590fc6", size = 31571 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/1d/ede8680603f6016887c062a2cf4fc8fdba905866a3ab8831aa8aa651320c/cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607", size = 31731 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/46/eb6eca305c77a4489affe1c5d8f4cae82f285d9addd8de4ec084a7184221/cachetools-6.2.2-py3-none-any.whl", hash = "sha256:6c09c98183bf58560c97b2abfcedcbaf6a896a490f534b031b661d3723b45ace", size = 11503 }, + { url = "https://files.pythonhosted.org/packages/2c/fc/1d7b80d0eb7b714984ce40efc78859c022cd930e402f599d8ca9e39c78a4/cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51", size = 11551 }, ] [[package]] name = "certifi" -version = "2025.11.12" +version = "2026.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268 } wheels = [ - { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438 }, + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900 }, ] [[package]] @@ -660,6 +658,50 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599 }, ] +[[package]] +name = "cryptography" +version = "46.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004 }, + { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667 }, + { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807 }, + { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615 }, + { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800 }, + { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707 }, + { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541 }, + { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464 }, + { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838 }, + { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596 }, + { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782 }, + { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381 }, + { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988 }, + { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451 }, + { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007 }, + { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248 }, + { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089 }, + { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029 }, + { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222 }, + { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280 }, + { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958 }, + { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714 }, + { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970 }, + { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236 }, + { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642 }, + { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126 }, + { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573 }, + { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695 }, + { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720 }, + { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740 }, + { url = "https://files.pythonhosted.org/packages/d9/cd/1a8633802d766a0fa46f382a77e096d7e209e0817892929655fe0586ae32/cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32", size = 3689163 }, + { url = "https://files.pythonhosted.org/packages/4c/59/6b26512964ace6480c3e54681a9859c974172fb141c38df11eadd8416947/cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c", size = 3429474 }, +] + [[package]] name = "cycler" version = "0.12.1" @@ -669,9 +711,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, ] +[[package]] +name = "databricks-sdk" +version = "0.77.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "google-auth" }, + { name = "protobuf" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1e/54/f2393af72974d8e70bfd44b52f17b917190b4934bab66508f4afec9e9285/databricks_sdk-0.77.0.tar.gz", hash = "sha256:56b6017ae17dc31ee821e49746d2ff627a029127166c702088428527813422bd", size = 827462 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/aa/d9186684dbcd338cf51e93621bcf53efa843fe647c0f29f549ebddbf2870/databricks_sdk-0.77.0-py3-none-any.whl", hash = "sha256:42e3211b7dbd53b81a795981149ee08d5b025442a73e464264569edc8c46ee0a", size = 779180 }, +] + [[package]] name = "datasets" -version = "4.4.1" +version = "4.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, @@ -689,9 +745,9 @@ dependencies = [ { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/93/bf/0dae295d6d1ba0b1a200a9dd216838464b5bbd05da01407cb1330b377445/datasets-4.4.1.tar.gz", hash = "sha256:80322699aa8c0bbbdb7caa87906da689c3c2e29523cff698775c67f28fdab1fc", size = 585341 } +sdist = { url = "https://files.pythonhosted.org/packages/c4/54/9359803da96bc65439a28fbb014dc2c90b7d4d8034a93b72362b0d40191f/datasets-4.4.2.tar.gz", hash = "sha256:9de16e415c4ba4713eac0493f7c7dc74f3aa21599297f00cc6ddab409cb7b24b", size = 586474 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/5e/6f8d874366788ad5d549e9ba258037d974dda6e004843be1bda794571701/datasets-4.4.1-py3-none-any.whl", hash = "sha256:c1163de5211e42546079ab355cc0250c7e6db16eb209ac5ac6252f801f596c44", size = 511591 }, + { url = "https://files.pythonhosted.org/packages/7b/b5/fefa518c809de7bced5cddb7c21c010da66fa2ae494bda96844a280cc6ce/datasets-4.4.2-py3-none-any.whl", hash = "sha256:6f5ef3417504d9cd663c71c1b90b9a494ff4c2076a2cd6a6e40ceee6ad95befc", size = 512268 }, ] [[package]] @@ -701,15 +757,15 @@ source = { git = "https://github.com/jedzill4/datetime_matcher#0e5793e8d1e3653f7 [[package]] name = "debugpy" -version = "1.8.17" +version = "1.8.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/ad/71e708ff4ca377c4230530d6a7aa7992592648c122a2cd2b321cf8b35a76/debugpy-1.8.17.tar.gz", hash = "sha256:fd723b47a8c08892b1a16b2c6239a8b96637c62a59b94bb5dab4bac592a58a8e", size = 1644129 } +sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/36/b57c6e818d909f6e59c0182252921cf435e0951126a97e11de37e72ab5e1/debugpy-1.8.17-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:c41d2ce8bbaddcc0009cc73f65318eedfa3dbc88a8298081deb05389f1ab5542", size = 2098021 }, - { url = "https://files.pythonhosted.org/packages/be/01/0363c7efdd1e9febd090bb13cee4fb1057215b157b2979a4ca5ccb678217/debugpy-1.8.17-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:1440fd514e1b815edd5861ca394786f90eb24960eb26d6f7200994333b1d79e3", size = 3087399 }, - { url = "https://files.pythonhosted.org/packages/79/bc/4a984729674aa9a84856650438b9665f9a1d5a748804ac6f37932ce0d4aa/debugpy-1.8.17-cp310-cp310-win32.whl", hash = "sha256:3a32c0af575749083d7492dc79f6ab69f21b2d2ad4cd977a958a07d5865316e4", size = 5230292 }, - { url = "https://files.pythonhosted.org/packages/5d/19/2b9b3092d0cf81a5aa10c86271999453030af354d1a5a7d6e34c574515d7/debugpy-1.8.17-cp310-cp310-win_amd64.whl", hash = "sha256:a3aad0537cf4d9c1996434be68c6c9a6d233ac6f76c2a482c7803295b4e4f99a", size = 5261885 }, - { url = "https://files.pythonhosted.org/packages/b0/d0/89247ec250369fc76db477720a26b2fce7ba079ff1380e4ab4529d2fe233/debugpy-1.8.17-py2.py3-none-any.whl", hash = "sha256:60c7dca6571efe660ccb7a9508d73ca14b8796c4ed484c2002abba714226cfef", size = 5283210 }, + { url = "https://files.pythonhosted.org/packages/bf/98/d57054371887f37d3c959a7a8dc3c76b763acb65f5e78d849d7db7cadc5b/debugpy-1.8.19-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:fce6da15d73be5935b4438435c53adb512326a3e11e4f90793ea87cd9f018254", size = 2098493 }, + { url = "https://files.pythonhosted.org/packages/ee/dd/c517b9aa3500157a30e4f4c4f5149f880026bd039d2b940acd2383a85d8e/debugpy-1.8.19-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:e24b1652a1df1ab04d81e7ead446a91c226de704ff5dde6bd0a0dbaab07aa3f2", size = 3087875 }, + { url = "https://files.pythonhosted.org/packages/d8/57/3d5a5b0da9b63445253107ead151eff29190c6ad7440c68d1a59d56613aa/debugpy-1.8.19-cp310-cp310-win32.whl", hash = "sha256:327cb28c3ad9e17bc925efc7f7018195fd4787c2fe4b7af1eec11f1d19bdec62", size = 5239378 }, + { url = "https://files.pythonhosted.org/packages/a6/36/7f9053c4c549160c87ae7e43800138f2695578c8b65947114c97250983b6/debugpy-1.8.19-cp310-cp310-win_amd64.whl", hash = "sha256:b7dd275cf2c99e53adb9654f5ae015f70415bbe2bacbe24cfee30d54b6aa03c5", size = 5271129 }, + { url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321 }, ] [[package]] @@ -787,6 +843,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094 }, ] +[[package]] +name = "docker" +version = "7.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774 }, +] + [[package]] name = "docopt" version = "0.6.2" @@ -804,36 +874,31 @@ wheels = [ [[package]] name = "dspy" -version = "3.0.4" +version = "3.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "asyncer" }, - { name = "backoff" }, { name = "cachetools" }, { name = "cloudpickle" }, { name = "diskcache" }, { name = "gepa" }, - { name = "joblib" }, { name = "json-repair" }, { name = "litellm" }, - { name = "magicattr" }, { name = "numpy" }, { name = "openai" }, { name = "optuna" }, { name = "orjson" }, - { name = "pillow" }, { name = "pydantic" }, { name = "regex" }, { name = "requests" }, - { name = "rich" }, { name = "tenacity" }, { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8e/18/0042d299cd5e85fdb381568f0cfcc7769122e8f70ea0a2d33e12fd63e705/dspy-3.0.4.tar.gz", hash = "sha256:cb4529df9a91353a16144d9d94ba6ff25f36fc5adfd921f127f4c49d0e309fb8", size = 236376 } +sdist = { url = "https://files.pythonhosted.org/packages/d9/bd/339e1d949aa24e50b6edca8574cf8afbff005a1dfadc2d5b82a0003fa7da/dspy-3.1.0.tar.gz", hash = "sha256:3c1660cb687411f064509cd7ac47ed0231761f50ed92823cbbb59b3af2885702", size = 242611 } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/52/56eed4828175f48f712a50a994293065afa7cc98cb112992a0b071179b6c/dspy-3.0.4-py3-none-any.whl", hash = "sha256:c0a88c7936f41f6f613ee6ca8cd92e63746ff2bd780e3896615ade7628eb6a6a", size = 285224 }, + { url = "https://files.pythonhosted.org/packages/ca/34/64e900657cad3c4df8a417fccbc4370ca851864edbd0f468210f1b57d084/dspy-3.1.0-py3-none-any.whl", hash = "sha256:b9f4d42cad9ac32b13fdf085dd3246c8ee8339c759cb291c5e7b7f9f5fb5dd72", size = 291317 }, ] [[package]] @@ -858,15 +923,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604 }, ] -[[package]] -name = "entrypoints" -version = "0.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/8d/a7121ffe5f402dc015277d2d31eb82d2187334503a011c18f2e78ecbb9b2/entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4", size = 13974 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/a8/365059bbcd4572cbc41de17fd5b682be5868b218c3c5479071865cab9078/entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f", size = 5294 }, -] - [[package]] name = "exceptiongroup" version = "1.3.1" @@ -902,7 +958,7 @@ wheels = [ [[package]] name = "fastapi" -version = "0.123.9" +version = "0.128.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -910,9 +966,9 @@ dependencies = [ { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/01/c3fb48c0135d89586a03c3e2c5bc04540dda52079a1af5cac4a63598efb9/fastapi-0.123.9.tar.gz", hash = "sha256:ab33d672d8e1cc6e0b49777eb73c32ccf20761011f5ca16755889ab406fd1de0", size = 355616 } +sdist = { url = "https://files.pythonhosted.org/packages/52/08/8c8508db6c7b9aae8f7175046af41baad690771c9bcde676419965e338c7/fastapi-0.128.0.tar.gz", hash = "sha256:1cc179e1cef10a6be60ffe429f79b829dce99d8de32d7acb7e6c8dfdf7f2645a", size = 365682 } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/15/a785e992a27620e022d0bc61b6c897ec14cff07c5ab7ff9f27651a21570b/fastapi-0.123.9-py3-none-any.whl", hash = "sha256:f54c69f23db14bd3dbcdfaf3fdce0483ca5f499512380c8e379a70cda30aa920", size = 111776 }, + { url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094 }, ] [package.optional-dependencies] @@ -921,13 +977,15 @@ standard = [ { name = "fastapi-cli", extra = ["standard"] }, { name = "httpx" }, { name = "jinja2" }, + { name = "pydantic-extra-types" }, + { name = "pydantic-settings" }, { name = "python-multipart" }, { name = "uvicorn", extra = ["standard"] }, ] [[package]] name = "fastapi-cli" -version = "0.0.16" +version = "0.0.20" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "rich-toolkit" }, @@ -935,9 +993,9 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/75/9407a6b452be4c988feacec9c9d2f58d8f315162a6c7258d5a649d933ebe/fastapi_cli-0.0.16.tar.gz", hash = "sha256:e8a2a1ecf7a4e062e3b2eec63ae34387d1e142d4849181d936b23c4bdfe29073", size = 19447 } +sdist = { url = "https://files.pythonhosted.org/packages/d3/ca/d90fb3bfbcbd6e56c77afd9d114dd6ce8955d8bb90094399d1c70e659e40/fastapi_cli-0.0.20.tar.gz", hash = "sha256:d17c2634f7b96b6b560bc16b0035ed047d523c912011395f49f00a421692bc3a", size = 19786 } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/43/678528c19318394320ee43757648d5e0a8070cf391b31f69d931e5c840d2/fastapi_cli-0.0.16-py3-none-any.whl", hash = "sha256:addcb6d130b5b9c91adbbf3f2947fe115991495fdb442fe3e51b5fc6327df9f4", size = 12312 }, + { url = "https://files.pythonhosted.org/packages/08/89/5c4eef60524d0fd704eb0706885b82cd5623a43396b94e4a5b17d3a3f516/fastapi_cli-0.0.20-py3-none-any.whl", hash = "sha256:e58b6a0038c0b1532b7a0af690656093dee666201b6b19d3c87175b358e9f783", size = 12390 }, ] [package.optional-dependencies] @@ -948,7 +1006,7 @@ standard = [ [[package]] name = "fastapi-cloud-cli" -version = "0.6.0" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastar" }, @@ -960,9 +1018,9 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/dd/e5890bb4ee63f9d8988660b755490e346cf5769aaa7f5f3ced9afb9f090a/fastapi_cloud_cli-0.6.0.tar.gz", hash = "sha256:2c333fff2e4b93b9efbec7896ce3ffa3e77ce4cf3d8cb14e35b4f823dfddac02", size = 30579 } +sdist = { url = "https://files.pythonhosted.org/packages/51/5d/3b33438de35521fab4968b232caa9a4bd568a5078f2b2dfb7bb8a4528603/fastapi_cloud_cli-0.8.0.tar.gz", hash = "sha256:cf07c502528bfd9e6b184776659f05d9212811d76bbec9fbb6bf34bed4c7456f", size = 30257 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ac/2f/5ba9b5faa75067e30ff48e3c454263ebc2d2301d5509cfefe12cf9fc8156/fastapi_cloud_cli-0.6.0-py3-none-any.whl", hash = "sha256:b654890b5302c90d2f347b123a35186096328838a526316c470b6005cabd4983", size = 23215 }, + { url = "https://files.pythonhosted.org/packages/dd/8e/abb95ef59e91bb5adaa2d18fbf9ea70fd524010bb03f406a2dd2a4775ef9/fastapi_cloud_cli-0.8.0-py3-none-any.whl", hash = "sha256:e9f40bee671d985fd25d7a5409b56d4f103777bf8a0c6d746ea5fbf97a8186d9", size = 22306 }, ] [[package]] @@ -1029,11 +1087,11 @@ wheels = [ [[package]] name = "filelock" -version = "3.20.0" +version = "3.20.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/46/0028a82567109b5ef6e4d2a1f04a583fb513e6cf9527fcdd09afd817deeb/filelock-3.20.0.tar.gz", hash = "sha256:711e943b4ec6be42e1d4e6690b48dc175c822967466bb31c0c293f34334c13f4", size = 18922 } +sdist = { url = "https://files.pythonhosted.org/packages/c1/e0/a75dbe4bca1e7d41307323dad5ea2efdd95408f74ab2de8bd7dba9b51a1a/filelock-3.20.2.tar.gz", hash = "sha256:a2241ff4ddde2a7cebddf78e39832509cb045d18ec1a09d7248d6bfc6bfbbe64", size = 19510 } wheels = [ - { url = "https://files.pythonhosted.org/packages/76/91/7216b27286936c16f5b4d0c530087e4a54eead683e6b0b73dd0c64844af6/filelock-3.20.0-py3-none-any.whl", hash = "sha256:339b4732ffda5cd79b13f4e2711a31b0365ce445d95d243bb996273d072546a2", size = 16054 }, + { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697 }, ] [[package]] @@ -1093,21 +1151,51 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, ] +[[package]] +name = "flask" +version = "3.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "blinker" }, + { name = "click" }, + { name = "itsdangerous" }, + { name = "jinja2" }, + { name = "markupsafe" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/6d/cfe3c0fcc5e477df242b98bfe186a4c34357b4847e87ecaef04507332dab/flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87", size = 720160 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308 }, +] + +[[package]] +name = "flask-cors" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "flask" }, + { name = "werkzeug" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/70/74/0fc0fa68d62f21daef41017dafab19ef4b36551521260987eb3a5394c7ba/flask_cors-6.0.2.tar.gz", hash = "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", size = 13472 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257 }, +] + [[package]] name = "fonttools" -version = "4.61.0" +version = "4.61.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/33/f9/0e84d593c0e12244150280a630999835a64f2852276161b62a0f98318de0/fonttools-4.61.0.tar.gz", hash = "sha256:ec520a1f0c7758d7a858a00f090c1745f6cde6a7c5e76fb70ea4044a15f712e7", size = 3561884 } +sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756 } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/f3/91bba2721fb173fc68e09d15b6ccf3ad4f83d127fbff579be7e5984888a6/fonttools-4.61.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:dc25a4a9c1225653e4431a9413d0381b1c62317b0f543bdcec24e1991f612f33", size = 2850151 }, - { url = "https://files.pythonhosted.org/packages/f5/8c/a1691dec01038ac7e7bb3ab83300dcc5087b11d8f48640928c02a873eb92/fonttools-4.61.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b493c32d2555e9944ec1b911ea649ff8f01a649ad9cba6c118d6798e932b3f0", size = 2389769 }, - { url = "https://files.pythonhosted.org/packages/2d/dd/5bb369a44319d92ba25612511eb8ed2a6fa75239979e0388907525626902/fonttools-4.61.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ad751319dc532a79bdf628b8439af167181b4210a0cd28a8935ca615d9fdd727", size = 4893189 }, - { url = "https://files.pythonhosted.org/packages/5e/02/51373fa8846bd22bb54e5efb30a824b417b058083f775a194a432f21a45f/fonttools-4.61.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2de14557d113faa5fb519f7f29c3abe4d69c17fe6a5a2595cc8cda7338029219", size = 4854415 }, - { url = "https://files.pythonhosted.org/packages/8b/64/9cdbbb804577a7e6191448851c57e6a36eb02aa4bf6a9668b528c968e44e/fonttools-4.61.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:59587bbe455dbdf75354a9dbca1697a35a8903e01fab4248d6b98a17032cee52", size = 4870927 }, - { url = "https://files.pythonhosted.org/packages/92/68/e40b22919dc96dc30a70b58fec609ab85112de950bdecfadf8dd478c5a88/fonttools-4.61.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:46cb3d9279f758ac0cf671dc3482da877104b65682679f01b246515db03dbb72", size = 4988674 }, - { url = "https://files.pythonhosted.org/packages/9b/5c/e857349ce8aedb2451b9448282e86544b2b7f1c8b10ea0fe49b7cb369b72/fonttools-4.61.0-cp310-cp310-win32.whl", hash = "sha256:58b4f1b78dfbfe855bb8a6801b31b8cdcca0e2847ec769ad8e0b0b692832dd3b", size = 1497663 }, - { url = "https://files.pythonhosted.org/packages/f9/0c/62961d5fe6f764d6cbc387ef2c001f5f610808c7aded837409836c0b3e7c/fonttools-4.61.0-cp310-cp310-win_amd64.whl", hash = "sha256:68704a8bbe0b61976262b255e90cde593dc0fe3676542d9b4d846bad2a890a76", size = 1546143 }, - { url = "https://files.pythonhosted.org/packages/0c/14/634f7daea5ffe6a5f7a0322ba8e1a0e23c9257b80aa91458107896d1dfc7/fonttools-4.61.0-py3-none-any.whl", hash = "sha256:276f14c560e6f98d24ef7f5f44438e55ff5a67f78fa85236b218462c9f5d0635", size = 1144485 }, + { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799 }, + { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032 }, + { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863 }, + { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076 }, + { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623 }, + { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327 }, + { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180 }, + { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654 }, + { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996 }, ] [[package]] @@ -1172,27 +1260,26 @@ wheels = [ [[package]] name = "gdown" -version = "4.6.0" +version = "5.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, { name = "filelock" }, { name = "requests", extra = ["socks"] }, - { name = "six" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/a8/eeda0086e118c5cc725c549aadadffad4d8d508781add1bd3347f8ad7808/gdown-4.6.0.tar.gz", hash = "sha256:5ce3db0aeda54f46caacb2df86f31c3e3ecd17c355689e6456d85fb528ba9749", size = 14165 } +sdist = { url = "https://files.pythonhosted.org/packages/09/6a/37e6b70c5bda3161e40265861e63b64a86bfc6ca6a8f1c35328a675c84fd/gdown-5.2.0.tar.gz", hash = "sha256:2145165062d85520a3cd98b356c9ed522c5e7984d408535409fd46f94defc787", size = 284647 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/54/0bbe240c6f59ac9209c2356dc65abd209963851569494376a077e55ef98d/gdown-4.6.0-py3-none-any.whl", hash = "sha256:e75c5aa8be8ea1cac642d4793f884339d887ab5e07aaa57fafa16c8a56a0cde5", size = 14400 }, + { url = "https://files.pythonhosted.org/packages/54/70/e07c381e6488a77094f04c85c9caf1c8008cdc30778f7019bc52e5285ef0/gdown-5.2.0-py3-none-any.whl", hash = "sha256:33083832d82b1101bdd0e9df3edd0fbc0e1c5f14c9d8c38d2a35bf1683b526d6", size = 18235 }, ] [[package]] name = "gepa" -version = "0.0.17" +version = "0.0.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/61/f0/fe312ed4405ddc2ca97dc1ce8915c4dd707e413503e6832910ab088fceb6/gepa-0.0.17.tar.gz", hash = "sha256:641ed46f8127618341b66ee82a87fb46a21c5d2d427a5e0b91c850a7f7f64e7f", size = 99816 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/be/9a4c31c65c4910e73bd4a316df99347681bce4f2ef6d10877cc1ed8d57da/gepa-0.0.22.tar.gz", hash = "sha256:0b13a644efd2af52186e456eaad2ae28fcf88c6f796a9c999910c587863d4315", size = 116337 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/dc/2bc81a01caa887ed58db3c725bebf1e98f37807a4d06c51ecaa85a7cabe0/gepa-0.0.17-py3-none-any.whl", hash = "sha256:0ea98f4179dbc8dd83bdf53494f302e663ee1da8300d086c4cc8ce4aefa4042c", size = 110464 }, + { url = "https://files.pythonhosted.org/packages/b3/0e/d41272b28f2163f5bf840b508cbaf4a0bc01eaeaa6e5d447558d1050eb3b/gepa-0.0.22-py3-none-any.whl", hash = "sha256:ff57ee0442399a5cc62d01411935476bc80cfa8f1c318bed82e3db4c2c834665", size = 119666 }, ] [[package]] @@ -1209,14 +1296,14 @@ wheels = [ [[package]] name = "gitpython" -version = "3.1.45" +version = "3.1.46" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitdb" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9a/c8/dd58967d119baab745caec2f9d853297cec1989ec1d63f677d3880632b88/gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c", size = 215076 } +sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371 } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/61/d4b89fec821f72385526e1b9d9a3a0385dda4a72b206d28049e2c7cd39b8/gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77", size = 208168 }, + { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620 }, ] [[package]] @@ -1237,16 +1324,15 @@ wheels = [ [[package]] name = "google-auth" -version = "2.43.0" +version = "2.47.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cachetools" }, { name = "pyasn1-modules" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/ef/66d14cf0e01b08d2d51ffc3c20410c4e134a1548fc246a6081eae585a4fe/google_auth-2.43.0.tar.gz", hash = "sha256:88228eee5fc21b62a1b5fe773ca15e67778cb07dc8363adcb4a8827b52d81483", size = 296359 } +sdist = { url = "https://files.pythonhosted.org/packages/60/3c/ec64b9a275ca22fa1cd3b6e77fefcf837b0732c890aa32d2bd21313d9b33/google_auth-2.47.0.tar.gz", hash = "sha256:833229070a9dfee1a353ae9877dcd2dec069a8281a4e72e72f77d4a70ff945da", size = 323719 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6f/d1/385110a9ae86d91cc14c5282c61fe9f4dc41c0b9f7d423c6ad77038c4448/google_auth-2.43.0-py2.py3-none-any.whl", hash = "sha256:af628ba6fa493f75c7e9dbe9373d148ca9f4399b5ea29976519e0a3848eddd16", size = 223114 }, + { url = "https://files.pythonhosted.org/packages/db/18/79e9008530b79527e0d5f79e7eef08d3b179b7f851cfd3a2f27822fbdfa9/google_auth-2.47.0-py3-none-any.whl", hash = "sha256:c516d68336bfde7cf0da26aab674a36fedcf04b37ac4edd59c597178760c3498", size = 234867 }, ] [package.optional-dependencies] @@ -1269,7 +1355,7 @@ wheels = [ [[package]] name = "google-cloud-storage" -version = "3.6.0" +version = "3.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-api-core" }, @@ -1279,44 +1365,43 @@ dependencies = [ { name = "google-resumable-media" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/cd/7e112cf025b2b591067b599e4bfe965df0c12b0cc0afdb5556469bff126d/google_cloud_storage-3.6.0.tar.gz", hash = "sha256:29cc6b9a6c0fc9cdad071e375d540a5a50fbc9a7fad8300fa02fb904f6fe2ca2", size = 17251072 } +sdist = { url = "https://files.pythonhosted.org/packages/d2/8e/fab2de1a0ab7fdbd452eaae5a9a5c933d0911c26b04efa0c76ddfd921259/google_cloud_storage-3.7.0.tar.gz", hash = "sha256:9ce59c65f4d6e372effcecc0456680a8d73cef4f2dc9212a0704799cb3d69237", size = 17258914 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ae/ef/3b57bf617ee0c79450c1ff211d1eb888db8fc1050ac74b3e52cc6ed86e63/google_cloud_storage-3.6.0-py3-none-any.whl", hash = "sha256:5decbdddd63b7d1fc3e266a393ad6453d2e27d172bd982b1e2f15481668db097", size = 299039 }, + { url = "https://files.pythonhosted.org/packages/2d/80/6e5c7c83cea15ed4dfc4843b9df9db0716bc551ac938f7b5dd18a72bd5e4/google_cloud_storage-3.7.0-py3-none-any.whl", hash = "sha256:469bc9540936e02f8a4bfd1619e9dca1e42dec48f95e4204d783b36476a15093", size = 303364 }, ] [[package]] name = "google-crc32c" -version = "1.7.1" +version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/19/ae/87802e6d9f9d69adfaedfcfd599266bf386a54d0be058b532d04c794f76d/google_crc32c-1.7.1.tar.gz", hash = "sha256:2bff2305f98846f3e825dbeec9ee406f89da7962accdb29356e4eadc251bd472", size = 14495 } +sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192 } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/69/b1b05cf415df0d86691d6a8b4b7e60ab3a6fb6efb783ee5cd3ed1382bfd3/google_crc32c-1.7.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:b07d48faf8292b4db7c3d64ab86f950c2e94e93a11fd47271c28ba458e4a0d76", size = 30467 }, - { url = "https://files.pythonhosted.org/packages/44/3d/92f8928ecd671bd5b071756596971c79d252d09b835cdca5a44177fa87aa/google_crc32c-1.7.1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:7cc81b3a2fbd932a4313eb53cc7d9dde424088ca3a0337160f35d91826880c1d", size = 30311 }, - { url = "https://files.pythonhosted.org/packages/33/42/c2d15a73df79d45ed6b430b9e801d0bd8e28ac139a9012d7d58af50a385d/google_crc32c-1.7.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1c67ca0a1f5b56162951a9dae987988679a7db682d6f97ce0f6381ebf0fbea4c", size = 37889 }, - { url = "https://files.pythonhosted.org/packages/57/ea/ac59c86a3c694afd117bb669bde32aaf17d0de4305d01d706495f09cbf19/google_crc32c-1.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc5319db92daa516b653600794d5b9f9439a9a121f3e162f94b0e1891c7933cb", size = 33028 }, - { url = "https://files.pythonhosted.org/packages/60/44/87e77e8476767a4a93f6cf271157c6d948eacec63688c093580af13b04be/google_crc32c-1.7.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcdf5a64adb747610140572ed18d011896e3b9ae5195f2514b7ff678c80f1603", size = 38026 }, - { url = "https://files.pythonhosted.org/packages/c8/bf/21ac7bb305cd7c1a6de9c52f71db0868e104a5b573a4977cd9d0ff830f82/google_crc32c-1.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:754561c6c66e89d55754106739e22fdaa93fafa8da7221b29c8b8e8270c6ec8a", size = 33476 }, - { url = "https://files.pythonhosted.org/packages/0b/43/31e57ce04530794917dfe25243860ec141de9fadf4aa9783dffe7dac7c39/google_crc32c-1.7.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8e9afc74168b0b2232fb32dd202c93e46b7d5e4bf03e66ba5dc273bb3559589", size = 28242 }, - { url = "https://files.pythonhosted.org/packages/eb/f3/8b84cd4e0ad111e63e30eb89453f8dd308e3ad36f42305cf8c202461cdf0/google_crc32c-1.7.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa8136cc14dd27f34a3221c0f16fd42d8a40e4778273e61a3c19aedaa44daf6b", size = 28049 }, + { url = "https://files.pythonhosted.org/packages/95/ac/6f7bc93886a823ab545948c2dd48143027b2355ad1944c7cf852b338dc91/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff", size = 31296 }, + { url = "https://files.pythonhosted.org/packages/f7/97/a5accde175dee985311d949cfcb1249dcbb290f5ec83c994ea733311948f/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288", size = 30870 }, + { url = "https://files.pythonhosted.org/packages/3d/63/bec827e70b7a0d4094e7476f863c0dbd6b5f0f1f91d9c9b32b76dcdfeb4e/google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d", size = 33214 }, + { url = "https://files.pythonhosted.org/packages/63/bc/11b70614df04c289128d782efc084b9035ef8466b3d0a8757c1b6f5cf7ac/google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092", size = 33589 }, + { url = "https://files.pythonhosted.org/packages/3e/00/a08a4bc24f1261cc5b0f47312d8aebfbe4b53c2e6307f1b595605eed246b/google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733", size = 34437 }, ] [[package]] name = "google-genai" -version = "1.53.0" +version = "1.56.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, + { name = "distro" }, { name = "google-auth", extra = ["requests"] }, { name = "httpx" }, { name = "pydantic" }, { name = "requests" }, + { name = "sniffio" }, { name = "tenacity" }, { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/b3/36fbfde2e21e6d3bc67780b61da33632f495ab1be08076cf0a16af74098f/google_genai-1.53.0.tar.gz", hash = "sha256:938a26d22f3fd32c6eeeb4276ef204ef82884e63af9842ce3eac05ceb39cbd8d", size = 260102 } +sdist = { url = "https://files.pythonhosted.org/packages/70/ad/d3ac5a102135bd3f1e4b1475ca65d2bd4bcc22eb2e9348ac40fe3fadb1d6/google_genai-1.56.0.tar.gz", hash = "sha256:0491af33c375f099777ae207d9621f044e27091fafad4c50e617eba32165e82f", size = 340451 } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/f2/97fefdd1ad1f3428321bac819ae7a83ccc59f6439616054736b7819fa56c/google_genai-1.53.0-py3-none-any.whl", hash = "sha256:65a3f99e5c03c372d872cda7419f5940e723374bb12a2f3ffd5e3e56e8eb2094", size = 262015 }, + { url = "https://files.pythonhosted.org/packages/84/93/94bc7a89ef4e7ed3666add55cd859d1483a22737251df659bf1aa46e9405/google_genai-1.56.0-py3-none-any.whl", hash = "sha256:9e6b11e0c105ead229368cb5849a480e4d0185519f8d9f538d61ecfcf193b052", size = 426563 }, ] [[package]] @@ -1333,14 +1418,50 @@ wheels = [ [[package]] name = "googleapis-common-protos" -version = "1.63.1" +version = "1.72.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4f/bc/cb5c74fca58d9c37bc621642e2c2b19c004d078b472d49fb03d9fa8ffeef/googleapis-common-protos-1.63.1.tar.gz", hash = "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a", size = 121632 } +sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/87/1608d23bb9879694579fff5dc56d60e3d48e012fd08670f140cf82f6cf26/googleapis_common_protos-1.63.1-py2.py3-none-any.whl", hash = "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877", size = 229151 }, + { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515 }, +] + +[[package]] +name = "graphene" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "graphql-core" }, + { name = "graphql-relay" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/f6/bf62ff950c317ed03e77f3f6ddd7e34aaa98fe89d79ebd660c55343d8054/graphene-3.4.3.tar.gz", hash = "sha256:2a3786948ce75fe7e078443d37f609cbe5bb36ad8d6b828740ad3b95ed1a0aaa", size = 44739 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl", hash = "sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71", size = 114894 }, +] + +[[package]] +name = "graphql-core" +version = "3.2.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/9b/037a640a2983b09aed4a823f9cf1729e6d780b0671f854efa4727a7affbe/graphql_core-3.2.7.tar.gz", hash = "sha256:27b6904bdd3b43f2a0556dad5d579bdfdeab1f38e8e8788e555bdcb586a6f62c", size = 513484 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/14/933037032608787fb92e365883ad6a741c235e0ff992865ec5d904a38f1e/graphql_core-3.2.7-py3-none-any.whl", hash = "sha256:17fc8f3ca4a42913d8e24d9ac9f08deddf0a0b2483076575757f6c412ead2ec0", size = 207262 }, +] + +[[package]] +name = "graphql-relay" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "graphql-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/13/98fbf8d67552f102488ffc16c6f559ce71ea15f6294728d33928ab5ff14d/graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c", size = 50027 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5", size = 16940 }, ] [[package]] @@ -1359,6 +1480,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740 }, ] +[[package]] +name = "gunicorn" +version = "23.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029 }, +] + [[package]] name = "h11" version = "0.16.0" @@ -1426,6 +1559,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, ] +[[package]] +name = "huey" +version = "2.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/29/3428d52eb8e85025e264a291641a9f9d6407cc1e51d1b630f6ac5815999a/huey-2.6.0.tar.gz", hash = "sha256:8d11f8688999d65266af1425b831f6e3773e99415027177b8734b0ffd5e251f6", size = 221068 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/34/fae9ac8f1c3a552fd3f7ff652b94c78d219dedc5fce0c0a4232457760a00/huey-2.6.0-py3-none-any.whl", hash = "sha256:1b9df9d370b49c6d5721ba8a01ac9a787cf86b3bdc584e4679de27b920395c3f", size = 76951 }, +] + [[package]] name = "huggingface-hub" version = "0.36.0" @@ -1465,24 +1607,27 @@ wheels = [ [[package]] name = "importlib-metadata" -version = "8.7.0" +version = "8.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107 } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656 }, + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865 }, ] [[package]] name = "intervaltree" -version = "3.1.0" +version = "3.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/fb/396d568039d21344639db96d940d40eb62befe704ef849b27949ded5c3bb/intervaltree-3.1.0.tar.gz", hash = "sha256:902b1b88936918f9b2a19e0e5eb7ccb430ae45cde4f39ea4b36932920d33952d", size = 32861 } +sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929 }, +] [[package]] name = "ipykernel" @@ -1510,7 +1655,7 @@ wheels = [ [[package]] name = "ipython" -version = "8.37.0" +version = "8.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, @@ -1525,9 +1670,9 @@ dependencies = [ { name = "traitlets" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/85/31/10ac88f3357fc276dc8a64e8880c82e80e7459326ae1d0a211b40abf6665/ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216", size = 5606088 } +sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996 } wheels = [ - { url = "https://files.pythonhosted.org/packages/91/d0/274fbf7b0b12643cbbc001ce13e6a5b1607ac4929d1b11c72460152c9fc3/ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2", size = 831864 }, + { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813 }, ] [[package]] @@ -1558,6 +1703,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, ] +[[package]] +name = "itsdangerous" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, +] + [[package]] name = "jedi" version = "0.19.2" @@ -1634,29 +1788,29 @@ wheels = [ [[package]] name = "joblib" -version = "1.5.2" +version = "1.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077 } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396 }, + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071 }, ] [[package]] name = "json-repair" -version = "0.54.2" +version = "0.55.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/05/9fbcd5ffab9c41455e7d80af65a90876718b8ea2fb4525e187ab11836dd4/json_repair-0.54.2.tar.gz", hash = "sha256:4b6b62ce17f1a505b220fa4aadba1fc37dc9c221544f158471efe3775620bad6", size = 38575 } +sdist = { url = "https://files.pythonhosted.org/packages/96/74/0f39677fa7c0127129c3f1a37c94d05c30a968ba3047200e54dea375b09a/json_repair-0.55.0.tar.gz", hash = "sha256:9fafb47d92582ef4bdd3520656bdb0fcb37b46cf6aa99c1926b7895abc0a3a4b", size = 38828 } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/3a/1b4df9adcd69fee9c9e4b439c13e8c866f2fae520054aede7030b2278be9/json_repair-0.54.2-py3-none-any.whl", hash = "sha256:be51cce5dca97e0c24ebdf61a1ede2449a8a7666012de99467bb7b0afb35179b", size = 29322 }, + { url = "https://files.pythonhosted.org/packages/bc/00/d7d6b6b3257f9b1f997a558b6f7087b8af7c0a2f525f4fbd864c267a88ab/json_repair-0.55.0-py3-none-any.whl", hash = "sha256:bcf4880f5e6ad21a0f70ab034e3d1d398c2ae9698dc5717d7015afbac77b8ed7", size = 29570 }, ] [[package]] name = "json5" -version = "0.12.1" +version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/ae/929aee9619e9eba9015207a9d2c1c54db18311da7eb4dcf6d41ad6f0eb67/json5-0.12.1.tar.gz", hash = "sha256:b2743e77b3242f8d03c143dd975a6ec7c52e2f2afe76ed934e53503dd4ad4990", size = 52191 } +sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441 } wheels = [ - { url = "https://files.pythonhosted.org/packages/85/e2/05328bd2621be49a6fed9e3030b1e51a2d04537d3f816d211b9cc53c5262/json5-0.12.1-py3-none-any.whl", hash = "sha256:d9c9b3bc34a5f54d43c35e11ef7cb87d8bdd098c6ace87117a7b7e83e705c1d5", size = 36119 }, + { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163 }, ] [[package]] @@ -1682,7 +1836,7 @@ wheels = [ [[package]] name = "jsonschema" -version = "4.25.1" +version = "4.26.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -1690,9 +1844,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342 } +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040 }, + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630 }, ] [package.optional-dependencies] @@ -1739,7 +1893,7 @@ wheels = [ [[package]] name = "jupyter-client" -version = "8.6.3" +version = "8.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-core" }, @@ -1748,9 +1902,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/27/d10de45e8ad4ce872372c4a3a37b7b35b6b064f6f023a5c14ffcced4d59d/jupyter_client-8.7.0.tar.gz", hash = "sha256:3357212d9cbe01209e59190f67a3a7e1f387a4f4e88d1e0433ad84d7b262531d", size = 344691 } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105 }, + { url = "https://files.pythonhosted.org/packages/bb/f5/fddaec430367be9d62a7ed125530e133bfd4a1c0350fe221149ee0f2b526/jupyter_client-8.7.0-py3-none-any.whl", hash = "sha256:3671a94fd25e62f5f2f554f5e95389c2294d89822378a5f2dd24353e1494a9e0", size = 106215 }, ] [[package]] @@ -1861,7 +2015,7 @@ wheels = [ [[package]] name = "jupyterlab" -version = "4.5.0" +version = "4.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-lru" }, @@ -1879,9 +2033,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/e5/4fa382a796a6d8e2cd867816b64f1ff27f906e43a7a83ad9eb389e448cd8/jupyterlab-4.5.0.tar.gz", hash = "sha256:aec33d6d8f1225b495ee2cf20f0514f45e6df8e360bdd7ac9bace0b7ac5177ea", size = 23989880 } +sdist = { url = "https://files.pythonhosted.org/packages/09/21/413d142686a4e8f4268d985becbdb4daf060524726248e73be4773786987/jupyterlab-4.5.1.tar.gz", hash = "sha256:09da1ddfbd9eec18b5101dbb8515612aa1e47443321fb99503725a88e93d20d9", size = 23992251 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/1e/5a4d5498eba382fee667ed797cf64ae5d1b13b04356df62f067f48bb0f61/jupyterlab-4.5.0-py3-none-any.whl", hash = "sha256:88e157c75c1afff64c7dc4b801ec471450b922a4eae4305211ddd40da8201c8a", size = 12380641 }, + { url = "https://files.pythonhosted.org/packages/af/c3/acced767eecc11a70c65c45295db5396c4f0c1937874937d5a76d7b177b6/jupyterlab-4.5.1-py3-none-any.whl", hash = "sha256:31b059de96de0754ff1f2ce6279774b6aab8c34d7082e9752db58207c99bd514", size = 12384821 }, ] [[package]] @@ -2061,14 +2215,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913 }, ] -[[package]] -name = "magicattr" -version = "0.1.6" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/7e/76b7e0c391bee7e9273725c29c8fe41c4df62a215ce58aa8e3518baee0bb/magicattr-0.1.6-py2.py3-none-any.whl", hash = "sha256:d96b18ee45b5ee83b09c17e15d3459a64de62d538808c2f71182777dd9dbbbdf", size = 4664 }, -] - [[package]] name = "mako" version = "1.3.10" @@ -2168,7 +2314,7 @@ wheels = [ [[package]] name = "matplotlib" -version = "3.10.7" +version = "3.10.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "contourpy" }, @@ -2181,17 +2327,17 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/e2/d2d5295be2f44c678ebaf3544ba32d20c1f9ef08c49fe47f496180e1db15/matplotlib-3.10.7.tar.gz", hash = "sha256:a06ba7e2a2ef9131c79c49e63dad355d2d878413a0376c1727c8b9335ff731c7", size = 34804865 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/87/3932d5778ab4c025db22710b61f49ccaed3956c5cf46ffb2ffa7492b06d9/matplotlib-3.10.7-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:7ac81eee3b7c266dd92cee1cd658407b16c57eed08c7421fa354ed68234de380", size = 8247141 }, - { url = "https://files.pythonhosted.org/packages/45/a8/bfed45339160102bce21a44e38a358a1134a5f84c26166de03fb4a53208f/matplotlib-3.10.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:667ecd5d8d37813a845053d8f5bf110b534c3c9f30e69ebd25d4701385935a6d", size = 8107995 }, - { url = "https://files.pythonhosted.org/packages/e2/3c/5692a2d9a5ba848fda3f48d2b607037df96460b941a59ef236404b39776b/matplotlib-3.10.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc1c51b846aca49a5a8b44fbba6a92d583a35c64590ad9e1e950dc88940a4297", size = 8680503 }, - { url = "https://files.pythonhosted.org/packages/ab/a0/86ace53c48b05d0e6e9c127b2ace097434901f3e7b93f050791c8243201a/matplotlib-3.10.7-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a11c2e9e72e7de09b7b72e62f3df23317c888299c875e2b778abf1eda8c0a42", size = 9514982 }, - { url = "https://files.pythonhosted.org/packages/a6/81/ead71e2824da8f72640a64166d10e62300df4ae4db01a0bac56c5b39fa51/matplotlib-3.10.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f19410b486fdd139885ace124e57f938c1e6a3210ea13dd29cab58f5d4bc12c7", size = 9566429 }, - { url = "https://files.pythonhosted.org/packages/65/7d/954b3067120456f472cce8fdcacaf4a5fcd522478db0c37bb243c7cb59dd/matplotlib-3.10.7-cp310-cp310-win_amd64.whl", hash = "sha256:b498e9e4022f93de2d5a37615200ca01297ceebbb56fe4c833f46862a490f9e3", size = 8108174 }, - { url = "https://files.pythonhosted.org/packages/1e/6c/a9bcf03e9afb2a873e0a5855f79bce476d1023f26f8212969f2b7504756c/matplotlib-3.10.7-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5c09cf8f2793f81368f49f118b6f9f937456362bee282eac575cca7f84cda537", size = 8241204 }, - { url = "https://files.pythonhosted.org/packages/5b/fd/0e6f5aa762ed689d9fa8750b08f1932628ffa7ed30e76423c399d19407d2/matplotlib-3.10.7-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:de66744b2bb88d5cd27e80dfc2ec9f0517d0a46d204ff98fe9e5f2864eb67657", size = 8104607 }, - { url = "https://files.pythonhosted.org/packages/b9/a9/21c9439d698fac5f0de8fc68b2405b738ed1f00e1279c76f2d9aa5521ead/matplotlib-3.10.7-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53cc80662dd197ece414dd5b66e07370201515a3eaf52e7c518c68c16814773b", size = 8682257 }, + { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828 }, + { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050 }, + { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452 }, + { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928 }, + { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377 }, + { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127 }, + { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252 }, + { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693 }, + { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205 }, ] [[package]] @@ -2217,14 +2363,14 @@ wheels = [ [[package]] name = "mistune" -version = "3.1.4" +version = "3.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d7/02/a7fb8b21d4d55ac93cdcde9d3638da5dd0ebdd3a4fed76c7725e10b81cbe/mistune-3.1.4.tar.gz", hash = "sha256:b5a7f801d389f724ec702840c11d8fc48f2b33519102fc7ee739e8177b672164", size = 94588 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/f0/8282d9641415e9e33df173516226b404d367a0fc55e1a60424a152913abc/mistune-3.1.4-py3-none-any.whl", hash = "sha256:93691da911e5d9d2e23bc54472892aff676df27a75274962ff9edc210364266d", size = 53481 }, + { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598 }, ] [[package]] @@ -2240,6 +2386,84 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, ] +[[package]] +name = "mlflow" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "alembic" }, + { name = "cryptography" }, + { name = "docker" }, + { name = "flask" }, + { name = "flask-cors" }, + { name = "graphene" }, + { name = "gunicorn", marker = "platform_system != 'Windows'" }, + { name = "huey" }, + { name = "matplotlib" }, + { name = "mlflow-skinny" }, + { name = "mlflow-tracing" }, + { name = "numpy" }, + { name = "pandas" }, + { name = "pyarrow" }, + { name = "scikit-learn" }, + { name = "scipy" }, + { name = "sqlalchemy" }, + { name = "waitress", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/f8/10ccb111ed53732dfceae0369073023f96acd6b00f92fb3c24473938702d/mlflow-3.8.1.tar.gz", hash = "sha256:0823377bedff4d530b0d560bf394daf9f7e9fbba53453add04eadad34de962cc", size = 8550037 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/d5/a20b87c6cd99395fee04d6034686512305530c71ceaabe3a151eeaa25ed7/mlflow-3.8.1-py3-none-any.whl", hash = "sha256:42f26b52438fdb615588e150407c6516d0f64d417436dfc75599c525a464f210", size = 9062281 }, +] + +[[package]] +name = "mlflow-skinny" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "click" }, + { name = "cloudpickle" }, + { name = "databricks-sdk" }, + { name = "fastapi" }, + { name = "gitpython" }, + { name = "importlib-metadata" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "sqlparse" }, + { name = "typing-extensions" }, + { name = "uvicorn" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7e/00/18486d9072739e63471c1e441e78cdb6a10c641312d98f6699715406451e/mlflow_skinny-3.8.1.tar.gz", hash = "sha256:0c0aade08187030a4653e267bcd63de2f12cbfebf4c6737832cba45d6fb3594d", size = 2082226 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/24/42e52320636fcbabeaf50704f9269a328acc995e1b8a44df6fea33130a0a/mlflow_skinny-3.8.1-py3-none-any.whl", hash = "sha256:3a6ee27f5ac1e67c1d565fa0e12c070b27129b03e669dcaf88ff841176429142", size = 2506002 }, +] + +[[package]] +name = "mlflow-tracing" +version = "3.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "databricks-sdk" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/e5/9cdca5a91afd71e15943f3dbe00e788bd36479637e9b2e0625224027ff01/mlflow_tracing-3.8.1.tar.gz", hash = "sha256:c032ba715994a4580323f3045fa2700a6323033d87e564bbcbda37e6ab993071", size = 1130700 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/e3/ddbe3e2d1219fa9235559ab88ebf98e1e4f48c62672f0dfb8f1eb07276dc/mlflow_tracing-3.8.1-py3-none-any.whl", hash = "sha256:12d9b5b7177b4152979d003e0d967b280c4252758639aebdfd672734283b17bf", size = 1359007 }, +] + [[package]] name = "more-itertools" version = "10.8.0" @@ -2320,16 +2544,16 @@ wheels = [ [[package]] name = "narwhals" -version = "2.13.0" +version = "2.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/89/ea/f82ef99ced4d03c33bb314c9b84a08a0a86c448aaa11ffd6256b99538aa5/narwhals-2.13.0.tar.gz", hash = "sha256:ee94c97f4cf7cfeebbeca8d274784df8b3d7fd3f955ce418af998d405576fdd9", size = 594555 } +sdist = { url = "https://files.pythonhosted.org/packages/47/6d/b57c64e5038a8cf071bce391bb11551657a74558877ac961e7fa905ece27/narwhals-2.15.0.tar.gz", hash = "sha256:a9585975b99d95084268445a1fdd881311fa26ef1caa18020d959d5b2ff9a965", size = 603479 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/0d/1861d1599571974b15b025e12b142d8e6b42ad66c8a07a89cb0fc21f1e03/narwhals-2.13.0-py3-none-any.whl", hash = "sha256:9b795523c179ca78204e3be53726da374168f906e38de2ff174c2363baaaf481", size = 426407 }, + { url = "https://files.pythonhosted.org/packages/3d/2e/cf2ffeb386ac3763526151163ad7da9f1b586aac96d2b4f7de1eaebf0c61/narwhals-2.15.0-py3-none-any.whl", hash = "sha256:cbfe21ca19d260d9fd67f995ec75c44592d1f106933b03ddd375df7ac841f9d6", size = 432856 }, ] [[package]] name = "nbclient" -version = "0.10.2" +version = "0.10.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-client" }, @@ -2337,9 +2561,9 @@ dependencies = [ { name = "nbformat" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/87/66/7ffd18d58eae90d5721f9f39212327695b749e23ad44b3881744eaf4d9e8/nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193", size = 62424 } +sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/6d/e7fa07f03a4a7b221d94b4d586edb754a9b0dc3c9e2c93353e9fa4e0d117/nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d", size = 25434 }, + { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465 }, ] [[package]] @@ -2414,16 +2638,16 @@ wheels = [ [[package]] name = "nodeenv" -version = "1.9.1" +version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438 }, ] [[package]] name = "notebook" -version = "7.5.0" +version = "7.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, @@ -2432,9 +2656,9 @@ dependencies = [ { name = "notebook-shim" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/89/ac/a97041621250a4fc5af379fb377942841eea2ca146aab166b8fcdfba96c2/notebook-7.5.0.tar.gz", hash = "sha256:3b27eaf9913033c28dde92d02139414c608992e1df4b969c843219acf2ff95e4", size = 14052074 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/a9/882707b0aa639e6d7d3e7df4bfbe07479d832e9a8f02d8471002a4ea6d65/notebook-7.5.1.tar.gz", hash = "sha256:b2fb4cef4d47d08c33aecce1c6c6e84be05436fbd791f88fce8df9fbca088b75", size = 14058696 } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/96/00df2a4760f10f5af0f45c4955573cae6189931f9a30265a35865f8c1031/notebook-7.5.0-py3-none-any.whl", hash = "sha256:3300262d52905ca271bd50b22617681d95f08a8360d099e097726e6d2efb5811", size = 14460968 }, + { url = "https://files.pythonhosted.org/packages/d1/86/ca516cb58ad2cb2064124d31cf0fd8b012fca64bebeb26da2d2ddf03fc79/notebook-7.5.1-py3-none-any.whl", hash = "sha256:f4e2451c19910c33b88709b84537e11f6368c1cdff1aa0c43db701aea535dd44", size = 14468080 }, ] [[package]] @@ -2672,6 +2896,58 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/86/8a/69176a64335aed183529207ba8bc3d329c2999d852b4f3818027203f50e6/opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca", size = 39402386 }, ] +[[package]] +name = "opentelemetry-api" +version = "1.39.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356 }, +] + +[[package]] +name = "opentelemetry-proto" +version = "1.39.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535 }, +] + +[[package]] +name = "opentelemetry-sdk" +version = "1.39.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565 }, +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.60b1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982 }, +] + [[package]] name = "optuna" version = "4.6.0" @@ -2692,23 +2968,23 @@ wheels = [ [[package]] name = "orjson" -version = "3.11.4" +version = "3.11.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188 } +sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870 }, - { url = "https://files.pythonhosted.org/packages/44/1f/da46563c08bef33c41fd63c660abcd2184b4d2b950c8686317d03b9f5f0c/orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44", size = 130622 }, - { url = "https://files.pythonhosted.org/packages/02/bd/b551a05d0090eab0bf8008a13a14edc0f3c3e0236aa6f5b697760dd2817b/orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c", size = 129344 }, - { url = "https://files.pythonhosted.org/packages/87/6c/9ddd5e609f443b2548c5e7df3c44d0e86df2c68587a0e20c50018cdec535/orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23", size = 136633 }, - { url = "https://files.pythonhosted.org/packages/95/f2/9f04f2874c625a9fb60f6918c33542320661255323c272e66f7dcce14df2/orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea", size = 137695 }, - { url = "https://files.pythonhosted.org/packages/d2/c2/c7302afcbdfe8a891baae0e2cee091583a30e6fa613e8bdf33b0e9c8a8c7/orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba", size = 136879 }, - { url = "https://files.pythonhosted.org/packages/c6/3a/b31c8f0182a3e27f48e703f46e61bb769666cd0dac4700a73912d07a1417/orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff", size = 136374 }, - { url = "https://files.pythonhosted.org/packages/29/d0/fd9ab96841b090d281c46df566b7f97bc6c8cd9aff3f3ebe99755895c406/orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac", size = 140519 }, - { url = "https://files.pythonhosted.org/packages/d6/ce/36eb0f15978bb88e33a3480e1a3fb891caa0f189ba61ce7713e0ccdadabf/orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79", size = 406522 }, - { url = "https://files.pythonhosted.org/packages/85/11/e8af3161a288f5c6a00c188fc729c7ba193b0cbc07309a1a29c004347c30/orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827", size = 149790 }, - { url = "https://files.pythonhosted.org/packages/ea/96/209d52db0cf1e10ed48d8c194841e383e23c2ced5a2ee766649fe0e32d02/orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b", size = 140040 }, - { url = "https://files.pythonhosted.org/packages/ef/0e/526db1395ccb74c3d59ac1660b9a325017096dc5643086b38f27662b4add/orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3", size = 135955 }, - { url = "https://files.pythonhosted.org/packages/e6/69/18a778c9de3702b19880e73c9866b91cc85f904b885d816ba1ab318b223c/orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc", size = 131577 }, + { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719 }, + { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467 }, + { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702 }, + { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907 }, + { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935 }, + { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541 }, + { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031 }, + { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622 }, + { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800 }, + { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198 }, + { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984 }, + { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272 }, + { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360 }, ] [[package]] @@ -2731,21 +3007,23 @@ wheels = [ [[package]] name = "pandas" -version = "1.5.3" +version = "2.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, { name = "pytz" }, + { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/74/ee/146cab1ff6d575b54ace8a6a5994048380dc94879b0125b25e62edcb9e52/pandas-1.5.3.tar.gz", hash = "sha256:74a3fd7e5a7ec052f183273dc7b0acd3a863edf7520f5d3a1765c04ffdb3b0b1", size = 5203060 } +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/cd/34f6b0780301be81be804d7aa71d571457369e6131e2b330af2b0fed1aad/pandas-1.5.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3749077d86e3a2f0ed51367f30bf5b82e131cc0f14260c4d3e499186fccc4406", size = 18619230 }, - { url = "https://files.pythonhosted.org/packages/5f/34/b7858bb7d6d6bf4d9df1dde777a11fcf3ff370e1d1b3956e3d0fcca8322c/pandas-1.5.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:972d8a45395f2a2d26733eb8d0f629b2f90bebe8e8eddbb8829b180c09639572", size = 11982991 }, - { url = "https://files.pythonhosted.org/packages/b8/6c/005bd604994f7cbede4d7bf030614ef49a2213f76bc3d738ecf5b0dcc810/pandas-1.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:50869a35cbb0f2e0cd5ec04b191e7b12ed688874bd05dd777c19b28cbea90996", size = 10927131 }, - { url = "https://files.pythonhosted.org/packages/27/c7/35b81ce5f680f2dac55eac14d103245cd8cf656ae4a2ff3be2e69fd1d330/pandas-1.5.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3ac844a0fe00bfaeb2c9b51ab1424e5c8744f89860b138434a363b1f620f354", size = 11368188 }, - { url = "https://files.pythonhosted.org/packages/49/e2/79e46612dc25ebc7603dc11c560baa7266c90f9e48537ecf1a02a0dd6bff/pandas-1.5.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0a56cef15fd1586726dace5616db75ebcfec9179a3a55e78f72c5639fa2a23", size = 12062104 }, - { url = "https://files.pythonhosted.org/packages/d9/cd/f27c2992cbe05a3e39937f73a4be635a9ec149ec3ca4467d8cf039718994/pandas-1.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:478ff646ca42b20376e4ed3fa2e8d7341e8a63105586efe54fa2508ee087f328", size = 10362473 }, + { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763 }, + { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217 }, + { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791 }, + { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373 }, + { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444 }, + { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459 }, + { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086 }, ] [[package]] @@ -2877,7 +3155,7 @@ sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d [[package]] name = "pre-commit" -version = "4.5.0" +version = "4.5.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cfgv" }, @@ -2886,9 +3164,9 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/9b/6a4ffb4ed980519da959e1cf3122fc6cb41211daa58dbae1c73c0e519a37/pre_commit-4.5.0.tar.gz", hash = "sha256:dc5a065e932b19fc1d4c653c6939068fe54325af8e741e74e88db4d28a4dd66b", size = 198428 } +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/c4/b2d28e9d2edf4f1713eb3c29307f1a63f3d67cf09bdda29715a36a68921a/pre_commit-4.5.0-py2.py3-none-any.whl", hash = "sha256:25e2ce09595174d9c97860a95609f9f852c0614ba602de3561e267547f2335e1", size = 226429 }, + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437 }, ] [[package]] @@ -2938,27 +3216,29 @@ wheels = [ [[package]] name = "proto-plus" -version = "1.26.1" +version = "1.27.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ac/87285f15f7cce6d4a008f33f1757fb5a13611ea8914eb58c3d0d26243468/proto_plus-1.26.1.tar.gz", hash = "sha256:21a515a4c4c0088a773899e23c7bbade3d18f9c66c73edd4c7ee3816bc96a012", size = 56142 } +sdist = { url = "https://files.pythonhosted.org/packages/01/89/9cbe2f4bba860e149108b683bc2efec21f14d5f7ed6e25562ad86acbc373/proto_plus-1.27.0.tar.gz", hash = "sha256:873af56dd0d7e91836aee871e5799e1c6f1bda86ac9a983e0bb9f0c266a568c4", size = 56158 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/6d/280c4c2ce28b1593a19ad5239c8b826871fc6ec275c21afc8e1820108039/proto_plus-1.26.1-py3-none-any.whl", hash = "sha256:13285478c2dcf2abb829db158e1047e2f1e8d63a077d94263c2b88b043c75a66", size = 50163 }, + { url = "https://files.pythonhosted.org/packages/cd/24/3b7a0818484df9c28172857af32c2397b6d8fcd99d9468bd4684f98ebf0a/proto_plus-1.27.0-py3-none-any.whl", hash = "sha256:1baa7f81cf0f8acb8bc1f6d085008ba4171eaf669629d1b6d1673b21ed1c0a82", size = 50205 }, ] [[package]] name = "protobuf" -version = "3.19.6" +version = "6.33.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/d1/79bfd1f481469b661a2eddab551255536401892722189433282bfb13cfb1/protobuf-3.19.6.tar.gz", hash = "sha256:5f5540d57a43042389e87661c6eaa50f47c19c6176e8cf1c4f287aeefeccb5c4", size = 218071 } +sdist = { url = "https://files.pythonhosted.org/packages/34/44/e49ecff446afeec9d1a66d6bbf9adc21e3c7cea7803a920ca3773379d4f6/protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4", size = 444296 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/3b/90f805b9e5ecacf8a216f2e5acabc2d3ad965b62803510be41804e6bfbfe/protobuf-3.19.6-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:010be24d5a44be7b0613750ab40bc8b8cedc796db468eae6c779b395f50d1fa1", size = 913631 }, - { url = "https://files.pythonhosted.org/packages/26/ef/bd6ba3b4ff9a35944bdd325e2c9ee56f71e855757f7d43938232499f0278/protobuf-3.19.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11478547958c2dfea921920617eb457bc26867b0d1aa065ab05f35080c5d9eb6", size = 1055327 }, - { url = "https://files.pythonhosted.org/packages/4a/25/85bcc155980b5d7754ebdf4cb32039105f6020b6b2b8f7536a866113fc1c/protobuf-3.19.6-cp310-cp310-win32.whl", hash = "sha256:559670e006e3173308c9254d63facb2c03865818f22204037ab76f7a0ff70b5f", size = 775745 }, - { url = "https://files.pythonhosted.org/packages/97/f9/a14bac5331f3e55bcbbed906a0c8b112f554152ddf09efeb6f5f95653ffd/protobuf-3.19.6-cp310-cp310-win_amd64.whl", hash = "sha256:347b393d4dd06fb93a77620781e11c058b3b0a5289262f094379ada2920a3730", size = 895657 }, - { url = "https://files.pythonhosted.org/packages/32/27/1141a8232723dcb10a595cc0ce4321dcbbd5215300bf4acfc142343205bf/protobuf-3.19.6-py2.py3-none-any.whl", hash = "sha256:14082457dc02be946f60b15aad35e9f5c69e738f80ebbc0900a19bc83734a5a4", size = 162648 }, + { url = "https://files.pythonhosted.org/packages/bc/91/1e3a34881a88697a7354ffd177e8746e97a722e5e8db101544b47e84afb1/protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d", size = 425603 }, + { url = "https://files.pythonhosted.org/packages/64/20/4d50191997e917ae13ad0a235c8b42d8c1ab9c3e6fd455ca16d416944355/protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4", size = 436930 }, + { url = "https://files.pythonhosted.org/packages/b2/ca/7e485da88ba45c920fb3f50ae78de29ab925d9e54ef0de678306abfbb497/protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43", size = 427621 }, + { url = "https://files.pythonhosted.org/packages/7d/4f/f743761e41d3b2b2566748eb76bbff2b43e14d5fcab694f494a16458b05f/protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e", size = 324460 }, + { url = "https://files.pythonhosted.org/packages/b1/fa/26468d00a92824020f6f2090d827078c09c9c587e34cbfd2d0c7911221f8/protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872", size = 339168 }, + { url = "https://files.pythonhosted.org/packages/56/13/333b8f421738f149d4fe5e49553bc2a2ab75235486259f689b4b91f96cec/protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f", size = 323270 }, + { url = "https://files.pythonhosted.org/packages/0e/15/4f02896cc3df04fc465010a4c6a0cd89810f54617a32a70ef531ed75d61c/protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c", size = 170501 }, ] [[package]] @@ -3099,6 +3379,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009 }, ] +[[package]] +name = "pydantic-extra-types" +version = "2.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296 }, +] + [[package]] name = "pydantic-settings" version = "2.12.0" @@ -3147,43 +3440,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, ] -[[package]] -name = "pympler" -version = "1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dd/37/c384631908029676d8e7213dd956bb686af303a80db7afbc9be36bc49495/pympler-1.1.tar.gz", hash = "sha256:1eaa867cb8992c218430f1708fdaccda53df064144d1c5656b1e6f1ee6000424", size = 179954 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/4f/a6a2e2b202d7fd97eadfe90979845b8706676b41cbd3b42ba75adf329d1f/Pympler-1.1-py3-none-any.whl", hash = "sha256:5b223d6027d0619584116a0cbc28e8d2e378f7a79c1e5e024f9ff3b673c58506", size = 165766 }, -] - [[package]] name = "pymupdf" -version = "1.26.6" +version = "1.26.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/d7/a6f0e03a117fa2ad79c4b898203bb212b17804f92558a6a339298faca7bb/pymupdf-1.26.6.tar.gz", hash = "sha256:a2b4531cd4ab36d6f1f794bb6d3c33b49bda22f36d58bb1f3e81cbc10183bd2b", size = 84322494 } +sdist = { url = "https://files.pythonhosted.org/packages/48/d6/09b28f027b510838559f7748807192149c419b30cb90e6d5f0cf916dc9dc/pymupdf-1.26.7.tar.gz", hash = "sha256:71add8bdc8eb1aaa207c69a13400693f06ad9b927bea976f5d5ab9df0bb489c3", size = 84327033 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/5c/dec354eee5fe4966c715f33818ed4193e0e6c986cf8484de35b6c167fb8e/pymupdf-1.26.6-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e46f320a136ad55e5219e8f0f4061bdf3e4c12b126d2740d5a49f73fae7ea176", size = 23178988 }, - { url = "https://files.pythonhosted.org/packages/ec/a0/11adb742d18142bd623556cd3b5d64649816decc5eafd30efc9498657e76/pymupdf-1.26.6-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:6844cd2396553c0fa06de4869d5d5ecb1260e6fc3b9d85abe8fa35f14dd9d688", size = 22469764 }, - { url = "https://files.pythonhosted.org/packages/e4/c8/377cf20e31f58d4c243bfcf2d3cb7466d5b97003b10b9f1161f11eb4a994/pymupdf-1.26.6-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:617ba69e02c44f0da1c0e039ea4a26cf630849fd570e169c71daeb8ac52a81d6", size = 23502227 }, - { url = "https://files.pythonhosted.org/packages/4f/bf/6e02e3d84b32c137c71a0a3dcdba8f2f6e9950619a3bc272245c7c06a051/pymupdf-1.26.6-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7777d0b7124c2ebc94849536b6a1fb85d158df3b9d873935e63036559391534c", size = 24115381 }, - { url = "https://files.pythonhosted.org/packages/ab/9d/30f7fcb3776bfedde66c06297960debe4883b1667294a1ee9426c942e94d/pymupdf-1.26.6-cp310-abi3-win32.whl", hash = "sha256:8f3ef05befc90ca6bb0f12983200a7048d5bff3e1c1edef1bb3de60b32cb5274", size = 17203613 }, - { url = "https://files.pythonhosted.org/packages/f9/e8/989f4eaa369c7166dc24f0eaa3023f13788c40ff1b96701f7047421554a8/pymupdf-1.26.6-cp310-abi3-win_amd64.whl", hash = "sha256:ce02ca96ed0d1acfd00331a4d41a34c98584d034155b06fd4ec0f051718de7ba", size = 18405680 }, + { url = "https://files.pythonhosted.org/packages/94/35/cd74cea1787b2247702ef8522186bdef32e9cb30a099e6bb864627ef6045/pymupdf-1.26.7-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:07085718dfdae5ab83b05eb5eb397f863bcc538fe05135318a01ea353e7a1353", size = 23179369 }, + { url = "https://files.pythonhosted.org/packages/72/74/448b6172927c829c6a3fba80078d7b0a016ebbe2c9ee528821f5ea21677a/pymupdf-1.26.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:31aa9c8377ea1eea02934b92f4dcf79fb2abba0bf41f8a46d64c3e31546a3c02", size = 22470101 }, + { url = "https://files.pythonhosted.org/packages/65/e7/47af26f3ac76be7ac3dd4d6cc7ee105948a8355d774e5ca39857bf91c11c/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e419b609996434a14a80fa060adec72c434a1cca6a511ec54db9841bc5d51b3c", size = 23502486 }, + { url = "https://files.pythonhosted.org/packages/2a/6b/3de1714d734ff949be1e90a22375d0598d3540b22ae73eb85c2d7d1f36a9/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:69dfc78f206a96e5b3ac22741263ebab945fdf51f0dbe7c5757c3511b23d9d72", size = 24115727 }, + { url = "https://files.pythonhosted.org/packages/62/9b/f86224847949577a523be2207315ae0fd3155b5d909cd66c274d095349a3/pymupdf-1.26.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1d5106f46e1ca0d64d46bd51892372a4f82076bdc14a9678d33d630702abca36", size = 24324386 }, + { url = "https://files.pythonhosted.org/packages/85/8e/a117d39092ca645fde8b903f4a941d9aa75b370a67b4f1f435f56393dc5a/pymupdf-1.26.7-cp310-abi3-win32.whl", hash = "sha256:7c9645b6f5452629c747690190350213d3e5bbdb6b2eca227d82702b327f6eee", size = 17203888 }, + { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952 }, ] [[package]] name = "pymupdf4llm" -version = "0.2.6" +version = "0.2.8" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pymupdf" }, { name = "tabulate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/bd/5c1958ac1ab68c12a09aef1128b3522e1ada6086c6cb42f880dcb294b13e/pymupdf4llm-0.2.6.tar.gz", hash = "sha256:e2deb44ba35aef92c4d84254ef70739feb982256235de2740ffb016b25480da4", size = 64787 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/ff/d2e856ff5db5fa57ebf13ae04de4da6c203f5fb17507c0dd21ffd0ae4a17/pymupdf4llm-0.2.8.tar.gz", hash = "sha256:c4f9815cff210cef45123e93ae3a6f802e0dc1d1ad4534a4a463c000aaec98fd", size = 66867 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/fa/2c7d7ce85d7844097d96a8085e719ef5508eaf60e0d0ec24d2d3d42fffc9/pymupdf4llm-0.2.6-py3-none-any.whl", hash = "sha256:0b8f19d867ca3d9f1e0835a376431b74ef799a0bc0bae1442d1d429fde2d355b", size = 66562 }, + { url = "https://files.pythonhosted.org/packages/58/d5/47e14346b6f57cbc7456cc24ded697b4037b399ff56ed12afccbd202361d/pymupdf4llm-0.2.8-py3-none-any.whl", hash = "sha256:e60587d151223fc9e118661a9c7bb04b04ae928187c201a14d60ac8a42963591", size = 68637 }, ] [[package]] @@ -3197,11 +3479,11 @@ wheels = [ [[package]] name = "pyparsing" -version = "3.2.5" +version = "3.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/181488fc2b9d093e3972d2a472855aae8a03f000592dbfce716a512b3359/pyparsing-3.2.5.tar.gz", hash = "sha256:2df8d5b7b2802ef88e8d016a2eb9c7aeaa923529cd251ed0fe4608275d4105b6", size = 1099274 } +sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512 } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/5e/1aa9a93198c6b64513c9d7752de7422c06402de6600a8767da1524f9570b/pyparsing-3.2.5-py3-none-any.whl", hash = "sha256:e38a4f02064cf41fe6593d328d0512495ad1f3d8a91c4f73fc401b3079a59a5e", size = 113890 }, + { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793 }, ] [[package]] @@ -3278,11 +3560,11 @@ wheels = [ [[package]] name = "python-multipart" -version = "0.0.20" +version = "0.0.21" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158 } +sdist = { url = "https://files.pythonhosted.org/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196 } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546 }, + { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541 }, ] [[package]] @@ -3525,16 +3807,16 @@ wheels = [ [[package]] name = "rich-toolkit" -version = "0.17.0" +version = "0.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/d0/8f8de36e1abf8339b497ce700dd7251ca465ffca4a1976969b0eaeb596fb/rich_toolkit-0.17.0.tar.gz", hash = "sha256:17ca7a32e613001aa0945ddea27a246f6de01dfc4c12403254c057a8ee542977", size = 187955 } +sdist = { url = "https://files.pythonhosted.org/packages/97/09/3f9b8d9daaf235195c626f21e03604c05b987404ee3bcacee0c1f67f2a8e/rich_toolkit-0.17.1.tar.gz", hash = "sha256:5af54df8d1dd9c8530e462e1bdcaed625c9b49f5a55b035aa0ba1c17bdb87c9a", size = 187925 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/42/ef2ed40699567661d03b0b511ac46cf6cee736de8f3666819c12d6d20696/rich_toolkit-0.17.0-py3-none-any.whl", hash = "sha256:06fb47a5c5259d6b480287cd38aff5f551b6e1a307f90ed592453dd360e4e71e", size = 31412 }, + { url = "https://files.pythonhosted.org/packages/7f/7b/15e55fa8a76d0d41bf34d965af78acdaf80a315907adb30de8b63c272694/rich_toolkit-0.17.1-py3-none-any.whl", hash = "sha256:96d24bb921ecd225ffce7c526a9149e74006410c05e6d405bd74ffd54d5631ed", size = 31412 }, ] [[package]] @@ -3709,20 +3991,19 @@ wheels = [ [[package]] name = "send2trash" -version = "1.8.3" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/3a/aec9b02217bb79b87bbc1a21bc6abc51e3d5dcf65c30487ac96c0908c722/Send2Trash-1.8.3.tar.gz", hash = "sha256:b18e7a3966d99871aefeb00cfbcfdced55ce4871194810fc71f4aa484b953abf", size = 17394 } +sdist = { url = "https://files.pythonhosted.org/packages/62/6e/421803dec0c0dfbf5a27e66491ebe6643a461e4f90422f00ea4c68ae24aa/send2trash-2.0.0.tar.gz", hash = "sha256:1761421da3f9930bfe51ed7c45343948573383ad4c27e3acebc91be324e7770d", size = 17206 } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/b0/4562db6223154aa4e22f939003cb92514c79f3d4dccca3444253fd17f902/Send2Trash-1.8.3-py3-none-any.whl", hash = "sha256:0c31227e0bd08961c7665474a3d1ef7193929fedda4233843689baa056be46c9", size = 18072 }, + { url = "https://files.pythonhosted.org/packages/1b/5a/f2f2e5eda25579f754acd83399c522ee03d6acbe001dfe53c8a1ec928b44/send2trash-2.0.0-py3-none-any.whl", hash = "sha256:e70d5ce41dbb890882cc78bc25d137478330b39a391e756fadf82e34da4d85b8", size = 17642 }, ] [[package]] name = "sentence-transformers" -version = "5.1.2" +version = "5.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, - { name = "pillow" }, { name = "scikit-learn" }, { name = "scipy" }, { name = "torch" }, @@ -3730,9 +4011,9 @@ dependencies = [ { name = "transformers" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0f/96/f3f3409179d14dbfdbea8622e2e9eaa3c8836ddcaecd2cd5ff0a11731d20/sentence_transformers-5.1.2.tar.gz", hash = "sha256:0f6c8bd916a78dc65b366feb8d22fd885efdb37432e7630020d113233af2b856", size = 375185 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/a1/64e7b111e753307ffb7c5b6d039c52d4a91a47fa32a7f5bc377a49b22402/sentence_transformers-5.2.0.tar.gz", hash = "sha256:acaeb38717de689f3dab45d5e5a02ebe2f75960a4764ea35fea65f58a4d3019f", size = 381004 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/a6/a607a737dc1a00b7afe267b9bfde101b8cee2529e197e57471d23137d4e5/sentence_transformers-5.1.2-py3-none-any.whl", hash = "sha256:724ce0ea62200f413f1a5059712aff66495bc4e815a1493f7f9bca242414c333", size = 488009 }, + { url = "https://files.pythonhosted.org/packages/40/d0/3b2897ef6a0c0c801e9fecca26bcc77081648e38e8c772885ebdd8d7d252/sentence_transformers-5.2.0-py3-none-any.whl", hash = "sha256:aa57180f053687d29b08206766ae7db549be5074f61849def7b17bf0b8025ca2", size = 493748 }, ] [[package]] @@ -3753,15 +4034,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "2.47.0" +version = "2.48.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/2a/d225cbf87b6c8ecce5664db7bcecb82c317e448e3b24a2dcdaacb18ca9a7/sentry_sdk-2.47.0.tar.gz", hash = "sha256:8218891d5e41b4ea8d61d2aed62ed10c80e39d9f2959d6f939efbf056857e050", size = 381895 } +sdist = { url = "https://files.pythonhosted.org/packages/40/f0/0e9dc590513d5e742d7799e2038df3a05167cba084c6ca4f3cdd75b55164/sentry_sdk-2.48.0.tar.gz", hash = "sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473", size = 384828 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/ac/d6286ea0d49e7b58847faf67b00e56bb4ba3d525281e2ac306e1f1f353da/sentry_sdk-2.47.0-py2.py3-none-any.whl", hash = "sha256:d72f8c61025b7d1d9e52510d03a6247b280094a327dd900d987717a4fce93412", size = 411088 }, + { url = "https://files.pythonhosted.org/packages/4d/19/8d77f9992e5cbfcaa9133c3bf63b4fbbb051248802e1e803fed5c552fbb2/sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172", size = 414555 }, ] [[package]] @@ -3820,32 +4101,31 @@ wheels = [ [[package]] name = "soupsieve" -version = "2.8" +version = "2.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6d/e6/21ccce3262dd4889aa3332e5a119a3491a95e8f60939870a3a035aabac0d/soupsieve-2.8.tar.gz", hash = "sha256:e2dd4a40a628cb5f28f6d4b0db8800b8f581b65bb380b97de22ba5ca8d72572f", size = 103472 } +sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856 } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/a0/bb38d3b76b8cae341dad93a2dd83ab7462e6dbcdd84d43f54ee60a8dc167/soupsieve-2.8-py3-none-any.whl", hash = "sha256:0cc76456a30e20f5d7f2e14a98a4ae2ee4e5abdc7c5ea0aafe795f344bc7984c", size = 36679 }, + { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710 }, ] [[package]] name = "sqlalchemy" -version = "2.0.44" +version = "2.0.45" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f0/f2/840d7b9496825333f532d2e3976b8eadbf52034178aac53630d09fe6e1ef/sqlalchemy-2.0.44.tar.gz", hash = "sha256:0ae7454e1ab1d780aee69fd2aae7d6b8670a581d8847f2d1e0f7ddfbf47e5a22", size = 9819830 } +sdist = { url = "https://files.pythonhosted.org/packages/be/f9/5e4491e5ccf42f5d9cfc663741d261b3e6e1683ae7812114e7636409fcc6/sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", size = 9869912 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/a7/e9ccfa7eecaf34c6f57d8cb0bb7cbdeeff27017cc0f5d0ca90fdde7a7c0d/sqlalchemy-2.0.44-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c77f3080674fc529b1bd99489378c7f63fcb4ba7f8322b79732e0258f0ea3ce", size = 2137282 }, - { url = "https://files.pythonhosted.org/packages/b1/e1/50bc121885bdf10833a4f65ecbe9fe229a3215f4d65a58da8a181734cae3/sqlalchemy-2.0.44-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4c26ef74ba842d61635b0152763d057c8d48215d5be9bb8b7604116a059e9985", size = 2127322 }, - { url = "https://files.pythonhosted.org/packages/46/f2/a8573b7230a3ce5ee4b961a2d510d71b43872513647398e595b744344664/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4a172b31785e2f00780eccab00bc240ccdbfdb8345f1e6063175b3ff12ad1b0", size = 3214772 }, - { url = "https://files.pythonhosted.org/packages/4a/d8/c63d8adb6a7edaf8dcb6f75a2b1e9f8577960a1e489606859c4d73e7d32b/sqlalchemy-2.0.44-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9480c0740aabd8cb29c329b422fb65358049840b34aba0adf63162371d2a96e", size = 3214434 }, - { url = "https://files.pythonhosted.org/packages/ee/a6/243d277a4b54fae74d4797957a7320a5c210c293487f931cbe036debb697/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:17835885016b9e4d0135720160db3095dc78c583e7b902b6be799fb21035e749", size = 3155365 }, - { url = "https://files.pythonhosted.org/packages/5f/f8/6a39516ddd75429fd4ee5a0d72e4c80639fab329b2467c75f363c2ed9751/sqlalchemy-2.0.44-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cbe4f85f50c656d753890f39468fcd8190c5f08282caf19219f684225bfd5fd2", size = 3178910 }, - { url = "https://files.pythonhosted.org/packages/43/f0/118355d4ad3c39d9a2f5ee4c7304a9665b3571482777357fa9920cd7a6b4/sqlalchemy-2.0.44-cp310-cp310-win32.whl", hash = "sha256:2fcc4901a86ed81dc76703f3b93ff881e08761c63263c46991081fd7f034b165", size = 2105624 }, - { url = "https://files.pythonhosted.org/packages/61/83/6ae5f9466f8aa5d0dcebfff8c9c33b98b27ce23292df3b990454b3d434fd/sqlalchemy-2.0.44-cp310-cp310-win_amd64.whl", hash = "sha256:9919e77403a483ab81e3423151e8ffc9dd992c20d2603bf17e4a8161111e55f5", size = 2129240 }, - { url = "https://files.pythonhosted.org/packages/9c/5e/6a29fa884d9fb7ddadf6b69490a9d45fded3b38541713010dad16b77d015/sqlalchemy-2.0.44-py3-none-any.whl", hash = "sha256:19de7ca1246fbef9f9d1bff8f1ab25641569df226364a0e40457dc5457c54b05", size = 1928718 }, + { url = "https://files.pythonhosted.org/packages/fe/70/75b1387d72e2847220441166c5eb4e9846dd753895208c13e6d66523b2d9/sqlalchemy-2.0.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c64772786d9eee72d4d3784c28f0a636af5b0a29f3fe26ff11f55efe90c0bd85", size = 2154148 }, + { url = "https://files.pythonhosted.org/packages/d8/a4/7805e02323c49cb9d1ae5cd4913b28c97103079765f520043f914fca4cb3/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ae64ebf7657395824a19bca98ab10eb9a3ecb026bf09524014f1bb81cb598d4", size = 3233051 }, + { url = "https://files.pythonhosted.org/packages/d7/ec/32ae09139f61bef3de3142e85c47abdee8db9a55af2bb438da54a4549263/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f02325709d1b1a1489f23a39b318e175a171497374149eae74d612634b234c0", size = 3232781 }, + { url = "https://files.pythonhosted.org/packages/ad/bd/bf7b869b6f5585eac34222e1cf4405f4ba8c3b85dd6b1af5d4ce8bca695f/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2c3684fca8a05f0ac1d9a21c1f4a266983a7ea9180efb80ffeb03861ecd01a0", size = 3182096 }, + { url = "https://files.pythonhosted.org/packages/21/6a/c219720a241bb8f35c88815ccc27761f5af7fdef04b987b0e8a2c1a6dcaa/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040f6f0545b3b7da6b9317fc3e922c9a98fc7243b2a1b39f78390fc0942f7826", size = 3205109 }, + { url = "https://files.pythonhosted.org/packages/bd/c4/6ccf31b2bc925d5d95fab403ffd50d20d7c82b858cf1a4855664ca054dce/sqlalchemy-2.0.45-cp310-cp310-win32.whl", hash = "sha256:830d434d609fe7bfa47c425c445a8b37929f140a7a44cdaf77f6d34df3a7296a", size = 2114240 }, + { url = "https://files.pythonhosted.org/packages/de/29/a27a31fca07316def418db6f7c70ab14010506616a2decef1906050a0587/sqlalchemy-2.0.45-cp310-cp310-win_amd64.whl", hash = "sha256:0209d9753671b0da74da2cfbb9ecf9c02f72a759e4b018b3ab35f244c91842c7", size = 2137615 }, + { url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672 }, ] [[package]] @@ -3867,6 +4147,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, ] +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138 }, +] + [[package]] name = "stack-data" version = "0.6.3" @@ -3896,7 +4185,7 @@ wheels = [ [[package]] name = "streamlit" -version = "1.21.0" +version = "1.52.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "altair" }, @@ -3904,7 +4193,6 @@ dependencies = [ { name = "cachetools" }, { name = "click" }, { name = "gitpython" }, - { name = "importlib-metadata" }, { name = "numpy" }, { name = "packaging" }, { name = "pandas" }, @@ -3912,20 +4200,16 @@ dependencies = [ { name = "protobuf" }, { name = "pyarrow" }, { name = "pydeck" }, - { name = "pympler" }, - { name = "python-dateutil" }, { name = "requests" }, - { name = "rich" }, + { name = "tenacity" }, { name = "toml" }, { name = "tornado" }, { name = "typing-extensions" }, - { name = "tzlocal" }, - { name = "validators" }, { name = "watchdog", marker = "platform_system != 'Darwin'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/17/95/89b0f5f51cd006ffb6cc216393793d05029c47e97f140a9bff02f8c291a8/streamlit-1.21.0.tar.gz", hash = "sha256:c72d9639508679c5e411d1f886d213777759501d01975285c049dc30db463c1a", size = 9345809 } +sdist = { url = "https://files.pythonhosted.org/packages/43/20/434aaceccc6e1912671d869926103051330437adba72d538d787a07727ef/streamlit-1.52.2.tar.gz", hash = "sha256:64a4dda8bc5cdd37bfd490e93bb53da35aaef946fcfc283a7980dacdf165108b", size = 8584178 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/fa/5b010610aa136c44a20de6ed9ec0b36867daf7322d0e3c8e626a99fab11a/streamlit-1.21.0-py2.py3-none-any.whl", hash = "sha256:05862598952a9126e16652caa5bc88eeeea7b2773af252e2daccf1c84ceaaef4", size = 9665093 }, + { url = "https://files.pythonhosted.org/packages/c0/95/6b7873f0267973ebd55ba9cd33a690b35a116f2779901ef6185a0e21864d/streamlit-1.52.2-py3-none-any.whl", hash = "sha256:a16bb4fbc9781e173ce9dfbd8ffb189c174f148f9ca4fb8fa56423e84e193fc8", size = 9025937 }, ] [[package]] @@ -3984,25 +4268,25 @@ wheels = [ [[package]] name = "tensorboardx" -version = "2.6" +version = "2.6.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "packaging" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/e3/c68897ee471518b1f8d3e53c602aec6f2b09092aa774da88764262f03f56/tensorboardX-2.6.tar.gz", hash = "sha256:d4c036964dd2deb075a1909832b276daa383eab3f9db519ad90b99f5aea06b0c", size = 91196 } +sdist = { url = "https://files.pythonhosted.org/packages/2b/c5/d4cc6e293fb837aaf9f76dd7745476aeba8ef7ef5146c3b3f9ee375fe7a5/tensorboardx-2.6.4.tar.gz", hash = "sha256:b163ccb7798b31100b9f5fa4d6bc22dad362d7065c2f24b51e50731adde86828", size = 4769801 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/9f/d532d37f10ac7af136d4c2ba71e1fe7af0f3cc0cc076dfc05826171e9737/tensorboardX-2.6-py2.py3-none-any.whl", hash = "sha256:24a7cd076488de1e9d15ef25371b8ebf90c4f8f622af2477c611198f03f4a606", size = 114480 }, + { url = "https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl", hash = "sha256:5970cf3a1f0a6a6e8b180ccf46f3fe832b8a25a70b86e5a237048a7c0beb18e2", size = 87201 }, ] [[package]] name = "termcolor" -version = "3.2.0" +version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/56/ab275c2b56a5e2342568838f0d5e3e66a32354adcc159b495e374cda43f5/termcolor-3.2.0.tar.gz", hash = "sha256:610e6456feec42c4bcd28934a8c87a06c3fa28b01561d46aa09a9881b8622c58", size = 14423 } +sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/d5/141f53d7c1eb2a80e6d3e9a390228c3222c27705cbe7f048d3623053f3ca/termcolor-3.2.0-py3-none-any.whl", hash = "sha256:a10343879eba4da819353c55cb8049b0933890c2ebf9ad5d3ecd2bb32ea96ea6", size = 7698 }, + { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734 }, ] [[package]] @@ -4061,27 +4345,32 @@ wheels = [ [[package]] name = "tokenizers" -version = "0.22.1" +version = "0.22.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1c/46/fb6854cec3278fbfa4a75b50232c77622bc517ac886156e6afbfa4d8fc6e/tokenizers-0.22.1.tar.gz", hash = "sha256:61de6522785310a309b3407bac22d99c4db5dba349935e99e4d15ea2226af2d9", size = 363123 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/33/f4b2d94ada7ab297328fc671fed209368ddb82f965ec2224eb1892674c3a/tokenizers-0.22.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:59fdb013df17455e5f950b4b834a7b3ee2e0271e6378ccb33aa74d178b513c73", size = 3069318 }, - { url = "https://files.pythonhosted.org/packages/1c/58/2aa8c874d02b974990e89ff95826a4852a8b2a273c7d1b4411cdd45a4565/tokenizers-0.22.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8d4e484f7b0827021ac5f9f71d4794aaef62b979ab7608593da22b1d2e3c4edc", size = 2926478 }, - { url = "https://files.pythonhosted.org/packages/1e/3b/55e64befa1e7bfea963cf4b787b2cea1011362c4193f5477047532ce127e/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:19d2962dd28bc67c1f205ab180578a78eef89ac60ca7ef7cbe9635a46a56422a", size = 3256994 }, - { url = "https://files.pythonhosted.org/packages/71/0b/fbfecf42f67d9b7b80fde4aabb2b3110a97fac6585c9470b5bff103a80cb/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:38201f15cdb1f8a6843e6563e6e79f4abd053394992b9bbdf5213ea3469b4ae7", size = 3153141 }, - { url = "https://files.pythonhosted.org/packages/17/a9/b38f4e74e0817af8f8ef925507c63c6ae8171e3c4cb2d5d4624bf58fca69/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1cbe5454c9a15df1b3443c726063d930c16f047a3cc724b9e6e1a91140e5a21", size = 3508049 }, - { url = "https://files.pythonhosted.org/packages/d2/48/dd2b3dac46bb9134a88e35d72e1aa4869579eacc1a27238f1577270773ff/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e7d094ae6312d69cc2a872b54b91b309f4f6fbce871ef28eb27b52a98e4d0214", size = 3710730 }, - { url = "https://files.pythonhosted.org/packages/93/0e/ccabc8d16ae4ba84a55d41345207c1e2ea88784651a5a487547d80851398/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:afd7594a56656ace95cdd6df4cca2e4059d294c5cfb1679c57824b605556cb2f", size = 3412560 }, - { url = "https://files.pythonhosted.org/packages/d0/c6/dc3a0db5a6766416c32c034286d7c2d406da1f498e4de04ab1b8959edd00/tokenizers-0.22.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2ef6063d7a84994129732b47e7915e8710f27f99f3a3260b8a38fc7ccd083f4", size = 3250221 }, - { url = "https://files.pythonhosted.org/packages/d7/a6/2c8486eef79671601ff57b093889a345dd3d576713ef047776015dc66de7/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ba0a64f450b9ef412c98f6bcd2a50c6df6e2443b560024a09fa6a03189726879", size = 9345569 }, - { url = "https://files.pythonhosted.org/packages/6b/16/32ce667f14c35537f5f605fe9bea3e415ea1b0a646389d2295ec348d5657/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:331d6d149fa9c7d632cde4490fb8bbb12337fa3a0232e77892be656464f4b446", size = 9271599 }, - { url = "https://files.pythonhosted.org/packages/51/7c/a5f7898a3f6baa3fc2685c705e04c98c1094c523051c805cdd9306b8f87e/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:607989f2ea68a46cb1dfbaf3e3aabdf3f21d8748312dbeb6263d1b3b66c5010a", size = 9533862 }, - { url = "https://files.pythonhosted.org/packages/36/65/7e75caea90bc73c1dd8d40438adf1a7bc26af3b8d0a6705ea190462506e1/tokenizers-0.22.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a0f307d490295717726598ef6fa4f24af9d484809223bbc253b201c740a06390", size = 9681250 }, - { url = "https://files.pythonhosted.org/packages/30/2c/959dddef581b46e6209da82df3b78471e96260e2bc463f89d23b1bf0e52a/tokenizers-0.22.1-cp39-abi3-win32.whl", hash = "sha256:b5120eed1442765cd90b903bb6cfef781fd8fe64e34ccaecbae4c619b7b12a82", size = 2472003 }, - { url = "https://files.pythonhosted.org/packages/b3/46/e33a8c93907b631a99377ef4c5f817ab453d0b34f93529421f42ff559671/tokenizers-0.22.1-cp39-abi3-win_amd64.whl", hash = "sha256:65fd6e3fb11ca1e78a6a93602490f134d1fdeb13bcef99389d5102ea318ed138", size = 2674684 }, +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275 }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472 }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736 }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835 }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673 }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818 }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195 }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982 }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245 }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069 }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263 }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429 }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363 }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786 }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133 }, + { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301 }, + { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308 }, + { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964 }, + { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542 }, ] [[package]] @@ -4102,15 +4391,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408 }, ] -[[package]] -name = "toolz" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/11/d6/114b492226588d6ff54579d95847662fc69196bdeec318eb45393b24c192/toolz-1.1.0.tar.gz", hash = "sha256:27a5c770d068c110d9ed9323f24f1543e83b2f300a687b7891c1a6d56b697b5b", size = 52613 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/12/5911ae3eeec47800503a238d971e51722ccea5feb8569b735184d5fcdbc0/toolz-1.1.0-py3-none-any.whl", hash = "sha256:15ccc861ac51c53696de0a5d6d4607f99c210739caf987b5d2054f3efed429d8", size = 58093 }, -] - [[package]] name = "torch" version = "2.9.1" @@ -4162,21 +4442,21 @@ wheels = [ [[package]] name = "tornado" -version = "6.5.2" +version = "6.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821 } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563 }, - { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729 }, - { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295 }, - { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644 }, - { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878 }, - { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549 }, - { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973 }, - { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954 }, - { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023 }, - { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427 }, - { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456 }, + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909 }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163 }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746 }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083 }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315 }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003 }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412 }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392 }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481 }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886 }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910 }, ] [[package]] @@ -4255,7 +4535,7 @@ wheels = [ [[package]] name = "typer" -version = "0.20.0" +version = "0.21.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -4263,9 +4543,9 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8f/28/7c85c8032b91dbe79725b6f17d2fffc595dff06a35c7a30a37bef73a1ab4/typer-0.20.0.tar.gz", hash = "sha256:1aaf6494031793e4876fb0bacfa6a912b551cf43c1e63c800df8b1a866720c37", size = 106492 } +sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371 } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/64/7713ffe4b5983314e9d436a90d5bd4f63b6054e2aca783a3cfc44cb95bbf/typer-0.20.0-py3-none-any.whl", hash = "sha256:5b463df6793ec1dca6213a3cf4c0f03bc6e322ac5e16e13ddd622a889489784a", size = 47028 }, + { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381 }, ] [[package]] @@ -4291,23 +4571,11 @@ wheels = [ [[package]] name = "tzdata" -version = "2025.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 }, -] - -[[package]] -name = "tzlocal" -version = "5.3.1" +version = "2025.3" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "tzdata", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026 }, + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521 }, ] [[package]] @@ -4330,25 +4598,25 @@ wheels = [ [[package]] name = "urllib3" -version = "2.6.0" +version = "2.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1c/43/554c2569b62f49350597348fc3ac70f786e3c32e7f19d266e19817812dd3/urllib3-2.6.0.tar.gz", hash = "sha256:cb9bcef5a4b345d5da5d145dc3e30834f58e8018828cbc724d30b4cb7d4d49f1", size = 432585 } +sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930 } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/1a/9ffe814d317c5224166b23e7c47f606d6e473712a2fad0f704ea9b99f246/urllib3-2.6.0-py3-none-any.whl", hash = "sha256:c90f7a39f716c572c4e3e58509581ebd83f9b59cced005b7db7ad2d22b0db99f", size = 131083 }, + { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182 }, ] [[package]] name = "uvicorn" -version = "0.38.0" +version = "0.40.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cb/ce/f06b84e2697fef4688ca63bdb2fdf113ca0a3be33f94488f2cadb690b0cf/uvicorn-0.38.0.tar.gz", hash = "sha256:fd97093bdd120a2609fc0d3afe931d4d4ad688b6e75f0f929fde1bc36fe0e91d", size = 80605 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/d9/d88e73ca598f4f6ff671fb5fde8a32925c2e08a637303a1d12883c7305fa/uvicorn-0.38.0-py3-none-any.whl", hash = "sha256:48c0afd214ceb59340075b4a052ea1ee91c16fbc2a9b1469cca0e54566977b02", size = 68109 }, + { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502 }, ] [package.optional-dependencies] @@ -4376,15 +4644,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261 }, ] -[[package]] -name = "validators" -version = "0.35.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/53/66/a435d9ae49850b2f071f7ebd8119dd4e84872b01630d6736761e6e7fd847/validators-0.35.0.tar.gz", hash = "sha256:992d6c48a4e77c81f1b4daba10d16c3a9bb0dbb79b3a19ea847ff0928e70497a", size = 73399 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/6e/3e955517e22cbdd565f2f8b2e73d52528b14b8bcfdb04f62466b071de847/validators-0.35.0-py3-none-any.whl", hash = "sha256:e8c947097eae7892cb3d26868d637f79f47b4a0554bc6b80065dfe5aac3705dd", size = 44712 }, -] - [[package]] name = "virtualenv" version = "20.35.4" @@ -4400,6 +4659,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095 }, ] +[[package]] +name = "waitress" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/cb/04ddb054f45faa306a230769e868c28b8065ea196891f09004ebace5b184/waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", size = 179901 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/57/a27182528c90ef38d82b636a11f606b0cbb0e17588ed205435f8affe3368/waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", size = 56232 }, +] + [[package]] name = "watchdog" version = "6.0.0" @@ -4507,6 +4775,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, ] +[[package]] +name = "werkzeug" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960 }, +] + [[package]] name = "widgetsnbextension" version = "4.0.15" From d349c693f89e3378cddc1dbca2d1eccbc6770b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Fri, 9 Jan 2026 15:21:10 -0300 Subject: [PATCH 030/104] Feature/document extract config (#69) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ Enhance document extraction with caching and configuration options * ✅ Update extractor tests to handle additional configuration parameters and improve error handling * 🔧 Update marker model warmup to include configuration setup for improved initialization * 🔖 Update aymurai package version to 2.0.0a6.dev3 * ⏪ Revert multiprocessing context change in run_safe_text_extraction * 🔖 Update aymurai package version to 2.0.0a6.dev5 * 🔥 Remove unused multiprocessing import from document_extract.py * 🔥 Remove unused logging import from extraction.py * 🔧 Change default value of force_ocr to False in pdf_to_text function * 📝 Update argument descriptions in pdf_to_text and plain_text_extractor functions to include default values * 📝 Remove duplicate argument description for path in BaseExtractor.extract method --- .../routers/misc/document_extract.py | 75 ++++++++++-- aymurai/api/startup/marker.py | 9 +- aymurai/text/extraction.py | 5 +- aymurai/text/extractors/base.py | 3 +- aymurai/text/extractors/docx.py | 3 +- aymurai/text/extractors/odt.py | 6 +- aymurai/text/extractors/pdf.py | 56 ++++++++- aymurai/text/extractors/utils.py | 109 +++++++++++++++--- test/text/test_extraction.py | 6 +- test/text/test_extractors.py | 55 +++++++++ uv.lock | 2 +- 11 files changed, 284 insertions(+), 45 deletions(-) diff --git a/aymurai/api/endpoints/routers/misc/document_extract.py b/aymurai/api/endpoints/routers/misc/document_extract.py index bdbcfc2e..7322b07a 100644 --- a/aymurai/api/endpoints/routers/misc/document_extract.py +++ b/aymurai/api/endpoints/routers/misc/document_extract.py @@ -19,16 +19,33 @@ router = APIRouter() -def extraction(path: str) -> str: +def extraction( + path: str, + use_cache: bool = True, + **kwargs, +) -> str: """ Wrapper function to call the extract_document function. This is necessary to ensure that the function can be pickled and run in a separate process. + + Args: + path (str): Path to the file to be processed. + use_cache (bool): Whether to use caching for the extraction. + **kwargs: Extractor-specific configuration overrides. + + Returns: + str: Extracted text from the document. """ - text = extract_document(path) + text = extract_document(path, use_cache=use_cache, **kwargs) return document_normalize(text) if text else "" -def run_safe_text_extraction(path: str, timeout_s: float | None = None) -> str: +def run_safe_text_extraction( + path: str, + timeout_s: float | None = None, + use_cache: bool = True, + **kwargs, +) -> str: """ Runs the text extraction in a separate process to avoid blocking the main thread. This is useful for long-running tasks or when the extraction might hang. @@ -37,6 +54,8 @@ def run_safe_text_extraction(path: str, timeout_s: float | None = None) -> str: path (str): Path to the file to be processed. timeout_s (float | None): Timeout in seconds for the extraction process. If None, waits indefinitely. Defaults to None. + use_cache (bool): Whether to use caching for the extraction. + **kwargs: Extractor-specific configuration overrides. Returns: str: Extracted text from the document. @@ -44,9 +63,8 @@ def run_safe_text_extraction(path: str, timeout_s: float | None = None) -> str: Raises: TimeoutError: If the extraction process exceeds the specified timeout. """ - with concurrent.futures.ProcessPoolExecutor(max_workers=1) as executor: - future = executor.submit(extraction, path) + future = executor.submit(extraction, path, use_cache, **kwargs) try: return future.result(timeout=timeout_s) except concurrent.futures.TimeoutError: @@ -56,7 +74,38 @@ def run_safe_text_extraction(path: str, timeout_s: float | None = None) -> str: @router.post("/document-extract", response_model=Document) -def plain_text_extractor(file: UploadFile) -> Document: +def plain_text_extractor( + file: UploadFile, + use_cache: bool = True, + layout_batch_size: int = 8, + detection_batch_size: int = 8, + table_rec_batch_size: int = 8, + recognition_batch_size: int = 8, + ocr_error_batch_size: int = 8, + force_ocr: bool = False, + strip_existing_ocr: bool = True, + torch_device: str | None = None, + debug: bool | None = None, +) -> Document: + """ + Extract plain text from an uploaded document. + + Args: + file (UploadFile): Incoming document upload. + use_cache (bool): Whether to use caching for the extraction. Defaults to True. + layout_batch_size (int): Batch size for layout model inference. Defaults to 8. + detection_batch_size (int): Batch size for detection model inference. Defaults to 8. + table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. + recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. + ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. + force_ocr (bool): Force OCR even if text is detected. Defaults to False. + strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. + torch_device (str | None): Optional override for the torch device. Defaults to None. + debug (bool | None): Optional override for marker debug mode. Defaults to None. + + Returns: + Document: Extracted and normalized document payload. + """ logger.info(f"receiving => {file.filename}") extension = MIMETYPE_EXTENSION_MAPPER.get(file.content_type) logger.info(f"detected extension: {extension} ({file.content_type})") @@ -74,7 +123,19 @@ def plain_text_extractor(file: UploadFile) -> Document: logger.info(f"saved temp file on local storage => {tmp_filename}") - document = run_safe_text_extraction(tmp_filename) + document = run_safe_text_extraction( + tmp_filename, + use_cache=use_cache, + layout_batch_size=layout_batch_size, + detection_batch_size=detection_batch_size, + table_rec_batch_size=table_rec_batch_size, + recognition_batch_size=recognition_batch_size, + ocr_error_batch_size=ocr_error_batch_size, + force_ocr=force_ocr, + strip_existing_ocr=strip_existing_ocr, + torch_device=torch_device, + debug=debug, + ) except concurrent.futures.TimeoutError: logger.error(f"Timeout while extracting text from {file.filename}") diff --git a/aymurai/api/startup/marker.py b/aymurai/api/startup/marker.py index 208afa43..fa40aa48 100644 --- a/aymurai/api/startup/marker.py +++ b/aymurai/api/startup/marker.py @@ -1,5 +1,9 @@ from aymurai.logger import get_logger -from aymurai.text.extractors.utils import get_marker_pdf_converter_and_md_renderer +from aymurai.text.extractors.utils import ( + _build_marker_pdf_config, + _marker_config_key, + get_marker_pdf_converter_and_md_renderer, +) logger = get_logger(__name__) @@ -7,7 +11,8 @@ def warm_marker_models() -> None: """Download marker-pdf artifacts at startup to avoid first-request latency.""" try: - get_marker_pdf_converter_and_md_renderer() + config = _build_marker_pdf_config() + get_marker_pdf_converter_and_md_renderer(_marker_config_key(config)) logger.info("marker-pdf models are ready") except Exception as exc: logger.warning("marker-pdf warmup failed: %s", exc) diff --git a/aymurai/text/extraction.py b/aymurai/text/extraction.py index 1e2735d2..b57cb531 100644 --- a/aymurai/text/extraction.py +++ b/aymurai/text/extraction.py @@ -1,4 +1,3 @@ -import logging import mimetypes import os import zipfile @@ -83,6 +82,7 @@ def get_extension(path: str) -> str: def extract_document( filename: str | Path, errors: str = "ignore", + use_cache: bool = True, **kwargs, ) -> str | None: """ @@ -96,6 +96,7 @@ def extract_document( and warn. - If :const:`'ignore'`, then invalid parsing will be set as :const:`NaN` but not warn. + use_cache (bool, optional): Toggle extractor-level caching. Defaults to True. **kwargs: keyword arguments for textract. Raises: @@ -127,7 +128,7 @@ def extract_document( extractor = get_extractor(ext) try: - return extractor.extract(Path(filename)) + return extractor.extract(Path(filename), use_cache=use_cache, **kwargs) except InvalidFile as exc: if errors == "raise": raise diff --git a/aymurai/text/extractors/base.py b/aymurai/text/extractors/base.py index 20282b09..1603519d 100644 --- a/aymurai/text/extractors/base.py +++ b/aymurai/text/extractors/base.py @@ -34,12 +34,13 @@ def ensure_file(self, path: Path) -> Path: return path @abstractmethod - def extract(self, path: Path) -> str: + def extract(self, path: Path, **kwargs) -> str: """ Extract normalized text from the source document. Args: path (Path): Input document path. + **kwargs: Optional extractor-specific flags. Returns: str: Cleaned textual content. diff --git a/aymurai/text/extractors/docx.py b/aymurai/text/extractors/docx.py index ae698e20..52824449 100644 --- a/aymurai/text/extractors/docx.py +++ b/aymurai/text/extractors/docx.py @@ -1,4 +1,5 @@ from pathlib import Path +from typing import Any from zipfile import BadZipFile import docx2txt @@ -11,7 +12,7 @@ class DocxExtractor(BaseExtractor): extension = "docx" - def extract(self, path: Path) -> str: + def extract(self, path: Path, **_: Any) -> str: file_path = self.ensure_file(path) try: diff --git a/aymurai/text/extractors/odt.py b/aymurai/text/extractors/odt.py index 7aaf3caa..41a55355 100644 --- a/aymurai/text/extractors/odt.py +++ b/aymurai/text/extractors/odt.py @@ -1,7 +1,7 @@ from pathlib import Path -from zipfile import BadZipFile - +from typing import Any from xml.etree.ElementTree import ParseError +from zipfile import BadZipFile from aymurai.text.extractors.base import BaseExtractor, InvalidFile, register_extractor from aymurai.text.extractors.utils import get_header, normalize_text, odt_to_text @@ -11,7 +11,7 @@ class OdtExtractor(BaseExtractor): extension = "odt" - def extract(self, path: Path) -> str: + def extract(self, path: Path, **_: Any) -> str: file_path = self.ensure_file(path) try: diff --git a/aymurai/text/extractors/pdf.py b/aymurai/text/extractors/pdf.py index 7a7e41b3..c4b273c2 100644 --- a/aymurai/text/extractors/pdf.py +++ b/aymurai/text/extractors/pdf.py @@ -13,24 +13,68 @@ class PdfExtractor(BaseExtractor): extension = "pdf" - def extract(self, path: Path) -> str: + def extract( + self, + path: Path, + *, + use_cache: bool = True, + layout_batch_size: int = 8, + detection_batch_size: int = 8, + table_rec_batch_size: int = 8, + recognition_batch_size: int = 8, + ocr_error_batch_size: int = 8, + force_ocr: bool = False, + strip_existing_ocr: bool = True, + torch_device: str | None = None, + debug: bool | None = None, + ) -> str: + """ + Extract normalized text from a PDF document. + + Args: + path (Path): Input document path. + use_cache (bool): Toggle extractor-level caching. Defaults to True. + layout_batch_size (int): Batch size for layout model inference. Defaults to 8. + detection_batch_size (int): Batch size for detection model inference. Defaults to 8. + table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. + recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. + ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. + force_ocr (bool): Force OCR even if text is detected. Defaults to False. + strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. + torch_device (str | None): Optional override for the torch device. Defaults to None. + debug (bool | None): Optional override for marker debug mode. Defaults to None. + + Returns: + str: Cleaned textual content. + """ file_path = self.ensure_file(path) - # Check cache first - cache_key = self._cache_key(file_path) - if cache_key: + # Check cache first when enabled + cache_key = self._cache_key(file_path) if use_cache else None + if use_cache and cache_key: cached_text = cache_load(cache_key) if cached_text is not None: logger.debug("PDF cache hit for %s", file_path) return cached_text try: - text = pdf_to_text(file_path) + text = pdf_to_text( + file_path, + layout_batch_size=layout_batch_size, + detection_batch_size=detection_batch_size, + table_rec_batch_size=table_rec_batch_size, + recognition_batch_size=recognition_batch_size, + ocr_error_batch_size=ocr_error_batch_size, + force_ocr=force_ocr, + strip_existing_ocr=strip_existing_ocr, + torch_device=torch_device, + debug=debug, + ) except (OSError, ValueError) as exc: raise InvalidFile(str(exc)) from exc except Exception as exc: raise InvalidFile(str(exc)) from exc - if cache_key: + if use_cache and cache_key: cache_save(text, key=cache_key) logger.debug("PDF cache stored for %s", file_path) diff --git a/aymurai/text/extractors/utils.py b/aymurai/text/extractors/utils.py index b7c9520b..6a98ba30 100644 --- a/aymurai/text/extractors/utils.py +++ b/aymurai/text/extractors/utils.py @@ -23,15 +23,7 @@ BLOCK_TAGS = {"h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "blockquote", "pre"} -MARKER_PDF_CONFIG = { - "layout_batch_size": 8, - "detection_batch_size": 8, - "table_rec_batch_size": 8, - "recognition_batch_size": 8, - "ocr_error_batch_size": 8, - "force_ocr": True, - "strip_existing_ocr": True, -} +MarkerPdfConfig = dict[str, int | str | bool] ODT_NS = {"text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0"} @@ -71,37 +63,76 @@ def markdown_to_text(md: str) -> str: return "\n\n".join(filter(None, chunks)) -def _build_marker_pdf_config() -> dict[str, int | str | bool]: +def _build_marker_pdf_config( + layout_batch_size: int = 8, + detection_batch_size: int = 8, + table_rec_batch_size: int = 8, + recognition_batch_size: int = 8, + ocr_error_batch_size: int = 8, + force_ocr: bool = False, + strip_existing_ocr: bool = True, + torch_device: str | None = None, + debug: bool | None = None, +) -> MarkerPdfConfig: """ Build marker configuration factoring in environment overrides. + Args: + layout_batch_size (int): Batch size for layout model inference. Defaults to 8. + detection_batch_size (int): Batch size for detection model inference. Defaults to 8. + table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. + recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. + ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. + force_ocr (bool): Force OCR even if text is detected. Defaults to False. + strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. + torch_device (str | None): Optional override for the torch device. Defaults to None. + debug (bool | None): Optional override for marker debug mode. Defaults to None. + Returns: dict[str, int | str | bool]: Effective configuration for marker-pdf. """ - config = MARKER_PDF_CONFIG.copy() - - torch_device = os.getenv("TORCH_DEVICE") + config: MarkerPdfConfig = { + "layout_batch_size": layout_batch_size, + "detection_batch_size": detection_batch_size, + "table_rec_batch_size": table_rec_batch_size, + "recognition_batch_size": recognition_batch_size, + "ocr_error_batch_size": ocr_error_batch_size, + "force_ocr": force_ocr, + "strip_existing_ocr": strip_existing_ocr, + } + + if torch_device is None: + torch_device = os.getenv("TORCH_DEVICE") if torch_device: config["TORCH_DEVICE"] = torch_device - log_level = os.getenv("LOG_LEVEL", "").lower() - if log_level == "debug": + if debug is None: + log_level = os.getenv("LOG_LEVEL", "").lower() + debug = log_level == "debug" + + if debug: config["debug"] = True return config @cache -def get_marker_pdf_converter_and_md_renderer() -> tuple[PdfConverter, MarkdownRenderer]: +def get_marker_pdf_converter_and_md_renderer( + config_items: tuple[tuple[str, int | str | bool], ...], +) -> tuple[PdfConverter, MarkdownRenderer]: """ Provide cached marker PDF converter and Markdown renderer instances. + Args: + config_items (tuple[tuple[str, int | str | bool], ...]): Sorted config items + to build a stable cache key. + Returns: tuple[PdfConverter, MarkdownRenderer]: Ready-to-use converter and renderer. """ pdf_converter = PdfConverter( artifact_dict=create_model_dict(), - config=_build_marker_pdf_config(), + config=dict(config_items), ) markdown_renderer = MarkdownRenderer( @@ -114,18 +145,58 @@ def get_marker_pdf_converter_and_md_renderer() -> tuple[PdfConverter, MarkdownRe return pdf_converter, markdown_renderer -def pdf_to_text(file_path: Path) -> str: +def _marker_config_key( + config: MarkerPdfConfig, +) -> tuple[tuple[str, int | str | bool], ...]: + return tuple(sorted(config.items())) + + +def pdf_to_text( + file_path: Path, + *, + layout_batch_size: int = 8, + detection_batch_size: int = 8, + table_rec_batch_size: int = 8, + recognition_batch_size: int = 8, + ocr_error_batch_size: int = 8, + force_ocr: bool = False, + strip_existing_ocr: bool = True, + torch_device: str | None = None, + debug: bool | None = None, +) -> str: """ Extract text from a PDF file and return normalized plain text. Args: file_path (Path): Path to the PDF document. + layout_batch_size (int): Batch size for layout model inference. Defaults to 8. + detection_batch_size (int): Batch size for detection model inference. Defaults to 8. + table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. + recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. + ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. + force_ocr (bool): Force OCR even if text is detected. Defaults to False. + strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. + torch_device (str | None): Optional override for the torch device. Defaults to None. + debug (bool | None): Optional override for marker debug mode. Defaults to None. Returns: str: Cleaned textual content extracted from the PDF. """ logger.info("Extracting text from PDF: %s", file_path) - pdf_converter, markdown_renderer = get_marker_pdf_converter_and_md_renderer() + config = _build_marker_pdf_config( + layout_batch_size=layout_batch_size, + detection_batch_size=detection_batch_size, + table_rec_batch_size=table_rec_batch_size, + recognition_batch_size=recognition_batch_size, + ocr_error_batch_size=ocr_error_batch_size, + force_ocr=force_ocr, + strip_existing_ocr=strip_existing_ocr, + torch_device=torch_device, + debug=debug, + ) + pdf_converter, markdown_renderer = get_marker_pdf_converter_and_md_renderer( + _marker_config_key(config) + ) document = pdf_converter.build_document(filepath=file_path.as_posix()) markdown_output = markdown_renderer(document) plain_text = markdown_to_text(markdown_output.markdown) diff --git a/test/text/test_extraction.py b/test/text/test_extraction.py index 5e4dba56..69df8f7e 100644 --- a/test/text/test_extraction.py +++ b/test/text/test_extraction.py @@ -21,7 +21,7 @@ def __init__(self) -> None: self.called = False self.called_path: Path | None = None - def extract(self, path: Path) -> str: + def extract(self, path: Path, **_: object) -> str: self.called = True self.called_path = path return "ok" @@ -48,7 +48,7 @@ def test_extract_document_handles_invalid_file(self): source.write_text("dummy") class BoomExtractor: - def extract(self, _path: Path) -> str: + def extract(self, _path: Path, **_: object) -> str: raise InvalidFile("boom") with patch( @@ -64,7 +64,7 @@ def test_extract_document_raises_unexpected(self): source.write_text("dummy") class BoomExtractor: - def extract(self, _path: Path) -> str: + def extract(self, _path: Path, **_: object) -> str: raise RuntimeError("boom") with patch( diff --git a/test/text/test_extractors.py b/test/text/test_extractors.py index 8beed5ff..37c883d8 100644 --- a/test/text/test_extractors.py +++ b/test/text/test_extractors.py @@ -92,6 +92,42 @@ def test_pdf_extractor_delegates(self): self.assertEqual(result, "PDF text") + def test_pdf_extractor_passes_config(self): + file_path = self.tmp_path / "sample.pdf" + file_path.write_bytes(b"fake pdf") + + with patch( + "aymurai.text.extractors.pdf.pdf_to_text", + return_value="PDF text", + ) as pdf_to_text: + extractor = PdfExtractor() + extractor.extract( + file_path, + use_cache=False, + layout_batch_size=4, + detection_batch_size=5, + table_rec_batch_size=6, + recognition_batch_size=7, + ocr_error_batch_size=8, + force_ocr=False, + strip_existing_ocr=False, + torch_device="cpu", + debug=True, + ) + + pdf_to_text.assert_called_once_with( + file_path, + layout_batch_size=4, + detection_batch_size=5, + table_rec_batch_size=6, + recognition_batch_size=7, + ocr_error_batch_size=8, + force_ocr=False, + strip_existing_ocr=False, + torch_device="cpu", + debug=True, + ) + def test_pdf_extractor_wraps_errors(self): file_path = self.tmp_path / "broken.pdf" file_path.write_bytes(b"") @@ -104,6 +140,25 @@ def test_pdf_extractor_wraps_errors(self): with self.assertRaises(InvalidFile): extractor.extract(file_path) + def test_odt_extractor_ignores_extra_kwargs(self): + file_path = self.tmp_path / "sample.odt" + file_path.write_bytes(b"fake odt content") + + with ( + patch( + "aymurai.text.extractors.odt.odt_to_text", + return_value="Paragraph one", + ), + patch( + "aymurai.text.extractors.odt.get_header", + return_value=[], + ), + ): + extractor = OdtExtractor() + result = extractor.extract(file_path, layout_batch_size=4) + + self.assertIn("Paragraph one", result) + if __name__ == "__main__": unittest.main() diff --git a/uv.lock b/uv.lock index dabb9fdc..be85f765 100644 --- a/uv.lock +++ b/uv.lock @@ -284,7 +284,7 @@ wheels = [ [[package]] name = "aymurai" -version = "2.0.0a5.dev8" +version = "2.0.0a6.dev5" source = { editable = "." } dependencies = [ { name = "alembic" }, From b6829afe64b420a0996f664a35c06f81ae4f82e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Tue, 13 Jan 2026 18:45:39 -0300 Subject: [PATCH 031/104] Feature/pre disambiguation optimization (#70) * New pre-disambigutation feature notebooks * New pre-disambigutation feature notebooks and metrics.py per label feature added * Conclusion added to pre-cluster investigation * utils.py ocr variable True * Changes in grid search function to store the best pre-clusterizated entities in a particular directory * New llm inference function in notebook 07 * New llm grid search inference function * Add disambiguation endpoint and utility functions for entity grouping * Remove unused models and tokenizers to streamline the codebase * Fix type hints for processor functions to avoid runtime errors --- .devcontainer/devcontainer.json | 4 +- .../routers/anonymizer/anonymizer.py | 64 +- .../api/endpoints/routers/anonymizer/utils.py | 212 ++ aymurai/evaluation/metrics.py | 62 +- ...tion-pre-clustered-manual-validation.ipynb | 2447 +++++++++++++++++ .../06-pre-disambiguation-optimization.ipynb | 1619 +++++++++++ .../07-PER-entities-disambiguation.ipynb | 1487 ++++++++++ .../08-disambiguation-endpoint-smoke.ipynb | 185 ++ uv.lock | 1953 +++++++------ 9 files changed, 7028 insertions(+), 1005 deletions(-) create mode 100644 aymurai/api/endpoints/routers/anonymizer/utils.py create mode 100644 notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb create mode 100644 notebooks/experiments/entity-disambiguation/06-pre-disambiguation-optimization.ipynb create mode 100644 notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb create mode 100644 notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5aa72ad5..d5eeaafa 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,9 +4,9 @@ "name": "aymurai", // "initializeCommand": "make core-build", "dockerComposeFile": "docker-compose.yml", - "service": "aymurai-devcontainer-gpu", + "service": "aymurai-devcontainer", "runServices": [ - "aymurai-devcontainer-gpu" + "aymurai-devcontainer" ], "workspaceFolder": "/workspace", "mounts": [ diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 00a562dd..63025082 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -5,12 +5,18 @@ from threading import Lock import torch -from fastapi import Body, Depends, Form, Query, UploadFile +from fastapi import Body, Depends, Form, HTTPException, Query, UploadFile from fastapi.responses import FileResponse from fastapi.routing import APIRouter from sqlmodel import Session from starlette.background import BackgroundTask +from aymurai.api.endpoints.routers.anonymizer.utils import ( + PROCESSOR_MAP, + SCORER_MAP, + build_canonical_entities, + resolve_processor, +) from aymurai.api.utils import load_pipeline from aymurai.database.crud.anonymization.document import anonymization_document_create from aymurai.database.crud.anonymization.paragraph import ( @@ -28,6 +34,7 @@ DocumentInformation, TextRequest, ) +from aymurai.meta.entities import CanonicalEntities from aymurai.settings import settings from aymurai.text.anonymization import DocAnonymizer from aymurai.text.extraction import MIMETYPE_EXTENSION_MAPPER @@ -107,6 +114,61 @@ async def anonymizer_paragraph_predict( return DocumentInformation(document=text, labels=paragraph.prediction) +@router.post("/disambiguate", response_model=CanonicalEntities) +async def anonymizer_disambiguate( + paragraphs: list[DocumentInformation] = Body( + ..., + description=( + "List of per-paragraph predictions returned by /anonymizer/predict." + ), + ), + target_labels: list[str] + | None = Query( + None, + description="Optional label filter, e.g. PER,DNI.", + ), + threshold: int = Query( + 70, + description="Minimum similarity score (0-100) to cluster entities.", + ), + scorer: str = Query( + "token_set_ratio", + description="RapidFuzz scorer name for similarity.", + ), + processor: str = Query( + "light_normalizer", + description="Text processor to normalize before similarity.", + ), +) -> CanonicalEntities: + """ + Prototype endpoint for canonical entity grouping using fuzzy matching. + """ + if threshold < 0 or threshold > 100: + raise HTTPException(status_code=400, detail="threshold must be 0-100.") + + scorer_fn = SCORER_MAP.get(scorer.lower()) + if scorer_fn is None: + raise HTTPException(status_code=400, detail=f"Unsupported scorer: {scorer}") + + if processor.lower() not in PROCESSOR_MAP: + raise HTTPException( + status_code=400, detail=f"Unsupported processor: {processor}" + ) + processor_fn = resolve_processor(processor) + + labels = [label for paragraph in paragraphs for label in (paragraph.labels or [])] + + target_set = {label.strip() for label in target_labels} if target_labels else None + canonical_entities = build_canonical_entities( + labels, + target_labels=target_set, + threshold=threshold, + scorer=scorer_fn, + processor=processor_fn, + ) + return CanonicalEntities(canonical_entities=canonical_entities) + + # MARK: Validate @router.post("/validation", response_model=list[DocLabel] | None) async def anonymizer_get_paragraph_validation( diff --git a/aymurai/api/endpoints/routers/anonymizer/utils.py b/aymurai/api/endpoints/routers/anonymizer/utils.py new file mode 100644 index 00000000..9c25cea2 --- /dev/null +++ b/aymurai/api/endpoints/routers/anonymizer/utils.py @@ -0,0 +1,212 @@ +import re +import unicodedata +from collections import Counter +from typing import Callable, Iterable + +from rapidfuzz import process +from rapidfuzz.fuzz import ( + WRatio, + partial_ratio, + partial_token_set_ratio, + partial_token_sort_ratio, + ratio, + token_set_ratio, + token_sort_ratio, +) + +from aymurai.meta.api_interfaces import DocLabel +from aymurai.meta.entities import CanonicalEntity + +__all__ = [ + "SCORER_MAP", + "PROCESSOR_MAP", + "build_canonical_entities", + "resolve_processor", +] + +SCORER_MAP = { + "ratio": ratio, + "partial_ratio": partial_ratio, + "token_sort_ratio": token_sort_ratio, + "token_set_ratio": token_set_ratio, + "partial_token_set_ratio": partial_token_set_ratio, + "partial_token_sort_ratio": partial_token_sort_ratio, + "wratio": WRatio, +} + +PROCESSOR_MAP = { + "none": None, + "light_normalizer": "light_normalizer", + "hard_normalizer": "hard_normalizer", + "legal_text_normalizer": "legal_text_normalizer", +} + + +def hard_normalizer(text: str) -> str: + if not text: + return "" + + normalized = "".join( + char + for char in unicodedata.normalize("NFD", text) + if unicodedata.category(char) != "Mn" + ) + normalized = re.sub(r"[.,\-]", " ", normalized) + normalized = " ".join(normalized.lower().split()) + return normalized + + +def light_normalizer(text: str) -> str: + return text.lower().strip() if text else "" + + +def legal_text_normalizer(text: str) -> str: + if not text: + return "" + + normalized = "".join( + char + for char in unicodedata.normalize("NFD", text) + if unicodedata.category(char) != "Mn" + ) + normalized = normalized.lower() + + legal_titles = r"\b(dr|dra|sr|sra|expte|nro|no|pcia)\b\.?" + normalized = re.sub(legal_titles, "", normalized) + + stopwords = r"\b(de|del|la|las|el|los|y|en)\b" + normalized = re.sub(stopwords, "", normalized) + normalized = re.sub(r"[^\w\s]", "", normalized) + + return " ".join(normalized.split()) + + +def resolve_processor(name: str) -> Callable[[str], str] | None: + key = name.lower() + mapped = PROCESSOR_MAP.get(key) + if mapped is None: + return None + if mapped == "light_normalizer": + return light_normalizer + if mapped == "hard_normalizer": + return hard_normalizer + if mapped == "legal_text_normalizer": + return legal_text_normalizer + return None + + +def cluster_with_cdist( + *, + items: list[dict[str, str]], + threshold: int, + scorer: Callable[[str, str], float], + processor: Callable[[str], str] | None, +) -> list[list[tuple[str, str, str]]]: + if not items: + return [] + + entities = [item.get("text", "") for item in items] + labels = [item.get("aymurai_label", "UNKNOWN") for item in items] + + if processor: + normed = [processor(entity) for entity in entities] + else: + normed = [str(entity) for entity in entities] + + sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold) + + parent = list(range(len(normed))) + + def find(idx: int) -> int: + if parent[idx] == idx: + return idx + parent[idx] = find(parent[idx]) + return parent[idx] + + def union(left: int, right: int) -> None: + root_left, root_right = find(left), find(right) + if root_left != root_right: + parent[root_right] = root_left + + n = len(normed) + for i in range(n): + for j in range(i + 1, n): + if sim[i][j] >= threshold: + union(i, j) + + clusters_map: dict[int, list[tuple[str, str, str]]] = {} + for idx in range(n): + root = find(idx) + clusters_map.setdefault(root, []).append( + (entities[idx], normed[idx], labels[idx]) + ) + + return list(clusters_map.values()) + + +def parse_item(item: tuple[str, str, str]) -> tuple[str, str, str]: + orig, norm, label = item + return label, orig, norm + + +def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str: + labels = [label for label, _, _ in parsed_items] + return Counter(labels).most_common(1)[0][0] + + +def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str: + return max(parsed_items, key=lambda item: len(item[1]))[1] + + +def clusters_to_canonical_entities( + clusters: list[list[tuple[str, str, str]]], +) -> list[CanonicalEntity]: + canonical_entities = [] + for cluster in clusters: + parsed = [parse_item(item) for item in cluster] + label = pick_cluster_label(parsed) + canonical_text = pick_canonical_text(parsed) + aliases = sorted({orig for _, orig, _ in parsed}) + canonical_entities.append( + CanonicalEntity( + aymurai_label=label, + canonical_text=canonical_text, + aliases=aliases, + attributes={}, + relations=[], + ) + ) + return canonical_entities + + +def build_canonical_entities( + labels: Iterable[DocLabel], + *, + target_labels: set[str] | None = None, + threshold: int, + scorer: Callable[[str, str], float], + processor: Callable[[str], str] | None, +) -> list[CanonicalEntity]: + grouped: dict[str, list[dict[str, str]]] = {} + for label in labels: + attrs = label.attrs + if not attrs or not attrs.aymurai_label: + continue + if target_labels and attrs.aymurai_label not in target_labels: + continue + alias = attrs.aymurai_alt_text or label.text + grouped.setdefault(attrs.aymurai_label, []).append( + {"text": alias, "aymurai_label": attrs.aymurai_label} + ) + + canonical_entities = [] + for items in grouped.values(): + clusters = cluster_with_cdist( + items=items, + threshold=threshold, + scorer=scorer, + processor=processor, + ) + canonical_entities.extend(clusters_to_canonical_entities(clusters)) + + return canonical_entities diff --git a/aymurai/evaluation/metrics.py b/aymurai/evaluation/metrics.py index e9b2058a..bea0a785 100644 --- a/aymurai/evaluation/metrics.py +++ b/aymurai/evaluation/metrics.py @@ -142,9 +142,10 @@ def compute_metrics_components( pred_entities: list[dict[str, Any]], sim_threshold: float = 0.3, normalize: bool = True, + target_label: str = None, ) -> dict[str, float]: """ - Compute each component of the disambiguation metric. + Compute each component of the disambiguation metric by label if provided. The metric includes entity-level F1, macro average alias F1, and accuracy for labels and roles on matched entities. @@ -160,6 +161,14 @@ def compute_metrics_components( Returns: dict[str, float]: Mapping with the keys F1_ent, AliasF1_macro, Acc_label, and Acc_role. """ + # Filter entities by target label if provided + if target_label: + gold_entities = [ + e for e in gold_entities if e.get("aymurai_label") == target_label + ] + pred_entities = [ + e for e in pred_entities if e.get("aymurai_label") == target_label + ] # Handle the trivial case where both sets are empty if not gold_entities and not pred_entities: @@ -268,9 +277,10 @@ def evaluate_disambiguation( w_role: float = 0.05, sim_threshold: float = 0.3, normalize: bool = True, + target_label: str = None, ) -> tuple[float, dict[str, float]]: """ - Evaluate disambiguation predictions against ground truth entities. + Evaluate disambiguation predictions against ground truth entities by label if provided. Args: gold_json (Any): Ground-truth entities as a parsed list or JSON string. @@ -300,7 +310,11 @@ def evaluate_disambiguation( pred_entities = pred_json metrics = compute_metrics_components( - gold_entities, pred_entities, sim_threshold=sim_threshold, normalize=normalize + gold_entities, + pred_entities, + sim_threshold=sim_threshold, + normalize=normalize, + target_label=target_label, ) score = ( @@ -314,41 +328,60 @@ def evaluate_disambiguation( def evaluate_prediction_directories( - test_dir: Path, + gold_dir: Path, preds_dir: Path, *, sim_threshold: float = 0.3, normalize: bool = True, + target_label: str = None, + gold_json_suffix: str = None, + pred_json_suffix: str = None, ) -> tuple[list[tuple[str, float, dict[str, float]]], float]: """ - Evaluate predictions stored on disk against the gold standard set. + Evaluate predictions stored on disk against the gold standard set by label if provided. + It has the feature of comparing files in two directories based on their core names, + ignoring predefined suffixes. Args: - test_dir (Path): Directory containing gold json files. + gold_dir (Path): Directory containing gold json files. preds_dir (Path): Directory containing predicted json files. sim_threshold (float): Minimum alias similarity to consider entities a match. Defaults to 0.3. normalize (bool): If True normalizes aliases before comparison. Defaults to True. + target_label (str, optional): If provided, evaluates only entities with this label. + Defaults to None. + gold_json_suffix (str, optional): Suffix to remove from gold json filenames + when matching with predictions. Defaults to None. + pred_json_suffix (str, optional): Suffix to remove from predicted json filenames + when matching with gold files. Defaults to None. Returns: tuple[list[tuple[str, float, dict[str, float]]], float]: Detailed results per document and the average score across all evaluated documents. """ - test_dir = Path(test_dir) + gold_dir = Path(gold_dir) preds_dir = Path(preds_dir) results = [] - for test_path in sorted(test_dir.glob("*.json")): - doc_id = test_id_from_filename(test_path) - pred_path = preds_dir / prediction_filename_for_test(test_path) + pred_map = {} + for p in preds_dir.glob("*.json"): + core_name = p.stem.replace(pred_json_suffix, "") + pred_map[core_name] = p - if not pred_path.exists(): - logger.warning(f"Prediction for {test_path.name} was not found; skipping.") + for gold_path in sorted(gold_dir.glob("*.json")): + core_id = gold_path.stem.replace(gold_json_suffix, "") + pred_path = pred_map.get(core_id) + + if not pred_path or not pred_path.exists(): + logger.warning( + f"Skipping: No prediction found for '{core_id}'. " + f"Expected something like '{core_id}{pred_json_suffix}.json'" + ) continue - gold_data = load_json(test_path) + gold_data = load_json(gold_path) pred_data = load_json(pred_path) score, metrics = evaluate_disambiguation( @@ -356,8 +389,9 @@ def evaluate_prediction_directories( pred_data, sim_threshold=sim_threshold, normalize=normalize, + target_label=target_label, ) - results.append((doc_id, score, metrics)) + results.append((core_id, score, metrics)) average_score = ( sum(score for _, score, _ in results) / len(results) diff --git a/notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb b/notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb new file mode 100644 index 00000000..f34b64d0 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb @@ -0,0 +1,2447 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "c8fc128c", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8eeefe8b", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import mimetypes\n", + "import os\n", + "import re\n", + "import time\n", + "import unicodedata\n", + "from collections import Counter\n", + "from operator import itemgetter\n", + "from pathlib import Path\n", + "from typing import Iterable\n", + "\n", + "import requests\n", + "from tqdm import tqdm\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import requests\n", + "from more_itertools import flatten, unique_everseen\n", + "from rapidfuzz import fuzz, process\n", + "\n", + "from aymurai.llm_providers import OllamaLLMProvider\n", + "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", + "from aymurai.utils.json_data import get_pretty, save_json, load_json" + ] + }, + { + "cell_type": "markdown", + "id": "84d11bba", + "metadata": {}, + "source": [ + "## /document-extract endpoint output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e0ec450", + "metadata": {}, + "outputs": [], + "source": [ + "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://127.0.0.1:8000\")\n", + "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", + "DATA_ROOT = Path(\n", + " os.getenv(\"DOCUMENT_DATA_ROOT\", \"../../../resources/data/restricted/disambiguation-eval/files\")\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef352767", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "print(f\"Discovered {len(documents)} documents.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21fd6e36", + "metadata": {}, + "outputs": [], + "source": [ + "def call_extraction_api(\n", + " session: requests.Session, file_path: Path\n", + ") -> dict[str, object]:\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " ENDPOINT,\n", + " files=files,\n", + " timeout=REQUEST_TIMEOUT_S,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload" + ] + }, + { + "cell_type": "markdown", + "id": "9254ef68", + "metadata": {}, + "source": [ + "## Inference" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a308cf90", + "metadata": {}, + "outputs": [], + "source": [ + "# Function to make inference using the API\n", + "def get_predictions(sample: str) -> dict:\n", + " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample})\n", + " response.raise_for_status()\n", + " return response.json()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ef6a0fa", + "metadata": {}, + "outputs": [], + "source": [ + "from itertools import chain\n", + "from operator import itemgetter\n", + "from typing import Any\n", + "\n", + "from more_itertools import unique_everseen\n", + "\n", + "\n", + "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", + " \"\"\"\n", + " Parse prediction labels to extract unique aymurai_label and aymurai_alt_text pairs.\n", + "\n", + " Args:\n", + " predictions (list[dict[str, Any]]): A list of prediction dictionaries.\n", + "\n", + " Returns:\n", + " list[dict[str, str]]: A list of dictionaries containing unique aymurai_label and aymurai_alt_text pairs.\n", + " \"\"\"\n", + " attrs_stream = (\n", + " label.get(\"attrs\") or {}\n", + " for label in chain.from_iterable(pred.get(\"labels\", ()) for pred in predictions)\n", + " )\n", + "\n", + " unique_pairs = unique_everseen(\n", + " (\n", + " attrs.get(\"aymurai_label\"),\n", + " attrs.get(\"aymurai_alt_text\"),\n", + " )\n", + " for attrs in attrs_stream\n", + " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", + " )\n", + "\n", + " return sorted(\n", + " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", + " key=itemgetter(\"aymurai_label\", \"text\"),\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "52d6b14d", + "metadata": {}, + "source": [ + "# 8241_90_17_10_2025_128 CAUSA 14663_2020-2" + ] + }, + { + "cell_type": "markdown", + "id": "7e113ea4", + "metadata": {}, + "source": [ + "In this case, I took the .json file that Juli passed me and made a first manual correction of the clustering he did in the [notebook 04 pipeline](04-entity-disambiguation-from-pre-clustered-validations.ipynb).\n", + "\n", + "For this .json, a function needs to be created to ensure that, instead of grouping the files into a single canonical entity, it divides each one into a different canonical entity of the type ***NOMBRE_ARCHIVO***." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa6bbadf", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare target filename\n", + "target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(documents[1]))[0]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "934be599", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare json to review\n", + "json_path = \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + "target_path = json_path + target_filename + \"-canonical-entities.json\"\n", + "canonical_entities_to_review = load_json(target_path)\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities_to_review = [\n", + " CanonicalEntity.model_validate(entity) for entity in canonical_entities_to_review\n", + "]\n", + "canonical_entities_to_review = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities_to_review\n", + "]\n", + "\n", + "canonical_entities_to_review" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b94f9ec8", + "metadata": {}, + "outputs": [], + "source": [ + "from copy import deepcopy\n", + "\n", + "def split_aliases_by_label(items: list[CanonicalEntity], target_label: str) -> list[CanonicalEntity]:\n", + " \"\"\"\n", + " Splits aliases into new CanonicalEntities if the item matches target_label.\n", + " Removes non-matching aliases from the original entity.\n", + " \"\"\"\n", + " processed_items = []\n", + "\n", + " for item in items:\n", + " # pass through items that don't match the target label\n", + " if item['aymurai_label'] != target_label:\n", + " processed_items.append(item)\n", + " continue\n", + "\n", + " # if it matches, we process the aliases\n", + " kept_aliases = []\n", + " new_entities = []\n", + "\n", + " for alias in item['aliases']:\n", + " if alias == item['canonical_text']:\n", + " # Keep this alias in the original item\n", + " kept_aliases.append(alias)\n", + " else:\n", + " # Create a NEW entity for this alias\n", + " new_ce = CanonicalEntity(\n", + " aymurai_label=target_label,\n", + " canonical_text=alias, # The alias becomes the new canonical text\n", + " aliases=[alias], # New entity starts with no aliases\n", + " attributes=deepcopy(item['attributes']),\n", + " relations=deepcopy(item['relations'])\n", + " )\n", + " new_entities.append(new_ce)\n", + "\n", + " # update the original item's aliases\n", + " item['aliases'] = kept_aliases\n", + " \n", + " # add the original item to the result\n", + " processed_items.append(item)\n", + " \n", + " # add the newly created entities to the result\n", + " processed_items.extend(new_entities)\n", + "\n", + " return processed_items" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d86ee5bb", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities_to_review = split_aliases_by_label(canonical_entities_to_review, target_label='NOMBRE_ARCHIVO')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b21bc5f4", + "metadata": {}, + "outputs": [], + "source": [ + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in canonical_entities_to_review\n", + "]\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6b9218a8", + "metadata": {}, + "outputs": [], + "source": [ + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7e362c6", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to load reviewed canonical entities\n", + "reviewed_canonical_entities = load_json(\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", + "]\n", + "\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d138d674", + "metadata": {}, + "outputs": [], + "source": [ + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "973600c7", + "metadata": {}, + "source": [ + "## CanonicalEntity extraction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16a8520a", + "metadata": {}, + "outputs": [], + "source": [ + "# Available models\n", + "model = \"phi4:14b\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "63c6d798", + "metadata": {}, + "outputs": [], + "source": [ + "# Sanity check\n", + "provider = OllamaLLMProvider(model=model)\n", + "provider.generate(\"hola, ¿cómo estás?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e665c5a5", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " stream_prompt = \"hola, ¿cómo estás?\"\n", + " pieces = []\n", + " for event in provider.stream(stream_prompt):\n", + " print(event.text, end=\"\", flush=True)\n", + " pieces.append(event.text)\n", + " print()\n", + " full_text = \"\".join(pieces)\n", + "\n", + "except Exception as exc:\n", + " print(\"La transmisión no está disponible:\", exc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80706810", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt = \"\"\"\n", + "Eres un asistente especializado en anonimización de sentencias judiciales.\n", + "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", + "Una **entidad canónica** es la representación única de una entidad real.\n", + "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", + "\n", + "# Reglas\n", + "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", + "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", + "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", + "- Cada entidad canónica debe incluir:\n", + " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", + " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", + " - `aliases` (todas las menciones textuales relevantes).\n", + " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", + "\n", + "# Notas\n", + "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", + "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + "\n", + "# Ejemplo\n", + "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", + "A: ```json\n", + "[\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Laura Beatriz Gómez\",\n", + " \"aliases\": [\"Laura Beatriz Gómez\"],\n", + " \"attributes\": {\"role\": \"Denunciante\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"42987654\",\n", + " \"aliases\": [\"42.987.654\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DIRECCION\",\n", + " \"canonical_text\": \"calle Falsa 123\",\n", + " \"aliases\": [\"calle Falsa 123\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", + " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", + " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", + " \"attributes\": {\"role\": \"Denunciado\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"27654321\",\n", + " \"aliases\": [\"27.654.321\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"calle Real 789\",\n", + " \"aliases\": [\"calle Real 789\"]\n", + " }\n", + "]\n", + "```\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "055fa7a6", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template = \"\"\"\n", + "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", + "\n", + "# Documento\n", + "{document_text}\n", + "\n", + "# Menciones de entidades canónicas agrupadas\n", + "{canonical_entities}\n", + "\n", + "# Instrucciones\n", + "1. Evalúa cada entidad canónica listada, poniendo especial atención en las aliases.\n", + "2. Si alguna alias no corresponde a esa entidad, elimínala de la lista de aliases y créala como una nueva entidad canónica.\n", + "3. Las diferencias textuales correctas en los aliases pueden ser variantes ortográficas, abreviaciones, iniciales o errores tipográficos.\n", + "4. Diferencias sutiles que permiten desambiguar entidades distintas (por ejemplo, nombres similares de personas diferentes, fechas próximas pero distintas, números de documentos, códigos de identificación o nombres de archivos con pequeñas variaciones, etc.).\n", + "5. Normaliza canonical_text; mantén los aliases tal como aparecen.\n", + "6. Identifica roles u otros atributos relevantes en el campo attributes (por ejemplo, {{\"role\": \"Denunciante\"}}).\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9bc94b25", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "session = requests.Session()\n", + "document = call_extraction_api(session, Path(documents[1]))\n", + "document = document.get(\"detail\", {}).get(\"document\")\n", + "\n", + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d53eae0", + "metadata": {}, + "outputs": [], + "source": [ + "# Get paragraphs with at least one NER predicted label\n", + "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + "pred_paragraphs = [paragraph['document'] for paragraph in ner_predictions if paragraph['labels']]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2b8a84d", + "metadata": {}, + "outputs": [], + "source": [ + "# Remove empty 'entity_id', 'relations' and 'attributes' fields\n", + "canonical_entities = [\n", + " {\n", + " k: v\n", + " for k, v in ce.items()\n", + " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", + " }\n", + " for ce in canonical_entities\n", + "]\n", + "\n", + "# Prepare user prompt\n", + "user_prompt = user_prompt_template.format(\n", + " document_text=\"\\n\".join(pred_paragraphs).strip(),\n", + " canonical_entities=get_pretty(canonical_entities),\n", + ")\n", + "\n", + "print(user_prompt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "04e638df", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " stream_prompt = messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ]\n", + " pieces = []\n", + " for event in provider.stream(\n", + " messages=stream_prompt,\n", + " options={\"temperature\": 0, \"num_ctx\": 9_500},\n", + " format=CanonicalEntities.model_json_schema(),\n", + " ):\n", + " print(event.text, end=\"\", flush=True)\n", + " pieces.append(event.text)\n", + " print()\n", + " full_text = \"\".join(pieces)\n", + "\n", + "except Exception as exc:\n", + " print(\"La transmisión no está disponible:\", exc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1377bcfa", + "metadata": {}, + "outputs": [], + "source": [ + "# Get canonical entities from the model\n", + "\n", + "provider = OllamaLLMProvider(model=model)\n", + "response = provider.generate(\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options={\"temperature\": 0, \"num_ctx\": 16_384},\n", + " format=CanonicalEntities.model_json_schema(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2868141f", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = [\n", + " output for output in json.loads(response.text)[\"canonical_entities\"]\n", + " ]\n", + "\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(canonical_entity)\n", + " for canonical_entity in canonical_entities\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0337fe0c", + "metadata": {}, + "outputs": [], + "source": [ + "# Save LLM-predicted canonical entities\n", + "os.makedirs(\"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\", exist_ok=True) \n", + "\n", + "target_path = Path(\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "save_json(\n", + " [\n", + " canonical_entity.model_dump()\n", + " | {\"entity_id\": canonical_entity.entity_id.hex}\n", + " for canonical_entity in canonical_entities\n", + " ],\n", + " str(target_path),\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "1ff322aa", + "metadata": {}, + "source": [ + "# 01 - NN x 5C" + ] + }, + { + "cell_type": "markdown", + "id": "924a5fc2", + "metadata": {}, + "source": [ + "# Pipeline NER - Clusterization - Validation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2197430d", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "session = requests.Session()\n", + "document = call_extraction_api(session, Path(documents[0]))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0e8b1e99", + "metadata": {}, + "outputs": [], + "source": [ + "document = document.get(\"detail\", {}).get(\"document\")\n", + "\n", + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")\n", + "\n", + "# Get NER predictions\n", + "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", + "ner_output_json = get_pretty(parsed_ner_labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "74407f30", + "metadata": {}, + "outputs": [], + "source": [ + "def normalize(s: str) -> str:\n", + " \"\"\"\n", + " Normalize string for clustering.\n", + "\n", + " Args:\n", + " s (str): input string\n", + "\n", + " Returns:\n", + " str: normalized string\n", + " \"\"\"\n", + " # strip accents, lowercase, collapse spaces\n", + " s = \"\".join(\n", + " c for c in unicodedata.normalize(\"NFD\", s) if unicodedata.category(c) != \"Mn\"\n", + " )\n", + " s = \" \".join(s.lower().split())\n", + " return s\n", + "\n", + "\n", + "def cluster_with_cdist(\n", + " entities: list[str], threshold: int = 90, scorer: callable = fuzz.token_set_ratio\n", + "):\n", + " \"\"\"\n", + " Cluster entities based on similarity using a distance matrix.\n", + "\n", + " Args:\n", + " entities (list[str]): list of entity strings\n", + " threshold (int): similarity threshold for clustering\n", + " scorer (callable): similarity scoring function\n", + "\n", + " Returns:\n", + " list[list[tuple[str, str]]]: clusters of (original, normalized) entity tuples\n", + " \"\"\"\n", + " # matrix of similarities on normalized strings\n", + " # normalize however you like; here just lower + strip\n", + " normed = [\" \".join(e.lower().split()) for e in entities]\n", + " sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold)\n", + " sim = np.array(sim)\n", + "\n", + " # union-find\n", + " parent = list(range(len(normed)))\n", + "\n", + " def find(i):\n", + " while parent[i] != i:\n", + " parent[i] = parent[parent[i]]\n", + " i = parent[i]\n", + " return i\n", + "\n", + " def union(i, j):\n", + " ri, rj = find(i), find(j)\n", + " if ri != rj:\n", + " parent[rj] = ri\n", + "\n", + " # link pairs above threshold (upper triangle only)\n", + " n = len(normed)\n", + " for i in range(n):\n", + " for j in range(i + 1, n):\n", + " if sim[i, j] >= threshold:\n", + " union(i, j)\n", + "\n", + " # collect clusters\n", + " clusters = {}\n", + " for idx in range(n):\n", + " root = find(idx)\n", + " clusters.setdefault(root, []).append((entities[idx], normed[idx]))\n", + " return list(clusters.values())\n", + "\n", + "\n", + "def pick_canonical(cluster: list[tuple[str, str]]) -> str:\n", + " \"\"\"\n", + " Pick canonical text from a cluster.\n", + "\n", + " Args:\n", + " cluster (list[tuple[str, str]]): cluster of (original, normalized) entity tuples\n", + "\n", + " Returns:\n", + " str: chosen canonical text\n", + " \"\"\"\n", + " # prefer longest original; fall back to first\n", + " return max(cluster, key=lambda x: len(x[0]))[0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6a355dc9", + "metadata": {}, + "outputs": [], + "source": [ + "# Cluster entities\n", + "clusters = cluster_with_cdist(\n", + " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", + " threshold=95,\n", + ")\n", + "\n", + "for cluster in clusters:\n", + " canonical = pick_canonical(cluster)\n", + " originals = [c[0] for c in cluster]\n", + " print(f\"Canonical: {canonical} -> {originals}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a1f5b54c", + "metadata": {}, + "outputs": [], + "source": [ + "def parse_item(item: tuple[str, ...]) -> tuple[str, str, str]:\n", + " \"\"\"\n", + " Parse an item into (label, orig, norm).\n", + "\n", + " Accepts:\n", + " - (orig, norm, label)\n", + " - (labelled_orig, labelled_norm) with prefix 'LABEL:'\n", + " Args:\n", + " item (tuple[str, ...]): input item\n", + "\n", + " Returns:\n", + " tuple[str, str, str]: (label, orig, norm)\n", + " \"\"\"\n", + " if len(item) == 3:\n", + " orig, norm, label = item\n", + " return label, orig, norm\n", + "\n", + " # len == 2: assume \"LABEL:text\"\n", + " labelled_orig, labelled_norm = item\n", + " label, orig = labelled_orig.split(\":\", 1)\n", + " _, norm = labelled_norm.split(\":\", 1)\n", + " return label, orig, norm\n", + "\n", + "\n", + "def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Pick the most common label from parsed items.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen label\n", + " \"\"\"\n", + " labels = [lbl for lbl, _, _ in parsed_items]\n", + " # majority vote; fallback to first\n", + " return Counter(labels).most_common(1)[0][0]\n", + "\n", + "\n", + "def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Choose the longest original surface form; tweak as needed.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen canonical text\n", + " \"\"\"\n", + " return max(parsed_items, key=lambda x: len(x[1]))[1]\n", + "\n", + "\n", + "def clusters_to_canonical_entities(\n", + " clusters: list[list[tuple[str, str]]],\n", + ") -> list[CanonicalEntity]:\n", + " \"\"\"\n", + " Convert clusters to CanonicalEntity objects.\n", + "\n", + " Args:\n", + " clusters (list[list[tuple[str, str]]]): clusters of (original, normalized) entity tuples\n", + "\n", + " Returns:\n", + " list[CanonicalEntity]: list of CanonicalEntity objects\n", + " \"\"\"\n", + " canonical_entities = []\n", + "\n", + " for cluster in clusters:\n", + " parsed = [parse_item(item) for item in cluster] # [(label, orig, norm), ...]\n", + " label = pick_cluster_label(parsed)\n", + " canonical_text = pick_canonical_text(parsed)\n", + " aliases = sorted({orig for _, orig, _ in parsed})\n", + " ce = CanonicalEntity(\n", + " aymurai_label=label,\n", + " canonical_text=canonical_text,\n", + " aliases=aliases,\n", + " attributes={},\n", + " relations=[],\n", + " )\n", + " canonical_entities.append(ce)\n", + "\n", + " return canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "758cf776", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = clusters_to_canonical_entities(clusters)\n", + "\n", + "# Sort by label and canonical text\n", + "canonical_entities = sorted(\n", + " canonical_entities,\n", + " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", + ")\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ba35eb5", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare target filename\n", + "target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(documents[0]))[0]\n", + ")\n", + "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19f0af6f", + "metadata": {}, + "outputs": [], + "source": [ + "target_filename" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bab1a112", + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "# Save canonical entities to JSON in to-review folder to save the raw output\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save canonical entities to JSON in reviewing folder to make te review manually\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8cc94d9c", + "metadata": {}, + "source": [ + "Make a pause and review the json manually for those wrong outputs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17c09855", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to load reviewed canonical entities\n", + "reviewed_canonical_entities = load_json(\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", + "]\n", + "\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "64ac9530", + "metadata": {}, + "outputs": [], + "source": [ + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "40a2dced", + "metadata": {}, + "source": [ + "## CanonicalEntity extraction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e1e15dce", + "metadata": {}, + "outputs": [], + "source": [ + "# Available models\n", + "model = \"phi4:14b\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "edba631d", + "metadata": {}, + "outputs": [], + "source": [ + "# Sanity check\n", + "provider = OllamaLLMProvider(model=model)\n", + "provider.generate(\"hola, ¿cómo estás?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cdb2d734", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt = \"\"\"\n", + "Eres un asistente especializado en anonimización de sentencias judiciales.\n", + "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", + "Una **entidad canónica** es la representación única de una entidad real.\n", + "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", + "\n", + "# Reglas\n", + "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", + "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", + "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", + "- Cada entidad canónica debe incluir:\n", + " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", + " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", + " - `aliases` (todas las menciones textuales relevantes).\n", + " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", + "\n", + "# Notas\n", + "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", + "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + "\n", + "# Ejemplo\n", + "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", + "A: ```json\n", + "[\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Laura Beatriz Gómez\",\n", + " \"aliases\": [\"Laura Beatriz Gómez\"],\n", + " \"attributes\": {\"role\": \"Denunciante\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"42987654\",\n", + " \"aliases\": [\"42.987.654\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DIRECCION\",\n", + " \"canonical_text\": \"calle Falsa 123\",\n", + " \"aliases\": [\"calle Falsa 123\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", + " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", + " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", + " \"attributes\": {\"role\": \"Denunciado\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"27654321\",\n", + " \"aliases\": [\"27.654.321\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"calle Real 789\",\n", + " \"aliases\": [\"calle Real 789\"]\n", + " }\n", + "]\n", + "```\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bedf1a83", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template = \"\"\"\n", + "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", + "\n", + "# Documento\n", + "{document_text}\n", + "\n", + "# Menciones de entidades canónicas agrupadas\n", + "{canonical_entities}\n", + "\n", + "# Instrucciones\n", + "1. Evalúa cada entidad canónica listada, poniendo especial atención en las aliases.\n", + "2. Si alguna alias no corresponde a esa entidad, elimínala de la lista de aliases y créala como una nueva entidad canónica.\n", + "3. Las diferencias textuales correctas en los aliases pueden ser variantes ortográficas, abreviaciones, iniciales o errores tipográficos.\n", + "4. Diferencias sutiles que permiten desambiguar entidades distintas (por ejemplo, nombres similares de personas diferentes, fechas próximas pero distintas, números de documentos, códigos de identificación o nombres de archivos con pequeñas variaciones, etc.).\n", + "5. Normaliza canonical_text; mantén los aliases tal como aparecen.\n", + "6. Identifica roles u otros atributos relevantes en el campo attributes (por ejemplo, {{\"role\": \"Denunciante\"}}).\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be7ced82", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "session = requests.Session()\n", + "document = call_extraction_api(session, Path(documents[0]))\n", + "document = document.get(\"detail\", {}).get(\"document\")\n", + "\n", + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc9607a8", + "metadata": {}, + "outputs": [], + "source": [ + "# Get paragraphs with at least one NER predicted label\n", + "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + "pred_paragraphs = [paragraph['document'] for paragraph in ner_predictions if paragraph['labels']]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42a89610", + "metadata": {}, + "outputs": [], + "source": [ + "# Remove empty 'entity_id', 'relations' and 'attributes' fields\n", + "canonical_entities = [\n", + " {\n", + " k: v\n", + " for k, v in ce.items()\n", + " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", + " }\n", + " for ce in canonical_entities\n", + "]\n", + "\n", + "# Prepare user prompt\n", + "user_prompt = user_prompt_template.format(\n", + " document_text=\"\\n\".join(document).strip(),\n", + " canonical_entities=get_pretty(canonical_entities),\n", + ")\n", + "\n", + "print(user_prompt)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6d3e2bc9", + "metadata": {}, + "outputs": [], + "source": [ + "# Get canonical entities from the model\n", + "provider = OllamaLLMProvider(model=model)\n", + "response = provider.generate(\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options={\"temperature\": 0, \"num_ctx\": 9_500},\n", + " format=CanonicalEntities.model_json_schema(),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "172ed8d4", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = [\n", + " output for output in json.loads(response.text)[\"canonical_entities\"]\n", + " ]\n", + "\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(canonical_entity)\n", + " for canonical_entity in canonical_entities\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87be578d", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24833143", + "metadata": {}, + "outputs": [], + "source": [ + "# Save LLM-predicted canonical entities\n", + "os.makedirs(\"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\", exist_ok=True) \n", + "\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9e0a7186", + "metadata": {}, + "source": [ + "# 1- FLORES (pdf)" + ] + }, + { + "cell_type": "markdown", + "id": "f758c28c", + "metadata": {}, + "source": [ + "# Pipeline NER - Clusterization - Validation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f59197b", + "metadata": {}, + "outputs": [], + "source": [ + "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/1- FLORES ABARCA, Francisco Alexander s 149 bis J-01-00369422-0-2022-1 Sala Feria (II) nnya vict do apela pp_response_1765835782205.json\"\n", + "\n", + "json_path = Path(json_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0d1e5f7b", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "document = load_json(json_path)[\"document\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb8086f8", + "metadata": {}, + "outputs": [], + "source": [ + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")\n", + "\n", + "# Get NER predictions\n", + "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", + "ner_output_json = get_pretty(parsed_ner_labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "afde9c03", + "metadata": {}, + "outputs": [], + "source": [ + "parsed_ner_labels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bc66c703", + "metadata": {}, + "outputs": [], + "source": [ + "# Cluster entities\n", + "clusters = cluster_with_cdist(\n", + " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", + " threshold=95,\n", + ")\n", + "\n", + "for cluster in clusters:\n", + " canonical = pick_canonical(cluster)\n", + " originals = [c[0] for c in cluster]\n", + " print(f\"Canonical: {canonical} -> {originals}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6d06d5b", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = clusters_to_canonical_entities(clusters)\n", + "\n", + "# Sort by label and canonical text\n", + "canonical_entities = sorted(\n", + " canonical_entities,\n", + " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", + ")\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c62763a", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare target filename\n", + "target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", + ")\n", + "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3317ee7f", + "metadata": {}, + "outputs": [], + "source": [ + "# Save canonical entities to JSON in to-review folder to save the raw output\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save canonical entities to JSON in reviewing folder to make te review manually\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4add5e66", + "metadata": {}, + "source": [ + "Make a pause and review the json manually for those wrong outputs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5b56adf8", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to load reviewed canonical entities\n", + "reviewed_canonical_entities = load_json(\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", + "]\n", + "\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b30019e1", + "metadata": {}, + "outputs": [], + "source": [ + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e5f587ef", + "metadata": {}, + "source": [ + "# 2 - FISSCHER (pdf)" + ] + }, + { + "cell_type": "markdown", + "id": "9d446c92", + "metadata": {}, + "source": [ + "# Pipeline NER - Clusterization - Validation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a45a578b", + "metadata": {}, + "outputs": [], + "source": [ + "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/2 - FISSCHER Alejandro Claudio s - 92_response_1765908855010.json\"\n", + "\n", + "json_path = Path(json_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37fea663", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "document = load_json(json_path)[\"document\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca4de17f", + "metadata": {}, + "outputs": [], + "source": [ + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")\n", + "\n", + "# Get NER predictions\n", + "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", + "ner_output_json = get_pretty(parsed_ner_labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8d8b9c0f", + "metadata": {}, + "outputs": [], + "source": [ + "parsed_ner_labels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa189443", + "metadata": {}, + "outputs": [], + "source": [ + "# Cluster entities\n", + "clusters = cluster_with_cdist(\n", + " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", + " threshold=95,\n", + ")\n", + "\n", + "for cluster in clusters:\n", + " canonical = pick_canonical(cluster)\n", + " originals = [c[0] for c in cluster]\n", + " print(f\"Canonical: {canonical} -> {originals}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d76f9a89", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = clusters_to_canonical_entities(clusters)\n", + "\n", + "# Sort by label and canonical text\n", + "canonical_entities = sorted(\n", + " canonical_entities,\n", + " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", + ")\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9e65d30f", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare target filename\n", + "target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", + ")\n", + "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f42c8398", + "metadata": {}, + "outputs": [], + "source": [ + "# Save canonical entities to JSON in to-review folder to save the raw output\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save canonical entities to JSON in reviewing folder to make te review manually\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2daee78a", + "metadata": {}, + "source": [ + "Make a pause and review the json manually for those wrong outputs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5a1c1c9", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to load reviewed canonical entities\n", + "reviewed_canonical_entities = load_json(\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", + "]\n", + "\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28359165", + "metadata": {}, + "outputs": [], + "source": [ + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "dfc64748", + "metadata": {}, + "source": [ + "# 2 - Feb. 2 (pdf)" + ] + }, + { + "cell_type": "markdown", + "id": "edf32104", + "metadata": {}, + "source": [ + "# Pipeline NER - Clusterization - Validation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bbafb4e9", + "metadata": {}, + "outputs": [], + "source": [ + "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/2 - Feb. 2 - DE ON, Kwan x 13944_response_1765836659235.json\"\n", + "\n", + "json_path = Path(json_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "679a5817", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "document = load_json(json_path)[\"document\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f640f548", + "metadata": {}, + "outputs": [], + "source": [ + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")\n", + "\n", + "# Get NER predictions\n", + "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", + "ner_output_json = get_pretty(parsed_ner_labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ce9cc2c1", + "metadata": {}, + "outputs": [], + "source": [ + "parsed_ner_labels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7a007f3c", + "metadata": {}, + "outputs": [], + "source": [ + "# Cluster entities\n", + "clusters = cluster_with_cdist(\n", + " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", + " threshold=95,\n", + ")\n", + "\n", + "for cluster in clusters:\n", + " canonical = pick_canonical(cluster)\n", + " originals = [c[0] for c in cluster]\n", + " print(f\"Canonical: {canonical} -> {originals}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c5ef7c49", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = clusters_to_canonical_entities(clusters)\n", + "\n", + "# Sort by label and canonical text\n", + "canonical_entities = sorted(\n", + " canonical_entities,\n", + " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", + ")\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b461fdab", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare target filename\n", + "target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", + ")\n", + "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "564fc2a4", + "metadata": {}, + "outputs": [], + "source": [ + "# Save canonical entities to JSON in to-review folder to save the raw output\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save canonical entities to JSON in reviewing folder to make te review manually\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "f8329a42", + "metadata": {}, + "source": [ + "Make a pause and review the json manually for those wrong outputs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ac09ef3", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to load reviewed canonical entities\n", + "reviewed_canonical_entities = load_json(\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", + "]\n", + "\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9006d7ec", + "metadata": {}, + "outputs": [], + "source": [ + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2f7a2ba5", + "metadata": {}, + "source": [ + "# Jul. 18 (pdf)" + ] + }, + { + "cell_type": "markdown", + "id": "83b4b16e", + "metadata": {}, + "source": [ + "# Pipeline NER - Clusterization - Validation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "431ecd13", + "metadata": {}, + "outputs": [], + "source": [ + "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/Jul. 18- SALA IV- IPANAQUE VILLAR Carlos Hector s 5c nnapes_response_1765835513742.json\"\n", + "\n", + "json_path = Path(json_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "692fc5d5", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "document = load_json(json_path)[\"document\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4176067e", + "metadata": {}, + "outputs": [], + "source": [ + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")\n", + "\n", + "# Get NER predictions\n", + "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", + "ner_output_json = get_pretty(parsed_ner_labels)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dbf3644d", + "metadata": {}, + "outputs": [], + "source": [ + "parsed_ner_labels" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cfda586", + "metadata": {}, + "outputs": [], + "source": [ + "# Cluster entities\n", + "clusters = cluster_with_cdist(\n", + " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", + " threshold=95,\n", + ")\n", + "\n", + "for cluster in clusters:\n", + " canonical = pick_canonical(cluster)\n", + " originals = [c[0] for c in cluster]\n", + " print(f\"Canonical: {canonical} -> {originals}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0c6b557", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities = clusters_to_canonical_entities(clusters)\n", + "\n", + "# Sort by label and canonical text\n", + "canonical_entities = sorted(\n", + " canonical_entities,\n", + " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", + ")\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4443d7c9", + "metadata": {}, + "outputs": [], + "source": [ + "# Prepare target filename\n", + "target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", + ")\n", + "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9de334ef", + "metadata": {}, + "outputs": [], + "source": [ + "# Save canonical entities to JSON in to-review folder to save the raw output\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save canonical entities to JSON in reviewing folder to make te review manually\n", + "save_json(\n", + " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "c0bb69fb", + "metadata": {}, + "source": [ + "Make a pause and review the json manually for those wrong outputs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "76b7ddc8", + "metadata": {}, + "outputs": [], + "source": [ + "# Execute this cell to load reviewed canonical entities\n", + "reviewed_canonical_entities = load_json(\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\"\n", + ")\n", + "\n", + "# Convert reviewed entities back to CanonicalEntity objects\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", + "]\n", + "\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f5e15c9", + "metadata": {}, + "outputs": [], + "source": [ + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")\n", + "\n", + "# Save reviewed canonical entities\n", + "save_json(\n", + " canonical_entities,\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", + " + target_filename\n", + " + \"-canonical-entities.json\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "555c7c5f", + "metadata": {}, + "source": [ + "# Start point of the old version of the pipeline" + ] + }, + { + "cell_type": "markdown", + "id": "ccbe21f4", + "metadata": {}, + "source": [ + "## CanonicalEntity extraction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dd025617", + "metadata": {}, + "outputs": [], + "source": [ + "# Available models\n", + "# model = \"gpt-oss:20b\"\n", + "# model = \"llama3\"\n", + "model = \"phi4:14b\"\n", + "# model = \"llama3.1:8b\"\n", + "# model = \"gemma3:270m\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25284997", + "metadata": {}, + "outputs": [], + "source": [ + "# Sanity check\n", + "provider = OllamaLLMProvider(model=model)\n", + "provider.generate(\"hola, ¿cómo estás?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33ca3dd3", + "metadata": {}, + "outputs": [], + "source": [ + "try:\n", + " stream_prompt = \"hola, ¿cómo estás?\"\n", + " pieces = []\n", + " for event in provider.stream(stream_prompt):\n", + " print(event.text, end=\"\", flush=True)\n", + " pieces.append(event.text)\n", + " print()\n", + " full_text = \"\".join(pieces)\n", + "\n", + "except Exception as exc:\n", + " print(\"La transmisión no está disponible:\", exc)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c7ec7c6", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt = \"\"\"\n", + "Eres un asistente especializado en anonimización de sentencias judiciales.\n", + "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", + "Una **entidad canónica** es la representación única de una entidad real.\n", + "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", + "\n", + "# Reglas\n", + "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", + "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", + "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", + "- Cada entidad canónica debe incluir:\n", + " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", + " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", + " - `aliases` (todas las menciones textuales relevantes).\n", + " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", + "\n", + "# Notas\n", + "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", + "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + "\n", + "# Ejemplo\n", + "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", + "A: ```json\n", + "[\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Laura Beatriz Gómez\",\n", + " \"aliases\": [\"Laura Beatriz Gómez\"],\n", + " \"attributes\": {\"role\": \"Denunciante\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"42987654\",\n", + " \"aliases\": [\"42.987.654\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DIRECCION\",\n", + " \"canonical_text\": \"calle Falsa 123\",\n", + " \"aliases\": [\"calle Falsa 123\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", + " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", + " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", + " \"attributes\": {\"role\": \"Denunciado\"}\n", + " },\n", + " {\n", + " \"aymurai_label\": \"DNI\",\n", + " \"canonical_text\": \"27654321\",\n", + " \"aliases\": [\"27.654.321\"]\n", + " },\n", + " {\n", + " \"aymurai_label\": \"LOC\",\n", + " \"canonical_text\": \"calle Real 789\",\n", + " \"aliases\": [\"calle Real 789\"]\n", + " }\n", + "]\n", + "```\n", + "\"\"\"\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6994e3c3", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template = \"\"\"\n", + "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", + "\n", + "# Documento\n", + "{document_text}\n", + "\n", + "# Menciones de entidades detectadas por el NER\n", + "{ner_output_json}\n", + "\n", + "# Instrucciones\n", + "1. Evalúa cada mención listada. Si representa una entidad real, inclúyela en la lista de aliases de alguna entidad canónica.\n", + "2. No omitas entidades válidas, alias con iniciales ni variantes abreviadas.\n", + "3. Solo fusiona menciones cuando exista evidencia clara de que se refieren a la misma entidad.\n", + "4. Normaliza canonical_text; mantén los alias tal como aparecen.\n", + "5. Utiliza attributes para indicar roles (p. ej. {{\"role\": \"Denunciante\"}}) o aclaraciones de desambiguación.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "349fa489", + "metadata": {}, + "outputs": [], + "source": [ + "def extract_canonical_entities(\n", + " doc_path: str, model: str = \"phi4:14b\"\n", + ") -> CanonicalEntities:\n", + " \"\"\"\n", + " Extract canonical entities from a document.\n", + "\n", + " Args:\n", + " doc_path (str): The path to the document.\n", + " model (str, optional): The model to use for extraction. Defaults to \"phi4:14b\".\n", + "\n", + " Raises:\n", + " ValueError: If the document is empty or not found.\n", + " ValueError: If the document summary is empty or not found.\n", + "\n", + " Returns:\n", + " CanonicalEntities: The extracted canonical entities.\n", + " \"\"\"\n", + " # Extract document\n", + " session = requests.Session()\n", + " document = call_extraction_api(session, Path(doc_path))\n", + " document = document.get(\"detail\", {}).get(\"document\")\n", + "\n", + " if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")\n", + "\n", + " # Get NER predictions\n", + " ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", + " parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", + " ner_output_json = get_pretty(parsed_ner_labels)\n", + "\n", + " # Prepare user prompt\n", + " user_prompt = user_prompt_template.format(\n", + " document_text=\"\\n\".join(document).strip(),\n", + " ner_output_json=ner_output_json,\n", + " )\n", + "\n", + " # Get canonical entities from the model\n", + " provider = OllamaLLMProvider(model=model)\n", + " response = provider.generate(\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options={\"temperature\": 0, \"num_ctx\": 12_000},\n", + " format=CanonicalEntities.model_json_schema(),\n", + " )\n", + "\n", + " # Parse canonical entities from response\n", + " canonical_entities = [\n", + " output for output in json.loads(response.text)[\"canonical_entities\"]\n", + " ]\n", + "\n", + " canonical_entities = [\n", + " CanonicalEntity.model_validate(canonical_entity)\n", + " for canonical_entity in canonical_entities\n", + " ]\n", + "\n", + " return canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52c14551", + "metadata": {}, + "outputs": [], + "source": [ + "output_root = Path(DATA_ROOT) / \"preds\"\n", + "output_root.mkdir(parents=True, exist_ok=True)\n", + "\n", + "prompt_version = \"1\"\n", + "\n", + "timestamp = time.strftime(\"%y%m%d_%H%M\")\n", + "base_dir_name = f\"preds-{model}-pv{prompt_version}-{timestamp}\"\n", + "output_dir = output_root / base_dir_name\n", + "\n", + "output_dir.mkdir(parents=True, exist_ok=False)\n", + "print(f\"Saving canonical entities to {output_dir}\")\n", + "\n", + "for doc_path in documents:\n", + " print(f\"Processing document: {doc_path}\")\n", + "\n", + " try:\n", + " canonical_entities = extract_canonical_entities(doc_path, model=model)\n", + " print(f\"Extracted {len(canonical_entities)} canonical entities.\")\n", + "\n", + " target_filename = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", + " )\n", + " target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)\n", + " target_path = output_dir / f\"{target_filename}.json\"\n", + "\n", + " save_json(\n", + " [\n", + " canonical_entity.model_dump()\n", + " | {\"entity_id\": canonical_entity.entity_id.hex}\n", + " for canonical_entity in canonical_entities\n", + " ],\n", + " str(target_path),\n", + " )\n", + "\n", + " except Exception as e:\n", + " print(f\"Error processing document {doc_path}: {e}\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/entity-disambiguation/06-pre-disambiguation-optimization.ipynb b/notebooks/experiments/entity-disambiguation/06-pre-disambiguation-optimization.ipynb new file mode 100644 index 00000000..fa875add --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/06-pre-disambiguation-optimization.ipynb @@ -0,0 +1,1619 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c8f3d033", + "metadata": {}, + "source": [ + "# Entity Resolution & Hyperparameter Optimization\n", + "\n", + "This notebook outlines a systematic process for optimizing our **Entity Disambiguation** pipeline. The goal is to identify the most accurate configuration for grouping person mentions by comparing localized model outputs against their corresponding ground truth data.\n", + "\n", + "## Methodology\n", + "\n", + "### 1. Data Correspondence & Ground Truth\n", + "To ensure data integrity, we have moved away from a single global file approach. The pipeline now maintains a strict 1:1 correspondence between files to prevent entity overlaps across different documents. The evaluation process compares:\n", + "\n", + "* **`gold_json`**: The benchmark \"Gold Standard\" for a specific document.\n", + "* **`input_ner_preds_json`**: The raw NER model predictions for that specific input.\n", + "* **`cluster_json`**: The output generated by our clustering logic for those specific predictions.\n", + "\n", + "### 2. NER Extraction & Processing\n", + "We deploy our **Named Entity Recognition (NER)** model across the source documents. Due to performance constraints on macOS when processing large batches in a single loop, we process documents individually. \n", + "\n", + "This sequential processing allows us to:\n", + "1. Effectively utilize cache memory.\n", + "2. Identify and fix incomplete entities (e.g., missing `entity_id`) before the evaluation phase.\n", + "3. Ensure each `input_ner_preds_json` is correctly mapped to its `gold_json`.\n", + "\n", + "### 3. Clustering via `cluster_with_cdist`\n", + "The core of our pipeline is the `cluster_with_cdist` function, which transforms raw NER predictions into grouped clusters:\n", + "\n", + "* **Similarity Matrix**: Uses `process.cdist` from `rapidfuzz` to calculate an efficient similarity matrix based on a specific `scorer`, `score_cutoff threshold` and `processor`.\n", + "* **Union-Find Algorithm**: Implements **Disjoint Set Union (DSU)** logic to link entities that exceed the similarity threshold.\n", + "* **Canonical Selection**: Through `pick_canonical`, the system selects the most representative string for each group, prioritizing the longest original string.\n", + "\n", + "### 4. Systematic Grid Search & Evaluation\n", + "We execute a **Grid Search** by iterating through clustering hyperparameters (`Scorers`, `Thresholds`, and `Processors`). For each iteration, the resulting `cluster_json` is validated against its correspondent `gold_json`.\n", + "\n", + "#### Evaluation Metric: Weighted Disambiguation Score\n", + "The performance of each hyperparameter combination is measured by a composite score that balances four key dimensions:\n", + "\n", + "* **Entity-level F1**: Measures the overall quality of entity discovery.\n", + "* **Alias Macro F1**: Evaluates how well different name variants (aliases) are grouped.\n", + "* **Label Accuracy**: Ensures the primary name assigned to the cluster is correct.\n", + "* **Role Accuracy**: Validates the secondary attributes (roles) associated with the entity.\n", + "\n", + "#### Winner Selection\n", + "To ensure the robustness of our pipeline, the **winning combination** is determined by calculating the **best average score across all documents**. This cross-document averaging prevents overfitting to a single file and ensures that the selected `scorer`, `threshold` and `processor` perform consistently across the entire corpus.\n", + "\n", + "---\n", + "\n", + "> **Implementation Note:** By analyzing the weighted score across discrete file correspondences, we can determine the optimal configuration while avoiding the data pollution issues found in previous single-file versions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e14b29a", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e0386121", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import mimetypes\n", + "import os\n", + "import re\n", + "import time\n", + "import unicodedata\n", + "from collections import Counter\n", + "from operator import itemgetter\n", + "from pathlib import Path\n", + "from typing import Iterable, Tuple\n", + "\n", + "import requests\n", + "from tqdm import tqdm\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import requests\n", + "from more_itertools import flatten, unique_everseen\n", + "\n", + "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", + "from aymurai.utils.json_data import get_pretty, save_json, load_json\n", + "import aymurai.evaluation.metrics as aymurai_metrics" + ] + }, + { + "cell_type": "markdown", + "id": "d4bd115d", + "metadata": {}, + "source": [ + "# #**1** First Step: Prepare the ***gold_json*** and ***ner_preds_json***" + ] + }, + { + "cell_type": "markdown", + "id": "34a4a0b7", + "metadata": {}, + "source": [ + "## /document-extract endpoint output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b76ddad4", + "metadata": {}, + "outputs": [], + "source": [ + "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://127.0.0.1:8999\")\n", + "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", + "DATA_ROOT = Path(\n", + " os.getenv(\n", + " \"DOCUMENT_DATA_ROOT\", \"../../../resources/data/restricted/disambiguation-eval/files\"\n", + " )\n", + ")\n", + "GOLD_JSON_ROOT = Path(\n", + " os.getenv(\n", + " \"GOLD_JSON_ROOT\",\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted\",\n", + " )\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "JSON_EXTENSION = {\".json\"}\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd44c127", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "print(f\"Discovered {len(documents)} documents.\")\n", + "\n", + "gold_jsons = discover_documents(GOLD_JSON_ROOT, JSON_EXTENSION)\n", + "print(f\"Discovered {len(gold_jsons)} gold JSON files.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efd22ec4", + "metadata": {}, + "outputs": [], + "source": [ + "def call_extraction_api(\n", + " session: requests.Session, file_path: Path\n", + ") -> dict[str, object]:\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " ENDPOINT,\n", + " files=files,\n", + " timeout=REQUEST_TIMEOUT_S,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload" + ] + }, + { + "cell_type": "markdown", + "id": "b0e88e1b", + "metadata": {}, + "source": [ + "## Inference" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11a316a1", + "metadata": {}, + "outputs": [], + "source": [ + "from itertools import chain\n", + "from operator import itemgetter\n", + "from typing import Any\n", + "\n", + "from more_itertools import unique_everseen\n", + "\n", + "\n", + "# Function to make inference using the API\n", + "def get_predictions(sample: str) -> dict:\n", + " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample})\n", + " response.raise_for_status()\n", + " return response.json()\n", + "\n", + "\n", + "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", + " \"\"\"\n", + " Parse prediction labels to extract unique aymurai_label and aymurai_alt_text pairs.\n", + "\n", + " Args:\n", + " predictions (list[dict[str, Any]]): A list of prediction dictionaries.\n", + "\n", + " Returns:\n", + " list[dict[str, str]]: A list of dictionaries containing unique aymurai_label and aymurai_alt_text pairs.\n", + " \"\"\"\n", + " attrs_stream = (\n", + " label.get(\"attrs\") or {}\n", + " for label in chain.from_iterable(pred.get(\"labels\", ()) for pred in predictions)\n", + " )\n", + "\n", + " unique_pairs = unique_everseen(\n", + " (\n", + " attrs.get(\"aymurai_label\"),\n", + " attrs.get(\"aymurai_alt_text\"),\n", + " )\n", + " for attrs in attrs_stream\n", + " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", + " )\n", + "\n", + " return sorted(\n", + " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", + " key=itemgetter(\"aymurai_label\", \"text\"),\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "4a3a97df", + "metadata": {}, + "source": [ + "## ***gold_json*** and ***ner_preds_json*** for input to clusterization developement" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1b3b2a74", + "metadata": {}, + "outputs": [], + "source": [ + "def extract_and_save_entities(\n", + " document_paths: list[Path], output_path: Path, file_ending: str, target_label: str\n", + ") -> None:\n", + " \"\"\"\n", + " Processes a list of documents to extract specific entities and saves\n", + " each result as an individual JSON file.\n", + " It has been optimized to handle both document files and pre-existing JSON files.\n", + " \"\"\"\n", + "\n", + " with requests.Session() as session:\n", + " if \".json\" not in document_paths[0].suffix:\n", + " for doc_path in tqdm(\n", + " document_paths, desc=f\"Extracting {target_label} entities\"\n", + " ):\n", + " doc_path = Path(doc_path)\n", + "\n", + " # 1. API Extraction\n", + " response = call_extraction_api(session, doc_path)\n", + " document_data = response.get(\"detail\", {}).get(\"document\")\n", + "\n", + " if not document_data:\n", + " print(f\"Warning: No document content found for {doc_path.name}\")\n", + " continue\n", + "\n", + " # 2. Processing\n", + " raw_predictions = [\n", + " get_predictions(paragraph) for paragraph in document_data\n", + " ]\n", + " parsed_labels = parse_prediction_labels(raw_predictions)\n", + "\n", + " # 3. Filtering by dynamic label\n", + " filtered_entities = [\n", + " item\n", + " for item in parsed_labels\n", + " if item.get(\"aymurai_label\") == target_label\n", + " ]\n", + "\n", + " # 4. Saving individual file\n", + " clean_base_name = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", + " )\n", + " clean_base_name = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + " clean_name = re.sub(r\"-{2,}\", \"-\", clean_base_name)\n", + " file_name = f\"{clean_name}{file_ending}\"\n", + " save_path = output_path / file_name\n", + "\n", + " save_json(file_path=save_path, json_data=filtered_entities)\n", + " else:\n", + " for doc_path in tqdm(\n", + " document_paths, desc=f\"Extracting {target_label} entities\"\n", + " ):\n", + " doc_path = Path(doc_path)\n", + "\n", + " # 1. Load existing JSON data\n", + " document_data = load_json(doc_path)\n", + "\n", + " if not document_data:\n", + " print(f\"Warning: No document content found for {doc_path.name}\")\n", + " continue\n", + "\n", + " # 2. Filtering by dynamic label\n", + " filtered_entities = [\n", + " item\n", + " for item in document_data\n", + " if item.get(\"aymurai_label\") == target_label\n", + " ]\n", + "\n", + " # 3. Saving individual file\n", + " clean_base_name = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", + " )\n", + " clean_base_name = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + " clean_name = re.sub(r\"-{2,}\", \"-\", clean_base_name)\n", + " file_name = f\"{clean_name}{file_ending}\"\n", + " save_path = output_path / file_name\n", + "\n", + " save_json(file_path=save_path, json_data=filtered_entities)" + ] + }, + { + "cell_type": "markdown", + "id": "48e5096b", + "metadata": {}, + "source": [ + "## ***gold-jsons***" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1e21607", + "metadata": {}, + "outputs": [], + "source": [ + "# We save the gold_json in a directory in /canonical-entities/pre-clusterization\n", + "\n", + "if not (\n", + " DATA_ROOT.parent / \"canonical-entities\" / \"pre-clusterization\" / \"gold-jsons\"\n", + ").exists():\n", + " os.makedirs(\n", + " DATA_ROOT.parent / \"canonical-entities\" / \"pre-clusterization\" / \"gold-jsons\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "9fe4d751", + "metadata": {}, + "source": [ + "#### We identified that some .json files were incomplete due to missing entity_id fields. Consequently, we implemented a function to resolve this issue." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "466b7153", + "metadata": {}, + "outputs": [], + "source": [ + "def correct_entity_id(json_path: str) -> None:\n", + " \"\"\"Correct the entity_id field in the given JSON file to ensure it is a hex string.\"\"\"\n", + "\n", + " # Load existing canonical entities from JSON file\n", + " canonical_entities = load_json(json_path)\n", + "\n", + " # Convert reviewed entities back to CanonicalEntity objects\n", + " canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in canonical_entities\n", + " ]\n", + "\n", + " # Update entity_id to be a hex string\n", + " canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + " ]\n", + "\n", + " save_json(file_path=json_path, json_data=canonical_entities)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49e0a3c1", + "metadata": {}, + "outputs": [], + "source": [ + "data = load_json(gold_jsons[0])\n", + "data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d2896169", + "metadata": {}, + "outputs": [], + "source": [ + "correct_entity_id(gold_jsons[0])" + ] + }, + { + "cell_type": "markdown", + "id": "de9e145e", + "metadata": {}, + "source": [ + "#### Now we are ready to proceed with the ***gold_jsons***" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53242f47", + "metadata": {}, + "outputs": [], + "source": [ + "extract_and_save_entities(\n", + " document_paths=gold_jsons,\n", + " output_path=DATA_ROOT.parent\n", + " / \"canonical-entities\"\n", + " / \"pre-clusterization\"\n", + " / \"gold-jsons\",\n", + " file_ending=\"-gold.json\",\n", + " target_label=\"PER\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "93cf26e0", + "metadata": {}, + "source": [ + "------------------------ START OF DISCARD SECTION ------------------------" + ] + }, + { + "cell_type": "markdown", + "id": "dd7c2dcf", + "metadata": {}, + "source": [ + "### This was the old version to make the ***gold_json***, all of the entities in a single file." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a02881f", + "metadata": {}, + "outputs": [], + "source": [ + "# DISCARD\n", + "def gold_json_labels(label: str, json_paths: list[Path]) -> list[dict[str, str]]:\n", + " g_json = [\n", + " item\n", + " for json_path in json_paths\n", + " for item in load_json(json_path)\n", + " if item.get(\"aymurai_label\") == label\n", + " ]\n", + "\n", + " return g_json" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7ffdc3a", + "metadata": {}, + "outputs": [], + "source": [ + "# DISCARD\n", + "gold_json = gold_json_labels(label=\"PER\", json_paths=gold_jsons)\n", + "\n", + "save_json(\n", + " file_path=DATA_ROOT.parent\n", + " / \"canonical-entities\"\n", + " / \"pre-clusterization\"\n", + " / \"gold.json\",\n", + " json_data=gold_json,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "974128cb", + "metadata": {}, + "source": [ + "------------------------ END OF DISCARD SECTION ------------------------" + ] + }, + { + "cell_type": "markdown", + "id": "5e7933e4", + "metadata": {}, + "source": [ + "## ***ner-preds-jsons***" + ] + }, + { + "cell_type": "markdown", + "id": "58f10ce9", + "metadata": {}, + "source": [ + "#### Due to performance issues on macOS when processing all documents in a single loop, we processed them individually first to ensure they were correctly stored in the cache." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b986a569", + "metadata": {}, + "outputs": [], + "source": [ + "# Extract document\n", + "session = requests.Session()\n", + "document = call_extraction_api(session, Path(documents[17]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21ab3461", + "metadata": {}, + "outputs": [], + "source": [ + "document = document.get(\"detail\", {}).get(\"document\")\n", + "\n", + "if not document:\n", + " raise ValueError(\"Document text is empty or not found.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d4b2b2d5", + "metadata": {}, + "outputs": [], + "source": [ + "document" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef45ca9a", + "metadata": {}, + "outputs": [], + "source": [ + "# We save the gold_json in a directory in /canonical-entities/pre-clusterization\n", + "\n", + "if not (\n", + " DATA_ROOT.parent / \"canonical-entities\" / \"pre-clusterization\" / \"ner-preds-jsons\"\n", + ").exists():\n", + " os.makedirs(\n", + " DATA_ROOT.parent\n", + " / \"canonical-entities\"\n", + " / \"pre-clusterization\"\n", + " / \"ner-preds-jsons\"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "f4c70898", + "metadata": {}, + "source": [ + "#### Now we are ready to proceed with the ***ner_preds_json***" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a3f58d78", + "metadata": {}, + "outputs": [], + "source": [ + "extract_and_save_entities(\n", + " document_paths=documents,\n", + " output_path=DATA_ROOT.parent\n", + " / \"canonical-entities\"\n", + " / \"pre-clusterization\"\n", + " / \"ner-preds-jsons\",\n", + " file_ending=\"-ner-preds.json\",\n", + " target_label=\"PER\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "e55481c4", + "metadata": {}, + "source": [ + "------------------------ START OF DISCARD SECTION ------------------------" + ] + }, + { + "cell_type": "markdown", + "id": "f0e34a8d", + "metadata": {}, + "source": [ + "#### The following cells belong to a previous version where all NER predictions were stored in a single input file. However, we discovered that certain entities appear in multiple files. Therefore, processing them in a single file would lead to incorrect comparisons against the ***gold_json***." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80045084", + "metadata": {}, + "outputs": [], + "source": [ + "# DISCARD\n", + "def get_entities_by_label(document_paths: list[Path], target_label: str) -> list[dict]:\n", + " \"\"\"\n", + " Iterates over a list of documents, extracts entities via API,\n", + " and returns a list of items matching the specified label.\n", + " \"\"\"\n", + " all_ner_preds = []\n", + "\n", + " # Using a session to reuse the connection for better performance\n", + " with requests.Session() as session:\n", + " for doc_path in tqdm(document_paths, desc=\"Processing documents\"):\n", + " # API Extraction\n", + " response = call_extraction_api(session, Path(doc_path))\n", + " document_data = response.get(\"detail\", {}).get(\"document\")\n", + "\n", + " if not document_data:\n", + " print(f\"Warning: No document content found for {doc_path}\")\n", + " continue\n", + "\n", + " # Get predictions for each paragraph\n", + " raw_predictions = [\n", + " get_predictions(paragraph) for paragraph in document_data\n", + " ]\n", + "\n", + " # Parse and flatten labels\n", + " parsed_labels = parse_prediction_labels(raw_predictions)\n", + "\n", + " # Filter by the selected label and extend the main list\n", + " filtered_entities = [\n", + " item\n", + " for item in parsed_labels\n", + " if item.get(\"aymurai_label\") == target_label\n", + " ]\n", + "\n", + " all_ner_preds.extend(filtered_entities)\n", + "\n", + " return all_ner_preds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7fb69feb", + "metadata": {}, + "outputs": [], + "source": [ + "# DISCARD\n", + "ner_preds_json = get_entities_by_label(document_paths=documents, target_label=\"PER\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8370add6", + "metadata": {}, + "outputs": [], + "source": [ + "# DISCARD\n", + "save_json(\n", + " file_path=DATA_ROOT.parent\n", + " / \"canonical-entities\"\n", + " / \"pre-clusterization\"\n", + " / \"ner_preds.json\",\n", + " json_data=ner_preds_json,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "05e4d66e", + "metadata": {}, + "source": [ + "------------------------ END OF DISCARD SECTION ------------------------" + ] + }, + { + "cell_type": "markdown", + "id": "d86a63e2", + "metadata": {}, + "source": [ + "## ***Evaluation Pipeline: Ground Truth and NER Prediction Pairing***\n", + "\n", + "We define the following function to ensure a correct implementation of the metrics evaluation for the performance of each combination of hyperparameters. The function returns each pair of .json paths for the clusterization and following evaluation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "02d574a8", + "metadata": {}, + "outputs": [], + "source": [ + "def pair_gold_and_preds(\n", + " gold_paths: list[Path], pred_paths: list[Path]\n", + ") -> list[Tuple[Path, Path]]:\n", + " \"\"\"\n", + " Pairs gold standard JSONs with their corresponding NER predictions\n", + " based on the common document prefix.\n", + " \"\"\"\n", + "\n", + " # 1. Helper to extract the core ID of the file. It takes everything before \"-ner-preds\" or \"-canonical-entities-gold\"\n", + " def get_document_id(path: Path) -> str:\n", + " name = path.stem\n", + " # Remove known suffixes to get the base ID\n", + " name = name.replace(\"-ner-preds\", \"\")\n", + " name = name.replace(\"-canonical-entities-gold\", \"\")\n", + " return name\n", + "\n", + " # 2. Create a mapping of {doc_id: pred_path}\n", + " preds_map = {get_document_id(p): p for p in pred_paths}\n", + "\n", + " paired_paths = []\n", + " missing_preds = []\n", + "\n", + " # 3. Iterate through gold files and find their match\n", + " for gold_path in gold_paths:\n", + " doc_id = get_document_id(gold_path)\n", + "\n", + " if doc_id in preds_map:\n", + " paired_paths.append((gold_path, preds_map[doc_id]))\n", + " else:\n", + " missing_preds.append(gold_path.name)\n", + "\n", + " # 4. Validation / Logging\n", + " if missing_preds:\n", + " print(f\"Warning: No predictions found for {len(missing_preds)} gold files.\")\n", + " for missing in missing_preds:\n", + " print(f\" - Missing match for: {missing}\")\n", + "\n", + " print(f\"Successfully paired {len(paired_paths)} documents.\")\n", + "\n", + " return paired_paths" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11af85fa", + "metadata": {}, + "outputs": [], + "source": [ + "PRE_CLUSTERIZATION_ROOT = GOLD_JSON_ROOT.parent / \"pre-clusterization\"\n", + "\n", + "gold_docs = discover_documents(\n", + " root=PRE_CLUSTERIZATION_ROOT / \"gold-jsons\", extensions=JSON_EXTENSION\n", + ")\n", + "pred_docs = discover_documents(\n", + " root=PRE_CLUSTERIZATION_ROOT / \"ner-preds-jsons\", extensions=JSON_EXTENSION\n", + ")\n", + "\n", + "document_pairs = pair_gold_and_preds(gold_docs, pred_docs)" + ] + }, + { + "cell_type": "markdown", + "id": "843b13b7", + "metadata": {}, + "source": [ + "### **Hyperparameter Grid Search & Evaluation Pipeline**\n", + "\n", + "We define a specialized function to orchestrate a **Grid Search** across multiple hyperparameters. The goal is to systematically evaluate the performance of our clustering model by testing every possible combination of **scorers**, **thresholds**, and **text processors**.\n", + "\n", + "#### **Pipeline Architecture**\n", + "\n", + "1. **Directory-Based Organization**:\n", + "For each unique combination of hyperparameters, the function creates a dedicated directory. The folder is named using the parameters (e.g., `scorer-cosine_threshold-0.8_proc-normalized`) to ensure clear traceability.\n", + "2. **Pre-Clustering Execution**:\n", + "Within each iteration, the pipeline processes the previously paired `gold-json` and `ner-preds-json` files. It generates a new `pre-cluster.json` file, preserving the original document's identity in the filename.\n", + "3. **Performance Evaluation**:\n", + "Once the cluster is generated, the function evaluates the results against the corresponding **Gold Standard**. This ensures that the metric reflects the actual accuracy of the current hyperparameter configuration.\n", + "4. **Iterative Metrics Logging**:\n", + "The evaluation results are stored in a centralized JSON file within the specific combination's folder.\n", + "* **Keys:** Represent the evaluated document name.\n", + "* **Values:** Represent the calculated performance metric.\n", + "This file is updated incrementally as the loop progresses through each document pair.\n", + "\n", + "\n", + "5. **Grid Progression**:\n", + "After all document pairs have been processed for a specific set of parameters, the function moves to the next grid cell, repeating the directory creation and evaluation steps until all combinations are exhausted." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f352cddd", + "metadata": {}, + "outputs": [], + "source": [ + "from rapidfuzz import fuzz, process, utils\n", + "from rapidfuzz.process import extractOne\n", + "from rapidfuzz.fuzz import (\n", + " ratio,\n", + " partial_ratio,\n", + " token_sort_ratio,\n", + " token_set_ratio,\n", + " partial_token_set_ratio,\n", + " partial_token_sort_ratio,\n", + " WRatio,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "559ffcac", + "metadata": {}, + "source": [ + "We take the functions defined by Juli in the `04-entity-disambiguation-from-pre-clustered-validations.ipynb` notebook and made one change:\n", + "- In `cluster_with_cdist` we added the text processor variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7b7b481e", + "metadata": {}, + "outputs": [], + "source": [ + "def cluster_with_cdist(\n", + " items: list[dict],\n", + " threshold: int = 90,\n", + " scorer: callable = token_set_ratio,\n", + " processor: callable = None,\n", + "):\n", + " \"\"\"\n", + " Cluster entities and prepare them for CanonicalEntity conversion.\n", + " \"\"\"\n", + " if not items:\n", + " return []\n", + "\n", + " # 1. Extract texts and apply normalization\n", + " # We keep track of the original text, the processed text, and the label\n", + " entities = [item.get(\"text\", \"\") for item in items]\n", + " labels = [item.get(\"aymurai_label\", \"UNKNOWN\") for item in items]\n", + "\n", + " if processor:\n", + " normed = [processor(e) for e in entities]\n", + " else:\n", + " normed = [str(e) for e in entities]\n", + "\n", + " # 2. Similarity Matrix\n", + " sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold)\n", + " sim = np.array(sim)\n", + "\n", + " # 3. Union-Find Logic\n", + " parent = list(range(len(normed)))\n", + "\n", + " def find(i):\n", + " if parent[i] == i:\n", + " return i\n", + " parent[i] = find(parent[i])\n", + " return parent[i]\n", + "\n", + " def union(i, j):\n", + " root_i, root_j = find(i), find(j)\n", + " if root_i != root_j:\n", + " parent[root_j] = root_i\n", + "\n", + " n = len(normed)\n", + " for i in range(n):\n", + " for j in range(i + 1, n):\n", + " if sim[i, j] >= threshold:\n", + " union(i, j)\n", + "\n", + " # 4. Group into the format parse_item expects: (orig, norm, label)\n", + " clusters_map = {}\n", + " for idx in range(n):\n", + " root = find(idx)\n", + " if root not in clusters_map:\n", + " clusters_map[root] = []\n", + " # This tuple matches your 'parse_item' len == 3 condition\n", + " clusters_map[root].append((entities[idx], normed[idx], labels[idx]))\n", + "\n", + " return list(clusters_map.values())\n", + "\n", + "\n", + "def parse_item(item: tuple[str, ...]) -> tuple[str, str, str]:\n", + " \"\"\"\n", + " Parse an item into (label, orig, norm).\n", + "\n", + " Accepts:\n", + " - (orig, norm, label)\n", + " - (labelled_orig, labelled_norm) with prefix 'LABEL:'\n", + " Args:\n", + " item (tuple[str, ...]): input item\n", + "\n", + " Returns:\n", + " tuple[str, str, str]: (label, orig, norm)\n", + " \"\"\"\n", + " if len(item) == 3:\n", + " orig, norm, label = item\n", + " return label, orig, norm\n", + "\n", + " # len == 2: assume \"LABEL:text\"\n", + " labelled_orig, labelled_norm = item\n", + " label, orig = labelled_orig.split(\":\", 1)\n", + " _, norm = labelled_norm.split(\":\", 1)\n", + " return label, orig, norm\n", + "\n", + "\n", + "def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Pick the most common label from parsed items.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen label\n", + " \"\"\"\n", + " labels = [lbl for lbl, _, _ in parsed_items]\n", + " # majority vote; fallback to first\n", + " return Counter(labels).most_common(1)[0][0]\n", + "\n", + "\n", + "def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Choose the longest original surface form; tweak as needed.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen canonical text\n", + " \"\"\"\n", + " return max(parsed_items, key=lambda x: len(x[1]))[1]\n", + "\n", + "\n", + "def clusters_to_canonical_entities(\n", + " clusters: list[list[tuple[str, str]]],\n", + ") -> list[CanonicalEntity]:\n", + " \"\"\"\n", + " Convert clusters to CanonicalEntity objects.\n", + "\n", + " Args:\n", + " clusters (list[list[tuple[str, str]]]): clusters of (original, normalized) entity tuples\n", + "\n", + " Returns:\n", + " list[CanonicalEntity]: list of CanonicalEntity objects\n", + " \"\"\"\n", + " canonical_entities = []\n", + "\n", + " for cluster in clusters:\n", + " parsed = [parse_item(item) for item in cluster] # [(label, orig, norm), ...]\n", + " label = pick_cluster_label(parsed)\n", + " canonical_text = pick_canonical_text(parsed)\n", + " aliases = sorted({orig for _, orig, _ in parsed})\n", + " ce = CanonicalEntity(\n", + " aymurai_label=label,\n", + " canonical_text=canonical_text,\n", + " aliases=aliases,\n", + " attributes={},\n", + " relations=[],\n", + " )\n", + " canonical_entities.append(ce)\n", + "\n", + " return canonical_entities" + ] + }, + { + "cell_type": "markdown", + "id": "afc1f54c", + "metadata": {}, + "source": [ + "We defined 2 new functions:\n", + "- `get_name` help us to get the cleaned name of the hyperparameters.\n", + "- `run_evaluation_grid_search` to run the grid search of the best hyperparameters combination.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b3df974d", + "metadata": {}, + "outputs": [], + "source": [ + "import shutil\n", + "\n", + "def get_name(obj):\n", + " \"\"\"Helper to extract a clean string name from a function or object.\"\"\"\n", + " if obj is None:\n", + " return \"None\"\n", + " if hasattr(obj, \"__name__\"):\n", + " return obj.__name__\n", + " # Fallback for complex objects or partials: remove memory addresses\n", + " clean_name = re.sub(r\" at 0x[0-9a-fA-F]+\", \"\", str(obj))\n", + " return clean_name.strip(\"<>\").replace(\"cyfunction \", \"\").replace(\"function \", \"\")\n", + "\n", + "\n", + "def run_evaluation_grid_search(\n", + " scorers: list,\n", + " thresholds: list,\n", + " processors: list,\n", + " document_pairs: list,\n", + " target_label: str,\n", + " base_output_path: Path,\n", + "):\n", + " \"\"\"\n", + " Runs a grid search over hyperparameters using nested loops.\n", + " \"\"\"\n", + "\n", + " # To keep track of all results and find the best\n", + " all_combinations_results = []\n", + "\n", + " for scorer in scorers:\n", + " for threshold in thresholds:\n", + " for processor in processors:\n", + " # 1. Create a descriptive folder name with the cleaned names\n", + " scorer_name = get_name(scorer)\n", + " processor_name = get_name(processor)\n", + " combo_name = (\n", + " f\"scorer-{scorer_name}-threshold-{threshold}-proc-{processor_name}\"\n", + " )\n", + "\n", + " combo_dir = base_output_path / combo_name\n", + " combo_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + " metrics_results = {}\n", + " metrics_file_path = (\n", + " combo_dir / f\"evaluation_metrics_{target_label}.json\"\n", + " )\n", + "\n", + " # List to collect scores for this specific combination\n", + " current_combo_scores = []\n", + "\n", + " # 2. Iterate over document pairs (Gold vs Prediction)\n", + " for gold_path, pred_path in tqdm(\n", + " document_pairs, desc=f\"Testing {combo_name}\"\n", + " ):\n", + " # Extract entities from the JSON, we filter by target label to ensure consistency if the file has multiple labels\n", + " entities = load_json(pred_path)\n", + " filtered_preds = [\n", + " p for p in entities if p[\"aymurai_label\"] == target_label\n", + " ]\n", + "\n", + " # --- Pre-clustering Logic ---\n", + " # Run the clustering using your hyperparameters\n", + " cluster_data = cluster_with_cdist(\n", + " items=filtered_preds,\n", + " threshold=threshold,\n", + " scorer=scorer,\n", + " processor=processor,\n", + " )\n", + "\n", + " # Convert to Canonical Entities\n", + " canonical_entities = clusters_to_canonical_entities(cluster_data)\n", + "\n", + " canonical_entities = [\n", + " CanonicalEntity.model_validate(entity)\n", + " for entity in canonical_entities\n", + " ]\n", + "\n", + " canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + " ]\n", + "\n", + " # Save the result as the pre-cluster.json\n", + " cluster_filename = f\"{pred_path.stem}-pre-cluster.json\"\n", + " cluster_output_path = combo_dir / cluster_filename\n", + "\n", + " save_json(\n", + " file_path=cluster_output_path, json_data=canonical_entities\n", + " )\n", + "\n", + " # --- Metric Evaluation ---\n", + " score, metrics = aymurai_metrics.evaluate_disambiguation(\n", + " gold_json=load_json(gold_path),\n", + " pred_json=load_json(cluster_output_path),\n", + " target_label=target_label,\n", + " )\n", + "\n", + " current_combo_scores.append(score)\n", + " doc_id = pred_path.stem\n", + " metrics_results[doc_id] = {\n", + " \"label\": target_label,\n", + " \"metric_value\": score,\n", + " \"detailed_metrics\": metrics,\n", + " }\n", + "\n", + " # --- Calculate Average for this combination ---\n", + " avg_score = (\n", + " np.mean(current_combo_scores) if current_combo_scores else 0.0\n", + " )\n", + "\n", + " # Add average to the results file for this folder\n", + " final_output = {\n", + " \"average_combination_score\": avg_score,\n", + " \"document_details\": metrics_results,\n", + " }\n", + "\n", + " with open(metrics_file_path, \"w\") as f:\n", + " json.dump(final_output, f, indent=4)\n", + "\n", + " # Store combination info for final ranking\n", + " all_combinations_results.append(\n", + " {\n", + " \"name\": combo_name,\n", + " \"score\": avg_score,\n", + " \"params\": {\n", + " \"scorer\": scorer_name,\n", + " \"threshold\": threshold,\n", + " \"processor\": processor_name,\n", + " },\n", + " }\n", + " )\n", + "\n", + " # Save all combinations results in a summary file\n", + " summary_file_path = (\n", + " base_output_path / f\"results_summary_{target_label}.json\"\n", + " )\n", + " with open(summary_file_path, \"w\") as f:\n", + " json.dump(all_combinations_results, f, indent=4)\n", + "\n", + " # --- Find the best combination ---\n", + " best_combo = max(all_combinations_results, key=lambda x: x[\"score\"])\n", + "\n", + " print(f\"\\nGrid Search for {target_label} completed.\")\n", + "\n", + " # We now copy the best combination folder to a new location with a standardized name\n", + " src = Path(base_output_path) / best_combo[\"name\"]\n", + " # Combine the parent destination path with the new folder name\n", + " new_name = f\"best-pre-clusterization-{target_label.lower()}\"\n", + " dest = Path(base_output_path.parent) / new_name\n", + " \n", + " try:\n", + " # copytree creates the destination directory with the 'new_name'\n", + " shutil.copytree(src, dest)\n", + " print(f\"Successfully copied '{src.name}' to '{dest}'\")\n", + " except FileExistsError:\n", + " print(f\"Error: A folder named '{new_name}' already exists in '{base_output_path.parent}'\")\n", + " except Exception as e:\n", + " print(f\"An error occurred: {e}\") \n", + "\n", + " return best_combo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6369c582", + "metadata": {}, + "outputs": [], + "source": [ + "# We have to install jellyfish for the phonetic processor\n", + "!pip install jellyfish" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f48e9d4c", + "metadata": {}, + "outputs": [], + "source": [ + "def hard_normalizer(s: str) -> str:\n", + " \"\"\"\n", + " Normalize string for clustering: strips accents, removes punctuation (.,-),\n", + " lowercases, and collapses spaces.\n", + "\n", + " Args:\n", + " s (str): input string\n", + " Returns:\n", + " str: normalized string\n", + " \"\"\"\n", + " if not s:\n", + " return \"\"\n", + "\n", + " # Strip accents\n", + " s = \"\".join(\n", + " c for c in unicodedata.normalize(\"NFD\", s) if unicodedata.category(c) != \"Mn\"\n", + " )\n", + "\n", + " # Remove commas, periods, and hyphens\n", + " s = re.sub(r\"[.,\\-]\", \" \", s)\n", + "\n", + " # Lowercase and collapse whitespace\n", + " s = \" \".join(s.lower().split())\n", + "\n", + " return s\n", + "\n", + "def light_normalizer(s: str) -> str:\n", + " return s.lower().strip() if s else \"\"\n", + "\n", + "\n", + "def legal_text_normalizer(s: str) -> str:\n", + " if not s:\n", + " return \"\"\n", + "\n", + " # Standard cleaning (accents/lowercase)\n", + " s = \"\".join(\n", + " c for c in unicodedata.normalize(\"NFD\", s) if unicodedata.category(c) != \"Mn\"\n", + " )\n", + " s = s.lower()\n", + "\n", + " # Remove Legal Titles & Prefixes\n", + " legal_titles = r\"\\b(dr|dra|sr|sra|expte|nro|no|pcia)\\b\\.?\"\n", + " s = re.sub(legal_titles, \"\", s)\n", + "\n", + " # Remove common Spanish stopwords\n", + " stopwords = r\"\\b(de|del|la|las|el|los|y|en)\\b\"\n", + " s = re.sub(stopwords, \"\", s)\n", + "\n", + " # Remove all non-alphanumeric except spaces\n", + " s = re.sub(r\"[^\\w\\s]\", \"\", s)\n", + "\n", + " return \" \".join(s.split())\n", + "\n", + "\n", + "import jellyfish\n", + "\n", + "\n", + "def phonetic_normalizer(s: str) -> str:\n", + " if not s:\n", + " return \"\"\n", + " # Standardize first\n", + " clean = \"\".join(\n", + " c for c in unicodedata.normalize(\"NFD\", s) if unicodedata.category(c) != \"Mn\"\n", + " ).lower()\n", + "\n", + " return jellyfish.nysiis(clean)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f641f4a", + "metadata": {}, + "outputs": [], + "source": [ + "scorers = [\n", + " ratio,\n", + " partial_ratio,\n", + " token_sort_ratio,\n", + " token_set_ratio,\n", + " partial_token_set_ratio,\n", + " partial_token_sort_ratio,\n", + " WRatio,\n", + "]\n", + "\n", + "thresholds = list(range(50, 100, 5))\n", + "\n", + "processors = [\n", + " None,\n", + " hard_normalizer,\n", + " light_normalizer,\n", + " legal_text_normalizer,\n", + " phonetic_normalizer,\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6562159d", + "metadata": {}, + "outputs": [], + "source": [ + "top_result = run_evaluation_grid_search(\n", + " scorers=scorers,\n", + " thresholds=thresholds,\n", + " processors=processors,\n", + " document_pairs=document_pairs,\n", + " target_label=\"PER\",\n", + " base_output_path=PRE_CLUSTERIZATION_ROOT / \"grid-search-results\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a8eecab", + "metadata": {}, + "outputs": [], + "source": [ + "print(\n", + " f\"The best hyperparameter combination is '{top_result['name']}' \"\n", + " f\"with an average score of {top_result['score']:.4f}.\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6aae6a7b", + "metadata": {}, + "outputs": [], + "source": [ + "gold_path = PRE_CLUSTERIZATION_ROOT / \"gold-jsons\"\n", + "\n", + "pred_path = PRE_CLUSTERIZATION_ROOT / \"grid-search-results\" / top_result[\"name\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8cfbd11f", + "metadata": {}, + "outputs": [], + "source": [ + "result_validation_results, result_validation_avg_score = (\n", + " aymurai_metrics.evaluate_prediction_directories(\n", + " gold_dir=gold_path,\n", + " preds_dir=pred_path,\n", + " target_label=\"PER\",\n", + " pred_json_suffix=\"-ner-preds-pre-cluster\",\n", + " gold_json_suffix=\"-canonical-entities-gold\",\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0bc466c9", + "metadata": {}, + "outputs": [], + "source": [ + "result_validation_avg_score" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f484a022", + "metadata": {}, + "outputs": [], + "source": [ + "result_validation_results" + ] + }, + { + "cell_type": "markdown", + "id": "86a21ede", + "metadata": {}, + "source": [ + "Check one of the pre-clusterization in one of the documents because there is only one cluster" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "163ecabc", + "metadata": {}, + "outputs": [], + "source": [ + "json_to_check = load_json(json_file_path=document_pairs[1][1])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9a00fc29", + "metadata": {}, + "outputs": [], + "source": [ + "pre_cluster_json = cluster_with_cdist(\n", + " items=json_to_check,\n", + " threshold=50,\n", + " scorer=partial_token_set_ratio,\n", + " processor=hard_normalizer,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "670abaf8", + "metadata": {}, + "outputs": [], + "source": [ + "# Convert to Canonical Entities\n", + "canonical_entities = clusters_to_canonical_entities(pre_cluster_json)\n", + "\n", + "canonical_entities = [\n", + " CanonicalEntity.model_validate(entity) for entity in canonical_entities\n", + "]\n", + "\n", + "canonical_entities = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in canonical_entities\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8c15e0a2", + "metadata": {}, + "outputs": [], + "source": [ + "canonical_entities" + ] + }, + { + "cell_type": "markdown", + "id": "844f939a", + "metadata": {}, + "source": [ + "We are now analyzing the similarity matrix to identify items connected to multiple neighbors. By leveraging the Union-Find algorithm, we can determine if these local connections form a chain or tree structure that merges all entities into a single global cluster." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2e9a0b46", + "metadata": {}, + "outputs": [], + "source": [ + "processor = light_normalizer\n", + "\n", + "item = load_json(document_pairs[1][1])\n", + "\n", + "entities = [item.get(\"text\", \"\") for item in item]\n", + "labels = [item.get(\"aymurai_label\", \"UNKNOWN\") for item in item]\n", + "\n", + "if processor:\n", + " normed = [processor(e) for e in entities]\n", + "else:\n", + " normed = [str(e) for e in entities]\n", + "\n", + "sim = process.cdist(normed, normed, scorer=partial_token_set_ratio, score_cutoff=50)\n", + "sim = np.array(sim)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "95270c37", + "metadata": {}, + "outputs": [], + "source": [ + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "from matplotlib.colors import ListedColormap\n", + "import numpy as np\n", + "\n", + "# Create a binary version for visualization: 0 if sim <= 0 else 1\n", + "viz_matrix = (sim > 0).astype(int)\n", + "\n", + "# Define the colormap: 0 -> white, 1 -> red\n", + "my_cmap = ListedColormap([\"white\", \"red\"])\n", + "\n", + "mask = np.triu(np.ones_like(sim, dtype=bool))\n", + "\n", + "# Plot the matrix using the binary color logic\n", + "plt.figure(figsize=(6, 6))\n", + "sns.heatmap(\n", + " viz_matrix,\n", + " cmap=my_cmap,\n", + " mask=mask,\n", + " cbar=False,\n", + " linewidths=0.5,\n", + " linecolor=\"lightgray\",\n", + " square=True, # Ensures cells are perfectly square\n", + ")\n", + "\n", + "plt.title(\"Connection Visualization (Red if > 0)\", fontsize=15)\n", + "plt.xlabel(\"Entity Index\")\n", + "plt.ylabel(\"Entity Index\")\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bb8d30cc", + "metadata": {}, + "outputs": [], + "source": [ + "item[24]" + ] + }, + { + "cell_type": "markdown", + "id": "947379d0", + "metadata": {}, + "source": [ + "Based on the similarity matrix, there is a high probability that the algorithm will generate a single \"giant cluster\" due to a phenomenon known as **chaining**.\n", + "\n", + "Observation of the similarity matrix shows that **item [24]** (identified as an **\"L\"**) and **item [0]** are almost entirely highlighted in red. This indicates that these entities maintain a similarity score above the threshold with nearly every other entity in the set.\n", + "* **Union-Find Logic:** Because the pipeline utilizes a **Union-Find (Disjoint Set Union)** algorithm, a single \"bridge\" is sufficient to merge two distinct groups. In this case, item [24] acts as a universal bridge.\n", + "* **Cluster Collapse:** Since item [24] is connected to almost all other nodes, the algorithm will transitively link every entity into a single tree structure, eventually collapsing the entire dataset into one oversized cluster." + ] + }, + { + "cell_type": "markdown", + "id": "d3b5b315", + "metadata": {}, + "source": [ + "## ***CONCLUSION***: Hyperparameter Optimization Results\n", + "\n", + "After a systematic grid search across various scorers, **`token_set_ratio`** was identified as the top-performing configuration. The following analysis breaks down why this method provided the best balance for our entity disambiguation task:\n", + "\n", + "#### 1. Robustness to Context and Alias Matching (The \"Set\" Advantage)\n", + "\n", + "Unlike character-level scorers (like `ratio` or `partial_ratio`), `token_set_ratio` treats strings as unordered collections of words (tokens). \n", + "\n", + "* **Handling Name Aliases:** It is particularly effective at linking different versions of a person's name. For example, it recognizes that **\"Juan Pérez\"** and **\"Juan Alberto Pérez\"** refer to the same entity by identifying the shared tokens (\"Juan\", \"Pérez\") as a subset, yielding a high similarity score despite the additional middle name.\n", + "* **The \"Intersection\" Logic:** This is crucial for our dataset when a name appears as \"Juan Pérez\" in one document and \"Juan Pérez Asesor/a\" in another (where the NER might have accidentally included the role).\n", + "* **Subset Resilience:** It yields a score of 100 if one name is a perfect subset of the other, effectively ignoring \"noise\" words or titles that often appear in raw NER extractions.\n", + "\n", + "#### 2. Superior Performance over `token_sort_ratio`\n", + "\n", + "While `token_sort_ratio` is excellent at handling word reordering (e.g., \"Juan Pérez\" vs. \"Pérez, Juan\"), it is highly sensitive to the length of the string. \n", + "* In scenarios involving **aliases with extra names** (e.g., \"Juan Pérez\" vs. \"Juan Alberto Pérez\") or **titles** (e.g., \"Doctor Juan Pérez\"), `token_sort_ratio` would penalize the score significantly because the total word count differs. \n", + "* **`token_set_ratio`** maintains a high similarity score in these cases by prioritizing the common intersection of words over the total string length.\n", + "\n", + "#### 3. Preventing Over-Clustering (Avoidance of \"Partial\" Aggression)\n", + "\n", + "The grid search revealed that more aggressive scorers, such as `partial_token_set_ratio`, often led to **over-clustering** and data pollution.\n", + "\n", + "* **The Risk of \"Partial\" Logic:** These scorers are too \"patient\" with differences. If they find a small, similar fragment within a much longer, unrelated string, they force a high score. \n", + "* **Chaining Effect:** This was the primary cause of the \"Chaining Effect\" (as seen with **Item [24]**), where a single-letter entity or a common word acts as a universal bridge, transitively merging hundreds of unrelated individuals into a single \"giant cluster.\"\n", + "* **The `token_set_ratio` Balance:** It provides the necessary flexibility to catch legitimate aliases without being so aggressive that it collapses the distinct identities of the entire corpus.\n", + "\n", + "### Final Recommendation\n", + "\n", + "The **`token_set_ratio`** achieved the highest **Weighted Disambiguation Score** because it effectively handles variable-length mentions, middle names, and word-order changes while maintaining a strict enough threshold to avoid the transitive merging of unrelated person entities." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb new file mode 100644 index 00000000..6af18cea --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb @@ -0,0 +1,1487 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "64957296", + "metadata": {}, + "source": [ + "from previous notebook `06-pre-disambiguation-optimization` we found that the best hyperparameters combinations are:\n", + "- scorer: `token_set_ratio`\n", + "- score_cutoff: `70`\n", + "- processor: `light_normalizer`\n", + "\n", + "we now proceed to make the canonical entities disambiguation checked by an LLM and we give the task to the LLM to give a role to each canonical entity when it is related to a person." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb2b1f59", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "607ea227", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import mimetypes\n", + "import os\n", + "import re\n", + "import time\n", + "import unicodedata\n", + "from collections import Counter\n", + "from operator import itemgetter\n", + "from pathlib import Path\n", + "from typing import Iterable, Tuple\n", + "\n", + "import requests\n", + "from tqdm import tqdm\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "import requests\n", + "from more_itertools import flatten, unique_everseen\n", + "\n", + "\n", + "from aymurai.llm_providers import OllamaLLMProvider\n", + "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", + "from aymurai.utils.json_data import get_pretty, save_json, load_json\n", + "import aymurai.evaluation.metrics as aymurai_metrics\n", + "\n", + "from rapidfuzz.fuzz import token_set_ratio\n", + "from rapidfuzz import process" + ] + }, + { + "cell_type": "markdown", + "id": "1003fbb5", + "metadata": {}, + "source": [ + "# #**1** First Step: Prepare the ***gold_json*** and ***ner_preds_json***" + ] + }, + { + "cell_type": "markdown", + "id": "7ec52f24", + "metadata": {}, + "source": [ + "## /document-extract endpoint output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7c3b672", + "metadata": {}, + "outputs": [], + "source": [ + "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://127.0.0.1:8000\")\n", + "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", + "DATA_ROOT = Path(\n", + " os.getenv(\n", + " \"DOCUMENT_DATA_ROOT\", \"../../../resources/data/restricted/disambiguation-eval/files\"\n", + " )\n", + ")\n", + "GOLD_JSON_ROOT = Path(\n", + " os.getenv(\n", + " \"GOLD_JSON_ROOT\",\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted\",\n", + " )\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "JSON_EXTENSION = {\".json\"}\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18a31502", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "print(f\"Discovered {len(documents)} documents.\")\n", + "\n", + "gold_jsons = discover_documents(GOLD_JSON_ROOT, JSON_EXTENSION)\n", + "print(f\"Discovered {len(gold_jsons)} gold JSON files.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65a2d588", + "metadata": {}, + "outputs": [], + "source": [ + "def call_extraction_api(\n", + " session: requests.Session, file_path: Path\n", + ") -> dict[str, object]:\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " ENDPOINT,\n", + " files=files,\n", + " timeout=REQUEST_TIMEOUT_S,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload" + ] + }, + { + "cell_type": "markdown", + "id": "dcaed02f", + "metadata": {}, + "source": [ + "## Inference" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "464e9132", + "metadata": {}, + "outputs": [], + "source": [ + "from itertools import chain\n", + "from operator import itemgetter\n", + "from typing import Any\n", + "\n", + "from more_itertools import unique_everseen\n", + "\n", + "\n", + "# Function to make inference using the API\n", + "def get_predictions(sample: str) -> dict:\n", + " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample})\n", + " response.raise_for_status()\n", + " return response.json()\n", + "\n", + "\n", + "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", + " \"\"\"\n", + " Parse prediction labels to extract unique aymurai_label and aymurai_alt_text pairs.\n", + "\n", + " Args:\n", + " predictions (list[dict[str, Any]]): A list of prediction dictionaries.\n", + "\n", + " Returns:\n", + " list[dict[str, str]]: A list of dictionaries containing unique aymurai_label and aymurai_alt_text pairs.\n", + " \"\"\"\n", + " attrs_stream = (\n", + " label.get(\"attrs\") or {}\n", + " for label in chain.from_iterable(pred.get(\"labels\", ()) for pred in predictions)\n", + " )\n", + "\n", + " unique_pairs = unique_everseen(\n", + " (\n", + " attrs.get(\"aymurai_label\"),\n", + " attrs.get(\"aymurai_alt_text\"),\n", + " )\n", + " for attrs in attrs_stream\n", + " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", + " )\n", + "\n", + " return sorted(\n", + " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", + " key=itemgetter(\"aymurai_label\", \"text\"),\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "b690bfc0", + "metadata": {}, + "source": [ + "## ***gold_json*** and ***ner_preds_json*** for input to clusterization developement" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b37a8ac", + "metadata": {}, + "outputs": [], + "source": [ + "def extract_and_save_entities(\n", + " document_paths: list[Path], output_path: Path, file_ending: str, target_label: str\n", + ") -> None:\n", + " \"\"\"\n", + " Processes a list of documents to extract specific entities and saves\n", + " each result as an individual JSON file.\n", + " It has been optimized to handle both document files and pre-existing JSON files.\n", + " \"\"\"\n", + "\n", + " with requests.Session() as session:\n", + " if \".json\" not in document_paths[0].suffix:\n", + " for doc_path in tqdm(\n", + " document_paths, desc=f\"Extracting {target_label} entities\"\n", + " ):\n", + " doc_path = Path(doc_path)\n", + "\n", + " # 1. API Extraction\n", + " response = call_extraction_api(session, doc_path)\n", + " document_data = response.get(\"detail\", {}).get(\"document\")\n", + "\n", + " if not document_data:\n", + " print(f\"Warning: No document content found for {doc_path.name}\")\n", + " continue\n", + "\n", + " # 2. Processing\n", + " raw_predictions = [\n", + " get_predictions(paragraph) for paragraph in document_data\n", + " ]\n", + " parsed_labels = parse_prediction_labels(raw_predictions)\n", + "\n", + " # 3. Filtering by dynamic label\n", + " filtered_entities = [\n", + " item\n", + " for item in parsed_labels\n", + " if item.get(\"aymurai_label\") == target_label\n", + " ]\n", + "\n", + " # 4. Saving individual file\n", + " clean_base_name = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", + " )\n", + " clean_base_name = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + " clean_name = re.sub(r\"-{2,}\", \"-\", clean_base_name)\n", + " file_name = f\"{clean_name}{file_ending}\"\n", + " save_path = output_path / file_name\n", + "\n", + " save_json(file_path=save_path, json_data=filtered_entities)\n", + " else:\n", + " for doc_path in tqdm(\n", + " document_paths, desc=f\"Extracting {target_label} entities\"\n", + " ):\n", + " doc_path = Path(doc_path)\n", + "\n", + " # 1. Load existing JSON data\n", + " document_data = load_json(doc_path)\n", + "\n", + " if not document_data:\n", + " print(f\"Warning: No document content found for {doc_path.name}\")\n", + " continue\n", + "\n", + " # 2. Filtering by dynamic label\n", + " filtered_entities = [\n", + " item\n", + " for item in document_data\n", + " if item.get(\"aymurai_label\") == target_label\n", + " ]\n", + "\n", + " # 3. Saving individual file\n", + " clean_base_name = re.sub(\n", + " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", + " )\n", + " clean_base_name = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + " clean_name = re.sub(r\"-{2,}\", \"-\", clean_base_name)\n", + " file_name = f\"{clean_name}{file_ending}\"\n", + " save_path = output_path / file_name\n", + "\n", + " save_json(file_path=save_path, json_data=filtered_entities)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4824a9c3", + "metadata": {}, + "outputs": [], + "source": [ + "def cluster_with_cdist(\n", + " items: list[dict],\n", + " threshold: int = 90,\n", + " scorer: callable = token_set_ratio,\n", + " processor: callable = None,\n", + "):\n", + " \"\"\"\n", + " Cluster entities and prepare them for CanonicalEntity conversion.\n", + " \"\"\"\n", + " if not items:\n", + " return []\n", + "\n", + " # 1. Extract texts and apply normalization\n", + " # We keep track of the original text, the processed text, and the label\n", + " entities = [item.get(\"text\", \"\") for item in items]\n", + " labels = [item.get(\"aymurai_label\", \"UNKNOWN\") for item in items]\n", + "\n", + " if processor:\n", + " normed = [processor(e) for e in entities]\n", + " else:\n", + " normed = [str(e) for e in entities]\n", + "\n", + " # 2. Similarity Matrix\n", + " sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold)\n", + " sim = np.array(sim)\n", + "\n", + " # 3. Union-Find Logic\n", + " parent = list(range(len(normed)))\n", + "\n", + " def find(i):\n", + " if parent[i] == i:\n", + " return i\n", + " parent[i] = find(parent[i])\n", + " return parent[i]\n", + "\n", + " def union(i, j):\n", + " root_i, root_j = find(i), find(j)\n", + " if root_i != root_j:\n", + " parent[root_j] = root_i\n", + "\n", + " n = len(normed)\n", + " for i in range(n):\n", + " for j in range(i + 1, n):\n", + " if sim[i, j] >= threshold:\n", + " union(i, j)\n", + "\n", + " # 4. Group into the format parse_item expects: (orig, norm, label)\n", + " clusters_map = {}\n", + " for idx in range(n):\n", + " root = find(idx)\n", + " if root not in clusters_map:\n", + " clusters_map[root] = []\n", + " # This tuple matches your 'parse_item' len == 3 condition\n", + " clusters_map[root].append((entities[idx], normed[idx], labels[idx]))\n", + "\n", + " return list(clusters_map.values())\n", + "\n", + "\n", + "def parse_item(item: tuple[str, ...]) -> tuple[str, str, str]:\n", + " \"\"\"\n", + " Parse an item into (label, orig, norm).\n", + "\n", + " Accepts:\n", + " - (orig, norm, label)\n", + " - (labelled_orig, labelled_norm) with prefix 'LABEL:'\n", + " Args:\n", + " item (tuple[str, ...]): input item\n", + "\n", + " Returns:\n", + " tuple[str, str, str]: (label, orig, norm)\n", + " \"\"\"\n", + " if len(item) == 3:\n", + " orig, norm, label = item\n", + " return label, orig, norm\n", + "\n", + " # len == 2: assume \"LABEL:text\"\n", + " labelled_orig, labelled_norm = item\n", + " label, orig = labelled_orig.split(\":\", 1)\n", + " _, norm = labelled_norm.split(\":\", 1)\n", + " return label, orig, norm\n", + "\n", + "\n", + "def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Pick the most common label from parsed items.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen label\n", + " \"\"\"\n", + " labels = [lbl for lbl, _, _ in parsed_items]\n", + " # majority vote; fallback to first\n", + " return Counter(labels).most_common(1)[0][0]\n", + "\n", + "\n", + "def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str:\n", + " \"\"\"\n", + " Choose the longest original surface form; tweak as needed.\n", + "\n", + " Args:\n", + " parsed_items (list[tuple[str, str, str]]): parsed items\n", + "\n", + " Returns:\n", + " str: chosen canonical text\n", + " \"\"\"\n", + " return max(parsed_items, key=lambda x: len(x[1]))[1]\n", + "\n", + "\n", + "def clusters_to_canonical_entities(\n", + " clusters: list[list[tuple[str, str]]],\n", + ") -> list[CanonicalEntity]:\n", + " \"\"\"\n", + " Convert clusters to CanonicalEntity objects.\n", + "\n", + " Args:\n", + " clusters (list[list[tuple[str, str]]]): clusters of (original, normalized) entity tuples\n", + "\n", + " Returns:\n", + " list[CanonicalEntity]: list of CanonicalEntity objects\n", + " \"\"\"\n", + " canonical_entities = []\n", + "\n", + " for cluster in clusters:\n", + " parsed = [parse_item(item) for item in cluster] # [(label, orig, norm), ...]\n", + " label = pick_cluster_label(parsed)\n", + " canonical_text = pick_canonical_text(parsed)\n", + " aliases = sorted({orig for _, orig, _ in parsed})\n", + " ce = CanonicalEntity(\n", + " aymurai_label=label,\n", + " canonical_text=canonical_text,\n", + " aliases=aliases,\n", + " attributes={},\n", + " relations=[],\n", + " )\n", + " canonical_entities.append(ce)\n", + "\n", + " return canonical_entities\n", + "\n", + "\n", + "def light_normalizer(s: str) -> str:\n", + " return s.lower().strip() if s else \"\"" + ] + }, + { + "cell_type": "markdown", + "id": "f2aa5d15", + "metadata": {}, + "source": [ + "## Canonical Entity extraction" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8220314e", + "metadata": {}, + "outputs": [], + "source": [ + "# Available models\n", + "\n", + "models = [\n", + " \"phi4:14b\",\n", + " \"gpt-oss:20b\",\n", + " \"llama3\",\n", + " \"llama3.1:8b\",\n", + " \"gemma3:270m\",\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82f8d1a2", + "metadata": {}, + "outputs": [], + "source": [ + "# Sanity check\n", + "provider = OllamaLLMProvider(model=models[0])\n", + "provider.generate(\"hola, ¿cómo estás?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f40ef8ed", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_1 = \"\"\"\n", + "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", + "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", + "\n", + "# Material de Trabajo\n", + "Para tu análisis, recibirás:\n", + "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", + "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", + "\n", + "# Tus Tareas\n", + "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", + "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", + "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", + "\n", + "# Reglas de Salida\n", + "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", + "- `canonical_text`: El nombre más completo y formal encontrado.\n", + "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Defensor/a de Cámara\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", + "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", + "\n", + "# Estructura de Respuesta (JSON)\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Alias Principal\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\n", + "# Ejemplo de Input\n", + "Contexto: \"...la declaración del Sr. Juan Carlos Ruiz ante este Juzgado. El imputado Ruiz negó los cargos. Por su parte, la Dra. Elena Sosa, fiscal de la causa, solicitó...\"\n", + "Entidades Candidatas:\n", + "[{\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Juan Carlos Ruiz\",\n", + " \"aliases\": [\n", + " \"Juan Carlos Ruiz\",\n", + " \"Ruiz\"\n", + " ]\n", + "},\n", + "{\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Elena Sosa\",\n", + " \"aliases\": [\n", + " \"Elena Sosa\"\n", + " ]\n", + "}]\n", + "\n", + "# Ejemplo de Output\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Juan Carlos Ruiz\",\n", + " \"aliases\": [\n", + " \"Juan Carlos Ruiz\",\n", + " \"Ruiz\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Imputado\"\n", + " }\n", + " },\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Elena Sosa\",\n", + " \"aliases\": [\n", + " \"Elena Sosa\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Fiscal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40c5f5ae", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_2 = \"\"\"\n", + "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", + "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", + "\n", + "# Material de Trabajo\n", + "Para tu análisis, recibirás:\n", + "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", + "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", + "\n", + "# Tus Tareas\n", + "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", + "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", + "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", + "\n", + "# Reglas de Salida\n", + "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", + "- `canonical_text`: El nombre más completo y formal encontrado.\n", + "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Defensor/a de Cámara\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", + "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", + "\n", + "# Estructura de Respuesta (JSON)\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Alias Principal\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3f2848b", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template_1 = \"\"\"\n", + "A continuación se proporcionan fragmentos relevantes de un documento judicial y una lista de entidades (personas) pre-clusterizadas por similitud de texto.\n", + "\n", + "# Contexto de la causa, párrafos con alguna mención a las personas:\n", + "{document_text}\n", + "\n", + "# Entidades Pre-clusterizadas a validar:\n", + "{canonical_entities}\n", + "\n", + "# Instrucciones:\n", + "1. **Validación de Aliases:** Analiza si los aliases dentro de cada entidad canónica pertenecen realmente a la misma persona según los párrafos de contexto. \n", + " - Si un alias pertenece a una persona distinta (ej. un familiar con nombre similar), sepáralo en una nueva entidad.\n", + " - Si dos grupos de entidades canónicas refieren a la misma persona, fusiónalos.\n", + "2. **Identificación de Roles:** Extrae el rol procesal de cada persona basándote en el contexto (ej: Juez/a, Fiscal, Denunciante, Imputado/a, Víctima, Abogado/a, Perito/a, Testigo).\n", + "3. **Normalización:** Define el `canonical_text` como el nombre más completo y formal que aparezca en los aliases, si este trabajo ya está bien hecho no lo modifiques.\n", + "4. **Formato:** Devuelve la lista final de entidades en el formato JSON solicitado en el system prompt, asegurándote de no omitir a nadie que sea relevante.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d9365ca", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_3 = \"\"\"\n", + "Eres un asistente experto en desambiguación de entidades judiciales.\n", + "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", + "\n", + "### Tu Tarea:\n", + "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", + "2. **Limpiar Aliases:** Elimina prefijos (Dr., Sra., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", + "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", + "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + " - **Nota:** No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica rol, usa `null`.\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve exclusivamente un array de objetos:\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Alias Principal\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f7bf0f7", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_4 = \"\"\"\n", + "Eres un asistente experto en desambiguación de entidades judiciales.\n", + "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", + "\n", + "### Tu Tarea:\n", + "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", + "2. **Limpiar Aliases:** Elimina prefijos (Dr., Dra., Dres., Sra., Sr., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", + "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", + "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + " \n", + " **Instrucciones críticas de rol:**\n", + " - Si una persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y el contexto no indica que es Juez, Fiscal o Defensor oficial, asígnale el rol de **\"Abogado/a\"**.\n", + " - No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica un rol de la lista, usa `null`.\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve exclusivamente un array de objetos:\n", + "[\n", + " {\n", + " \"canonical_text\": \"Nombre Completo Normalizado\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9bed0ca", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_5 = \"\"\"\n", + "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", + "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", + "4. **Limpiar:** En `canonical_text` y `aliases`, elimina otras palabras que no sean nombres propios.\n", + "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ac77829", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_6 = \"\"\"\n", + "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", + "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", + "4. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", + "5. No modifiques los `canonical_text` ni los `aliases` originales.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26f1b81b", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_7 = \"\"\"\n", + "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", + "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", + "4. **Manejo de Siglas e Iniciales:** Ten en cuenta que las personas pueden ser mencionadas por sus iniciales (ej: \"M.L.\" para \"Martín López\"). Si el contexto permite confirmar que unas iniciales refieren a una persona ya identificada, trátalas como un alias de esa misma entidad.\n", + "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona (ya sea por nombre completo, apellido solo o iniciales), devuélvelas como una sola entidad unificada.\n", + "6. **Integridad:** No modifiques los `canonical_text` ni los `aliases` originales; mantén la literalidad de lo extraído por el NER.\n", + "\n", + "Devuelve exclusivamente un array de objetos:\n", + "[\n", + " {\n", + " \"canonical_text\": \"Nombre Completo Normalizado\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3eec132", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template_2 = \"\"\"\n", + "A continuación se proporcionan fragmentos relevantes de un documento judicial y una lista de entidades (personas) pre-clusterizadas por similitud de texto.\n", + "\n", + "# Contexto de la causa, párrafos con alguna mención a las personas:\n", + "{document_text}\n", + "\n", + "# Entidades Pre-clusterizadas a validar:\n", + "{canonical_entities}\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e07fffe7", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompts = [\n", + " system_prompt_1,\n", + " system_prompt_2,\n", + " system_prompt_3,\n", + " system_prompt_4,\n", + " system_prompt_5,\n", + " system_prompt_6,\n", + " system_prompt_7,\n", + "]\n", + "\n", + "user_prompt_templates = [\n", + " user_prompt_template_1,\n", + " user_prompt_template_2,\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82835596", + "metadata": {}, + "outputs": [], + "source": [ + "def llm_infer_canonical_entities(\n", + " system_prompt: str,\n", + " user_prompt_template: str,\n", + " model: str,\n", + " document_path: Path,\n", + " pre_cluster_path: Path,\n", + " gold_path: Path,\n", + " context_window_length: int = 120,\n", + " model_context: int = 9_500,\n", + " target_label: str = \"PER\"\n", + ") -> dict:\n", + " \n", + " \"\"\"\n", + " Infers canonical entities using an LLM by providing context windows \n", + " around detected PER entities and pre-clusterization results.\n", + " \"\"\"\n", + "\n", + " # 1. Filename cleaning\n", + " clean_base_name = document_path.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", + " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + "\n", + " print(f\"Processing document: {target_filename}\")\n", + "\n", + " # 2. Extract document text via API\n", + " session = requests.Session()\n", + " api_response = call_extraction_api(session, Path(document_path))\n", + " document_paragraphs = api_response.get(\"detail\", {}).get(\"document\")\n", + "\n", + " if not document_paragraphs:\n", + " raise ValueError(\"Document text is empty or not found for {target_filename}.\")\n", + "\n", + " # 3. Extract context windows for target label\n", + " context_windows = set()\n", + "\n", + " for paragraph in tqdm(document_paragraphs, desc=\"Extracting context\"):\n", + " preds = get_predictions(paragraph)\n", + " doc_text = preds['document']\n", + " \n", + " for label in preds['labels']:\n", + " label_type = label['attrs'].get('aymurai_label')\n", + " \n", + " # Filter: only PER labels\n", + " if label_type == target_label:\n", + " start = label['start_char']\n", + " end = label['end_char']\n", + " \n", + " # Define window boundaries\n", + " window_start = max(0, start - context_window_length)\n", + " window_end = min(len(doc_text), end + context_window_length)\n", + "\n", + " # Extract and clean the snippet\n", + " snippet = \" \".join(doc_text[window_start:window_end].split())\n", + " context_windows.add(snippet)\n", + "\n", + " context_windows = list(context_windows)\n", + " \n", + " # 4. Prepare Canonical Entities from Pre-cluster\n", + " canonical_entities_pre_cluster = load_json(json_file_path=pre_cluster_path)\n", + "\n", + " # Clean entities to save tokens\n", + " canonical_entities_prompt = [\n", + " {\n", + " k: v\n", + " for k, v in ce.items()\n", + " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", + " }\n", + " for ce in canonical_entities_pre_cluster\n", + " ]\n", + "\n", + " # 5. Build Final User Prompt\n", + " user_prompt = user_prompt_template.format(\n", + " document_text=\"\\n\".join(context_windows).strip(),\n", + " canonical_entities=get_pretty(canonical_entities_prompt),\n", + " )\n", + "\n", + " # 6. LLM Inference\n", + " provider = OllamaLLMProvider(model=model)\n", + " response = provider.generate(\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options={\"temperature\": 0, \"num_ctx\": model_context},\n", + " format=CanonicalEntities.model_json_schema(),\n", + " )\n", + "\n", + " # 7. Parse and Validate Output\n", + " raw_llm_output = [\n", + " output for output in json.loads(response.text)[\"canonical_entities\"]\n", + " ]\n", + "\n", + " canonical_entities_llm = [\n", + " CanonicalEntity.model_validate(canonical_entity)\n", + " for canonical_entity in raw_llm_output\n", + " ]\n", + "\n", + " # 8. Load Gold Standard for reference\n", + " canonical_entities_gold = load_json(json_file_path=gold_path)\n", + "\n", + " print(f\"\\nSummary for {target_filename}:\")\n", + " print(f\"- Pre-cluster entities: {len(canonical_entities_pre_cluster)}\")\n", + " print(f\"- LLM generated entities: {len(canonical_entities_llm)}\")\n", + " print(f\"- Gold standard entities: {len(canonical_entities_gold)}\")\n", + "\n", + " # Return structured results\n", + " return {\n", + " \"pre_cluster_json\": canonical_entities_pre_cluster,\n", + " \"llm_output_json\": canonical_entities_llm,\n", + " \"gold_standard_json\": canonical_entities_gold,\n", + " \"system_prompt\": system_prompt,\n", + " \"user_prompt\": user_prompt\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "586b1ddd", + "metadata": {}, + "outputs": [], + "source": [ + "def get_document_paths(document_check: Path, pre_clusterization_root: Path) -> dict:\n", + " \"\"\"\n", + " Generates the pre-cluster and gold JSON paths for a given document.\n", + " \n", + " Args:\n", + " document_check (Path): The original document Path object.\n", + " pre_clusterization_root (Path): The root directory for pre-clusterization data.\n", + " \n", + " Returns:\n", + " dict: A dictionary containing the 'pre_cluster_path' and 'gold_path'.\n", + " \"\"\"\n", + " # 1. Prepare target filename\n", + " clean_base_name = document_check.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", + " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + "\n", + " # 2. Define subdirectories\n", + " pre_cluster_dir = pre_clusterization_root / 'best-pre-clusterization-per'\n", + " gold_dir = pre_clusterization_root / 'gold-jsons'\n", + "\n", + " # 3. Build final paths\n", + " pre_cluster_json_path = pre_cluster_dir / f\"{target_filename}-ner-preds-pre-cluster.json\"\n", + " gold_json_path = gold_dir / f\"{target_filename}-canonical-entities-gold.json\"\n", + "\n", + " return {\n", + " \"target_filename\": target_filename,\n", + " \"pre_cluster_path\": pre_cluster_json_path,\n", + " \"gold_path\": gold_json_path\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c2163a5", + "metadata": {}, + "outputs": [], + "source": [ + "document_check = documents[0]\n", + "PRE_CLUSTERIZATION_ROOT = GOLD_JSON_ROOT.parent / \"pre-clusterization\"\n", + "paths = get_document_paths(document_check, PRE_CLUSTERIZATION_ROOT)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42211950", + "metadata": {}, + "outputs": [], + "source": [ + "context_window_lengths = list(range(80, 200, 10))\n", + "\n", + "model_context_lengths = [7_500, 8_000, 8_500, 9_000, 9_500]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d5f542f5", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict = llm_infer_canonical_entities(\n", + " system_prompt=system_prompts['system_prompt_7'],\n", + " user_prompt_template=user_prompt_templates['user_prompt_template_2'],\n", + " model=models[0],\n", + " document_path=document_check,\n", + " pre_cluster_path=paths[\"pre_cluster_path\"],\n", + " gold_path=paths[\"gold_path\"],\n", + " context_window_length=120,\n", + " model_context=9_500,\n", + " target_label=\"PER\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3a029e62", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict['llm_output_json']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "027b77cc", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict['pre_cluster_json']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1087e778", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict['gold_standard_json']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5c28436f", + "metadata": {}, + "outputs": [], + "source": [ + "print(llm_response_dict['user_prompt'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b51fc151", + "metadata": {}, + "outputs": [], + "source": [ + "print(llm_response_dict['system_prompt'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90229978", + "metadata": {}, + "outputs": [], + "source": [ + "import shutil\n", + "\n", + "def get_name(obj):\n", + " \"\"\"Helper to extract a clean string name from a function or object.\"\"\"\n", + " if obj is None:\n", + " return \"None\"\n", + " if hasattr(obj, \"__name__\"):\n", + " return obj.__name__\n", + " # Fallback for complex objects or partials: remove memory addresses\n", + " clean_name = re.sub(r\" at 0x[0-9a-fA-F]+\", \"\", str(obj))\n", + " return clean_name.strip(\"<>\").replace(\"cyfunction \", \"\").replace(\"function \", \"\")\n", + "\n", + "\n", + "def run_llm_grid_search(\n", + " models: list,\n", + " system_prompts: dict,\n", + " user_prompt_templates: dict,\n", + " context_window_lengths: list,\n", + " model_context_lengths: list,\n", + " documents: list[Path],\n", + " target_label: str,\n", + " base_output_path: Path,\n", + "):\n", + " \"\"\"\n", + " Runs a grid search over hyperparameters using nested loops.\n", + " \"\"\"\n", + "\n", + " # To keep track of all results and find the best\n", + " all_combinations_results = []\n", + "\n", + " for model in models:\n", + " for system_prompt_name, system_prompt in system_prompts.items():\n", + " for user_prompt_template_name, user_prompt_template in user_prompt_templates.items():\n", + " for context_window_length in context_window_lengths:\n", + " for model_context in model_context_lengths:\n", + " \n", + " print(\n", + " f\"\\nRunning grid search with model: {model}, \"\n", + " f\"context_window_length: {context_window_length}, \"\n", + " f\"model_context: {model_context}\"\n", + " )\n", + "\n", + " # 1. Create a descriptive folder name with the cleaned names\n", + " combo_name = (\n", + " f\"model-{model}-system_prompt-{system_prompt_name}-\"\n", + " f\"user_prompt_template-{user_prompt_template_name}-context_window-{context_window_length}-\"\n", + " f\"model_context-{model_context}\"\n", + " )\n", + "\n", + " combo_dir = base_output_path / combo_name\n", + " combo_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + " metrics_results = {}\n", + " metrics_file_path = (\n", + " combo_dir / f\"evaluation_metrics_{target_label}.json\"\n", + " )\n", + "\n", + " # List to collect scores for this specific combination\n", + " current_combo_scores = []\n", + "\n", + " for document in documents:\n", + " \n", + " # Get document paths\n", + " paths = get_document_paths(document, PRE_CLUSTERIZATION_ROOT)\n", + "\n", + " # Run LLM inference\n", + " llm_response_dict = llm_infer_canonical_entities(\n", + " system_prompt=system_prompt,\n", + " user_prompt_template=user_prompt_template,\n", + " model=model,\n", + " document_path=document,\n", + " pre_cluster_path=paths['pre_cluster_path'],\n", + " gold_path=paths['gold_path'],\n", + " context_window_length=context_window_length,\n", + " model_context=model_context,\n", + " target_label=target_label\n", + " )\n", + " # Extract predictions\n", + " ce_llm = llm_response_dict['llm_output_json']\n", + " \n", + " # Validate and prepare for saving\n", + " ce_llm = [\n", + " CanonicalEntity.model_validate(entity)\n", + " for entity in ce_llm\n", + " ]\n", + "\n", + " ce_llm = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in ce_llm\n", + " ]\n", + "\n", + " # Save the result as the llm-pred.json\n", + " target_filename = paths['target_filename']\n", + " llm_filename = f\"{target_filename}-llm-pred.json\"\n", + " llm_output_path = combo_dir / llm_filename\n", + "\n", + " save_json(\n", + " file_path=llm_output_path, json_data=ce_llm\n", + " )\n", + "\n", + " # Extract gold standard\n", + " ce_gold = llm_response_dict['gold_standard_json']\n", + " \n", + " # Validate and prepare for saving\n", + " ce_gold = [\n", + " CanonicalEntity.model_validate(entity)\n", + " for entity in ce_gold\n", + " ]\n", + "\n", + " ce_gold = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in ce_gold\n", + " ]\n", + "\n", + " len_llm = len(ce_llm)\n", + " len_gold = len(ce_gold)\n", + "\n", + " # Evaluate metrics\n", + " score, metrics = aymurai_metrics.evaluate_disambiguation(\n", + " gold_json=ce_gold,\n", + " pred_json=ce_llm,\n", + " target_label=target_label,\n", + " )\n", + " current_combo_scores.append(score)\n", + " doc_id = target_filename\n", + " metrics_results[doc_id] = {\n", + " \"label\": target_label,\n", + " \"metric_value\": score,\n", + " \"detailed_metrics\": metrics,\n", + " \"len_llm_predictions\": len_llm,\n", + " \"len_gold_standard\": len_gold\n", + " }\n", + "\n", + " # --- Calculate Average for this combination ---\n", + " avg_score = (\n", + " np.mean(current_combo_scores) if current_combo_scores else 0.0\n", + " )\n", + "\n", + " # Add average to the results file for this folder\n", + " final_output = {\n", + " \"average_combination_score\": avg_score,\n", + " \"document_details\": metrics_results,\n", + " }\n", + "\n", + " with open(metrics_file_path, \"w\") as f:\n", + " json.dump(final_output, f, indent=4)\n", + "\n", + " # Store combination info for final ranking\n", + " all_combinations_results.append(\n", + " {\n", + " \"name\": combo_name,\n", + " \"score\": avg_score,\n", + " \"params\": {\n", + " \"model\": model,\n", + " \"system_prompt\": system_prompt_name,\n", + " \"user_prompt_template\": user_prompt_template_name,\n", + " \"context_window_length\": context_window_length,\n", + " \"model_context\": model_context\n", + " },\n", + " }\n", + " )\n", + "\n", + " # Save all combinations results in a summary file\n", + " summary_file_path = (\n", + " base_output_path / f\"results_summary_{target_label}.json\"\n", + " )\n", + " with open(summary_file_path, \"w\") as f:\n", + " json.dump(all_combinations_results, f, indent=4)\n", + "\n", + " # --- Find the best combination ---\n", + " best_combo = max(all_combinations_results, key=lambda x: x[\"score\"])\n", + "\n", + " print(f\"\\nGrid Search for {target_label} completed.\")\n", + "\n", + " # We now copy the best combination folder to a new location with a standardized name\n", + " src = Path(base_output_path) / best_combo[\"name\"]\n", + " # Combine the parent destination path with the new folder name\n", + " new_name = f\"best-llm-pred-{target_label.lower()}\"\n", + " dest = Path(base_output_path.parent) / new_name\n", + " \n", + " try:\n", + " # copytree creates the destination directory with the 'new_name'\n", + " shutil.copytree(src, dest)\n", + " print(f\"Successfully copied '{src.name}' to '{dest}'\")\n", + " except FileExistsError:\n", + " print(f\"Error: A folder named '{new_name}' already exists in '{base_output_path.parent}'\")\n", + " except Exception as e:\n", + " print(f\"An error occurred: {e}\") \n", + "\n", + " return best_combo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5110dc60", + "metadata": {}, + "outputs": [], + "source": [ + "models = [\n", + " \"phi4:14b\",\n", + " \"gpt-oss:20b\",\n", + " \"llama3\",\n", + " \"llama3.1:8b\",\n", + " \"gemma3:270m\",\n", + "]\n", + "\n", + "system_prompts = {\n", + " \"system_prompt_1\": system_prompt_1,\n", + " \"system_prompt_2\": system_prompt_2,\n", + " \"system_prompt_3\": system_prompt_3,\n", + " \"system_prompt_4\": system_prompt_4,\n", + " \"system_prompt_5\": system_prompt_5,\n", + " \"system_prompt_6\": system_prompt_6,\n", + " \"system_prompt_7\": system_prompt_7\n", + "}\n", + "\n", + "\n", + "user_prompt_templates = {\n", + " \"user_prompt_template_1\": user_prompt_template_1,\n", + " \"user_prompt_template_2\": user_prompt_template_2,\n", + "}\n", + "\n", + "context_window_lengths = list(range(80, 200, 10))\n", + "\n", + "model_context_lengths = [7_500, 8_000, 8_500, 9_000, 9_500]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fe27195", + "metadata": {}, + "outputs": [], + "source": [ + "models = [\n", + " \"phi4:14b\",\n", + "]\n", + "\n", + "system_prompts = {\n", + " \"system_prompt_7\": system_prompt_7\n", + "}\n", + "\n", + "\n", + "user_prompt_templates = {\n", + " \"user_prompt_template_2\": user_prompt_template_2,\n", + "}\n", + "\n", + "context_window_lengths = [120]\n", + "\n", + "model_context_lengths = [9_500]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a32b4244", + "metadata": {}, + "outputs": [], + "source": [ + "top_result = run_llm_grid_search(\n", + " models=models,\n", + " system_prompts=system_prompts,\n", + " user_prompt_templates=user_prompt_templates,\n", + " context_window_lengths=context_window_lengths,\n", + " model_context_lengths=model_context_lengths,\n", + " documents=documents[0:3],\n", + " target_label=\"PER\",\n", + " base_output_path=GOLD_JSON_ROOT.parent / \"llm-grid-search-results\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86da6a45", + "metadata": {}, + "outputs": [], + "source": [ + "print(\n", + " f\"The best hyperparameter combination is '{top_result['name']}' \"\n", + " f\"with an average score of {top_result['score']:.4f}.\"\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb new file mode 100644 index 00000000..61c88f82 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb @@ -0,0 +1,185 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b3a62938", + "metadata": {}, + "source": [ + "# Disambiguation endpoint smoke test\n", + "\n", + "This notebook runs the full flow using the API endpoints:\n", + "1) document extraction\n", + "2) NER prediction per paragraph\n", + "3) disambiguation\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e468613", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import os\n", + "from pathlib import Path\n", + "\n", + "import requests\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a54d0295", + "metadata": {}, + "outputs": [], + "source": [ + "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8999\")\n", + "DATA_ROOT = Path(\n", + " os.getenv(\n", + " \"DISAMBIGUATION_DATA_ROOT\",\n", + " \"/resources/data/restricted/disambiguation-eval/documents\",\n", + " )\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "\n", + "LIMIT = int(os.getenv(\"DISAMBIGUATION_DOC_LIMIT\", \"0\")) # 0 = no limit\n", + "TARGET_LABELS = os.getenv(\"DISAMBIGUATION_TARGET_LABELS\", \"PER\")\n", + "TARGET_LABELS = [label.strip() for label in TARGET_LABELS.split(\",\") if label.strip()]\n", + "\n", + "FUZZY_THRESHOLD = int(os.getenv(\"DISAMBIGUATION_THRESHOLD\", \"70\"))\n", + "FUZZY_SCORER = os.getenv(\"DISAMBIGUATION_SCORER\", \"token_set_ratio\")\n", + "FUZZY_PROCESSOR = os.getenv(\"DISAMBIGUATION_PROCESSOR\", \"light_normalizer\")\n", + "\n", + "print(f\"API: {API_BASE_URL}\")\n", + "print(f\"Data root: {DATA_ROOT}\")\n", + "print(f\"Target labels: {TARGET_LABELS or 'ALL'}\")\n", + "print(\n", + " f\"Fuzzy params: scorer={FUZZY_SCORER}, threshold={FUZZY_THRESHOLD}, processor={FUZZY_PROCESSOR}\"\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d3d5787", + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.experiments.entity_disambiguation.runner import (\n", + " call_extraction_api as extract_document,\n", + ")\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: set[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "def predict_paragraphs(paragraphs: list[str]) -> list[dict]:\n", + " endpoint = f\"{API_BASE_URL}/anonymizer/predict\"\n", + " predictions = []\n", + " for paragraph in paragraphs:\n", + " response = requests.post(endpoint, json={\"text\": paragraph}, timeout=60)\n", + " response.raise_for_status()\n", + " predictions.append(response.json())\n", + " return predictions\n", + "\n", + "\n", + "def disambiguate(predictions: list[dict]) -> dict:\n", + " endpoint = f\"{API_BASE_URL}/anonymizer/disambiguate\"\n", + " params = {\n", + " \"threshold\": FUZZY_THRESHOLD,\n", + " \"scorer\": FUZZY_SCORER,\n", + " \"processor\": FUZZY_PROCESSOR,\n", + " \"target_labels\": TARGET_LABELS,\n", + " }\n", + " if TARGET_LABELS:\n", + " params[\"target_labels\"] = TARGET_LABELS\n", + " response = requests.post(endpoint, params=params, json=predictions, timeout=120)\n", + " response.raise_for_status()\n", + " return response.json()\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "72f3d427", + "metadata": {}, + "outputs": [], + "source": [ + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "if LIMIT > 0:\n", + " documents = documents[:LIMIT]\n", + "\n", + "print(f\"Found {len(documents)} documents\")\n", + "documents[:5]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1eb1c141", + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.experiments.entity_disambiguation.runner import call_extraction_api\n", + "\n", + "\n", + "for doc_path in documents:\n", + " print(f\"\\n=== {doc_path.name} ===\")\n", + " session = requests.Session()\n", + " document = extract_document(\n", + " session,\n", + " endpoint=f\"{API_BASE_URL}/misc/document-extract\",\n", + " file_path=doc_path,\n", + " timeout_s=300,\n", + " )\n", + " paragraphs = document[\"detail\"][\"document\"]\n", + " print(f\"Paragraphs: {len(paragraphs)}\")\n", + "\n", + " predictions = predict_paragraphs(paragraphs)\n", + " print(f\"Predictions: {len(predictions)}\")\n", + "\n", + " disambiguated = disambiguate(predictions)\n", + " print(f\"Canonical entities: {len(disambiguated.get('canonical_entities', []))}\")\n", + " print(json.dumps(disambiguated, indent=2, ensure_ascii=False))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "877f5167", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai (3.10.19)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.19" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/uv.lock b/uv.lock index be85f765..9913d119 100644 --- a/uv.lock +++ b/uv.lock @@ -1,18 +1,19 @@ version = 1 +revision = 3 requires-python = "==3.10.*" resolution-markers = [ - "platform_system == 'Darwin'", - "platform_machine == 'aarch64' and platform_system == 'Linux'", - "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')", + "sys_platform == 'darwin'", + "platform_machine == 'aarch64' and sys_platform == 'linux'", + "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')", ] [[package]] name = "absl-py" version = "2.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588 } +sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811 }, + { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" }, ] [[package]] @@ -37,9 +38,9 @@ wheels = [ name = "aiohappyeyeballs" version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760 } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265 }, + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, ] [[package]] @@ -85,9 +86,9 @@ dependencies = [ { name = "frozenlist" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007 } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490 }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, ] [[package]] @@ -100,9 +101,9 @@ dependencies = [ { name = "tomli" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064 } +sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064, upload-time = "2025-11-14T20:35:04.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554 }, + { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554, upload-time = "2025-11-14T20:35:05.699Z" }, ] [[package]] @@ -125,18 +126,18 @@ wheels = [ name = "annotated-doc" version = "0.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288 } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303 }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, ] [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] [[package]] @@ -152,9 +153,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191, upload-time = "2025-02-18T20:35:33.314Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228 }, + { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228, upload-time = "2025-02-18T20:35:28.659Z" }, ] [[package]] @@ -175,9 +176,9 @@ wheels = [ name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] [[package]] @@ -187,9 +188,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, ] [[package]] @@ -199,23 +200,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, - { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549 }, - { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539 }, - { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467 }, - { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355 }, - { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187 }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, + { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549, upload-time = "2025-07-30T10:02:00.101Z" }, + { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539, upload-time = "2025-07-30T10:02:00.929Z" }, + { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467, upload-time = "2025-07-30T10:02:02.08Z" }, + { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355, upload-time = "2025-07-30T10:02:02.867Z" }, + { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187, upload-time = "2025-07-30T10:02:03.674Z" }, ] [[package]] @@ -226,18 +227,18 @@ dependencies = [ { name = "python-dateutil" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797 }, + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, ] [[package]] name = "asttokens" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, ] [[package]] @@ -247,18 +248,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380 } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069 }, + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, ] [[package]] name = "async-timeout" version = "5.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, ] [[package]] @@ -268,18 +269,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217, upload-time = "2024-08-24T23:15:36.449Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209 }, + { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209, upload-time = "2024-08-24T23:15:35.317Z" }, ] [[package]] name = "attrs" version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251 } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615 }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] [[package]] @@ -411,9 +412,9 @@ mlops = [ name = "babel" version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] [[package]] @@ -424,9 +425,9 @@ dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 }, + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, ] [[package]] @@ -440,9 +441,9 @@ dependencies = [ { name = "lxml" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924 } +sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924, upload-time = "2023-08-15T22:34:59.047Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419 }, + { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419, upload-time = "2023-08-15T22:34:56.022Z" }, ] [[package]] @@ -452,9 +453,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533 } +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437 }, + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, ] [package.optional-dependencies] @@ -466,9 +467,9 @@ css = [ name = "blinker" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, ] [[package]] @@ -524,54 +525,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283 }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504 }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811 }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402 }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217 }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079 }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475 }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829 }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211 }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036 }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184 }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790 }, + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, ] [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709 }, - { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814 }, - { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467 }, - { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280 }, - { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454 }, - { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609 }, - { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849 }, - { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586 }, - { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290 }, - { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663 }, - { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964 }, - { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064 }, - { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015 }, - { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792 }, - { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198 }, - { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262 }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] [[package]] @@ -579,29 +580,29 @@ name = "click" version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] [[package]] name = "cloudpickle" version = "3.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330 } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228 }, + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] @@ -609,29 +610,29 @@ name = "colorlog" version = "6.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743 }, + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, ] [[package]] name = "comm" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, ] [[package]] name = "conllu" version = "4.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768 } +sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768, upload-time = "2023-06-19T12:37:49.632Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098 }, + { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098, upload-time = "2023-06-19T12:37:47.885Z" }, ] [[package]] @@ -641,7 +642,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, @@ -706,7 +707,7 @@ wheels = [ name = "cycler" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, ] @@ -772,18 +773,18 @@ wheels = [ name = "decorator" version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] [[package]] name = "defusedxml" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, ] [[package]] @@ -793,52 +794,52 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523 } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298 }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, ] [[package]] name = "dill" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976 } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668 }, + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, ] [[package]] name = "diskcache" version = "5.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916 } +sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550 }, + { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" }, ] [[package]] name = "distlib" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "distro" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] [[package]] name = "dnspython" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251 } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094 }, ] @@ -861,15 +862,15 @@ wheels = [ name = "docopt" version = "0.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } [[package]] name = "docx2txt" version = "0.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613 } +sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613, upload-time = "2025-03-24T20:59:25.21Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025 }, + { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025, upload-time = "2025-03-24T20:59:24.394Z" }, ] [[package]] @@ -905,9 +906,9 @@ wheels = [ name = "einops" version = "0.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805 } +sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805, upload-time = "2025-02-09T03:17:00.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359 }, + { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359, upload-time = "2025-02-09T03:17:01.998Z" }, ] [[package]] @@ -918,9 +919,9 @@ dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238 } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604 }, + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, ] [[package]] @@ -930,18 +931,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] [[package]] name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, ] [[package]] @@ -951,9 +952,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644, upload-time = "2023-06-27T15:24:28.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039 }, + { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039, upload-time = "2023-06-27T15:24:24.869Z" }, ] [[package]] @@ -1027,62 +1028,62 @@ wheels = [ name = "fastar" version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536 }, - { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235 }, - { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386 }, - { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955 }, - { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987 }, - { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900 }, - { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523 }, - { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268 }, - { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286 }, - { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921 }, - { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302 }, - { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141 }, - { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544 }, - { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701 }, - { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544 }, - { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020 }, - { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735 }, - { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779 }, - { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755 }, - { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732 }, - { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571 }, - { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440 }, - { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424 }, - { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675 }, - { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098 }, - { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397 }, +sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524, upload-time = "2025-11-26T02:36:00.72Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536, upload-time = "2025-11-26T02:34:35.236Z" }, + { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235, upload-time = "2025-11-26T02:34:19.367Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386, upload-time = "2025-11-26T02:33:47.613Z" }, + { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955, upload-time = "2025-11-26T02:32:44.279Z" }, + { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987, upload-time = "2025-11-26T02:32:59.701Z" }, + { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900, upload-time = "2025-11-26T02:33:16.059Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523, upload-time = "2025-11-26T02:33:30.897Z" }, + { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268, upload-time = "2025-11-26T02:34:04.003Z" }, + { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286, upload-time = "2025-11-26T02:34:50.279Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921, upload-time = "2025-11-26T02:35:07.292Z" }, + { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302, upload-time = "2025-11-26T02:35:24.995Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141, upload-time = "2025-11-26T02:35:42.449Z" }, + { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544, upload-time = "2025-11-26T02:36:23.801Z" }, + { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701, upload-time = "2025-11-26T02:36:09.625Z" }, + { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544, upload-time = "2025-11-26T02:34:46.195Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020, upload-time = "2025-11-26T02:34:31.085Z" }, + { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735, upload-time = "2025-11-26T02:34:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779, upload-time = "2025-11-26T02:32:55.109Z" }, + { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755, upload-time = "2025-11-26T02:33:11.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732, upload-time = "2025-11-26T02:33:27.122Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571, upload-time = "2025-11-26T02:33:42.986Z" }, + { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440, upload-time = "2025-11-26T02:34:15.439Z" }, + { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424, upload-time = "2025-11-26T02:35:02.742Z" }, + { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675, upload-time = "2025-11-26T02:35:20.252Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098, upload-time = "2025-11-26T02:35:37.643Z" }, + { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397, upload-time = "2025-11-26T02:35:56.215Z" }, ] [[package]] name = "fastjsonschema" version = "2.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130 } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024 }, + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, ] [[package]] name = "fastuuid" version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760 }, - { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748 }, - { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537 }, - { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994 }, - { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003 }, - { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583 }, - { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955 }, - { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763 }, - { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613 }, - { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045 }, - { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122 }, + { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760, upload-time = "2025-10-19T22:25:21.509Z" }, + { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748, upload-time = "2025-10-19T22:41:52.873Z" }, + { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537, upload-time = "2025-10-19T22:33:55.603Z" }, + { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994, upload-time = "2025-10-19T22:26:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003, upload-time = "2025-10-19T22:23:45.415Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583, upload-time = "2025-10-19T22:26:00.756Z" }, + { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955, upload-time = "2025-10-19T22:36:25.196Z" }, + { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763, upload-time = "2025-10-19T22:24:28.451Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613, upload-time = "2025-10-19T22:25:06.827Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045, upload-time = "2025-10-19T22:28:32.732Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122, upload-time = "2025-10-19T22:23:15.59Z" }, ] [[package]] @@ -1098,9 +1099,9 @@ wheels = [ name = "filetype" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020 } +sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020, upload-time = "2022-11-02T17:34:04.141Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970 }, + { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, ] [[package]] @@ -1110,9 +1111,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "termcolor" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720 } +sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720, upload-time = "2025-08-16T20:20:24.175Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945 }, + { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945, upload-time = "2025-08-16T20:20:22.87Z" }, ] [[package]] @@ -1146,7 +1147,7 @@ dependencies = [ { name = "transformers", extra = ["sentencepiece"] }, { name = "wikipedia-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607 } +sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607, upload-time = "2025-02-05T14:45:44.322Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, ] @@ -1202,43 +1203,43 @@ wheels = [ name = "fqdn" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015 } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121 }, + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, ] [[package]] name = "frozenlist" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875 } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230 }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621 }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889 }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464 }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649 }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188 }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748 }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351 }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767 }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887 }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785 }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312 }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650 }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659 }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837 }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989 }, - { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] [[package]] name = "fsspec" version = "2025.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285 } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966 }, + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, ] [package.optional-dependencies] @@ -1253,9 +1254,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927 } +sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927, upload-time = "2024-10-26T00:50:35.149Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821 }, + { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821, upload-time = "2024-10-26T00:50:33.425Z" }, ] [[package]] @@ -1289,9 +1290,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "smmap" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684 } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794 }, + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, ] [[package]] @@ -1317,9 +1318,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759 } +sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759, upload-time = "2025-10-28T21:34:51.529Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706 }, + { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706, upload-time = "2025-10-28T21:34:50.151Z" }, ] [[package]] @@ -1348,9 +1349,9 @@ dependencies = [ { name = "google-api-core" }, { name = "google-auth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469 }, + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, ] [[package]] @@ -1411,9 +1412,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-crc32c" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265 } +sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload-time = "2025-11-17T15:38:06.659Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340 }, + { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload-time = "2025-11-17T15:38:05.594Z" }, ] [[package]] @@ -1468,7 +1469,7 @@ wheels = [ name = "greenlet" version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658 }, { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810 }, @@ -1496,24 +1497,24 @@ wheels = [ name = "h11" version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] [[package]] name = "hf-xet" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099 }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178 }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214 }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054 }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812 }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920 }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735 }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, ] [[package]] @@ -1524,24 +1525,24 @@ dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, ] [[package]] name = "httptools" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531 }, - { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408 }, - { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889 }, - { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460 }, - { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267 }, - { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429 }, - { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173 }, + { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531, upload-time = "2025-10-10T03:54:20.887Z" }, + { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408, upload-time = "2025-10-10T03:54:22.455Z" }, + { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889, upload-time = "2025-10-10T03:54:23.753Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460, upload-time = "2025-10-10T03:54:25.313Z" }, + { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267, upload-time = "2025-10-10T03:54:26.81Z" }, + { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429, upload-time = "2025-10-10T03:54:28.174Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173, upload-time = "2025-10-10T03:54:29.5Z" }, ] [[package]] @@ -1554,7 +1555,7 @@ dependencies = [ { name = "httpcore" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, ] @@ -1582,27 +1583,27 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358 } +sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094 }, + { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" }, ] [[package]] name = "identify" version = "2.6.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183 }, + { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, ] [[package]] name = "idna" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] @@ -1634,7 +1635,7 @@ name = "ipykernel" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "appnope", marker = "platform_system == 'Darwin'" }, + { name = "appnope", marker = "sys_platform == 'darwin'" }, { name = "comm" }, { name = "debugpy" }, { name = "ipython" }, @@ -1648,9 +1649,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968 }, + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, ] [[package]] @@ -1658,7 +1659,7 @@ name = "ipython" version = "8.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "decorator" }, { name = "exceptiongroup" }, { name = "jedi" }, @@ -1686,9 +1687,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808 }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, ] [[package]] @@ -1698,7 +1699,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arrow" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649 } +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, ] @@ -1719,9 +1720,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, ] [[package]] @@ -1731,37 +1732,29 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "jiter" version = "0.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652 }, - { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829 }, - { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568 }, - { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052 }, - { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585 }, - { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541 }, - { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423 }, - { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958 }, - { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084 }, - { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054 }, - { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368 }, - { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847 }, - { url = "https://files.pythonhosted.org/packages/fe/54/5339ef1ecaa881c6948669956567a64d2670941925f245c434f494ffb0e5/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8", size = 311144 }, - { url = "https://files.pythonhosted.org/packages/27/74/3446c652bffbd5e81ab354e388b1b5fc1d20daac34ee0ed11ff096b1b01a/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3", size = 305877 }, - { url = "https://files.pythonhosted.org/packages/a1/f4/ed76ef9043450f57aac2d4fbeb27175aa0eb9c38f833be6ef6379b3b9a86/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e", size = 340419 }, - { url = "https://files.pythonhosted.org/packages/21/01/857d4608f5edb0664aa791a3d45702e1a5bcfff9934da74035e7b9803846/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d", size = 347212 }, - { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974 }, - { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233 }, - { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537 }, - { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110 }, +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294, upload-time = "2025-11-09T20:49:23.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652, upload-time = "2025-11-09T20:46:41.021Z" }, + { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829, upload-time = "2025-11-09T20:46:43.281Z" }, + { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568, upload-time = "2025-11-09T20:46:45.075Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052, upload-time = "2025-11-09T20:46:46.818Z" }, + { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585, upload-time = "2025-11-09T20:46:48.319Z" }, + { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541, upload-time = "2025-11-09T20:46:49.643Z" }, + { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423, upload-time = "2025-11-09T20:46:51.731Z" }, + { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958, upload-time = "2025-11-09T20:46:53.432Z" }, + { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084, upload-time = "2025-11-09T20:46:54.848Z" }, + { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054, upload-time = "2025-11-09T20:46:56.487Z" }, + { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368, upload-time = "2025-11-09T20:46:58.638Z" }, + { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847, upload-time = "2025-11-09T20:47:00.295Z" }, ] [[package]] @@ -1772,18 +1765,18 @@ dependencies = [ { name = "click" }, { name = "rapidfuzz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537 } +sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537, upload-time = "2024-11-01T16:18:57.337Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990 }, + { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990, upload-time = "2024-11-01T16:18:55.928Z" }, ] [[package]] name = "jmespath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, ] [[package]] @@ -1820,18 +1813,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359 } +sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359, upload-time = "2023-09-01T12:34:44.187Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701 }, + { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701, upload-time = "2023-09-01T12:34:42.563Z" }, ] [[package]] name = "jsonpointer" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114 } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595 }, + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, ] [[package]] @@ -1869,9 +1862,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855 } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437 }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] [[package]] @@ -1886,9 +1879,9 @@ dependencies = [ { name = "nbconvert" }, { name = "notebook" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959 } +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657 }, + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, ] [[package]] @@ -1921,9 +1914,9 @@ dependencies = [ { name = "pyzmq" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510 }, + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, ] [[package]] @@ -1934,9 +1927,9 @@ dependencies = [ { name = "platformdirs" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, ] [[package]] @@ -1953,9 +1946,9 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, ] [[package]] @@ -1965,9 +1958,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687 }, + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, ] [[package]] @@ -1987,7 +1980,7 @@ dependencies = [ { name = "overrides" }, { name = "packaging" }, { name = "prometheus-client" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "pyzmq" }, { name = "send2trash" }, { name = "terminado" }, @@ -1995,9 +1988,9 @@ dependencies = [ { name = "traitlets" }, { name = "websocket-client" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221 }, + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, ] [[package]] @@ -2005,12 +1998,12 @@ name = "jupyter-server-terminals" version = "0.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "terminado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656 }, + { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, ] [[package]] @@ -2042,9 +2035,9 @@ wheels = [ name = "jupyterlab-pygments" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, ] [[package]] @@ -2060,44 +2053,44 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830 }, + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, ] [[package]] name = "jupyterlab-widgets" version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423 } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, ] [[package]] name = "kiwisolver" version = "1.4.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159 }, - { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578 }, - { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312 }, - { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458 }, - { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640 }, - { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074 }, - { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036 }, - { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310 }, - { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943 }, - { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488 }, - { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787 }, - { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730 }, - { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036 }, - { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183 }, - { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675 }, - { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277 }, - { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994 }, - { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744 }, +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159, upload-time = "2025-08-10T21:25:35.472Z" }, + { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578, upload-time = "2025-08-10T21:25:36.73Z" }, + { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312, upload-time = "2025-08-10T21:25:37.658Z" }, + { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458, upload-time = "2025-08-10T21:25:39.067Z" }, + { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640, upload-time = "2025-08-10T21:25:40.489Z" }, + { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074, upload-time = "2025-08-10T21:25:42.221Z" }, + { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036, upload-time = "2025-08-10T21:25:43.801Z" }, + { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310, upload-time = "2025-08-10T21:25:45.045Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943, upload-time = "2025-08-10T21:25:46.393Z" }, + { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488, upload-time = "2025-08-10T21:25:48.074Z" }, + { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787, upload-time = "2025-08-10T21:25:49.442Z" }, + { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730, upload-time = "2025-08-10T21:25:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036, upload-time = "2025-08-10T21:25:52.063Z" }, + { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183, upload-time = "2025-08-10T21:27:37.669Z" }, + { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675, upload-time = "2025-08-10T21:27:39.031Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277, upload-time = "2025-08-10T21:27:40.129Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994, upload-time = "2025-08-10T21:27:41.181Z" }, + { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744, upload-time = "2025-08-10T21:27:42.254Z" }, ] [[package]] @@ -2107,7 +2100,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } [[package]] name = "langextract" @@ -2131,9 +2124,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029 } +sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029, upload-time = "2025-11-14T22:21:30.511Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592 }, + { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592, upload-time = "2025-11-14T22:21:29.044Z" }, ] [package.optional-dependencies] @@ -2145,9 +2138,9 @@ openai = [ name = "lark" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732 } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, ] [[package]] @@ -2157,9 +2150,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fire" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292, upload-time = "2022-09-06T16:09:06.607Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594 }, + { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594, upload-time = "2022-09-06T16:09:04.658Z" }, ] [[package]] @@ -2180,39 +2173,39 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976, upload-time = "2025-11-16T00:03:51.812Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975 }, + { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975, upload-time = "2025-11-16T00:03:49.182Z" }, ] [[package]] name = "lxml" version = "6.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589 }, - { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671 }, - { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961 }, - { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087 }, - { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620 }, - { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664 }, - { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397 }, - { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178 }, - { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148 }, - { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035 }, - { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111 }, - { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662 }, - { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973 }, - { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953 }, - { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695 }, - { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051 }, - { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264 }, - { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435 }, - { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913 }, - { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357 }, - { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295 }, - { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913 }, +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, ] [[package]] @@ -2222,9 +2215,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509 }, + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, ] [[package]] @@ -2234,18 +2227,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321 }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] [[package]] name = "markdown2" version = "2.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652 } +sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652, upload-time = "2025-07-27T16:16:24.307Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954 }, + { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954, upload-time = "2025-07-27T16:16:23.026Z" }, ] [[package]] @@ -2256,9 +2249,9 @@ dependencies = [ { name = "beautifulsoup4" }, { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816 } +sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816, upload-time = "2025-11-16T19:21:18.565Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724 }, + { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724, upload-time = "2025-11-16T19:21:17.622Z" }, ] [[package]] @@ -2288,28 +2281,28 @@ dependencies = [ { name = "tqdm" }, { name = "transformers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302 } +sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302, upload-time = "2025-09-30T15:44:59.591Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914 }, + { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914, upload-time = "2025-09-30T15:44:58.441Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631 }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057 }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050 }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681 }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705 }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524 }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282 }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745 }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571 }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056 }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932 }, + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, ] [[package]] @@ -2347,18 +2340,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516 }, + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] [[package]] @@ -2381,7 +2374,7 @@ dependencies = [ { name = "absl-py" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356 } +sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356, upload-time = "2025-04-17T08:25:02.247Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, ] @@ -2468,9 +2461,9 @@ wheels = [ name = "more-itertools" version = "10.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431 } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 }, + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, ] [[package]] @@ -2481,18 +2474,18 @@ dependencies = [ { name = "jinja2" }, { name = "matplotlib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433, upload-time = "2025-11-05T18:12:24.183Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, + { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051, upload-time = "2025-11-05T18:12:22.527Z" }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, ] [[package]] @@ -2502,27 +2495,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153 }, - { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993 }, - { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607 }, - { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847 }, - { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616 }, - { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333 }, - { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239 }, - { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618 }, - { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655 }, - { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245 }, - { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523 }, - { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129 }, - { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999 }, - { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711 }, - { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504 }, - { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422 }, - { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050 }, - { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153 }, - { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317 }, +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153, upload-time = "2025-10-06T14:48:26.409Z" }, + { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993, upload-time = "2025-10-06T14:48:28.4Z" }, + { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607, upload-time = "2025-10-06T14:48:29.581Z" }, + { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847, upload-time = "2025-10-06T14:48:32.107Z" }, + { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616, upload-time = "2025-10-06T14:48:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333, upload-time = "2025-10-06T14:48:35.9Z" }, + { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239, upload-time = "2025-10-06T14:48:37.302Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618, upload-time = "2025-10-06T14:48:38.963Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655, upload-time = "2025-10-06T14:48:40.312Z" }, + { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245, upload-time = "2025-10-06T14:48:41.848Z" }, + { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523, upload-time = "2025-10-06T14:48:43.749Z" }, + { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129, upload-time = "2025-10-06T14:48:45.225Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999, upload-time = "2025-10-06T14:48:46.703Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711, upload-time = "2025-10-06T14:48:48.146Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504, upload-time = "2025-10-06T14:48:49.447Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422, upload-time = "2025-10-06T14:48:50.789Z" }, + { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050, upload-time = "2025-10-06T14:48:51.938Z" }, + { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153, upload-time = "2025-10-06T14:48:53.146Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] [[package]] @@ -2532,14 +2525,14 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503 } +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083 }, - { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128 }, - { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132 }, - { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948 }, - { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636 }, - { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478 }, + { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083, upload-time = "2025-04-17T03:11:04.223Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128, upload-time = "2025-04-17T03:11:06.045Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132, upload-time = "2025-04-17T03:11:07.533Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, ] [[package]] @@ -2586,9 +2579,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715 } +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525 }, + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, ] [[package]] @@ -2601,9 +2594,9 @@ dependencies = [ { name = "jupyter-core" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, ] [[package]] @@ -2613,27 +2606,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nbformat" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747 } +sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747, upload-time = "2025-11-16T17:38:55.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122 }, + { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122, upload-time = "2025-11-16T17:38:54.164Z" }, ] [[package]] name = "nest-asyncio" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, ] [[package]] name = "networkx" version = "3.4.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, ] [[package]] @@ -2668,25 +2661,25 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167 } +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 }, + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, ] [[package]] name = "numpy" version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129 } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468 }, - { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411 }, - { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016 }, - { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889 }, - { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746 }, - { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620 }, - { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659 }, - { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, + { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411, upload-time = "2024-02-05T23:48:29.038Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016, upload-time = "2024-02-05T23:48:54.098Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889, upload-time = "2024-02-05T23:49:25.361Z" }, + { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746, upload-time = "2024-02-05T23:49:51.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620, upload-time = "2024-02-05T23:50:22.515Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659, upload-time = "2024-02-05T23:50:35.834Z" }, + { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905, upload-time = "2024-02-05T23:51:03.701Z" }, ] [[package]] @@ -2694,8 +2687,7 @@ name = "nvidia-cublas-cu12" version = "12.8.4.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, ] [[package]] @@ -2703,8 +2695,7 @@ name = "nvidia-cuda-cupti-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, ] [[package]] @@ -2712,8 +2703,7 @@ name = "nvidia-cuda-nvrtc-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, - { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, ] [[package]] @@ -2721,8 +2711,7 @@ name = "nvidia-cuda-runtime-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, ] [[package]] @@ -2730,11 +2719,10 @@ name = "nvidia-cudnn-cu12" version = "9.10.2.21" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, ] [[package]] @@ -2742,11 +2730,10 @@ name = "nvidia-cufft-cu12" version = "11.3.3.83" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, ] [[package]] @@ -2754,8 +2741,7 @@ name = "nvidia-cufile-cu12" version = "1.13.1.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, - { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, ] [[package]] @@ -2763,8 +2749,7 @@ name = "nvidia-curand-cu12" version = "10.3.9.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, ] [[package]] @@ -2772,13 +2757,12 @@ name = "nvidia-cusolver-cu12" version = "11.7.3.90" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, - { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, ] [[package]] @@ -2786,11 +2770,10 @@ name = "nvidia-cusparse-cu12" version = "12.5.8.93" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux') or (platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, ] [[package]] @@ -2798,8 +2781,7 @@ name = "nvidia-cusparselt-cu12" version = "0.7.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, ] [[package]] @@ -2807,8 +2789,7 @@ name = "nvidia-nccl-cu12" version = "2.27.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, ] [[package]] @@ -2816,8 +2797,7 @@ name = "nvidia-nvjitlink-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, - { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, ] [[package]] @@ -2825,8 +2805,7 @@ name = "nvidia-nvshmem-cu12" version = "3.3.20" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/9d/3dd98852568fb845ec1f7902c90a22b240fe1cbabda411ccedf2fd737b7b/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0", size = 124484616 }, - { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145 }, + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" }, ] [[package]] @@ -2834,8 +2813,7 @@ name = "nvidia-nvtx-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, ] [[package]] @@ -2845,7 +2823,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "defusedxml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045 } +sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045, upload-time = "2020-01-18T16:55:48.852Z" } [[package]] name = "ollama" @@ -2855,9 +2833,9 @@ dependencies = [ { name = "httpx" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620, upload-time = "2025-11-13T23:02:17.416Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354 }, + { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354, upload-time = "2025-11-13T23:02:16.292Z" }, ] [[package]] @@ -2874,9 +2852,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133 } +sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133, upload-time = "2025-09-24T13:00:53.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627 }, + { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627, upload-time = "2025-09-24T13:00:50.754Z" }, ] [[package]] @@ -2886,7 +2864,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929 } +sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929, upload-time = "2025-01-16T13:53:40.22Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/dc/53/2c50afa0b1e05ecdb4603818e85f7d174e683d874ef63a6abe3ac92220c8/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca", size = 37326460 }, { url = "https://files.pythonhosted.org/packages/3b/43/68555327df94bb9b59a1fd645f63fafb0762515344d2046698762fc19d58/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81", size = 56723330 }, @@ -2961,9 +2939,9 @@ dependencies = [ { name = "sqlalchemy" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444 } +sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444, upload-time = "2025-11-10T05:14:30.151Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708 }, + { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708, upload-time = "2025-11-10T05:14:28.6Z" }, ] [[package]] @@ -2991,18 +2969,18 @@ wheels = [ name = "overrides" version = "7.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812 } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832 }, + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, ] [[package]] name = "packaging" version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] [[package]] @@ -3030,18 +3008,18 @@ wheels = [ name = "pandocfilters" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, ] [[package]] name = "parso" version = "0.8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668 }, + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] [[package]] @@ -3054,9 +3032,9 @@ dependencies = [ { name = "pydantic-settings" }, { name = "pypdfium2" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968, upload-time = "2025-06-11T14:42:09.492Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693 }, + { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693, upload-time = "2025-06-11T14:42:08.157Z" }, ] [[package]] @@ -3066,53 +3044,53 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] [[package]] name = "pillow" version = "10.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, - { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, - { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, - { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, - { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, - { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, - { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, - { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, - { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, - { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, - { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, - { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, - { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, - { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, - { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, - { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, - { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, - { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, +sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059, upload-time = "2024-07-01T09:48:43.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271, upload-time = "2024-07-01T09:45:22.07Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658, upload-time = "2024-07-01T09:45:25.292Z" }, + { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075, upload-time = "2024-07-01T09:45:27.94Z" }, + { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808, upload-time = "2024-07-01T09:45:30.305Z" }, + { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290, upload-time = "2024-07-01T09:45:32.868Z" }, + { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163, upload-time = "2024-07-01T09:45:35.279Z" }, + { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100, upload-time = "2024-07-01T09:45:37.74Z" }, + { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880, upload-time = "2024-07-01T09:45:39.89Z" }, + { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218, upload-time = "2024-07-01T09:45:42.771Z" }, + { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487, upload-time = "2024-07-01T09:45:45.176Z" }, + { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219, upload-time = "2024-07-01T09:45:47.274Z" }, + { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889, upload-time = "2024-07-01T09:48:04.815Z" }, + { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160, upload-time = "2024-07-01T09:48:07.206Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020, upload-time = "2024-07-01T09:48:09.66Z" }, + { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539, upload-time = "2024-07-01T09:48:12.529Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125, upload-time = "2024-07-01T09:48:14.891Z" }, + { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373, upload-time = "2024-07-01T09:48:17.601Z" }, + { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661, upload-time = "2024-07-01T09:48:20.293Z" }, ] [[package]] name = "pip" version = "25.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622 }, + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, ] [[package]] name = "platformdirs" version = "4.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715 } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731 }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] [[package]] @@ -3124,14 +3102,14 @@ dependencies = [ { name = "pyee" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424 }, - { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228 }, - { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424 }, - { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122 }, - { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645 }, - { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837 }, - { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843 }, - { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959 }, + { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424, upload-time = "2025-11-11T18:39:10.175Z" }, + { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228, upload-time = "2025-11-11T18:39:13.915Z" }, + { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424, upload-time = "2025-11-11T18:39:17.093Z" }, + { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122, upload-time = "2025-11-11T18:39:20.619Z" }, + { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645, upload-time = "2025-11-11T18:39:24.005Z" }, + { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837, upload-time = "2025-11-11T18:39:27.174Z" }, + { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843, upload-time = "2025-11-11T18:39:30.851Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959, upload-time = "2025-11-11T18:39:33.998Z" }, ] [[package]] @@ -3142,16 +3120,16 @@ dependencies = [ { name = "narwhals" }, { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624 } +sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624, upload-time = "2025-11-17T18:39:24.523Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174 }, + { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174, upload-time = "2025-11-17T18:39:20.351Z" }, ] [[package]] name = "pptree" version = "3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043 } +sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043, upload-time = "2020-04-15T18:28:53.362Z" } [[package]] name = "pre-commit" @@ -3173,9 +3151,9 @@ wheels = [ name = "prometheus-client" version = "0.23.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481 } +sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481, upload-time = "2025-09-18T20:47:25.043Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145 }, + { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145, upload-time = "2025-09-18T20:47:23.875Z" }, ] [[package]] @@ -3185,33 +3163,33 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, ] [[package]] name = "propcache" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534 }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526 }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263 }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012 }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491 }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319 }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856 }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241 }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552 }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113 }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778 }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047 }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093 }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638 }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229 }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] [[package]] @@ -3245,57 +3223,57 @@ wheels = [ name = "psutil" version = "6.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } +sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565, upload-time = "2024-10-17T21:31:45.68Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, - { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, - { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, - { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, - { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, - { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, - { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762, upload-time = "2024-10-17T21:32:05.991Z" }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777, upload-time = "2024-10-17T21:32:07.872Z" }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259, upload-time = "2024-10-17T21:32:10.177Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255, upload-time = "2024-10-17T21:32:11.964Z" }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804, upload-time = "2024-10-17T21:32:13.785Z" }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386, upload-time = "2024-10-17T21:32:21.399Z" }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228, upload-time = "2024-10-17T21:32:23.88Z" }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] [[package]] name = "pyarrow" version = "22.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151 } +sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968 }, - { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085 }, - { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613 }, - { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059 }, - { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043 }, - { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505 }, - { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641 }, + { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, + { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085, upload-time = "2025-10-24T10:03:38.146Z" }, + { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613, upload-time = "2025-10-24T10:03:46.516Z" }, + { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059, upload-time = "2025-10-24T10:03:55.353Z" }, + { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043, upload-time = "2025-10-24T10:04:05.408Z" }, + { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505, upload-time = "2025-10-24T10:04:15.786Z" }, + { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641, upload-time = "2025-10-24T10:04:22.57Z" }, ] [[package]] name = "pyasn1" version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135 }, + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, ] [[package]] @@ -3305,18 +3283,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892 } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259 }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] [[package]] name = "pycparser" version = "2.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, ] [[package]] @@ -3329,9 +3307,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591 } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580 }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, ] [package.optional-dependencies] @@ -3346,7 +3324,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298 }, { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475 }, @@ -3401,9 +3379,9 @@ dependencies = [ { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184 } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880 }, + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] [[package]] @@ -3414,9 +3392,9 @@ dependencies = [ { name = "jinja2" }, { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240, upload-time = "2024-05-10T15:36:21.153Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, + { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403, upload-time = "2024-05-10T15:36:17.36Z" }, ] [[package]] @@ -3426,18 +3404,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250 } +sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250, upload-time = "2025-03-17T18:53:15.955Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730 }, + { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730, upload-time = "2025-03-17T18:53:14.532Z" }, ] [[package]] name = "pygments" version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] [[package]] @@ -3472,9 +3450,9 @@ wheels = [ name = "pypandoc" version = "1.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477, upload-time = "2025-11-13T16:30:29.608Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451 }, + { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451, upload-time = "2025-11-13T16:30:07.66Z" }, ] [[package]] @@ -3490,29 +3468,29 @@ wheels = [ name = "pypdfium2" version = "4.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239, upload-time = "2024-05-09T18:33:17.552Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254 }, - { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624 }, - { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126 }, - { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077 }, - { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431 }, - { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008 }, - { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543 }, - { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911 }, - { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430 }, - { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951 }, - { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098 }, - { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118 }, + { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254, upload-time = "2024-05-09T18:32:48.653Z" }, + { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624, upload-time = "2024-05-09T18:32:51.458Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126, upload-time = "2024-05-09T18:32:53.581Z" }, + { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077, upload-time = "2024-05-09T18:32:55.99Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431, upload-time = "2024-05-09T18:32:57.911Z" }, + { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008, upload-time = "2024-05-09T18:32:59.886Z" }, + { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543, upload-time = "2024-05-09T18:33:02.597Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911, upload-time = "2024-05-09T18:33:05.376Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430, upload-time = "2024-05-09T18:33:08.067Z" }, + { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951, upload-time = "2024-05-09T18:33:10.567Z" }, + { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098, upload-time = "2024-05-09T18:33:13.107Z" }, + { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118, upload-time = "2024-05-09T18:33:15.489Z" }, ] [[package]] name = "pysocks" version = "1.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 }, + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, ] [[package]] @@ -3522,9 +3500,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] [[package]] @@ -3535,27 +3513,27 @@ dependencies = [ { name = "lxml" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987 }, + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, ] [[package]] name = "python-dotenv" version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] [[package]] name = "python-json-logger" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683 } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548 }, + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, ] [[package]] @@ -3583,9 +3561,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889 } +sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889, upload-time = "2022-11-25T19:33:07.958Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949 }, + { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949, upload-time = "2022-11-25T19:33:06.093Z" }, ] [[package]] @@ -3596,18 +3574,18 @@ dependencies = [ { name = "numpy" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086 } +sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086, upload-time = "2021-01-09T17:35:49.131Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564 }, + { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564, upload-time = "2021-01-09T17:35:47.543Z" }, ] [[package]] name = "pytz" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] [[package]] @@ -3615,35 +3593,35 @@ name = "pywin32" version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432 }, - { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103 }, - { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557 }, + { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, + { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, ] [[package]] name = "pywinpty" version = "3.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669, upload-time = "2025-10-03T21:16:29.205Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330 }, + { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330, upload-time = "2025-10-03T21:20:15.656Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, ] [[package]] @@ -3653,52 +3631,52 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850 }, - { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380 }, - { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421 }, - { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149 }, - { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070 }, - { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441 }, - { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529 }, - { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276 }, - { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208 }, - { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766 }, - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, - { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266 }, - { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206 }, - { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747 }, - { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371 }, - { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862 }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, ] [[package]] name = "rapidfuzz" version = "3.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900 } +sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900, upload-time = "2025-11-01T11:54:52.321Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376 }, - { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903 }, - { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655 }, - { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708 }, - { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106 }, - { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048 }, - { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020 }, - { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958 }, - { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043 }, - { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273 }, - { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875 }, + { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376, upload-time = "2025-11-01T11:52:29.175Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903, upload-time = "2025-11-01T11:52:31.239Z" }, + { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655, upload-time = "2025-11-01T11:52:32.852Z" }, + { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708, upload-time = "2025-11-01T11:52:34.618Z" }, + { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106, upload-time = "2025-11-01T11:52:36.069Z" }, + { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048, upload-time = "2025-11-01T11:52:37.936Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020, upload-time = "2025-11-01T11:52:39.657Z" }, + { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958, upload-time = "2025-11-01T11:52:41.017Z" }, + { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043, upload-time = "2025-11-01T11:52:42.465Z" }, + { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273, upload-time = "2025-11-01T11:52:44.005Z" }, + { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875, upload-time = "2025-11-01T11:52:45.405Z" }, ] [[package]] @@ -3710,33 +3688,33 @@ dependencies = [ { name = "rpds-py" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036 } +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766 }, + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, ] [[package]] name = "regex" version = "2024.11.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674 }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684 }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589 }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511 }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149 }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707 }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702 }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976 }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397 }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726 }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098 }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325 }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277 }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197 }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714 }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042 }, + { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, + { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, + { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, + { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, + { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, + { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, + { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, + { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, + { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, + { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, + { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, + { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, + { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, + { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, + { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, ] [[package]] @@ -3749,9 +3727,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [package.optional-dependencies] @@ -3766,18 +3744,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513 } +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490 }, + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, ] [[package]] name = "rfc3986-validator" version = "0.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760 } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, ] [[package]] @@ -3787,9 +3765,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046 }, + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, ] [[package]] @@ -3800,9 +3778,9 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990 } +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393 }, + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, ] [[package]] @@ -3823,56 +3801,56 @@ wheels = [ name = "rignore" version = "0.7.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999 }, - { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824 }, - { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121 }, - { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813 }, - { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019 }, - { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822 }, - { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820 }, - { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050 }, - { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164 }, - { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028 }, - { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024 }, - { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531 }, - { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817 }, - { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001 }, - { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462 }, - { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918 }, - { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922 }, - { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987 }, - { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110 }, - { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339 }, - { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680 }, - { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045 }, - { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310 }, - { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998 }, - { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178 }, - { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190 }, +sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999, upload-time = "2025-11-05T20:42:38.373Z" }, + { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824, upload-time = "2025-11-05T20:42:22.1Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121, upload-time = "2025-11-05T20:40:48.94Z" }, + { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813, upload-time = "2025-11-05T20:41:04.71Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019, upload-time = "2025-11-05T20:41:20.723Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822, upload-time = "2025-11-05T20:41:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820, upload-time = "2025-11-05T20:42:06.364Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050, upload-time = "2025-11-05T20:41:51.124Z" }, + { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164, upload-time = "2025-11-05T21:40:10.368Z" }, + { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028, upload-time = "2025-11-05T21:40:27.977Z" }, + { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024, upload-time = "2025-11-05T21:40:45.148Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531, upload-time = "2025-11-05T21:41:02.734Z" }, + { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817, upload-time = "2025-11-05T21:41:47.51Z" }, + { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001, upload-time = "2025-11-05T21:41:32.778Z" }, + { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462, upload-time = "2025-11-05T20:42:50.804Z" }, + { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918, upload-time = "2025-11-05T20:42:33.689Z" }, + { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922, upload-time = "2025-11-05T20:41:00.361Z" }, + { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987, upload-time = "2025-11-05T20:41:16.219Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110, upload-time = "2025-11-05T20:41:32.631Z" }, + { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339, upload-time = "2025-11-05T20:41:47.128Z" }, + { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680, upload-time = "2025-11-05T20:42:18.061Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045, upload-time = "2025-11-05T20:42:02.315Z" }, + { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310, upload-time = "2025-11-05T21:40:23.184Z" }, + { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998, upload-time = "2025-11-05T21:40:40.603Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178, upload-time = "2025-11-05T21:40:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190, upload-time = "2025-11-05T21:41:16.403Z" }, ] [[package]] name = "rpds-py" version = "0.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469 } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490 }, - { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751 }, - { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696 }, - { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136 }, - { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699 }, - { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022 }, - { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522 }, - { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579 }, - { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305 }, - { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503 }, - { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322 }, - { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792 }, - { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901 }, - { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823 }, + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, ] [[package]] @@ -3882,9 +3860,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, ] [[package]] @@ -3894,35 +3872,35 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827 } +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830 }, + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, ] [[package]] name = "safetensors" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781 }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058 }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748 }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881 }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463 }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855 }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152 }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856 }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060 }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715 }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377 }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368 }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423 }, - { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380 }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430 }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977 }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890 }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885 }, +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, + { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, + { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, ] [[package]] @@ -3935,13 +3913,13 @@ dependencies = [ { name = "scipy" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136 } +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221 }, - { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834 }, - { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938 }, - { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818 }, - { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969 }, + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, ] [[package]] @@ -3951,16 +3929,16 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870, upload-time = "2024-06-24T20:35:18.532Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226 }, - { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893 }, - { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258 }, - { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715 }, - { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038 }, - { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959 }, - { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514 }, - { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252 }, + { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226, upload-time = "2024-06-24T20:31:50.451Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893, upload-time = "2024-06-24T20:31:57.337Z" }, + { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258, upload-time = "2024-06-24T20:32:02.711Z" }, + { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715, upload-time = "2024-06-24T20:32:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038, upload-time = "2024-06-24T20:32:17.305Z" }, + { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959, upload-time = "2024-06-24T20:32:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514, upload-time = "2024-06-24T20:32:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252, upload-time = "2024-06-24T20:32:45.06Z" }, ] [[package]] @@ -3972,9 +3950,9 @@ dependencies = [ { name = "numpy" }, { name = "pandas" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 }, + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, ] [[package]] @@ -3984,9 +3962,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244 } +sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244, upload-time = "2021-12-15T21:56:14.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332 }, + { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332, upload-time = "2021-12-15T21:56:12.508Z" }, ] [[package]] @@ -4020,16 +3998,16 @@ wheels = [ name = "sentencepiece" version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106, upload-time = "2024-02-19T17:06:47.428Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979 }, - { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845 }, - { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472 }, - { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151 }, - { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931 }, - { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537 }, - { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747 }, - { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525 }, + { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979, upload-time = "2024-02-19T17:05:34.651Z" }, + { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845, upload-time = "2024-02-19T17:05:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472, upload-time = "2024-02-19T17:05:39.775Z" }, + { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151, upload-time = "2024-02-19T17:05:42.594Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931, upload-time = "2024-02-19T17:05:44.695Z" }, + { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537, upload-time = "2024-02-19T17:05:46.713Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747, upload-time = "2024-02-19T17:05:48.705Z" }, + { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525, upload-time = "2024-02-19T17:05:55.145Z" }, ] [[package]] @@ -4049,54 +4027,54 @@ wheels = [ name = "setuptools" version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, ] [[package]] name = "shellingham" version = "1.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "smmap" version = "5.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329 } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303 }, + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, ] [[package]] name = "sniffio" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] [[package]] name = "sortedcontainers" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, ] [[package]] @@ -4132,7 +4110,7 @@ wheels = [ name = "sqlitedict" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846 } +sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846, upload-time = "2022-12-03T13:39:13.102Z" } [[package]] name = "sqlmodel" @@ -4142,7 +4120,7 @@ dependencies = [ { name = "pydantic" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392, upload-time = "2024-08-31T09:43:24.088Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, ] @@ -4165,9 +4143,9 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] [[package]] @@ -4178,9 +4156,9 @@ dependencies = [ { name = "anyio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033 }, + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, ] [[package]] @@ -4231,9 +4209,9 @@ dependencies = [ { name = "torch" }, { name = "transformers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481, upload-time = "2025-09-23T21:41:37.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395 }, + { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395, upload-time = "2025-09-23T21:41:35.369Z" }, ] [[package]] @@ -4243,27 +4221,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, ] [[package]] name = "tabulate" version = "0.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090 } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, ] [[package]] name = "tenacity" version = "9.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036 } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 }, + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, ] [[package]] @@ -4295,21 +4273,21 @@ version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, ] [[package]] name = "threadpoolctl" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274 } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638 }, + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, ] [[package]] @@ -4320,15 +4298,15 @@ dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991 }, - { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798 }, - { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865 }, - { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856 }, - { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308 }, - { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697 }, - { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, + { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991, upload-time = "2025-10-06T20:21:34.098Z" }, + { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798, upload-time = "2025-10-06T20:21:35.579Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865, upload-time = "2025-10-06T20:21:36.675Z" }, + { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856, upload-time = "2025-10-06T20:21:37.873Z" }, + { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308, upload-time = "2025-10-06T20:21:39.577Z" }, + { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697, upload-time = "2025-10-06T20:21:41.154Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375, upload-time = "2025-10-06T20:21:43.201Z" }, ] [[package]] @@ -4338,9 +4316,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, ] [[package]] @@ -4377,18 +4355,18 @@ wheels = [ name = "toml" version = "0.10.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, ] [[package]] name = "tomli" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392 } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408 }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, ] [[package]] @@ -4400,30 +4378,30 @@ dependencies = [ { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681 }, - { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036 }, - { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861 }, - { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222 }, + { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681, upload-time = "2025-11-12T15:19:56.48Z" }, + { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036, upload-time = "2025-11-12T15:21:01.886Z" }, + { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861, upload-time = "2025-11-12T15:21:30.145Z" }, + { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222, upload-time = "2025-11-12T15:20:46.223Z" }, ] [[package]] @@ -4435,9 +4413,9 @@ dependencies = [ { name = "packaging" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144, upload-time = "2023-03-10T22:02:20.455Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162 }, + { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162, upload-time = "2023-03-10T22:02:18.818Z" }, ] [[package]] @@ -4464,20 +4442,20 @@ name = "tqdm" version = "4.67.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, ] [[package]] @@ -4488,9 +4466,9 @@ dependencies = [ { name = "torch" }, { name = "transformers", extra = ["sentencepiece", "torch"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754 } +sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754, upload-time = "2025-06-15T13:34:38.522Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073 }, + { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073, upload-time = "2025-06-15T13:34:37.468Z" }, ] [[package]] @@ -4509,9 +4487,9 @@ dependencies = [ { name = "tokenizers" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680 } +sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680, upload-time = "2025-11-25T15:51:30.139Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463 }, + { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463, upload-time = "2025-11-25T15:51:26.493Z" }, ] [package.optional-dependencies] @@ -4529,8 +4507,7 @@ name = "triton" version = "3.5.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/2e/f95e673222afa2c7f0c687d8913e98fcf2589ef0b1405de76894e37fe18f/triton-3.5.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f63e34dcb32d7bd3a1d0195f60f30d2aee8b08a69a0424189b71017e23dfc3d2", size = 159821655 }, - { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692 }, + { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692, upload-time = "2025-11-11T17:40:46.074Z" }, ] [[package]] @@ -4552,9 +4529,9 @@ wheels = [ name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] @@ -4564,9 +4541,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] @@ -4582,18 +4559,18 @@ wheels = [ name = "unidecode" version = "1.3.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701 } +sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701, upload-time = "2024-01-11T11:58:35.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494 }, + { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494, upload-time = "2024-01-11T11:58:33.012Z" }, ] [[package]] name = "uri-template" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678 } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140 }, + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, ] [[package]] @@ -4621,7 +4598,7 @@ wheels = [ [package.optional-dependencies] standard = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "httptools" }, { name = "python-dotenv" }, { name = "pyyaml" }, @@ -4634,14 +4611,14 @@ standard = [ name = "uvloop" version = "0.22.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250 } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335 }, - { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903 }, - { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499 }, - { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133 }, - { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681 }, - { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261 }, + { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335, upload-time = "2025-10-16T22:16:11.43Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903, upload-time = "2025-10-16T22:16:12.979Z" }, + { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499, upload-time = "2025-10-16T22:16:14.451Z" }, + { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133, upload-time = "2025-10-16T22:16:16.272Z" }, + { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681, upload-time = "2025-10-16T22:16:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261, upload-time = "2025-10-16T22:16:19.596Z" }, ] [[package]] @@ -4654,7 +4631,7 @@ dependencies = [ { name = "platformdirs" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799 } +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095 }, ] @@ -4672,18 +4649,18 @@ wheels = [ name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, ] [[package]] @@ -4693,67 +4670,67 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318 }, - { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478 }, - { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894 }, - { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065 }, - { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377 }, - { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837 }, - { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456 }, - { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614 }, - { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690 }, - { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459 }, - { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663 }, - { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453 }, - { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611 }, - { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889 }, - { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616 }, - { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413 }, + { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318, upload-time = "2025-10-14T15:04:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478, upload-time = "2025-10-14T15:04:20.297Z" }, + { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894, upload-time = "2025-10-14T15:04:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065, upload-time = "2025-10-14T15:04:22.795Z" }, + { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377, upload-time = "2025-10-14T15:04:24.138Z" }, + { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837, upload-time = "2025-10-14T15:04:25.057Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456, upload-time = "2025-10-14T15:04:26.497Z" }, + { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614, upload-time = "2025-10-14T15:04:27.539Z" }, + { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690, upload-time = "2025-10-14T15:04:28.495Z" }, + { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459, upload-time = "2025-10-14T15:04:29.491Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663, upload-time = "2025-10-14T15:04:30.435Z" }, + { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453, upload-time = "2025-10-14T15:04:31.53Z" }, + { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, + { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413, upload-time = "2025-10-14T15:06:09.209Z" }, ] [[package]] name = "wcwidth" version = "0.2.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293 } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286 }, + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, ] [[package]] name = "webcolors" version = "25.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491 } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, ] [[package]] name = "websocket-client" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, ] [[package]] name = "websockets" version = "15.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423 }, { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080 }, @@ -4791,9 +4768,9 @@ wheels = [ name = "widgetsnbextension" version = "4.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503 }, + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, ] [[package]] @@ -4803,59 +4780,59 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581480705f912040172f6570cc12e68a245ba9258c32ef/wikipedia_api-0.8.1.tar.gz", hash = "sha256:b31e93b3f5407c1a1ba413ed7326a05379a3c270df6cf6a211aca67a14c5658b", size = 19934 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581480705f912040172f6570cc12e68a245ba9258c32ef/wikipedia_api-0.8.1.tar.gz", hash = "sha256:b31e93b3f5407c1a1ba413ed7326a05379a3c270df6cf6a211aca67a14c5658b", size = 19934, upload-time = "2025-01-19T23:44:33.488Z" } [[package]] name = "wrapt" version = "2.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040 } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481 }, - { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692 }, - { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574 }, - { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688 }, - { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698 }, - { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096 }, - { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878 }, - { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298 }, - { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361 }, - { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035 }, - { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383 }, - { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894 }, - { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046 }, + { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481, upload-time = "2025-11-07T00:43:11.103Z" }, + { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692, upload-time = "2025-11-07T00:43:13.697Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574, upload-time = "2025-11-07T00:43:14.967Z" }, + { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688, upload-time = "2025-11-07T00:43:18.275Z" }, + { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698, upload-time = "2025-11-07T00:43:19.407Z" }, + { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096, upload-time = "2025-11-07T00:43:16.5Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878, upload-time = "2025-11-07T00:43:20.81Z" }, + { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298, upload-time = "2025-11-07T00:43:22.229Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361, upload-time = "2025-11-07T00:43:24.301Z" }, + { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035, upload-time = "2025-11-07T00:43:28.96Z" }, + { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383, upload-time = "2025-11-07T00:43:25.804Z" }, + { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894, upload-time = "2025-11-07T00:43:27.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, ] [[package]] name = "xmltodict" version = "0.14.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942 } +sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942, upload-time = "2024-10-16T06:10:29.683Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981 }, + { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981, upload-time = "2024-10-16T06:10:27.649Z" }, ] [[package]] name = "xxhash" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160 } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845 }, - { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807 }, - { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786 }, - { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830 }, - { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606 }, - { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872 }, - { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217 }, - { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139 }, - { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669 }, - { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018 }, - { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058 }, - { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628 }, - { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577 }, - { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487 }, - { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863 }, + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, ] [[package]] @@ -4867,32 +4844,32 @@ dependencies = [ { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169 } +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517 }, - { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495 }, - { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400 }, - { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545 }, - { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598 }, - { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893 }, - { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240 }, - { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965 }, - { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026 }, - { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637 }, - { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082 }, - { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811 }, - { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223 }, - { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118 }, - { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852 }, - { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012 }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] [[package]] name = "zipp" version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, ] From 4f844a2c348a7541b4cc9c82c8b20c5b752b78b0 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Tue, 10 Feb 2026 10:54:02 -0300 Subject: [PATCH 032/104] Endpoint /disambiguate with LLM Inference (#72) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Changes in old 07 notebook adding the usage of the disambiguate endpoint and its own name * New token counter to check if the LLM inference won't allucinate * New tokenizer function for token counting and proessing specifics documents * Batch optimization feature in llm-inference function * Mapping feature added to llm-inference function * Updated the /disambiguate endpoint to return DocumentAnnotations similar to the NER predictions, now enriched with role and entity_id fields where applicable. * New /disambiguatev2 endpoint which makes the LLM inference and return the DocumentAnnotations list with the role and the canonincal_entity_id where applicable. When there is a prediction that wasn't mapped the program generates a canonical_entity_id * New /disambiguatev2 endpoint which makes the LLM inference and return the DocumentAnnotations list with the role and the canonincal_entity_id where applicable. When there is a prediction that wasn't mapped the program generates a canonical_entity_id * New /disambiguatev2 endpoint which makes the LLM inference and return the DocumentAnnotations list with the role and the canonincal_entity_id where applicable. When there is a prediction that wasn't mapped the program generates a canonical_entity_id * New updates on endpoint /disambiguatev2 and notebook 07 * Cleaned code in anonymizer.py and utils.py following Raúl comments * New classes defined for LLM prompts to validate each set of prompts per label before the LLM inference * Sorted canonical entities before LLM inference to avoid (or trying to) processing two or more canonical entities that are only one in separate batches * Cleaned anonymizer.py script and experimental notebook 07 discarding the old pre-cluster endpoint. * Cleaned anonymizer.py script and experimental notebook 07 discarding the old pre-cluster endpoint. * Cleaned anonymizer.py script and experimental notebook 07 discarding the old pre-cluster endpoint. New disambiguation.py script to store functions to pre-clusterize the canonical entities. * Cleaned anonymizer.py script and experimental notebook 07 discarding the old pre-cluster endpoint. New disambiguation.py script to store functions to pre-clusterize the canonical entities. * Code cleaned following Juli's comments regarding the new /disambiguate endpoint * Remove unused relations field from CanonicalEntity class for LLM inference phase * Final changes to the code adding the entity_disambiguation.yaml to handle the prompts * Add entity disambiguation utilities and enhance canonical entity processing - Introduced new utility functions for entity disambiguation in `fuzzy.py`. - Implemented `assign_label_instances` and `map_canonical_entities_ner_preds` in `core.py`. - Added LLM inference capabilities in `llm.py` for refining canonical entities. - Updated `entities.py` to include `aymurai_label_instance` for ordered label indexing. * Refactor anonymizer and paragraph modules for improved entity disambiguation and serialization * Remove unused logger import from paragraph module * Reviewed code and added some features to 07 experiment notebook * Implement label policies for disambiguation and anonymization; enhance entity processing and prediction mapping * New datetime formatter function and changes in old code, there is a bug with my OS that unsupports the setlocale * New functioanlity added to get_canonical_dates for dates with the same day and month * New functioanlity added to get_canonical_dates for dates with the same day and month * 🐛 Fix entity handling in anonymizer and datapublic routers when use_cache is disabled to improve label processing * Remove commented-out code * DatetimeFormatter used after NER predictions in postprocess so we only have to take the datetime from aymurai_label_subclass to build the canonical entities from dates * Fix locale setting for date formatting to ensure correct month name handling * Add docstring for get_canonical_dates function to clarify input and output * Remove DIRECCION prompt templates * Update notebook formatting, remove unused MODE param and improve code readability * Update uv.lock --- .env.common | 2 +- .../routers/anonymizer/anonymizer.py | 384 +++- .../api/endpoints/routers/anonymizer/utils.py | 212 -- .../routers/datapublic/datapublic.py | 9 +- .../database/crud/anonymization/paragraph.py | 110 +- aymurai/meta/api_interfaces.py | 28 + aymurai/meta/entities.py | 18 +- aymurai/settings.py | 27 + .../transforms/datetime_formatter/__init__.py | 1 + aymurai/transforms/datetime_formatter/core.py | 4 +- .../transforms/datetime_formatter/patterns.py | 7 + .../utils/entity_disambiguation/__init__.py | 21 + aymurai/utils/entity_disambiguation/core.py | 128 ++ .../entity_disambiguation/date_formatter.py | 45 + aymurai/utils/entity_disambiguation/fuzzy.py | 199 ++ aymurai/utils/entity_disambiguation/llm.py | 379 ++++ .../07-LLM-entities-disambiguation.ipynb | 1713 +++++++++++++++ .../07-PER-entities-disambiguation.ipynb | 1487 ------------- .../08-disambiguation-endpoint-smoke.ipynb | 300 ++- .../09-date-formatter-disambiguation.ipynb | 360 +++ resources/llm/entity_disambiguation.yml | 69 + .../production/flair-anonymizer/pipeline.json | 4 + uv.lock | 1949 +++++++++-------- 23 files changed, 4690 insertions(+), 2766 deletions(-) delete mode 100644 aymurai/api/endpoints/routers/anonymizer/utils.py create mode 100644 aymurai/utils/entity_disambiguation/__init__.py create mode 100644 aymurai/utils/entity_disambiguation/core.py create mode 100644 aymurai/utils/entity_disambiguation/date_formatter.py create mode 100644 aymurai/utils/entity_disambiguation/fuzzy.py create mode 100644 aymurai/utils/entity_disambiguation/llm.py create mode 100644 notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb delete mode 100644 notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb create mode 100644 notebooks/experiments/entity-disambiguation/09-date-formatter-disambiguation.ipynb create mode 100644 resources/llm/entity_disambiguation.yml diff --git a/.env.common b/.env.common index 38601115..25d41bb8 100644 --- a/.env.common +++ b/.env.common @@ -16,4 +16,4 @@ MLFLOW_TRACKING_URI=http://localhost:5000 MLFLOW_S3_ENDPOINT_URL=http://localhost:9002 MLFLOW_S3_IGNORE_TLS=true MLFLOW_EXPERIMENT_NAME=entity-disambiguation -MLFLOW_ARTIFACT_ROOT=s3://mlflow/artifacts +MLFLOW_ARTIFACT_ROOT=s3://mlflow/artifacts \ No newline at end of file diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 63025082..dc7f3d56 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -5,18 +5,12 @@ from threading import Lock import torch -from fastapi import Body, Depends, Form, HTTPException, Query, UploadFile +from fastapi import Body, Depends, Form, Query, UploadFile from fastapi.responses import FileResponse from fastapi.routing import APIRouter from sqlmodel import Session from starlette.background import BackgroundTask -from aymurai.api.endpoints.routers.anonymizer.utils import ( - PROCESSOR_MAP, - SCORER_MAP, - build_canonical_entities, - resolve_processor, -) from aymurai.api.utils import load_pipeline from aymurai.database.crud.anonymization.document import anonymization_document_create from aymurai.database.crud.anonymization.paragraph import ( @@ -24,7 +18,7 @@ anonymization_paragraph_create, anonymization_paragraph_read, ) -from aymurai.database.schema import AnonymizationParagraph +from aymurai.database.schema import AnonymizationParagraph, AnonymizationParagraphCreate from aymurai.database.session import get_session from aymurai.database.utils import data_to_uuid, text_to_uuid from aymurai.logger import get_logger @@ -32,12 +26,20 @@ DocLabel, DocumentAnnotations, DocumentInformation, + LabelPolicy, + PromptLibrary, TextRequest, ) -from aymurai.meta.entities import CanonicalEntities from aymurai.settings import settings from aymurai.text.anonymization import DocAnonymizer from aymurai.text.extraction import MIMETYPE_EXTENSION_MAPPER +from aymurai.utils.entity_disambiguation import ( + build_canonical_entities, + get_canonical_dates, + llm_canonical_entities_inference, + load_prompts_from_yaml, + map_canonical_entities_ner_preds, +) from aymurai.utils.misc import get_element logger = get_logger(__name__) @@ -51,6 +53,100 @@ router = APIRouter() +def _entities_to_doclabels(entities: list[dict]) -> list[DocLabel]: + """ + Convert raw entities to DocLabel objects. + + Args: + entities (list[dict]): List of entity dictionaries. + + Returns: + list[DocLabel]: List of DocLabel objects. + """ + doclabels: list[DocLabel] = [] + + for ent in entities: + try: + doclabels.append( + DocLabel.model_validate( + { + "text": ent.get("text", ""), + "start_char": ent.get("start_char"), + "end_char": ent.get("end_char"), + "attrs": ent.get("attrs", {}), + } + ) + ) + except Exception as exc: # keep going if a single entity is malformed + logger.warning(f"Skipping invalid entity for DocLabel: {exc}") + + return doclabels + + +def _merge_label_policies( + request_policies: dict[str, LabelPolicy] | None, +) -> dict[str, LabelPolicy]: + """ + Merges label policies from settings and request, with request policies taking precedence. + + Args: + request_policies (dict[str, LabelPolicy] | None): Per-label policies provided in the request body. + + Returns: + dict[str, LabelPolicy]: Effective per-label policies after merging settings and request policies. + """ + policies: dict[str, LabelPolicy] = {} + + if settings.DISAMBIGUATION_LABEL_POLICIES: + for label, policy in settings.DISAMBIGUATION_LABEL_POLICIES.items(): + incoming = LabelPolicy.model_validate(policy) + current = policies.get(label, LabelPolicy()) + if incoming.disambiguation is not None: + current.disambiguation = incoming.disambiguation + if incoming.anonymize is not None: + current.anonymize = incoming.anonymize + policies[label] = current + + if request_policies: + for label, policy in request_policies.items(): + incoming = LabelPolicy.model_validate(policy) + current = policies.get(label, LabelPolicy()) + if incoming.disambiguation is not None: + current.disambiguation = incoming.disambiguation + if incoming.anonymize is not None: + current.anonymize = incoming.anonymize + policies[label] = current + + return policies + + +def _should_anonymize_label( + label: DocLabel, + label_policies: dict[str, LabelPolicy], +) -> bool: + """ + Determines whether a given label should be anonymized based on its attributes and the effective label policies. + + Args: + label (DocLabel): The document label to evaluate for anonymization. + label_policies (dict[str, LabelPolicy]): Effective per-label policies that may override default anonymization behavior. + + Returns: + bool: True if the label should be anonymized, False otherwise. + """ + if label.attrs and label.attrs.aymurai_anonymize is not None: + return bool(label.attrs.aymurai_anonymize) + + policy = label_policies.get(label.attrs.aymurai_label) if label.attrs else None + if policy is None: + return True + + if policy.anonymize is None: + return True + + return bool(policy.anonymize) + + # MARK: Predict @router.post("/predict", response_model=DocumentInformation) async def anonymizer_paragraph_predict( @@ -85,8 +181,8 @@ async def anonymizer_paragraph_predict( logger.info(f"cache loaded from key: {paragraph_id}") logger.debug(f"{cached_prediction}") - labels = cached_prediction.prediction - return DocumentInformation(document=cached_prediction.text, labels=labels or []) + labels = _entities_to_doclabels(cached_prediction.prediction or []) + return DocumentInformation(document=cached_prediction.text, labels=labels) logger.info("Running prediction") item = [{"path": "empty", "data": {"doc.text": text_request.text}}] @@ -100,21 +196,22 @@ async def anonymizer_paragraph_predict( processed = pipeline.postprocess([processed]) text = get_element(processed[0], ["data", "doc.text"]) or "" - labels = get_element(processed[0], ["predictions", "entities"]) or [] + raw_entities = get_element(processed[0], ["predictions", "entities"]) or [] + labels = _entities_to_doclabels(raw_entities) if use_cache: logger.info(f"saving in cache: {paragraph_id}") - paragraph = AnonymizationParagraph( - id=paragraph_id, + paragraph = AnonymizationParagraphCreate( text=text, prediction=labels, ) paragraph = anonymization_paragraph_create(paragraph, session=session) - return DocumentInformation(document=text, labels=paragraph.prediction) + return DocumentInformation(document=text, labels=labels) -@router.post("/disambiguate", response_model=CanonicalEntities) +# MARK: Disambiguate +@router.post("/disambiguate", response_model=DocumentAnnotations) async def anonymizer_disambiguate( paragraphs: list[DocumentInformation] = Body( ..., @@ -122,51 +219,215 @@ async def anonymizer_disambiguate( "List of per-paragraph predictions returned by /anonymizer/predict." ), ), + custom_prompts: PromptLibrary = Body( + default_factory=PromptLibrary, + description=( + "Set of prompts, user and system, for each label if it is provided." + ), + ), + label_policies: dict[str, LabelPolicy] + | None = Body( + None, + description=( + "Optional per-label policy overrides for disambiguation/anonymization." + ), + ), target_labels: list[str] | None = Query( None, - description="Optional label filter, e.g. PER,DNI.", - ), - threshold: int = Query( - 70, - description="Minimum similarity score (0-100) to cluster entities.", - ), - scorer: str = Query( - "token_set_ratio", - description="RapidFuzz scorer name for similarity.", - ), - processor: str = Query( - "light_normalizer", - description="Text processor to normalize before similarity.", + description=( + "Optional label filter for LLM refinement (e.g., PER,DNI). " + "Fuzzy clustering still runs across all detected labels." + ), ), -) -> CanonicalEntities: + session: Session = Depends(get_session), +) -> DocumentAnnotations: """ - Prototype endpoint for canonical entity grouping using fuzzy matching. + Performs canonical entity disambiguation using fuzzy matching and LLM refinement. + + Args: + paragraphs: A list of DocumentInformation objects containing the NER + predictions per paragraph that need to be disambiguated. + custom_prompts: A PromptLibrary object containing optional system and + user prompts. If not provided, the service uses the default prompts + configured in the environment. + label_policies: Optional per-label disambiguation/anonymization policies. + target_labels: An optional list of entity labels to refine via LLM + (e.g., ["PER", "DNI"]). Fuzzy clustering still runs across all + detected labels. + Returns: + DocumentAnnotations: The original annotations enriched with + 'canonical_entity_id' and 'role' fields for each resolved mention. """ - if threshold < 0 or threshold > 100: - raise HTTPException(status_code=400, detail="threshold must be 0-100.") + logger.info( + "disambiguation start: paragraphs=%d", + len(paragraphs), + ) + + labels = [label for paragraph in paragraphs for label in (paragraph.labels or [])] + effective_policies = _merge_label_policies(label_policies) + logger.info("disambiguation labels: %d", len(labels)) - scorer_fn = SCORER_MAP.get(scorer.lower()) - if scorer_fn is None: - raise HTTPException(status_code=400, detail=f"Unsupported scorer: {scorer}") + prompt_library = load_prompts_from_yaml() + + all_detected_labels = { + label.attrs.aymurai_label + for label in labels + if label.attrs and label.attrs.aymurai_label + } + + default_llm_labels = ( + target_labels if target_labels else list(prompt_library.as_dict.keys()) + ) + + llm_labels: list[str] = [] + fuzzy_labels: set[str] = set() + + for label in all_detected_labels: + policy = effective_policies.get(label) + if policy and policy.disambiguation == "llm": + llm_labels.append(label) + fuzzy_labels.add(label) + continue + if policy and policy.disambiguation == "fuzzy": + fuzzy_labels.add(label) + continue + if policy and policy.disambiguation == "none": + continue + + if label in default_llm_labels: + llm_labels.append(label) + fuzzy_labels.add(label) + else: + fuzzy_labels.add(label) + + effective_disambiguation_by_label: dict[str, str] = {} + for label in all_detected_labels: + if label in llm_labels: + effective_disambiguation_by_label[label] = "llm" + elif label in fuzzy_labels: + effective_disambiguation_by_label[label] = "fuzzy" + else: + effective_disambiguation_by_label[label] = "none" + logger.info( + "disambiguation targets: detected=%s llm=%s", + sorted(all_detected_labels), + llm_labels, + ) - if processor.lower() not in PROCESSOR_MAP: - raise HTTPException( - status_code=400, detail=f"Unsupported processor: {processor}" + canonical_entities = ( + build_canonical_entities( + labels, + target_labels=[label for label in fuzzy_labels if label != "FECHA"] + if fuzzy_labels + else None, + threshold=settings.THRESHOLD, ) - processor_fn = resolve_processor(processor) + if fuzzy_labels + else [] + ) - labels = [label for paragraph in paragraphs for label in (paragraph.labels or [])] + canonical_entities += get_canonical_dates(labels=labels) + + logger.info( + "fuzzy clustering produced %d canonical entities", len(canonical_entities) + ) + + # --- LLM REFINEMENT (policy-driven) --- + canonical_entities_llm = [] + + for label in llm_labels: + logger.info("llm refinement: label=%s", label) + prompt_set = custom_prompts.get(label) or prompt_library.get(label) + + if ( + not prompt_set + or not prompt_set.system.strip() + or not prompt_set.user.strip() + ): + logger.info("llm refinement skipped: missing prompt for label=%s", label) + continue + + entities_for_this_label = [ + e for e in canonical_entities if e.aymurai_label == label + ] + + if not entities_for_this_label: + logger.info("llm refinement skipped: no entities for label=%s", label) + continue + logger.info( + "llm refinement input: label=%s entities=%d", + label, + len(entities_for_this_label), + ) - target_set = {label.strip() for label in target_labels} if target_labels else None - canonical_entities = build_canonical_entities( - labels, - target_labels=target_set, - threshold=threshold, - scorer=scorer_fn, - processor=processor_fn, + llm_response = llm_canonical_entities_inference( + paragraphs=paragraphs, + canonical_entities_pre_cluster=entities_for_this_label, + system_prompt=prompt_set.system, + user_prompt_template=prompt_set.user, + model=settings.MODEL, + context_window_length=settings.CONTEXT_WINDOW_LENGTH, + model_context=settings.MODEL_CONTEXT, + token_limit_frac=settings.TOKEN_LIMIT_FRAC, + tokenizer_model=settings.TOKENIZER_MODEL, + target_label=label, + temperature=settings.TEMPERATURE, + decompose_by=settings.DECOMPOSE_BY, + ) + + if llm_response: + canonical_entities_llm.extend(llm_response) + logger.info( + "llm refinement output: label=%s entities=%d", + label, + len(llm_response), + ) + + canonical_entities_merged = canonical_entities_llm + [ + ce for ce in canonical_entities if ce.aymurai_label not in set(llm_labels) + ] + logger.info( + "disambiguation merge: llm=%d fuzzy_only=%d total=%d", + len(canonical_entities_llm), + len(canonical_entities_merged) - len(canonical_entities_llm), + len(canonical_entities_merged), + ) + + predictions = map_canonical_entities_ner_preds( + predictions=paragraphs, + canonical_entities=canonical_entities_merged, + force_labels=set(llm_labels), + ) + + for document in predictions: + for label in document.labels or []: + label.attrs.aymurai_disambiguation = effective_disambiguation_by_label.get( + label.attrs.aymurai_label, "fuzzy" + ) + + policy = effective_policies.get(label.attrs.aymurai_label) + label.attrs.aymurai_anonymize = ( + policy.anonymize if policy and policy.anonymize is not None else True + ) + + paragraph_updates = [ + AnonymizationParagraphCreate( + text=paragraph.document, + prediction=paragraph.labels or [], + ) + for paragraph in predictions + ] + anonymization_paragraph_batch_create_update(paragraph_updates, session=session) + logger.info( + "disambiguation persisted predictions for %d paragraphs", + len(paragraph_updates), + ) + + return DocumentAnnotations( + data=predictions, + label_policies=effective_policies if effective_policies else None, ) - return CanonicalEntities(canonical_entities=canonical_entities) # MARK: Validate @@ -241,12 +502,12 @@ async def anonymizer_compile_document( annots_json = json.loads(annotations) annots = DocumentAnnotations.model_validate(annots_json) logger.info(f"processing annotations => {annots}") + effective_policies = _merge_label_policies(annots.label_policies) # Add paragraphs to the database # validation MUST be at least an empty list, to remember user feedback paragraphs = [ - AnonymizationParagraph( - id=text_to_uuid(paragraph.document), + AnonymizationParagraphCreate( text=paragraph.document, validation=paragraph.labels or [], ) @@ -267,11 +528,28 @@ async def anonymizer_compile_document( # Anonymize the document doc_anonymizer = DocAnonymizer() + filtered_annotations = [] + for paragraph in annots.data: + filtered_labels = [ + label + for label in (paragraph.labels or []) + if _should_anonymize_label(label, effective_policies) + ] + filtered_annotations.append( + DocumentInformation( + document=paragraph.document, + labels=filtered_labels, + ) + ) + if suffix == ".docx": item = {"path": tmp_filename} doc_anonymizer( item, - [document_information.model_dump() for document_information in annots.data], + [ + document_information.model_dump() + for document_information in filtered_annotations + ], tmp_dir, ) logger.info(f"saved temp file on local storage => {tmp_filename}") @@ -282,7 +560,7 @@ async def anonymizer_compile_document( doc_anonymizer.replace_labels_in_text(document_information.model_dump()) .replace("<", "<") .replace(">", ">") - for document_information in annots.data + for document_information in filtered_annotations ] with open(tmp_filename, "w") as f: f.write("\n".join(anonymized_doc)) diff --git a/aymurai/api/endpoints/routers/anonymizer/utils.py b/aymurai/api/endpoints/routers/anonymizer/utils.py deleted file mode 100644 index 9c25cea2..00000000 --- a/aymurai/api/endpoints/routers/anonymizer/utils.py +++ /dev/null @@ -1,212 +0,0 @@ -import re -import unicodedata -from collections import Counter -from typing import Callable, Iterable - -from rapidfuzz import process -from rapidfuzz.fuzz import ( - WRatio, - partial_ratio, - partial_token_set_ratio, - partial_token_sort_ratio, - ratio, - token_set_ratio, - token_sort_ratio, -) - -from aymurai.meta.api_interfaces import DocLabel -from aymurai.meta.entities import CanonicalEntity - -__all__ = [ - "SCORER_MAP", - "PROCESSOR_MAP", - "build_canonical_entities", - "resolve_processor", -] - -SCORER_MAP = { - "ratio": ratio, - "partial_ratio": partial_ratio, - "token_sort_ratio": token_sort_ratio, - "token_set_ratio": token_set_ratio, - "partial_token_set_ratio": partial_token_set_ratio, - "partial_token_sort_ratio": partial_token_sort_ratio, - "wratio": WRatio, -} - -PROCESSOR_MAP = { - "none": None, - "light_normalizer": "light_normalizer", - "hard_normalizer": "hard_normalizer", - "legal_text_normalizer": "legal_text_normalizer", -} - - -def hard_normalizer(text: str) -> str: - if not text: - return "" - - normalized = "".join( - char - for char in unicodedata.normalize("NFD", text) - if unicodedata.category(char) != "Mn" - ) - normalized = re.sub(r"[.,\-]", " ", normalized) - normalized = " ".join(normalized.lower().split()) - return normalized - - -def light_normalizer(text: str) -> str: - return text.lower().strip() if text else "" - - -def legal_text_normalizer(text: str) -> str: - if not text: - return "" - - normalized = "".join( - char - for char in unicodedata.normalize("NFD", text) - if unicodedata.category(char) != "Mn" - ) - normalized = normalized.lower() - - legal_titles = r"\b(dr|dra|sr|sra|expte|nro|no|pcia)\b\.?" - normalized = re.sub(legal_titles, "", normalized) - - stopwords = r"\b(de|del|la|las|el|los|y|en)\b" - normalized = re.sub(stopwords, "", normalized) - normalized = re.sub(r"[^\w\s]", "", normalized) - - return " ".join(normalized.split()) - - -def resolve_processor(name: str) -> Callable[[str], str] | None: - key = name.lower() - mapped = PROCESSOR_MAP.get(key) - if mapped is None: - return None - if mapped == "light_normalizer": - return light_normalizer - if mapped == "hard_normalizer": - return hard_normalizer - if mapped == "legal_text_normalizer": - return legal_text_normalizer - return None - - -def cluster_with_cdist( - *, - items: list[dict[str, str]], - threshold: int, - scorer: Callable[[str, str], float], - processor: Callable[[str], str] | None, -) -> list[list[tuple[str, str, str]]]: - if not items: - return [] - - entities = [item.get("text", "") for item in items] - labels = [item.get("aymurai_label", "UNKNOWN") for item in items] - - if processor: - normed = [processor(entity) for entity in entities] - else: - normed = [str(entity) for entity in entities] - - sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold) - - parent = list(range(len(normed))) - - def find(idx: int) -> int: - if parent[idx] == idx: - return idx - parent[idx] = find(parent[idx]) - return parent[idx] - - def union(left: int, right: int) -> None: - root_left, root_right = find(left), find(right) - if root_left != root_right: - parent[root_right] = root_left - - n = len(normed) - for i in range(n): - for j in range(i + 1, n): - if sim[i][j] >= threshold: - union(i, j) - - clusters_map: dict[int, list[tuple[str, str, str]]] = {} - for idx in range(n): - root = find(idx) - clusters_map.setdefault(root, []).append( - (entities[idx], normed[idx], labels[idx]) - ) - - return list(clusters_map.values()) - - -def parse_item(item: tuple[str, str, str]) -> tuple[str, str, str]: - orig, norm, label = item - return label, orig, norm - - -def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str: - labels = [label for label, _, _ in parsed_items] - return Counter(labels).most_common(1)[0][0] - - -def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str: - return max(parsed_items, key=lambda item: len(item[1]))[1] - - -def clusters_to_canonical_entities( - clusters: list[list[tuple[str, str, str]]], -) -> list[CanonicalEntity]: - canonical_entities = [] - for cluster in clusters: - parsed = [parse_item(item) for item in cluster] - label = pick_cluster_label(parsed) - canonical_text = pick_canonical_text(parsed) - aliases = sorted({orig for _, orig, _ in parsed}) - canonical_entities.append( - CanonicalEntity( - aymurai_label=label, - canonical_text=canonical_text, - aliases=aliases, - attributes={}, - relations=[], - ) - ) - return canonical_entities - - -def build_canonical_entities( - labels: Iterable[DocLabel], - *, - target_labels: set[str] | None = None, - threshold: int, - scorer: Callable[[str, str], float], - processor: Callable[[str], str] | None, -) -> list[CanonicalEntity]: - grouped: dict[str, list[dict[str, str]]] = {} - for label in labels: - attrs = label.attrs - if not attrs or not attrs.aymurai_label: - continue - if target_labels and attrs.aymurai_label not in target_labels: - continue - alias = attrs.aymurai_alt_text or label.text - grouped.setdefault(attrs.aymurai_label, []).append( - {"text": alias, "aymurai_label": attrs.aymurai_label} - ) - - canonical_entities = [] - for items in grouped.values(): - clusters = cluster_with_cdist( - items=items, - threshold=threshold, - scorer=scorer, - processor=processor, - ) - canonical_entities.extend(clusters_to_canonical_entities(clusters)) - - return canonical_entities diff --git a/aymurai/api/endpoints/routers/datapublic/datapublic.py b/aymurai/api/endpoints/routers/datapublic/datapublic.py index b83ae0d0..62af6761 100644 --- a/aymurai/api/endpoints/routers/datapublic/datapublic.py +++ b/aymurai/api/endpoints/routers/datapublic/datapublic.py @@ -2,16 +2,16 @@ from threading import Lock import torch -from fastapi import Body, Depends, Query, HTTPException +from fastapi import Body, Depends, HTTPException, Query from fastapi.routing import APIRouter from pydantic import UUID5 from sqlmodel import Session from aymurai.api.utils import load_pipeline from aymurai.database.schema import ( - DataPublicParagraph, DataPublicDocument, DataPublicDocumentParagraph, + DataPublicParagraph, ) from aymurai.database.session import get_session from aymurai.database.utils import text_to_uuid @@ -72,6 +72,7 @@ async def predict_over_text( text = get_element(processed[0], ["data", "doc.text"]) or "" labels = get_element(processed[0], ["predictions", "entities"]) or [] + paragraph: DataPublicParagraph | None = None if use_cache: logger.info(f"saving in cache: {paragraph_id}") @@ -92,7 +93,9 @@ async def predict_over_text( # paragraph = datapublic_paragraph_create(paragraph, session=session) - return DocumentInformation(document=text, labels=paragraph.prediction) + return DocumentInformation( + document=text, labels=paragraph.prediction if paragraph else labels + ) # MARK: Validate Paragraph diff --git a/aymurai/database/crud/anonymization/paragraph.py b/aymurai/database/crud/anonymization/paragraph.py index 593ebbdc..1d169036 100644 --- a/aymurai/database/crud/anonymization/paragraph.py +++ b/aymurai/database/crud/anonymization/paragraph.py @@ -1,5 +1,6 @@ import uuid +from pydantic import TypeAdapter from sqlmodel import Session from aymurai.database.schema import ( @@ -8,9 +9,42 @@ AnonymizationParagraphUpdate, ) from aymurai.database.utils import text_to_uuid -from aymurai.logger import get_logger +from aymurai.meta.api_interfaces import DocLabel -logger = get_logger(__name__) + +_DOC_LABELS_ADAPTER = TypeAdapter(list[DocLabel]) + + +def _serialize_doclabels(value: list[DocLabel] | None): + """ + Serializes DocLabel objects into JSON-compatible data structures. + + Args: + value (list[DocLabel] | None): DocLabel list to serialize. + + Returns: + list[dict] | None: JSON-safe list of labels, or None if input is None. + """ + if value is None: + return None + return _DOC_LABELS_ADAPTER.dump_python(value, mode="json") + + +def _normalize_paragraph_payload(payload: dict) -> dict: + """ + Normalizes paragraph payload fields for JSON storage. + + Args: + payload (dict): Paragraph payload possibly containing DocLabel objects. + + Returns: + dict: Payload with JSON-serializable prediction/validation fields. + """ + if "prediction" in payload: + payload["prediction"] = _serialize_doclabels(payload.get("prediction")) + if "validation" in payload: + payload["validation"] = _serialize_doclabels(payload.get("validation")) + return payload def anonymization_paragraph_create( @@ -18,7 +52,19 @@ def anonymization_paragraph_create( session: Session, override: bool = False, ) -> AnonymizationParagraph: - new_paragraph = AnonymizationParagraph(**paragraph_in.model_dump()) + """ + Creates a new anonymization paragraph record. + + Args: + paragraph_in (AnonymizationParagraphCreate): Paragraph creation payload. + session (Session): Database session. + override (bool): If True, delete any existing paragraph with the same ID. + + Returns: + AnonymizationParagraph: The persisted paragraph record. + """ + payload = _normalize_paragraph_payload(paragraph_in.model_dump()) + new_paragraph = AnonymizationParagraph(**payload) if override: existing = session.get(AnonymizationParagraph, new_paragraph.id) @@ -36,6 +82,16 @@ def anonymization_paragraph_read( paragraph_id: uuid.UUID, session: Session, ) -> AnonymizationParagraph | None: + """ + Reads a paragraph record by ID. + + Args: + paragraph_id (uuid.UUID): Paragraph UUID. + session (Session): Database session. + + Returns: + AnonymizationParagraph | None: Paragraph record if found. + """ return session.get(AnonymizationParagraph, paragraph_id) @@ -44,12 +100,26 @@ def anonymization_paragraph_update( paragraph_in: AnonymizationParagraphUpdate, session: Session, ) -> AnonymizationParagraph: + """ + Updates an existing paragraph record. + + Args: + paragraph_id (uuid.UUID): Paragraph UUID to update. + paragraph_in (AnonymizationParagraphUpdate): Update payload. + session (Session): Database session. + + Returns: + AnonymizationParagraph: The updated paragraph record. + """ paragraph = session.get(AnonymizationParagraph, paragraph_id) if not paragraph: raise ValueError(f"Paragraph not found: {paragraph_id}") - for field, value in paragraph_in.model_dump(exclude_none=True).items(): + payload = _normalize_paragraph_payload( + paragraph_in.model_dump(exclude_none=True, mode="json") + ) + for field, value in payload.items(): setattr(paragraph, field, value) session.add(paragraph) @@ -59,6 +129,16 @@ def anonymization_paragraph_update( def anonymization_paragraph_delete(paragraph_id: uuid.UUID, session: Session): + """ + Deletes a paragraph record by ID. + + Args: + paragraph_id (uuid.UUID): Paragraph UUID to delete. + session (Session): Database session. + + Returns: + None + """ paragraph = session.get(AnonymizationParagraph, paragraph_id) if not paragraph: @@ -74,6 +154,16 @@ def anonymization_paragraph_delete(paragraph_id: uuid.UUID, session: Session): def anonymization_paragraph_batch_create_update( paragraphs_in: list[AnonymizationParagraphCreate], session: Session ) -> list[AnonymizationParagraph]: + """ + Creates or updates a batch of paragraph records. + + Args: + paragraphs_in (list[AnonymizationParagraphCreate]): Paragraph payloads. + session (Session): Database session. + + Returns: + list[AnonymizationParagraph]: Persisted paragraph records. + """ paragraphs = [] for p_in in paragraphs_in: @@ -81,13 +171,15 @@ def anonymization_paragraph_batch_create_update( paragraph = session.get(AnonymizationParagraph, paragraph_id) if paragraph: - update = AnonymizationParagraphUpdate(**p_in.model_dump()) - - for field, value in update.model_dump(exclude_none=True).items(): - setattr(paragraph, field, value) + payload = _normalize_paragraph_payload(p_in.model_dump()) + payload.pop("id", None) + for field, value in payload.items(): + if value is not None: + setattr(paragraph, field, value) else: - paragraph = AnonymizationParagraph(**p_in.model_dump()) + payload = _normalize_paragraph_payload(p_in.model_dump()) + paragraph = AnonymizationParagraph(**payload) session.add(paragraph) session.commit() diff --git a/aymurai/meta/api_interfaces.py b/aymurai/meta/api_interfaces.py index 1ff51443..9fd601ce 100644 --- a/aymurai/meta/api_interfaces.py +++ b/aymurai/meta/api_interfaces.py @@ -1,9 +1,12 @@ import uuid from pydantic import UUID5, BaseModel, Field, RootModel +from typing import Literal from aymurai.meta.entities import EntityAttributes +from functools import cached_property + class SuccessResponse(BaseModel): id: int | uuid.UUID | None = None @@ -42,10 +45,18 @@ class DocumentInformation(BaseModel): labels: list[DocLabel] = Field(default_factory=list) +class LabelPolicy(BaseModel): + """Per-label policy for disambiguation and anonymization.""" + + disambiguation: Literal["none", "fuzzy", "llm"] | None = None + anonymize: bool | None = None + + class DocumentAnnotations(BaseModel): """Datatype for document annotations""" data: list[DocumentInformation] + label_policies: dict[str, LabelPolicy] | None = None class DataPublicDocumentAnnotations(RootModel): @@ -59,3 +70,20 @@ class Document(BaseModel): document_id: UUID5 header: list[str] | None = None footer: list[str] | None = None + + +class PromptSet(BaseModel): + label: str + system: str + user: str + + +class PromptLibrary(RootModel): + root: list[PromptSet] = Field(default_factory=list) + + @cached_property + def as_dict(self) -> dict[str, PromptSet]: + return {p.label: p for p in self.root} + + def get(self, label: str) -> PromptSet | None: + return self.as_dict.get(label) diff --git a/aymurai/meta/entities.py b/aymurai/meta/entities.py index 08eca7ae..871ee462 100644 --- a/aymurai/meta/entities.py +++ b/aymurai/meta/entities.py @@ -32,6 +32,20 @@ class EntityAttributes(BaseModel): description="Method used on the prediction label", ) aymurai_score: float | None = Field(None, description="Score for prediction") + aymurai_label_instance: int | None = Field( + None, + description="Label instance index assigned by order of appearance (e.g., 1, 2, 3).", + ) + aymurai_disambiguation: str | None = Field( + None, + description=( + "Override disambiguation mode for this entity (none, fuzzy, llm)." + ), + ) + aymurai_anonymize: bool | None = Field( + None, + description="Whether this entity should be anonymized in output.", + ) canonical_entity_id: UUID | None = Field( None, description="Reference to the canonical entity ID" ) @@ -103,10 +117,6 @@ class CanonicalEntity(BaseModel): attributes: dict[str, Any] = Field( default_factory=dict, description="Additional metadata for the entity" ) - relations: list[EntityRelation] = Field( - default_factory=list, - description="References to relations involving this entity", - ) @model_validator(mode="after") def validate_entity_id(self) -> CanonicalEntity: diff --git a/aymurai/settings.py b/aymurai/settings.py index 9fdd5331..cfaee728 100644 --- a/aymurai/settings.py +++ b/aymurai/settings.py @@ -1,3 +1,4 @@ +import json import os from pathlib import Path @@ -61,6 +62,32 @@ def assemble_cors_origins(cls, v) -> list[str]: LIBREOFFICE_BIN: str = "libreoffice" + # Disambiguation Config + + # Fuzzy Matching + THRESHOLD: int = 70 + + # LLM + MODEL: str = "phi4:14b" + MODEL_CONTEXT: int = 9500 + TEMPERATURE: float = 0.0 + CONTEXT_WINDOW_LENGTH: int | None = 120 + TOKEN_LIMIT_FRAC: float = 2 / 3 + TOKENIZER_MODEL: str = "microsoft/phi-4" + DECOMPOSE_BY: int | None = None + + # Label policies (JSON dict: label -> {disambiguation, anonymize}) + DISAMBIGUATION_LABEL_POLICIES: dict | None = None + + @field_validator("DISAMBIGUATION_LABEL_POLICIES", mode="before") + @classmethod + def parse_label_policies(cls, v): + if v is None or v == "": + return None + if isinstance(v, str): + return json.loads(v) + return v + load_env() settings = Settings() diff --git a/aymurai/transforms/datetime_formatter/__init__.py b/aymurai/transforms/datetime_formatter/__init__.py index e69de29b..822a1d04 100644 --- a/aymurai/transforms/datetime_formatter/__init__.py +++ b/aymurai/transforms/datetime_formatter/__init__.py @@ -0,0 +1 @@ +from .core import DatetimeFormatter diff --git a/aymurai/transforms/datetime_formatter/core.py b/aymurai/transforms/datetime_formatter/core.py index 8f3c49c9..fbdab7e1 100644 --- a/aymurai/transforms/datetime_formatter/core.py +++ b/aymurai/transforms/datetime_formatter/core.py @@ -55,7 +55,9 @@ def process(self, ent): text_repr = datetime.strftime("%d/%m/%Y") suggestions.append(text_repr) - ent["attrs"]["aymurai_label_subclass"] = suggestions + ent["attrs"]["aymurai_label_subclass"] = ( + [max(suggestions)] if suggestions else [] + ) return ent diff --git a/aymurai/transforms/datetime_formatter/patterns.py b/aymurai/transforms/datetime_formatter/patterns.py index 77bf1d9d..242b04e4 100644 --- a/aymurai/transforms/datetime_formatter/patterns.py +++ b/aymurai/transforms/datetime_formatter/patterns.py @@ -10,7 +10,13 @@ r"%d/%m/%y", r"(?i)%-d de %B del? %Y", r"(?i)%-d de %B %Y", + r"(?i)%-d %B de %Y", + r"(?i)%-d de %B %Y", + r"%d-%m-%Y", + r"%Y-%m-%d", + r"(?i)%-d de %B", ] + HOURS = [ r"%H[\.:]%M", r"(?i)%-H[\.:]%M horas", @@ -19,6 +25,7 @@ patterns = { "FECHA_RESOLUCION": DATES, + "FECHA": DATES, "HORA_DE_INICIO": HOURS, "HORA_DE_CIERRE": HOURS, } diff --git a/aymurai/utils/entity_disambiguation/__init__.py b/aymurai/utils/entity_disambiguation/__init__.py new file mode 100644 index 00000000..0794d1b3 --- /dev/null +++ b/aymurai/utils/entity_disambiguation/__init__.py @@ -0,0 +1,21 @@ +from aymurai.utils.entity_disambiguation.core import ( + assign_label_instances, + map_canonical_entities_ner_preds, +) +from aymurai.utils.entity_disambiguation.fuzzy import ( + build_canonical_entities, +) +from aymurai.utils.entity_disambiguation.llm import ( + llm_canonical_entities_inference, + load_prompts_from_yaml, +) +from aymurai.utils.entity_disambiguation.date_formatter import get_canonical_dates + +__all__ = [ + "assign_label_instances", + "build_canonical_entities", + "llm_canonical_entities_inference", + "map_canonical_entities_ner_preds", + "load_prompts_from_yaml", + "get_canonical_dates", +] diff --git a/aymurai/utils/entity_disambiguation/core.py b/aymurai/utils/entity_disambiguation/core.py new file mode 100644 index 00000000..085d94de --- /dev/null +++ b/aymurai/utils/entity_disambiguation/core.py @@ -0,0 +1,128 @@ +import copy +import uuid + +from aymurai.meta.api_interfaces import DocumentAnnotations +from aymurai.meta.entities import CanonicalEntities + + +def assign_label_instances( + predictions: DocumentAnnotations, +) -> DocumentAnnotations: + """ + Assigns ordered label instance indices (e.g., 1, 2) by appearance. + + Args: + predictions (DocumentAnnotations): Predictions with canonical IDs assigned. + + Returns: + DocumentAnnotations: Updated predictions with `aymurai_label_instance`. + """ + predictions_with_instances = copy.deepcopy(predictions) + + next_index_by_label: dict[str, int] = {} + instance_by_label_and_id: dict[tuple[str, str], int] = {} + + for document in predictions_with_instances: + if not document.labels: + continue + + for label in document.labels: + label_name = label.attrs.aymurai_label + entity_id = label.attrs.canonical_entity_id + + if not label_name or entity_id is None: + continue + + key = (label_name, str(entity_id)) + if key not in instance_by_label_and_id: + next_index_by_label[label_name] = ( + next_index_by_label.get(label_name, 0) + 1 + ) + instance_by_label_and_id[key] = next_index_by_label[label_name] + + label.attrs.aymurai_label_instance = instance_by_label_and_id[key] + + return predictions_with_instances + + +def map_canonical_entities_ner_preds( + predictions: DocumentAnnotations, + canonical_entities: CanonicalEntities, + *, + include_label_instances: bool = True, + force_labels: set[str] | None = None, +) -> DocumentAnnotations: + """ + Applies canonical entity IDs and roles back onto NER predictions. + + Args: + predictions (DocumentAnnotations): Original predictions to update. + canonical_entities (CanonicalEntities): Canonical entities with IDs/roles. + include_label_instances (bool): Whether to assign ordered label instance + indices (e.g., 1, 2). Defaults to True. + force_labels (set[str] | None): Labels to remap even if a canonical ID + already exists. + + Returns: + DocumentAnnotations: Updated predictions with canonical IDs, roles, and + optionally `aymurai_label_instance`. + """ + predictions_mapped = copy.deepcopy(predictions) + force_labels = force_labels or set() + + new_ids_map = {} + + for document in predictions_mapped: + if not document.labels: + continue + + for label in document.labels: + if not label.attrs: + continue + + if label.attrs.aymurai_label_subclass is None: + label.attrs.aymurai_label_subclass = [] + + force_remap = label.attrs.aymurai_label in force_labels + if force_remap: + label.attrs.canonical_entity_id = None + label.attrs.aymurai_label_subclass = [] + + if ( + label.attrs.canonical_entity_id is None + and len(label.attrs.aymurai_label_subclass) == 0 + ): + for ce in canonical_entities: + if label.attrs.aymurai_label == ce.aymurai_label: + entity_id = ce.entity_id + attributes = ce.attributes or {} + role = attributes.get("role") + aliases = ce.aliases + + clean_aliases = [str(a).strip().lower() for a in aliases] + label_text = ( + str(label.attrs.aymurai_alt_text or label.text) + .strip() + .lower() + ) + + if label_text in clean_aliases: + label.attrs.canonical_entity_id = entity_id + if ce.aymurai_label == "PER" and role is not None: + label.attrs.aymurai_label_subclass.append(role) + break + + if label.attrs.canonical_entity_id is None: + key = ( + label.attrs.aymurai_label, + str(label.attrs.aymurai_alt_text).strip(), + ) + if key not in new_ids_map: + new_ids_map[key] = uuid.uuid4() + + label.attrs.canonical_entity_id = new_ids_map[key] + + if include_label_instances: + return assign_label_instances(predictions_mapped) + + return predictions_mapped diff --git a/aymurai/utils/entity_disambiguation/date_formatter.py b/aymurai/utils/entity_disambiguation/date_formatter.py new file mode 100644 index 00000000..92e38aea --- /dev/null +++ b/aymurai/utils/entity_disambiguation/date_formatter.py @@ -0,0 +1,45 @@ +from aymurai.meta.api_interfaces import DocLabel +from aymurai.meta.entities import CanonicalEntity + + +def get_canonical_dates(labels: list[DocLabel]) -> list[CanonicalEntity]: + """ + Groups date labels by their normalized day and month (if available) to create canonical entities. + + Args: + labels (list[DocLabel]): A list of document labels to process. + + Returns: + list[CanonicalEntity]: A list of canonical entities representing unique dates, + each with its aliases and attributes. + """ + groups = {} + + for label in labels: + if label.attrs.aymurai_label != "FECHA": + continue + + raw_date = label.attrs.aymurai_alt_text or label.text + + norm_date = ( + max(label.attrs.aymurai_label_subclass) + if label.attrs.aymurai_label_subclass + else None + ) + + day_month_key = norm_date[:5] if norm_date is not None else norm_date + + if day_month_key not in groups: + groups[day_month_key] = CanonicalEntity( + aymurai_label="FECHA", + canonical_text=raw_date, + aliases=[], + attributes={}, + ) + + if day_month_key in groups and raw_date not in groups[day_month_key].aliases: + groups[day_month_key].aliases.append(raw_date) + + label.attrs.canonical_entity_id = groups[day_month_key].entity_id + + return list(groups.values()) diff --git a/aymurai/utils/entity_disambiguation/fuzzy.py b/aymurai/utils/entity_disambiguation/fuzzy.py new file mode 100644 index 00000000..71ceed76 --- /dev/null +++ b/aymurai/utils/entity_disambiguation/fuzzy.py @@ -0,0 +1,199 @@ +from collections import Counter +from typing import Iterable + +from rapidfuzz import process +from rapidfuzz.fuzz import token_set_ratio + +from aymurai.meta.api_interfaces import DocLabel +from aymurai.meta.entities import CanonicalEntity + + +def _find_parent(parent: list[int], idx: int) -> int: + """ + Finds the root representative of a union-find set with path compression. + + Args: + parent (list[int]): Parent pointers for the union-find structure. + idx (int): Index to resolve to its root. + + Returns: + int: The root index for the provided `idx`. + """ + if parent[idx] == idx: + return idx + parent[idx] = _find_parent(parent, parent[idx]) + return parent[idx] + + +def _union_parent(parent: list[int], left: int, right: int) -> None: + """ + Unions two indices in a union-find structure. + + Args: + parent (list[int]): Parent pointers for the union-find structure. + left (int): First index to union. + right (int): Second index to union. + + Returns: + None + """ + root_left, root_right = _find_parent(parent, left), _find_parent(parent, right) + if root_left != root_right: + parent[root_right] = root_left + + +def _cluster_aliases_with_cdist( + *, + items: list[dict[str, str]], + threshold: int, +) -> list[list[tuple[str, str, str]]]: + """ + Clusters alias items using RapidFuzz pairwise similarity with union-find. + + Args: + items (list[dict[str, str]]): Items containing "text" and "aymurai_label". + threshold (int): Minimum similarity threshold for clustering. + + Returns: + list[list[tuple[str, str, str]]]: Clusters of (original, normalized, label). + """ + if not items: + return [] + + entities = [item.get("text", "") for item in items] + labels = [item.get("aymurai_label", "UNKNOWN") for item in items] + + normed = [str(e).lower().strip() if e else "" for e in entities] + + sim = process.cdist(normed, normed, scorer=token_set_ratio, score_cutoff=threshold) + + parent = list(range(len(normed))) + + n = len(normed) + for i in range(n): + for j in range(i + 1, n): + if sim[i][j] >= threshold: + _union_parent(parent, i, j) + + clusters_map: dict[int, list[tuple[str, str, str]]] = {} + for idx in range(n): + root = _find_parent(parent, idx) + clusters_map.setdefault(root, []).append( + (entities[idx], normed[idx], labels[idx]) + ) + + return list(clusters_map.values()) + + +def _parse_cluster_item(item: tuple[str, str, str]) -> tuple[str, str, str]: + """ + Reorders a tuple from (original, normalized, label) to (label, original, normalized). + + Args: + item (tuple[str, str, str]): Tuple in the form (original, normalized, label). + + Returns: + tuple[str, str, str]: Tuple in the form (label, original, normalized). + """ + orig, norm, label = item + return label, orig, norm + + +def _pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str: + """ + Selects the most frequent label from a cluster. + + Args: + parsed_items (list[tuple[str, str, str]]): Items in (label, original, normalized). + + Returns: + str: The most common label in the cluster. + """ + labels = [label for label, _, _ in parsed_items] + return Counter(labels).most_common(1)[0][0] + + +def _pick_longest_alias(parsed_items: list[tuple[str, str, str]]) -> str: + """ + Picks a canonical text representation from a cluster. + + Args: + parsed_items (list[tuple[str, str, str]]): Items in (label, original, normalized). + + Returns: + str: The longest alias text in the cluster. + """ + return max(parsed_items, key=lambda item: len(item[1]))[1] + + +def _clusters_to_canonical_entities( + clusters: list[list[tuple[str, str, str]]], +) -> list[CanonicalEntity]: + """ + Converts clustered alias groups into CanonicalEntity objects. + + Args: + clusters (list[list[tuple[str, str, str]]]): Clusters of + (original, normalized, label). + + Returns: + list[CanonicalEntity]: Canonical entities derived from clusters. + """ + canonical_entities = [] + for cluster in clusters: + parsed = [_parse_cluster_item(item) for item in cluster] + label = _pick_cluster_label(parsed) + canonical_text = _pick_longest_alias(parsed) + aliases = sorted({orig for _, orig, _ in parsed}) + canonical_entities.append( + CanonicalEntity( + aymurai_label=label, + canonical_text=canonical_text, + aliases=aliases, + attributes={}, + ) + ) + return canonical_entities + + +def build_canonical_entities( + labels: Iterable[DocLabel], + *, + target_labels: set[str] | None = None, + threshold: int, +) -> list[CanonicalEntity]: + """ + Builds canonical entities by clustering label aliases per entity type. + + Args: + labels (Iterable[DocLabel]): NER labels to cluster. + target_labels (set[str] | None): Optional label filter; if provided, + only these labels are clustered. + threshold (int): Minimum similarity threshold for clustering. + + Returns: + list[CanonicalEntity]: Canonical entities built from clustered aliases. + """ + grouped: dict[str, list[dict[str, str]]] = {} + for label in labels: + attrs = label.attrs + if not attrs or not attrs.aymurai_label: + continue + if target_labels and attrs.aymurai_label not in target_labels: + continue + alias = attrs.aymurai_alt_text or label.text + grouped.setdefault(attrs.aymurai_label, []).append( + {"text": alias, "aymurai_label": attrs.aymurai_label} + ) + + canonical_entities: list[CanonicalEntity] = [] + for items in grouped.values(): + clusters = _cluster_aliases_with_cdist( + items=items, + threshold=threshold, + ) + canonical_entities.extend(_clusters_to_canonical_entities(clusters)) + + canonical_entities = sorted(canonical_entities, key=lambda x: x.canonical_text) + + return canonical_entities diff --git a/aymurai/utils/entity_disambiguation/llm.py b/aymurai/utils/entity_disambiguation/llm.py new file mode 100644 index 00000000..f3cc3fb7 --- /dev/null +++ b/aymurai/utils/entity_disambiguation/llm.py @@ -0,0 +1,379 @@ +import copy +import json +from functools import lru_cache +from pathlib import Path + +from more_itertools import unique_everseen +from transformers import AutoTokenizer + +from aymurai.llm_providers import OllamaLLMProvider +from aymurai.meta.api_interfaces import ( + DocLabel, + DocumentAnnotations, + PromptLibrary, + PromptSet, +) +from aymurai.meta.entities import CanonicalEntities, CanonicalEntity +from aymurai.settings import settings +from aymurai.utils.json_data import get_pretty +from aymurai.utils.yaml_data import load_yaml + + +@lru_cache(maxsize=1) +def load_prompts_from_yaml(): + """ + Loads and caches LLM prompt templates from the resources directory. + + Returns: + PromptLibrary: The loaded prompt library. + """ + path = Path(settings.RESOURCES_BASEPATH) / "llm/entity_disambiguation.yaml" + data = load_yaml(file_path=str(path)) + + prompts = [] + for label, content in data.items(): + prompts.append( + PromptSet( + label=label, + system=content.get("system", ""), + user=content.get("user", ""), + ) + ) + return PromptLibrary(root=prompts) + + +def _extract_snippet(doc_text: str, label: DocLabel, window_length: int | None) -> str: + """ + Extracts and normalizes a text snippet around a label span. + + Args: + doc_text (str): Full document text. + label (DocLabel): Label containing span offsets. + window_length (int | None): Number of characters to include around + the label. If None, returns the full document text. + + Returns: + str: The extracted and normalized snippet. + """ + + if window_length is None: + return " ".join(doc_text.split()) + + start, end = label.start_char, label.end_char + window_start = max(0, start - window_length) + window_end = min(len(doc_text), end + window_length) + + # Expand to word boundaries to avoid truncating leading/trailing words. + while window_start > 0 and not doc_text[window_start - 1].isspace(): + window_start -= 1 + while window_end < len(doc_text) and not doc_text[window_end - 1].isspace(): + window_end += 1 + + snippet = doc_text[window_start:window_end] + return " ".join(snippet.split()) + + +def _iter_alias_snippets( + predictions: DocumentAnnotations, + *, + entity_label: str, + aliases_set: set[str], + window_length: int | None, +): + """ + Yields (alias, snippet) pairs for labels matching the target entity label. + + Args: + predictions (DocumentAnnotations): Document annotations to scan. + entity_label (str): Target NER label to match. + aliases_set (set[str]): Alias set to filter matches. + window_length (int | None): Window length for snippet extraction. + + Yields: + tuple[str, str]: (alias, snippet) pairs in appearance order. + """ + for pred in predictions: + if not pred.labels: + continue + doc_text = getattr(pred, "document", "") + + for label in pred.labels: + if label.attrs.aymurai_label != entity_label: + continue + + alias = label.attrs.aymurai_alt_text or label.text + if alias not in aliases_set: + continue + + snippet = _extract_snippet(doc_text, label, window_length) + yield alias, snippet + + +def _collect_entity_context( + predictions: DocumentAnnotations, + entity_label: str, + aliases: list[str], + window_length: int | None, + max_context_snippets: int | None = 5, +) -> list[str]: + """ + Collects unique context snippets for aliases, preserving appearance order. + + Args: + predictions (DocumentAnnotations): Document annotations to search within. + entity_label (str): NER label category to match (e.g., "PER"). + aliases (list[str]): Aliases to match against label text. + window_length (int | None): Characters to include around each match. + max_context_snippets (int | None): Max number of snippets to return. + If None, returns all unique snippets. Defaults to 5. + + Returns: + list[str]: Ordered, deduplicated context snippets. + """ + aliases_set = set(aliases) + + deduped_in_order = list( + unique_everseen( + _iter_alias_snippets( + predictions, + entity_label=entity_label, + aliases_set=aliases_set, + window_length=window_length, + ), + key=lambda item: item[1], + ) + ) + + # baseline in appearance order: first snippet per alias + seen_aliases: set[str] = set() + baseline = [ + snippet + for alias, snippet in deduped_in_order + if not (alias in seen_aliases or seen_aliases.add(alias)) + ] + + # remaining snippets in appearance order + baseline_set = set(baseline) + remaining = [ + snippet for _, snippet in deduped_in_order if snippet not in baseline_set + ] + + merged = baseline + remaining + + effective_limit = ( + None + if max_context_snippets is None + else max(max_context_snippets, len(baseline)) + ) + + return merged if effective_limit is None else merged[:effective_limit] + + +def _add_canonical_entities_context( + predictions: DocumentAnnotations, + entities: CanonicalEntities, + context_window_length: int | None = 120, + target_label: str | None = None, + max_snippets_per_entity: int | None = 5, +) -> CanonicalEntities: + """ + Attaches context snippets to each canonical entity based on predictions. + + Args: + predictions (DocumentAnnotations): Full document annotations. + entities (CanonicalEntities): Canonical entities to enrich with context. + context_window_length (int | None): Characters to include around each + mention. If None, uses the full document text. + target_label (str | None): Optional label filter to restrict extraction. + max_snippets_per_entity (int | None): Max snippets per entity. If None, + returns all unique snippets. + + Returns: + CanonicalEntities: Entities enriched with context snippets in attributes. + """ + + entities_with_context = copy.deepcopy(entities) + + for entity in entities_with_context: + if entity.attributes is None: + entity.attributes = {} + + current_target = target_label or entity.aymurai_label + + entity.attributes["context"] = _collect_entity_context( + predictions, + current_target, + list(entity.aliases), + context_window_length, + max_snippets_per_entity, + ) + + return entities_with_context + + +_TOKENIZER_CACHE = {} + + +def _get_model_tokens( + system_prompt: str, user_prompt: str, tokenizer_model: str +) -> int: + """ + Estimates token count for a system/user prompt using a HuggingFace tokenizer. + + Args: + system_prompt (str): System role prompt. + user_prompt (str): User role prompt. + tokenizer_model (str): HuggingFace tokenizer identifier or local path. + + Returns: + int: Approximate token count for the combined prompts. + """ + try: + if tokenizer_model not in _TOKENIZER_CACHE: + _TOKENIZER_CACHE[tokenizer_model] = AutoTokenizer.from_pretrained( + tokenizer_model + ) + + tokenizer = _TOKENIZER_CACHE[tokenizer_model] + + messages = [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt}, + ] + + full_text = tokenizer.apply_chat_template(messages, tokenize=False) + tokens = tokenizer.encode(full_text) + + return len(tokens) + + except Exception: + # Fallback: simple word count approximation (one word ~ 1.4 tokens) + combined_text = f"{system_prompt} {user_prompt}" + word_count = len(combined_text.split()) + + approx_tokens = int(word_count * 1.4) + 20 + + return approx_tokens + + +def llm_canonical_entities_inference( + paragraphs: DocumentAnnotations, + canonical_entities_pre_cluster: CanonicalEntities, + system_prompt: str, + user_prompt_template: str, + model: str, + tokenizer_model: str, + target_label: str, + context_window_length: int | None = 120, + model_context: int = 9_500, + token_limit_frac: float = 2 / 3, + temperature: int = 0, + decompose_by: int | None = 0, +) -> CanonicalEntities: + """ + Refines pre-clustered entities into canonical forms using LLM inference. + + Args: + paragraphs (DocumentAnnotations): Annotated paragraphs containing labels. + canonical_entities_pre_cluster (CanonicalEntities): Pre-clustered entities. + system_prompt (str): System prompt for the LLM. + user_prompt_template (str): Template for user prompt formatting. + model (str): LLM model identifier. + tokenizer_model (str): Tokenizer identifier for token counting. + target_label (str): NER label to process (e.g., "PER"). + context_window_length (int | None): Context window length around mentions. + model_context (int): Max context window size for the LLM. + token_limit_frac (float): Fraction of model_context to use for batching. + temperature (int): Sampling temperature. + decompose_by (int | None): Batch size; if None, inferred. + + Returns: + CanonicalEntities: Canonical entities refined by the LLM. + """ + + canonical_entities_with_context = _add_canonical_entities_context( + predictions=paragraphs, + entities=canonical_entities_pre_cluster, + context_window_length=context_window_length, + target_label=target_label, + ) + + canonical_entities_prompt = [ + ce.model_dump(include={"canonical_text", "aliases", "attributes"}) + for ce in canonical_entities_with_context + ] + + token_limit = int(model_context * token_limit_frac) + + if decompose_by is None: + # NOTE: dynamically find the maximum batch size that fits the token limit + # by iteratively shrinking the candidate list. + current_batch_size = len(canonical_entities_prompt) + + while current_batch_size > 0: + test_batch = canonical_entities_prompt[:current_batch_size] + test_prompt = user_prompt_template.format( + canonical_entities=get_pretty(test_batch) + ) + + num_tokens = _get_model_tokens( + system_prompt=system_prompt, + user_prompt=test_prompt, + tokenizer_model=tokenizer_model, + ) + + if num_tokens <= token_limit: + decompose_by = current_batch_size + break + + current_batch_size -= 1 + + if not decompose_by: + # NOTE: returns None if even a single entity exceeds the token limit. + return None + + if decompose_by <= 0: + entity_batches = [canonical_entities_prompt] + else: + entity_batches = [ + canonical_entities_prompt[i : i + decompose_by] + for i in range(0, len(canonical_entities_prompt), decompose_by) + ] + + all_raw_outputs = [] + all_user_prompts = [] + + for batch_index, batch in enumerate(entity_batches): + user_prompt = user_prompt_template.format( + canonical_entities=get_pretty(batch), + ) + + all_user_prompts.append(user_prompt) + + len_tokens = _get_model_tokens( + system_prompt=system_prompt, + user_prompt=user_prompt, + tokenizer_model=tokenizer_model, + ) + if len_tokens > model_context: + # NOTE: skip batches that exceed physical context window to prevent LLM hallucination or crash. + continue + + provider = OllamaLLMProvider(model=model) + response = provider.generate( + messages=[ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt}, + ], + options={"temperature": temperature, "num_ctx": model_context}, + format=CanonicalEntities.model_json_schema(), + ) + + batch_entities = json.loads(response.text).get("canonical_entities", []) + all_raw_outputs.extend(batch_entities) + + canonical_entities_llm = [ + CanonicalEntity.model_validate(e) for e in all_raw_outputs + ] + + return canonical_entities_llm diff --git a/notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb new file mode 100644 index 00000000..5cc52d55 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb @@ -0,0 +1,1713 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "64957296", + "metadata": {}, + "source": [ + "from previous notebook `06-pre-disambiguation-optimization` we found that the best hyperparameters combinations are:\n", + "- scorer: `token_set_ratio`\n", + "- score_cutoff: `70`\n", + "- processor: `light_normalizer`\n", + "\n", + "we now proceed to make the canonical entities disambiguation checked by an LLM and we give the task to the LLM to give a role to each canonical entity when it is related to a person." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb2b1f59", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "607ea227", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import json\n", + "import os\n", + "import re\n", + "from more_itertools import unique_everseen\n", + "\n", + "from pathlib import Path\n", + "from typing import Iterable\n", + "import uuid\n", + "\n", + "import requests\n", + "\n", + "import numpy as np\n", + "\n", + "from aymurai.llm_providers import OllamaLLMProvider\n", + "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", + "from aymurai.utils.json_data import get_pretty, save_json, load_json\n", + "\n", + "import aymurai.evaluation.metrics as aymurai_metrics\n", + "from aymurai.utils.entity_disambiguation import build_canonical_entities\n", + "from aymurai.meta.api_interfaces import DocumentAnnotations" + ] + }, + { + "cell_type": "markdown", + "id": "7ec52f24", + "metadata": {}, + "source": [ + "## /document-extract endpoint output and new endpoint anonymizer/disambiguate" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c7c3b672", + "metadata": {}, + "outputs": [], + "source": [ + "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8000\")\n", + "ENDPOINT_DOCUMENT_EXTRACT = f\"{API_BASE_URL}/misc/document-extract\"\n", + "\n", + "DATA_ROOT = Path(\n", + " os.getenv(\n", + " \"DOCUMENT_DATA_ROOT\", \"../../../resources/data/restricted/disambiguation-eval/files\"\n", + " )\n", + ")\n", + "GOLD_JSON_ROOT = Path(\n", + " os.getenv(\n", + " \"GOLD_JSON_ROOT\",\n", + " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted\",\n", + " )\n", + ")\n", + "\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", + "JSON_EXTENSION = {\".json\"}\n", + "\n", + "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", + "\n", + "print(f\"Target endpoint: {ENDPOINT_DOCUMENT_EXTRACT}\")\n", + "print(f\"Data root: {DATA_ROOT.resolve()}\")\n", + "\n", + "LIMIT = int(os.getenv(\"DISAMBIGUATION_DOC_LIMIT\", \"0\")) # 0 = no limit\n", + "TARGET_LABELS = os.getenv(\"DISAMBIGUATION_TARGET_LABELS\", \"PER,DIRECCION\")\n", + "TARGET_LABELS = [label.strip() for label in TARGET_LABELS.split(\",\") if label.strip()]\n", + "\n", + "FUZZY_THRESHOLD = int(os.getenv(\"DISAMBIGUATION_THRESHOLD\", \"70\"))\n", + "FUZZY_SCORER = os.getenv(\"DISAMBIGUATION_SCORER\", \"token_set_ratio\")\n", + "FUZZY_PROCESSOR = os.getenv(\"DISAMBIGUATION_PROCESSOR\", \"light_normalizer\")\n", + "\n", + "print(f\"API: {API_BASE_URL}\")\n", + "print(f\"Data root: {DATA_ROOT}\")\n", + "print(f\"Target labels: {TARGET_LABELS or 'ALL'}\")\n", + "print(\n", + " f\"Fuzzy params: scorer={FUZZY_SCORER}, threshold={FUZZY_THRESHOLD}, processor={FUZZY_PROCESSOR}\"\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18a31502", + "metadata": {}, + "outputs": [], + "source": [ + "if not DATA_ROOT.exists():\n", + " raise FileNotFoundError(\n", + " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", + " )\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "if LIMIT > 0:\n", + " documents = documents[:LIMIT]\n", + "print(f\"Discovered {len(documents)} documents.\")\n", + "\n", + "gold_jsons = discover_documents(GOLD_JSON_ROOT, JSON_EXTENSION)\n", + "if LIMIT > 0:\n", + " gold_jsons = gold_jsons[:LIMIT]\n", + "print(f\"Discovered {len(gold_jsons)} gold JSON files.\")" + ] + }, + { + "cell_type": "markdown", + "id": "dcaed02f", + "metadata": {}, + "source": [ + "## Functions for API endpoints usage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "464e9132", + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.experiments.entity_disambiguation.runner import (\n", + " call_extraction_api as extract_document,\n", + ")\n", + "\n", + "def predict_paragraphs(paragraphs: list[str]) -> list[dict]:\n", + " endpoint = f\"{API_BASE_URL}/anonymizer/predict\"\n", + " predictions = []\n", + " for paragraph in paragraphs:\n", + " response = requests.post(endpoint, json={\"text\": paragraph}, timeout=60)\n", + " response.raise_for_status()\n", + " predictions.append(response.json())\n", + " return predictions" + ] + }, + { + "cell_type": "markdown", + "id": "f2aa5d15", + "metadata": {}, + "source": [ + "## Canonical Entity extraction with ***LLM inference***" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8220314e", + "metadata": {}, + "outputs": [], + "source": [ + "# Available models\n", + "models = [\n", + " \"phi4:14b\",\n", + " \"gpt-oss:20b\",\n", + " \"llama3\",\n", + " \"llama3.1:8b\",\n", + " \"gemma3:270m\",\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "82f8d1a2", + "metadata": {}, + "outputs": [], + "source": [ + "# # Sanity check\n", + "# provider = OllamaLLMProvider(model=models[0])\n", + "# provider.generate(\"hola, ¿cómo estás?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f40ef8ed", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_1 = \"\"\"\n", + "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", + "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", + "\n", + "# Material de Trabajo\n", + "Para tu análisis, recibirás:\n", + "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", + "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", + "\n", + "# Tus Tareas\n", + "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", + "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", + "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", + "\n", + "# Reglas de Salida\n", + "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", + "- `canonical_text`: El nombre más completo y formal encontrado.\n", + "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Defensor/a de Cámara\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", + "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", + "\n", + "# Estructura de Respuesta (JSON)\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Alias Principal\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\n", + "# Ejemplo de Input\n", + "Contexto: \"...la declaración del Sr. Juan Carlos Ruiz ante este Juzgado. El imputado Ruiz negó los cargos. Por su parte, la Dra. Elena Sosa, fiscal de la causa, solicitó...\"\n", + "Entidades Candidatas:\n", + "[{\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Juan Carlos Ruiz\",\n", + " \"aliases\": [\n", + " \"Juan Carlos Ruiz\",\n", + " \"Ruiz\"\n", + " ]\n", + "},\n", + "{\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Elena Sosa\",\n", + " \"aliases\": [\n", + " \"Elena Sosa\"\n", + " ]\n", + "}]\n", + "\n", + "# Ejemplo de Output\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Juan Carlos Ruiz\",\n", + " \"aliases\": [\n", + " \"Juan Carlos Ruiz\",\n", + " \"Ruiz\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Imputado\"\n", + " }\n", + " },\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Elena Sosa\",\n", + " \"aliases\": [\n", + " \"Elena Sosa\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Fiscal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40c5f5ae", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_2 = \"\"\"\n", + "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", + "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", + "\n", + "# Material de Trabajo\n", + "Para tu análisis, recibirás:\n", + "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", + "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", + "\n", + "# Tus Tareas\n", + "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", + "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", + "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", + "\n", + "# Reglas de Salida\n", + "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", + "- `canonical_text`: El nombre más completo y formal encontrado.\n", + "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", + " * \"Denunciante\"\n", + " * \"Denunciado/a\"\n", + " * \"Víctima\"\n", + " * \"Juez/a\"\n", + " * \"Defensor/a de Cámara\"\n", + " * \"Fiscal\"\n", + " * \"Abogado/a\"\n", + " * \"Perito/a\"\n", + " * \"Testigo\"\n", + " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", + "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", + "\n", + "# Estructura de Respuesta (JSON)\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Alias Principal\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3f2848b", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template_1 = \"\"\"\n", + "A continuación se proporcionan fragmentos relevantes de un documento judicial y una lista de entidades (personas) pre-clusterizadas por similitud de texto.\n", + "\n", + "# Contexto de la causa, párrafos con alguna mención a las personas:\n", + "{document_text}\n", + "\n", + "# Entidades Pre-clusterizadas a validar:\n", + "{canonical_entities}\n", + "\n", + "# Instrucciones:\n", + "1. **Validación de Aliases:** Analiza si los aliases dentro de cada entidad canónica pertenecen realmente a la misma persona según los párrafos de contexto. \n", + " - Si un alias pertenece a una persona distinta (ej. un familiar con nombre similar), sepáralo en una nueva entidad.\n", + " - Si dos grupos de entidades canónicas refieren a la misma persona, fusiónalos.\n", + "2. **Identificación de Roles:** Extrae el rol procesal de cada persona basándote en el contexto (ej: Juez/a, Fiscal, Denunciante, Imputado/a, Víctima, Abogado/a, Perito/a, Testigo).\n", + "3. **Normalización:** Define el `canonical_text` como el nombre más completo y formal que aparezca en los aliases, si este trabajo ya está bien hecho no lo modifiques.\n", + "4. **Formato:** Devuelve la lista final de entidades en el formato JSON solicitado en el system prompt, asegurándote de no omitir a nadie que sea relevante.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7d9365ca", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_3 = \"\"\"\n", + "Eres un asistente experto en desambiguación de entidades judiciales.\n", + "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", + "\n", + "### Tu Tarea:\n", + "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", + "2. **Limpiar Aliases:** Elimina prefijos (Dr., Sra., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", + "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", + "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + " - **Nota:** No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica rol, usa `null`.\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve exclusivamente un array de objetos:\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Alias Principal\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0f7bf0f7", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_4 = \"\"\"\n", + "Eres un asistente experto en desambiguación de entidades judiciales.\n", + "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", + "\n", + "### Tu Tarea:\n", + "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", + "2. **Limpiar Aliases:** Elimina prefijos (Dr., Dra., Dres., Sra., Sr., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", + "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", + "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + " \n", + " **Instrucciones críticas de rol:**\n", + " - Si una persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y el contexto no indica que es Juez, Fiscal o Defensor oficial, asígnale el rol de **\"Abogado/a\"**.\n", + " - No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica un rol de la lista, usa `null`.\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve exclusivamente un array de objetos:\n", + "[\n", + " {\n", + " \"canonical_text\": \"Nombre Completo Normalizado\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f9bed0ca", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_5 = \"\"\"\n", + "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", + "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", + "4. **Limpiar:** En `canonical_text` y `aliases`, elimina otras palabras que no sean nombres propios.\n", + "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5ac77829", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_6 = \"\"\"\n", + "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", + "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", + "4. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", + "5. No modifiques los `canonical_text` ni los `aliases` originales.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26f1b81b", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_7 = \"\"\"\n", + "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", + "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", + "4. **Manejo de Siglas e Iniciales:** Ten en cuenta que las personas pueden ser mencionadas por sus iniciales (ej: \"M.L.\" para \"Martín López\"). Si el contexto permite confirmar que unas iniciales refieren a una persona ya identificada, trátalas como un alias de esa misma entidad.\n", + "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona (ya sea por nombre completo, apellido solo o iniciales), devuélvelas como una sola entidad unificada.\n", + "6. **Integridad:** No modifiques los `canonical_text` ni los `aliases` originales; mantén la literalidad de lo extraído por el NER.\n", + "\n", + "Devuelve exclusivamente un array de objetos:\n", + "[\n", + " {\n", + " \"canonical_text\": \"Nombre Completo Normalizado\",\n", + " \"aliases\": [\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol Procesal\"\n", + " }\n", + " }\n", + "]\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "55aff26f", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_8 = \"\"\"\n", + "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", + " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", + " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", + "2. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", + "3. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", + "4. **Asignación de Rol:** Identifica el rol procesal basándote EXCLUSIVAMENTE en esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "5. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve un array de objetos con esta estructura:\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Nombre de la entidad,\n", + " \"aliases\": [\n", + " \"Nombre de la entidad\",\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol de la lista o null\"\n", + " }\n", + " }\n", + "]\n", + "No incluyas el campo 'context' en tu respuesta final.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "822e348e", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_9 = \"\"\"\n", + "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Asignación de Rol:** Identifica el rol procesal basándote en las ventanas de contexto dentro de cada entidad canónica en la parte de `attributes`['context']\n", + " Elija un rol EXCLUSIVAMENTE en esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "2. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", + "3. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", + " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", + " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", + "4. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", + "5. **Limpieza:** Limpiá los `aliases` y el `canonical_text` si los mismos tienen otras palabras, pero respeta que estén escritos de igual manera a que sus ventanas de contexto.\n", + " Te dejo un ejemplo de esta instrucción.\n", + " Vos recibís:\n", + " {\n", + " \"canonical_text\": \"por DREXLER, JORGE\",\n", + " \"aliases\": [\n", + " \"por DREXLER, JORGE\",\n", + " \"Jorge Drexler\"\n", + " ],\n", + " \"attributes\": {\n", + " \"context\": [\n", + " \"Fdo. por DREXLER, JORGE - JUEZ DE CÁMARA el mismo cita en el documento 56 que Juan es culpable\",\n", + " \"es acaso Jorge Drexler el juez designado para esta causa\"\n", + " ]\n", + " }\n", + " \n", + " Debés entregar:\n", + " {\n", + " \"canonical_text\": \"DREXLER, JORGE\",\n", + " \"aliases\": [\n", + " \"DREXLER, JORGE\",\n", + " \"Jorge Drexler\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Juez/a\"\n", + " }\n", + " \n", + "6. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve un array de objetos con esta estructura:\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Nombre de la entidad,\n", + " \"aliases\": [\n", + " \"Nombre de la entidad\",\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol de la lista o null\"\n", + " }\n", + " }\n", + "]\n", + "\n", + "No incluyas el campo 'context' en tu respuesta final.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fc51a3ea", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_10 = \"\"\"\n", + "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", + " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", + " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", + "2. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", + "3. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", + "4. **Asignación de Rol:** Identifica el rol procesal basándote EXCLUSIVAMENTE en esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "5. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", + "6. **Limpieza:** No modifiques la literalidad de los `aliases` ni del `canonical_text`.\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve un array de objetos con esta estructura:\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Nombre de la entidad,\n", + " \"aliases\": [\n", + " \"Nombre de la entidad\",\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol de la lista o null\"\n", + " }\n", + " }\n", + "]\n", + "No incluyas el campo 'context' en tu respuesta final.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cb600013", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_11 = \"\"\"\n", + "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y corregir una lista de personas pre-agrupadas basándote en su contexto.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Validación de Límites (Boundaries):** El modelo NER a veces incluye palabras adyacentes que no son parte del nombre (ej: \"por\", \"Fdo.\", \"Dres\", \"dijo\", \"con\"). Tu tarea es corregir los `aliases` y el `canonical_text` para que contengan ÚNICAMENTE el nombre de la persona, pero manteniendo la literalidad exacta (mayúsculas, tildes, comas) de cómo está escrito en el fragmento de `context`.\n", + "2. **Fusión y Desambiguación:** - Si dos grupos de entidades refieren a la misma persona física, fusiónalos.\n", + " - Si una persona aparece por sus iniciales (ej: \"M.L.\"), asóciala como alias del nombre completo si el contexto lo confirma.\n", + "3. **Filtrado:** Elimina entidades que no sean personas físicas.\n", + "4. **Asignación de Rol:** Usa exclusivamente: \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "5. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, el rol es \"Abogado/a\".\n", + "6. **Limpieza:** No modifiques la literalidad de los `aliases` ni del `canonical_text`.\n", + "\n", + "### Formato de Salida (JSON):\n", + "[\n", + " {\n", + " \"entity_id\": \"ID original\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Nombre exacto extraído del texto\",\n", + " \"aliases\": [\n", + " \"Nombre exacto extraído del texto (Igual al canonical)\",\n", + " \"Otros aliases exactos del texto...\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol de la lista o null\"\n", + " }\n", + " }\n", + "]\n", + "**IMPORTANTE:** El primer elemento de `aliases` debe ser idéntico al `canonical_text`. No incluyas el campo 'context' en la respuesta.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca7b8755", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_DIR = \"\"\"\n", + "Eres un auditor experto en desambiguación de domicilios y direcciones en documentos judiciales. Tu tarea es validar y consolidar una lista de direcciones pre-agrupadas basándote en su contexto.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Consolidación Geográfica:** - Si dos entidades refieren a la misma ubicación física, fusiónalas en una sola entidad. \n", + " - Considera que una dirección puede estar escrita de forma completa en un alias (ej: \"Av. Rivadavia 123, CABA\") y de forma abreviada en otro (ej: \"Rivadavia 123\"). \n", + " - Trata las variantes ortográficas o abreviaturas (Av. vs Avenida, Piso vs P., Dpto vs Departamento) como aliases de la misma ubicación.\n", + "2. **Filtrado:** Elimina entidades que no sean direcciones postales o domicilios físicos (ej: correos electrónicos, URLs, nombres de juzgados o menciones abstractas como \"el domicilio constituido\").\n", + "\n", + "### Formato de Salida (JSON):\n", + "[\n", + " {\n", + " \"entity_id\": \"ID original\",\n", + " \"aymurai_label\": \"DIRECCION\",\n", + " \"canonical_text\": \"Dirección más completa extraída del texto\",\n", + " \"aliases\": [\n", + " \"Dirección más completa (Igual al canonical)\",\n", + " \"Variante 1\",\n", + " \"Variante 2\"\n", + " ],\n", + " \"attributes\": []\n", + " }\n", + "]\n", + "**IMPORTANTE:** No incluyas el campo 'context' en la respuesta.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d9feb9f", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template_DIR= \"\"\"\n", + "Se proporciona la lista de entidades (direcciones) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su validez y si hay otras entidades de direcciones que corresponden a esa.\n", + "\n", + "# Entidades Pre-clusterizadas a validar:\n", + "{canonical_entities}\n", + "\n", + "Procesa la lista siguiendo las instrucciones de filtrado y fusión.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0d4ad36", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template_PER = \"\"\"\n", + "Se proporciona la lista de entidades (personas) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su rol y validez.\n", + "\n", + "# Entidades Pre-clusterizadas a validar:\n", + "{canonical_entities}\n", + "\n", + "Procesa la lista siguiendo las instrucciones de filtrado, fusión y asignación de roles.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efc48244", + "metadata": {}, + "outputs": [], + "source": [ + "def pre_cluster(\n", + " paragraphs: list[dict],\n", + " target_labels: list[str] = None,\n", + " threshold: int = 70,\n", + ") -> CanonicalEntities:\n", + "\n", + " predictions = DocumentAnnotations(data=paragraphs)\n", + "\n", + " labels = [\n", + " label for paragraph in predictions.data for label in (paragraph.labels or [])\n", + " ]\n", + "\n", + " target_set = {label.strip() for label in target_labels} if target_labels else None\n", + "\n", + " canonical_entities = build_canonical_entities(\n", + " labels,\n", + " target_labels=target_set,\n", + " threshold=threshold,\n", + " )\n", + "\n", + " return canonical_entities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1431d116", + "metadata": {}, + "outputs": [], + "source": [ + "import copy\n", + "\n", + "def add_canonical_entities_context(\n", + " predictions: list[dict], \n", + " entities: list[dict],\n", + " context_window_length: int | None = 120,\n", + " max_context_snippets: int | None = 5,\n", + ") -> list[dict]:\n", + " \"\"\"\n", + " Creates a deep copy of entities and adds context. \n", + " \n", + " Args:\n", + " predictions: List of prediction dictionaries from the API.\n", + " entities: List of canonical entities.\n", + " context_window_length: Length of the window around the label. If None, full paragraph is used.\n", + " target_label: The specific label to filter. If None, all labels are considered.\n", + " \"\"\"\n", + " # 1. Deep copy to protect original variable\n", + " entities_with_context = copy.deepcopy(entities)\n", + "\n", + " # 2. Process each entity\n", + " for entity in entities_with_context:\n", + " if 'attributes' not in entity or entity['attributes'] is None:\n", + " entity['attributes'] = {}\n", + " if 'context' not in entity['attributes']:\n", + " entity['attributes']['context'] = []\n", + " \n", + " aliases = [a for a in entity.get('aliases', [])]\n", + "\n", + " alias_to_snippets = {alias: [] for alias in aliases}\n", + " all_snippets_ordered = []\n", + "\n", + " # 3. Iterate through predictions\n", + " for pred in predictions:\n", + " if not pred.get('labels'):\n", + " continue\n", + "\n", + " doc_text = pred.get('document', '')\n", + " \n", + " for label in pred.get('labels', []):\n", + " if entity.get('aymurai_label') and label['attrs']['aymurai_label'] != entity.get('aymurai_label'):\n", + " continue\n", + "\n", + " alias_name = label['attrs']['aymurai_alt_text']\n", + " if alias_name not in aliases:\n", + " continue\n", + " \n", + " # Handle Window vs Full Paragraph\n", + " if context_window_length is None:\n", + " snippet = doc_text\n", + " else:\n", + " start = label['start_char']\n", + " end = label['end_char']\n", + "\n", + " window_start = max(0, start - context_window_length)\n", + " window_end = min(len(doc_text), end + context_window_length)\n", + "\n", + " # Expand to word boundaries to avoid truncating leading/trailing words.\n", + " while window_start > 0 and not doc_text[window_start - 1].isspace():\n", + " window_start -= 1\n", + " while window_end < len(doc_text) and not doc_text[window_end - 1].isspace():\n", + " window_end += 1\n", + "\n", + " snippet = doc_text[window_start:window_end]\n", + "\n", + " clean_snippet = \" \".join(snippet.split())\n", + "\n", + " if clean_snippet not in alias_to_snippets[alias_name]:\n", + " alias_to_snippets[alias_name].append(clean_snippet)\n", + " if clean_snippet not in all_snippets_ordered:\n", + " all_snippets_ordered.append(clean_snippet)\n", + "\n", + " baseline = []\n", + " for alias in aliases:\n", + " snips = alias_to_snippets.get(alias, [])\n", + " if snips:\n", + " baseline.append(snips[0])\n", + " \n", + " baseline = list(unique_everseen(baseline))\n", + " \n", + " remaining = [s for s in all_snippets_ordered if s not in baseline]\n", + " merged = baseline + remaining\n", + "\n", + " effective_limit = max(max_context_snippets, len(baseline))\n", + " entity['attributes']['context'] = merged[:effective_limit]\n", + "\n", + " return entities_with_context\n", + "\n", + "def validate_canonical_entities(\n", + " canonical_entities_raw: list[CanonicalEntity], target_label: str | None = None\n", + ") -> list[CanonicalEntity]:\n", + "\n", + " if target_label:\n", + " canonical_entities_val = [\n", + " e for e in canonical_entities_raw if e.aymurai_label == target_label\n", + " ]\n", + " else:\n", + " canonical_entities_val = canonical_entities_raw\n", + "\n", + " canonical_entities_val = [\n", + " CanonicalEntity.model_validate(canonical_entity)\n", + " for canonical_entity in canonical_entities_val\n", + " ]\n", + "\n", + " canonical_entities_val = [\n", + " entity.model_dump() | {\"entity_id\": uuid.uuid4()}\n", + " for entity in canonical_entities_val\n", + " ]\n", + "\n", + " return canonical_entities_val" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fded1133", + "metadata": {}, + "outputs": [], + "source": [ + "tokenizers = {\n", + " \"phi4:14b\": \"microsoft/phi-4\",\n", + " \"gpt-oss:20b\": \"EleutherAI/gpt-neox-20b\",\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f93c8263", + "metadata": {}, + "outputs": [], + "source": [ + "from transformers import AutoTokenizer\n", + "\n", + "def get_phi4_tokens(system_prompt, user_prompt, model):\n", + " \n", + " try:\n", + " tokenizer = AutoTokenizer.from_pretrained(tokenizers[model])\n", + " \n", + " messages = [\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ]\n", + " try:\n", + " full_text = tokenizer.apply_chat_template(\n", + " messages, \n", + " tokenize=False, \n", + " add_generation_prompt=True\n", + " )\n", + " except Exception:\n", + " full_text = f\"{system_prompt}\\n{user_prompt}\"\n", + " \n", + " tokens = tokenizer.encode(full_text)\n", + " return len(tokens)\n", + " \n", + " except Exception as e:\n", + " print(f\"Error loading tokenizer {tokenizers[model]}: {e}\")\n", + " return int(len((system_prompt + user_prompt).split()) * 1.4)\n", + "\n", + "\n", + "\n", + "def llm_infer_canonical_entities(\n", + " system_prompt: str,\n", + " user_prompt_template: str,\n", + " model: str,\n", + " document_path: Path,\n", + " gold_path: Path,\n", + " context_window_length: int | None = 120,\n", + " model_context: int = 9_500,\n", + " token_limit_frac: float = 2/3,\n", + " target_label: str = \"PER\",\n", + " temperature: int = 0,\n", + " decompose_by: int | None = 0,\n", + ") -> dict:\n", + " \n", + " \"\"\"\n", + " Infers canonical entities using an LLM by providing context windows \n", + " around detected entities and pre-clusterization results.\n", + " \"\"\"\n", + "\n", + " # 1. Filename cleaning\n", + " clean_base_name = document_path.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", + " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + "\n", + " print(f\"----- Processing document: {target_filename} -----\")\n", + "\n", + " # 2. Extract document text via API\n", + " session = requests.Session()\n", + " api_response = extract_document(\n", + " session,\n", + " file_path = Path(document_path),\n", + " endpoint=f\"{API_BASE_URL}/misc/document-extract\",\n", + " timeout_s=300,\n", + " )\n", + " \n", + " document_paragraphs = api_response.get(\"detail\", {}).get(\"document\")\n", + "\n", + " if not document_paragraphs:\n", + " raise ValueError(\"Document text is empty or not found for {target_filename}.\")\n", + "\n", + " # 3. Get the pre-clustered entities with context from API calls\n", + " predictions = predict_paragraphs(document_paragraphs)\n", + " \n", + " canonical_entities_pre_cluster = pre_cluster(\n", + " paragraphs=predictions,\n", + " target_labels=[target_label],\n", + " threshold=70,\n", + " )\n", + "\n", + " canonical_entities_pre_cluster = validate_canonical_entities(\n", + " canonical_entities_raw=canonical_entities_pre_cluster,\n", + " target_label=target_label\n", + " )\n", + "\n", + " canonical_entities_with_context = add_canonical_entities_context(\n", + " predictions=predictions,\n", + " entities=canonical_entities_pre_cluster,\n", + " context_window_length=context_window_length,\n", + " )\n", + "\n", + " # 4. Clean entities to save tokens\n", + " canonical_entities_prompt = [\n", + " {\n", + " k: v\n", + " for k, v in ce.items()\n", + " if k in (\"canonical_text\",\"aliases\",\"attributes\")\n", + " }\n", + " for ce in canonical_entities_with_context\n", + " ]\n", + "\n", + " token_limit = int(model_context*token_limit_frac)\n", + "\n", + " # 5. Find Optimal Batch Size if decompose_by is None\n", + " if decompose_by is None:\n", + " current_batch_size = len(canonical_entities_prompt)\n", + " print(f\"{'-' * 60}\")\n", + " print(\"Searching for optimal batch size...\")\n", + " print(f\"Starting with {current_batch_size} entities.\")\n", + " \n", + " while current_batch_size > 0:\n", + " # Test with the first N entities\n", + " test_batch = canonical_entities_prompt[:current_batch_size]\n", + " test_prompt = user_prompt_template.format(\n", + " canonical_entities=get_pretty(test_batch)\n", + " )\n", + " \n", + " num_tokens = get_phi4_tokens(system_prompt=system_prompt, user_prompt=test_prompt, model=model)\n", + " \n", + " if num_tokens <= token_limit:\n", + " decompose_by = current_batch_size\n", + " print(f\"{'-' * 60}\")\n", + " print(f\"Optimal batch size found: {decompose_by} entities ({num_tokens} tokens).\")\n", + " break\n", + " \n", + " current_batch_size -= 1\n", + " \n", + " if not decompose_by: # Safety check if even 1 entity is too large\n", + " print(\"\\nEven a single entity exceeds the token limit.\")\n", + " return None\n", + "\n", + " # 6. Prepare batches. If decompose_by is 0 or less, we put all entities in one single list (one batch)\n", + " if decompose_by <= 0:\n", + " entity_batches = [canonical_entities_prompt]\n", + " else:\n", + " entity_batches = [\n", + " canonical_entities_prompt[i : i + decompose_by]\n", + " for i in range(0, len(canonical_entities_prompt), decompose_by)\n", + " ]\n", + "\n", + " all_raw_outputs = []\n", + " all_user_prompts = []\n", + "\n", + " # 7. Iterate through batches\n", + " for batch_index, batch in enumerate(entity_batches):\n", + " print(f\"{'-' * 60}\")\n", + " print(f\"Processing batch {batch_index + 1}/{len(entity_batches)}.\")\n", + " \n", + " user_prompt = user_prompt_template.format(\n", + " canonical_entities=get_pretty(batch),\n", + " )\n", + " \n", + " all_user_prompts.append(user_prompt)\n", + "\n", + " # 7.A Token Validation\n", + " len_tokens = get_phi4_tokens(system_prompt=system_prompt, user_prompt=user_prompt, model=model)\n", + " if len_tokens > model_context:\n", + " print(f\"Batch {batch_index} too large ({len_tokens} tokens).\")\n", + " print(\"Skipping batch.\")\n", + " continue\n", + " else:\n", + " print(f\"Total batch tokens: {len_tokens} within model context ({model_context}).\")\n", + "\n", + " # 7.B LLM Inference\n", + " provider = OllamaLLMProvider(model=model)\n", + " response = provider.generate(\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt},\n", + " ],\n", + " options={\"temperature\": temperature, \"num_ctx\": model_context},\n", + " format=CanonicalEntities.model_json_schema(),\n", + " )\n", + "\n", + " # 7.C Parse and collect results\n", + " batch_entities = json.loads(response.text).get(\"canonical_entities\", [])\n", + " all_raw_outputs.extend(batch_entities)\n", + "\n", + "\n", + " canonical_entities_llm = validate_canonical_entities(\n", + " canonical_entities_raw=all_raw_outputs\n", + " )\n", + "\n", + " # 8. Load Gold Standard for reference\n", + " canonical_entities_gold = load_json(json_file_path=gold_path)\n", + "\n", + " print(f\"{'-' * 60}\")\n", + " print(f\"Summary for {target_filename}:\")\n", + " print(f\"- Pre-cluster entities: {len(canonical_entities_pre_cluster)}\")\n", + " print(f\"- LLM generated entities: {len(canonical_entities_llm)}\")\n", + " print(f\"- Gold standard entities: {len(canonical_entities_gold)}\")\n", + "\n", + " # 9. Map the canonical entities in the predictions documents te return the right format for the front-end\n", + "\n", + " predictions_llm = copy.deepcopy(predictions)\n", + " \n", + " new_ids_map = {}\n", + "\n", + " for document in predictions_llm:\n", + " if not document.get('labels'):\n", + " continue\n", + "\n", + " for label in document.get('labels'):\n", + " label_text = label['attrs']['aymurai_alt_text']\n", + " if (\n", + " label['attrs']['canonical_entity_id'] is None\n", + " and len(label['attrs']['aymurai_label_subclass']) == 0\n", + " ):\n", + " pred_label = label['attrs']['aymurai_label']\n", + " for ce in canonical_entities_llm:\n", + " ce_label = ce.get(\"aymurai_label\")\n", + " if pred_label == ce_label:\n", + " entity_id = ce.get(\"entity_id\")\n", + " attributes = ce.get(\"attributes\") or {}\n", + " role = attributes.get(\"role\")\n", + " aliases = ce.get(\"aliases\") or []\n", + "\n", + " if any(\n", + " str(alias).strip() == str(label_text).strip()\n", + " for alias in aliases\n", + " ):\n", + " label['attrs']['canonical_entity_id'] = entity_id\n", + " if ce_label == \"PER\" and role is not None:\n", + " label['attrs']['aymurai_label_subclass'].append(role)\n", + " break\n", + "\n", + " if label['attrs']['canonical_entity_id'] is None:\n", + " key = (label['attrs']['aymurai_label'], str(label_text).strip())\n", + " if key not in new_ids_map:\n", + " new_ids_map[key] = uuid.uuid4()\n", + "\n", + " label['attrs']['canonical_entity_id'] = new_ids_map[key]\n", + "\n", + " # 10. Return structured results\n", + " return {\n", + " \"target_filename\": target_filename,\n", + " \"pre_cluster_json\": canonical_entities_pre_cluster,\n", + " \"canonical_entities_with_context\": canonical_entities_with_context,\n", + " \"llm_output_json\": canonical_entities_llm,\n", + " \"gold_standard_json\": canonical_entities_gold,\n", + " \"system_prompt\": system_prompt,\n", + " \"user_prompts\": all_user_prompts,\n", + " \"len_tokens\": len_tokens,\n", + " \"predictions\": predictions_llm\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "586b1ddd", + "metadata": {}, + "outputs": [], + "source": [ + "def get_document_paths(document_check: Path, pre_clusterization_root: Path) -> dict:\n", + " \"\"\"\n", + " Generates the pre-cluster and gold JSON paths for a given document.\n", + " \n", + " Args:\n", + " document_check (Path): The original document Path object.\n", + " pre_clusterization_root (Path): The root directory for pre-clusterization data.\n", + " \n", + " Returns:\n", + " dict: A dictionary containing the 'pre_cluster_path' and 'gold_path'.\n", + " \"\"\"\n", + " # 1. Prepare target filename\n", + " clean_base_name = document_check.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", + " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", + "\n", + " # 2. Define subdirectories\n", + " pre_cluster_dir = pre_clusterization_root / 'best-pre-clusterization-per'\n", + " gold_dir = pre_clusterization_root / 'gold-jsons'\n", + "\n", + " # 3. Build final paths\n", + " pre_cluster_json_path = pre_cluster_dir / f\"{target_filename}-ner-preds-pre-cluster.json\"\n", + " gold_json_path = gold_dir / f\"{target_filename}-canonical-entities-gold.json\"\n", + "\n", + " return {\n", + " \"target_filename\": target_filename,\n", + " \"pre_cluster_path\": pre_cluster_json_path,\n", + " \"gold_path\": gold_json_path\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3f419ede", + "metadata": {}, + "outputs": [], + "source": [ + "PRE_CLUSTERIZATION_ROOT = GOLD_JSON_ROOT.parent / \"pre-clusterization\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "90229978", + "metadata": {}, + "outputs": [], + "source": [ + "import shutil\n", + "\n", + "def run_llm_grid_search(\n", + " models: list,\n", + " system_prompts: dict,\n", + " user_prompt_templates: dict,\n", + " context_window_lengths: list,\n", + " model_context_lengths: list,\n", + " temperatures: list,\n", + " token_limit_frac: float,\n", + " documents: list[Path],\n", + " target_label: str,\n", + " base_output_path: Path,\n", + " decompose_by: int | None = 0\n", + "):\n", + " \"\"\"\n", + " Runs a grid search over hyperparameters using nested loops.\n", + " \"\"\"\n", + "\n", + " # To keep track of all results and find the best\n", + " all_combinations_results = []\n", + "\n", + " for model in models:\n", + " for system_prompt_name, system_prompt in system_prompts.items():\n", + " for user_prompt_template_name, user_prompt_template in user_prompt_templates.items():\n", + " for context_window_length in context_window_lengths:\n", + " for model_context in model_context_lengths:\n", + " for temperature in temperatures:\n", + " \n", + " print(\n", + " f\"\\nRunning grid search with model: {model}, \"\n", + " f\"context_window_length: {context_window_length}, \"\n", + " f\"model_context: {model_context}, \"\n", + " f\"temperature: {temperature}\"\n", + " )\n", + "\n", + " # 1. Create a descriptive folder name with the cleaned names\n", + " combo_name = (\n", + " f\"model-{model}-{system_prompt_name}-\"\n", + " f\"{user_prompt_template_name}-context_window-{context_window_length}-\"\n", + " f\"model_context-{model_context}-temperature-{temperature}\"\n", + " )\n", + "\n", + " combo_dir = base_output_path / combo_name\n", + " combo_dir.mkdir(parents=True, exist_ok=True)\n", + "\n", + " metrics_results = {}\n", + " metrics_file_path = (\n", + " combo_dir / f\"evaluation_metrics_{target_label}.json\"\n", + " )\n", + "\n", + " # List to collect scores for this specific combination\n", + " current_combo_scores = []\n", + "\n", + " for document in documents:\n", + " \n", + " # Get document paths\n", + " paths = get_document_paths(document, PRE_CLUSTERIZATION_ROOT) # We use this because the gold_json is in an specific folder\n", + "\n", + " # Run LLM inference\n", + " llm_response_dict = llm_infer_canonical_entities(\n", + " system_prompt=system_prompt,\n", + " user_prompt_template=user_prompt_template,\n", + " model=model,\n", + " document_path=document,\n", + " gold_path=paths['gold_path'], # When adding this to the experiment runner, make sure to pass the correct gold path\n", + " context_window_length=context_window_length,\n", + " model_context=model_context,\n", + " target_label=target_label,\n", + " temperature=temperature,\n", + " decompose_by=decompose_by,\n", + " token_limit_frac=token_limit_frac\n", + " )\n", + " # Extract predictions\n", + " ce_llm = llm_response_dict['llm_output_json']\n", + " \n", + " # Validate and prepare for saving\n", + " ce_llm = [\n", + " CanonicalEntity.model_validate(entity)\n", + " for entity in ce_llm\n", + " ]\n", + "\n", + " ce_llm = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in ce_llm\n", + " ]\n", + "\n", + " # Save the result as the llm-pred.json\n", + " target_filename = llm_response_dict['target_filename']\n", + " llm_filename = f\"{target_filename}-llm-pred.json\"\n", + " llm_output_path = combo_dir / llm_filename\n", + "\n", + " save_json(\n", + " file_path=llm_output_path, json_data=ce_llm\n", + " )\n", + "\n", + " # Extract gold standard\n", + " ce_gold = llm_response_dict['gold_standard_json']\n", + " \n", + " # Validate and prepare for saving\n", + " ce_gold = [\n", + " CanonicalEntity.model_validate(entity)\n", + " for entity in ce_gold\n", + " ]\n", + "\n", + " ce_gold = [\n", + " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", + " for entity in ce_gold\n", + " ]\n", + "\n", + " len_llm = len(ce_llm)\n", + " len_gold = len(ce_gold)\n", + "\n", + " # Evaluate metrics\n", + " score, metrics = aymurai_metrics.evaluate_disambiguation(\n", + " gold_json=ce_gold,\n", + " pred_json=ce_llm,\n", + " target_label=target_label,\n", + " )\n", + " current_combo_scores.append(score)\n", + " doc_id = target_filename\n", + " metrics_results[doc_id] = {\n", + " \"label\": target_label,\n", + " \"metric_value\": score,\n", + " \"detailed_metrics\": metrics,\n", + " \"len_llm_predictions\": len_llm,\n", + " \"len_gold_standard\": len_gold\n", + " }\n", + "\n", + " # --- Calculate Average for this combination ---\n", + " avg_score = (\n", + " np.mean(current_combo_scores) if current_combo_scores else 0.0\n", + " )\n", + "\n", + " # Add average to the results file for this folder\n", + " final_output = {\n", + " \"average_combination_score\": avg_score,\n", + " \"document_details\": metrics_results,\n", + " }\n", + "\n", + " with open(metrics_file_path, \"w\") as f:\n", + " json.dump(final_output, f, indent=4)\n", + "\n", + " # Store combination info for final ranking\n", + " all_combinations_results.append(\n", + " {\n", + " \"name\": combo_name,\n", + " \"score\": avg_score,\n", + " \"params\": {\n", + " \"model\": model,\n", + " \"system_prompt\": system_prompt_name,\n", + " \"user_prompt_template\": user_prompt_template_name,\n", + " \"context_window_length\": context_window_length,\n", + " \"model_context\": model_context\n", + " },\n", + " }\n", + " )\n", + "\n", + " # Save all combinations results in a summary file\n", + " summary_file_path = (\n", + " base_output_path / f\"results_summary_{target_label}.json\"\n", + " )\n", + " with open(summary_file_path, \"w\") as f:\n", + " json.dump(all_combinations_results, f, indent=4)\n", + "\n", + " # --- Find the best combination ---\n", + " best_combo = max(all_combinations_results, key=lambda x: x[\"score\"])\n", + "\n", + " print(f\"\\nGrid Search for {target_label} completed.\")\n", + "\n", + " # We now copy the best combination folder to a new location with a standardized name\n", + " src = Path(base_output_path) / best_combo[\"name\"]\n", + " # Combine the parent destination path with the new folder name\n", + " new_name = f\"best-llm-pred-{target_label.lower()}\"\n", + " dest = Path(base_output_path.parent) / new_name\n", + " \n", + " try:\n", + " # copytree creates the destination directory with the 'new_name'\n", + " shutil.copytree(src, dest)\n", + " print(f\"Successfully copied '{src.name}' to '{dest}'\")\n", + " except FileExistsError:\n", + " print(f\"Error: A folder named '{new_name}' already exists in '{base_output_path.parent}'\")\n", + " except Exception as e:\n", + " print(f\"An error occurred: {e}\") \n", + "\n", + " return best_combo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5110dc60", + "metadata": {}, + "outputs": [], + "source": [ + "models = [\n", + " \"phi4:14b\",\n", + " \"gpt-oss:20b\",\n", + " \"llama3\",\n", + " \"llama3.1:8b\",\n", + " \"gemma3:270m\",\n", + "]\n", + "\n", + "system_prompts = {\n", + " \"system_prompt_1\": system_prompt_1,\n", + " \"system_prompt_2\": system_prompt_2,\n", + " \"system_prompt_3\": system_prompt_3,\n", + " \"system_prompt_4\": system_prompt_4,\n", + " \"system_prompt_5\": system_prompt_5,\n", + " \"system_prompt_6\": system_prompt_6,\n", + " \"system_prompt_7\": system_prompt_7,\n", + " \"system_prompt_8\": system_prompt_8,\n", + " \"system_prompt_9\": system_prompt_9,\n", + " \"system_prompt_10\": system_prompt_10,\n", + " \"system_prompt_11\": system_prompt_11\n", + "}\n", + "\n", + "\n", + "user_prompt_templates = {\n", + " \"user_prompt_template_PER\": user_prompt_template_PER,\n", + "}\n", + "\n", + "context_window_lengths = list(range(80, 200, 10))\n", + "\n", + "model_context_lengths = [7_500, 8_000, 8_500, 9_000, 9_500]\n", + "\n", + "temperatures = list(np.arange(0,0.3,0.1))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7949d277", + "metadata": {}, + "outputs": [], + "source": [ + "document_check = documents[1]\n", + "paths = get_document_paths(document_check, PRE_CLUSTERIZATION_ROOT)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d6ff4f5a", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict = llm_infer_canonical_entities(\n", + " system_prompt=system_prompts['system_prompt_9'],\n", + " user_prompt_template=user_prompt_templates['user_prompt_template_PER'],\n", + " model=models[0],\n", + " document_path=document_check,\n", + " gold_path=paths[\"gold_path\"],\n", + " context_window_length=120,\n", + " model_context=9_500,\n", + " token_limit_frac=2/3,\n", + " temperature=0,\n", + " target_label=\"PER\",\n", + " decompose_by=None\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "60a2356a", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict = llm_infer_canonical_entities(\n", + " system_prompt=system_prompt_DIR,\n", + " user_prompt_template=user_prompt_template_DIR,\n", + " model=models[0],\n", + " document_path=document_check,\n", + " gold_path=paths[\"gold_path\"],\n", + " context_window_length=None,\n", + " model_context=9_500,\n", + " token_limit_frac=2/3,\n", + " temperature=0,\n", + " target_label=\"DIRECCION\",\n", + " decompose_by=None\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "690c940d", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict['predictions']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8e8bcb07", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict['llm_output_json']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "135c1f36", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict['canonical_entities_with_context']" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "59f003a9", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict[\"pre_cluster_json\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22e29b34", + "metadata": {}, + "outputs": [], + "source": [ + "llm_response_dict[\"gold_standard_json\"]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2845f2f5", + "metadata": {}, + "outputs": [], + "source": [ + "print(llm_response_dict[\"user_prompts\"][0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38e587f3", + "metadata": {}, + "outputs": [], + "source": [ + "print(llm_response_dict['system_prompt'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4fe27195", + "metadata": {}, + "outputs": [], + "source": [ + "models = [\n", + " \"phi4:14b\",\n", + "]\n", + "\n", + "system_prompts = {\n", + " \"system_prompt_9\": system_prompt_9\n", + "}\n", + "\n", + "\n", + "user_prompt_templates = {\n", + " \"user_prompt_template_PER\": user_prompt_template_PER,\n", + "}\n", + "\n", + "context_window_lengths = [120]\n", + "\n", + "model_context_lengths = [9_500]\n", + "\n", + "temperatures = [0]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a32b4244", + "metadata": {}, + "outputs": [], + "source": [ + "top_result = run_llm_grid_search(\n", + " models=models,\n", + " system_prompts=system_prompts,\n", + " user_prompt_templates=user_prompt_templates,\n", + " context_window_lengths=context_window_lengths,\n", + " model_context_lengths=model_context_lengths,\n", + " temperatures=temperatures,\n", + " documents=documents,\n", + " target_label=\"PER\",\n", + " base_output_path=GOLD_JSON_ROOT.parent / \"llm-grid-search-results\",\n", + " token_limit_frac=2/3,\n", + " decompose_by=None\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "86da6a45", + "metadata": {}, + "outputs": [], + "source": [ + "print(\n", + " f\"The best hyperparameter combination is '{top_result['name']}' \"\n", + " f\"with an average score of {top_result['score']:.4f}.\"\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb deleted file mode 100644 index 6af18cea..00000000 --- a/notebooks/experiments/entity-disambiguation/07-PER-entities-disambiguation.ipynb +++ /dev/null @@ -1,1487 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "64957296", - "metadata": {}, - "source": [ - "from previous notebook `06-pre-disambiguation-optimization` we found that the best hyperparameters combinations are:\n", - "- scorer: `token_set_ratio`\n", - "- score_cutoff: `70`\n", - "- processor: `light_normalizer`\n", - "\n", - "we now proceed to make the canonical entities disambiguation checked by an LLM and we give the task to the LLM to give a role to each canonical entity when it is related to a person." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fb2b1f59", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext rich\n", - "\n", - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "607ea227", - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import json\n", - "import mimetypes\n", - "import os\n", - "import re\n", - "import time\n", - "import unicodedata\n", - "from collections import Counter\n", - "from operator import itemgetter\n", - "from pathlib import Path\n", - "from typing import Iterable, Tuple\n", - "\n", - "import requests\n", - "from tqdm import tqdm\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "import requests\n", - "from more_itertools import flatten, unique_everseen\n", - "\n", - "\n", - "from aymurai.llm_providers import OllamaLLMProvider\n", - "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", - "from aymurai.utils.json_data import get_pretty, save_json, load_json\n", - "import aymurai.evaluation.metrics as aymurai_metrics\n", - "\n", - "from rapidfuzz.fuzz import token_set_ratio\n", - "from rapidfuzz import process" - ] - }, - { - "cell_type": "markdown", - "id": "1003fbb5", - "metadata": {}, - "source": [ - "# #**1** First Step: Prepare the ***gold_json*** and ***ner_preds_json***" - ] - }, - { - "cell_type": "markdown", - "id": "7ec52f24", - "metadata": {}, - "source": [ - "## /document-extract endpoint output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c7c3b672", - "metadata": {}, - "outputs": [], - "source": [ - "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://127.0.0.1:8000\")\n", - "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", - "DATA_ROOT = Path(\n", - " os.getenv(\n", - " \"DOCUMENT_DATA_ROOT\", \"../../../resources/data/restricted/disambiguation-eval/files\"\n", - " )\n", - ")\n", - "GOLD_JSON_ROOT = Path(\n", - " os.getenv(\n", - " \"GOLD_JSON_ROOT\",\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted\",\n", - " )\n", - ")\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "JSON_EXTENSION = {\".json\"}\n", - "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", - "\n", - "print(f\"Target endpoint: {ENDPOINT}\")\n", - "print(f\"Data root: {DATA_ROOT.resolve()}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18a31502", - "metadata": {}, - "outputs": [], - "source": [ - "if not DATA_ROOT.exists():\n", - " raise FileNotFoundError(\n", - " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", - " )\n", - "\n", - "\n", - "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "\n", - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "print(f\"Discovered {len(documents)} documents.\")\n", - "\n", - "gold_jsons = discover_documents(GOLD_JSON_ROOT, JSON_EXTENSION)\n", - "print(f\"Discovered {len(gold_jsons)} gold JSON files.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "65a2d588", - "metadata": {}, - "outputs": [], - "source": [ - "def call_extraction_api(\n", - " session: requests.Session, file_path: Path\n", - ") -> dict[str, object]:\n", - " payload: dict[str, object] = {\n", - " \"path\": str(file_path),\n", - " \"status\": \"failure\",\n", - " \"status_code\": None,\n", - " \"elapsed_s\": None,\n", - " \"detail\": None,\n", - " }\n", - "\n", - " if not file_path.exists():\n", - " payload[\"detail\"] = \"File does not exist\"\n", - " return payload\n", - "\n", - " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", - " files = {\n", - " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", - " }\n", - "\n", - " try:\n", - " start = time.perf_counter()\n", - " response = session.post(\n", - " ENDPOINT,\n", - " files=files,\n", - " timeout=REQUEST_TIMEOUT_S,\n", - " )\n", - " elapsed = time.perf_counter() - start\n", - " except requests.RequestException as exc:\n", - " payload[\"detail\"] = f\"Request failed: {exc}\"\n", - " return payload\n", - " finally:\n", - " files[\"file\"][1].close()\n", - "\n", - " payload[\"status_code\"] = response.status_code\n", - " payload[\"elapsed_s\"] = elapsed\n", - "\n", - " try:\n", - " response_body = response.json()\n", - " except ValueError:\n", - " response_body = {\"raw\": response.text[:500]}\n", - "\n", - " if response.ok:\n", - " payload[\"status\"] = \"success\"\n", - " payload[\"detail\"] = {\n", - " \"document_id\": response_body.get(\"document_id\"),\n", - " \"document\": response_body.get(\"document\", []),\n", - " }\n", - " else:\n", - " payload[\"detail\"] = response_body\n", - "\n", - " return payload" - ] - }, - { - "cell_type": "markdown", - "id": "dcaed02f", - "metadata": {}, - "source": [ - "## Inference" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "464e9132", - "metadata": {}, - "outputs": [], - "source": [ - "from itertools import chain\n", - "from operator import itemgetter\n", - "from typing import Any\n", - "\n", - "from more_itertools import unique_everseen\n", - "\n", - "\n", - "# Function to make inference using the API\n", - "def get_predictions(sample: str) -> dict:\n", - " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample})\n", - " response.raise_for_status()\n", - " return response.json()\n", - "\n", - "\n", - "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", - " \"\"\"\n", - " Parse prediction labels to extract unique aymurai_label and aymurai_alt_text pairs.\n", - "\n", - " Args:\n", - " predictions (list[dict[str, Any]]): A list of prediction dictionaries.\n", - "\n", - " Returns:\n", - " list[dict[str, str]]: A list of dictionaries containing unique aymurai_label and aymurai_alt_text pairs.\n", - " \"\"\"\n", - " attrs_stream = (\n", - " label.get(\"attrs\") or {}\n", - " for label in chain.from_iterable(pred.get(\"labels\", ()) for pred in predictions)\n", - " )\n", - "\n", - " unique_pairs = unique_everseen(\n", - " (\n", - " attrs.get(\"aymurai_label\"),\n", - " attrs.get(\"aymurai_alt_text\"),\n", - " )\n", - " for attrs in attrs_stream\n", - " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", - " )\n", - "\n", - " return sorted(\n", - " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", - " key=itemgetter(\"aymurai_label\", \"text\"),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "b690bfc0", - "metadata": {}, - "source": [ - "## ***gold_json*** and ***ner_preds_json*** for input to clusterization developement" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0b37a8ac", - "metadata": {}, - "outputs": [], - "source": [ - "def extract_and_save_entities(\n", - " document_paths: list[Path], output_path: Path, file_ending: str, target_label: str\n", - ") -> None:\n", - " \"\"\"\n", - " Processes a list of documents to extract specific entities and saves\n", - " each result as an individual JSON file.\n", - " It has been optimized to handle both document files and pre-existing JSON files.\n", - " \"\"\"\n", - "\n", - " with requests.Session() as session:\n", - " if \".json\" not in document_paths[0].suffix:\n", - " for doc_path in tqdm(\n", - " document_paths, desc=f\"Extracting {target_label} entities\"\n", - " ):\n", - " doc_path = Path(doc_path)\n", - "\n", - " # 1. API Extraction\n", - " response = call_extraction_api(session, doc_path)\n", - " document_data = response.get(\"detail\", {}).get(\"document\")\n", - "\n", - " if not document_data:\n", - " print(f\"Warning: No document content found for {doc_path.name}\")\n", - " continue\n", - "\n", - " # 2. Processing\n", - " raw_predictions = [\n", - " get_predictions(paragraph) for paragraph in document_data\n", - " ]\n", - " parsed_labels = parse_prediction_labels(raw_predictions)\n", - "\n", - " # 3. Filtering by dynamic label\n", - " filtered_entities = [\n", - " item\n", - " for item in parsed_labels\n", - " if item.get(\"aymurai_label\") == target_label\n", - " ]\n", - "\n", - " # 4. Saving individual file\n", - " clean_base_name = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", - " )\n", - " clean_base_name = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", - " clean_name = re.sub(r\"-{2,}\", \"-\", clean_base_name)\n", - " file_name = f\"{clean_name}{file_ending}\"\n", - " save_path = output_path / file_name\n", - "\n", - " save_json(file_path=save_path, json_data=filtered_entities)\n", - " else:\n", - " for doc_path in tqdm(\n", - " document_paths, desc=f\"Extracting {target_label} entities\"\n", - " ):\n", - " doc_path = Path(doc_path)\n", - "\n", - " # 1. Load existing JSON data\n", - " document_data = load_json(doc_path)\n", - "\n", - " if not document_data:\n", - " print(f\"Warning: No document content found for {doc_path.name}\")\n", - " continue\n", - "\n", - " # 2. Filtering by dynamic label\n", - " filtered_entities = [\n", - " item\n", - " for item in document_data\n", - " if item.get(\"aymurai_label\") == target_label\n", - " ]\n", - "\n", - " # 3. Saving individual file\n", - " clean_base_name = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", - " )\n", - " clean_base_name = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", - " clean_name = re.sub(r\"-{2,}\", \"-\", clean_base_name)\n", - " file_name = f\"{clean_name}{file_ending}\"\n", - " save_path = output_path / file_name\n", - "\n", - " save_json(file_path=save_path, json_data=filtered_entities)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4824a9c3", - "metadata": {}, - "outputs": [], - "source": [ - "def cluster_with_cdist(\n", - " items: list[dict],\n", - " threshold: int = 90,\n", - " scorer: callable = token_set_ratio,\n", - " processor: callable = None,\n", - "):\n", - " \"\"\"\n", - " Cluster entities and prepare them for CanonicalEntity conversion.\n", - " \"\"\"\n", - " if not items:\n", - " return []\n", - "\n", - " # 1. Extract texts and apply normalization\n", - " # We keep track of the original text, the processed text, and the label\n", - " entities = [item.get(\"text\", \"\") for item in items]\n", - " labels = [item.get(\"aymurai_label\", \"UNKNOWN\") for item in items]\n", - "\n", - " if processor:\n", - " normed = [processor(e) for e in entities]\n", - " else:\n", - " normed = [str(e) for e in entities]\n", - "\n", - " # 2. Similarity Matrix\n", - " sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold)\n", - " sim = np.array(sim)\n", - "\n", - " # 3. Union-Find Logic\n", - " parent = list(range(len(normed)))\n", - "\n", - " def find(i):\n", - " if parent[i] == i:\n", - " return i\n", - " parent[i] = find(parent[i])\n", - " return parent[i]\n", - "\n", - " def union(i, j):\n", - " root_i, root_j = find(i), find(j)\n", - " if root_i != root_j:\n", - " parent[root_j] = root_i\n", - "\n", - " n = len(normed)\n", - " for i in range(n):\n", - " for j in range(i + 1, n):\n", - " if sim[i, j] >= threshold:\n", - " union(i, j)\n", - "\n", - " # 4. Group into the format parse_item expects: (orig, norm, label)\n", - " clusters_map = {}\n", - " for idx in range(n):\n", - " root = find(idx)\n", - " if root not in clusters_map:\n", - " clusters_map[root] = []\n", - " # This tuple matches your 'parse_item' len == 3 condition\n", - " clusters_map[root].append((entities[idx], normed[idx], labels[idx]))\n", - "\n", - " return list(clusters_map.values())\n", - "\n", - "\n", - "def parse_item(item: tuple[str, ...]) -> tuple[str, str, str]:\n", - " \"\"\"\n", - " Parse an item into (label, orig, norm).\n", - "\n", - " Accepts:\n", - " - (orig, norm, label)\n", - " - (labelled_orig, labelled_norm) with prefix 'LABEL:'\n", - " Args:\n", - " item (tuple[str, ...]): input item\n", - "\n", - " Returns:\n", - " tuple[str, str, str]: (label, orig, norm)\n", - " \"\"\"\n", - " if len(item) == 3:\n", - " orig, norm, label = item\n", - " return label, orig, norm\n", - "\n", - " # len == 2: assume \"LABEL:text\"\n", - " labelled_orig, labelled_norm = item\n", - " label, orig = labelled_orig.split(\":\", 1)\n", - " _, norm = labelled_norm.split(\":\", 1)\n", - " return label, orig, norm\n", - "\n", - "\n", - "def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str:\n", - " \"\"\"\n", - " Pick the most common label from parsed items.\n", - "\n", - " Args:\n", - " parsed_items (list[tuple[str, str, str]]): parsed items\n", - "\n", - " Returns:\n", - " str: chosen label\n", - " \"\"\"\n", - " labels = [lbl for lbl, _, _ in parsed_items]\n", - " # majority vote; fallback to first\n", - " return Counter(labels).most_common(1)[0][0]\n", - "\n", - "\n", - "def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str:\n", - " \"\"\"\n", - " Choose the longest original surface form; tweak as needed.\n", - "\n", - " Args:\n", - " parsed_items (list[tuple[str, str, str]]): parsed items\n", - "\n", - " Returns:\n", - " str: chosen canonical text\n", - " \"\"\"\n", - " return max(parsed_items, key=lambda x: len(x[1]))[1]\n", - "\n", - "\n", - "def clusters_to_canonical_entities(\n", - " clusters: list[list[tuple[str, str]]],\n", - ") -> list[CanonicalEntity]:\n", - " \"\"\"\n", - " Convert clusters to CanonicalEntity objects.\n", - "\n", - " Args:\n", - " clusters (list[list[tuple[str, str]]]): clusters of (original, normalized) entity tuples\n", - "\n", - " Returns:\n", - " list[CanonicalEntity]: list of CanonicalEntity objects\n", - " \"\"\"\n", - " canonical_entities = []\n", - "\n", - " for cluster in clusters:\n", - " parsed = [parse_item(item) for item in cluster] # [(label, orig, norm), ...]\n", - " label = pick_cluster_label(parsed)\n", - " canonical_text = pick_canonical_text(parsed)\n", - " aliases = sorted({orig for _, orig, _ in parsed})\n", - " ce = CanonicalEntity(\n", - " aymurai_label=label,\n", - " canonical_text=canonical_text,\n", - " aliases=aliases,\n", - " attributes={},\n", - " relations=[],\n", - " )\n", - " canonical_entities.append(ce)\n", - "\n", - " return canonical_entities\n", - "\n", - "\n", - "def light_normalizer(s: str) -> str:\n", - " return s.lower().strip() if s else \"\"" - ] - }, - { - "cell_type": "markdown", - "id": "f2aa5d15", - "metadata": {}, - "source": [ - "## Canonical Entity extraction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8220314e", - "metadata": {}, - "outputs": [], - "source": [ - "# Available models\n", - "\n", - "models = [\n", - " \"phi4:14b\",\n", - " \"gpt-oss:20b\",\n", - " \"llama3\",\n", - " \"llama3.1:8b\",\n", - " \"gemma3:270m\",\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "82f8d1a2", - "metadata": {}, - "outputs": [], - "source": [ - "# Sanity check\n", - "provider = OllamaLLMProvider(model=models[0])\n", - "provider.generate(\"hola, ¿cómo estás?\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f40ef8ed", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_1 = \"\"\"\n", - "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", - "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", - "\n", - "# Material de Trabajo\n", - "Para tu análisis, recibirás:\n", - "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", - "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", - "\n", - "# Tus Tareas\n", - "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", - "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", - "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", - "\n", - "# Reglas de Salida\n", - "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", - "- `canonical_text`: El nombre más completo y formal encontrado.\n", - "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Defensor/a de Cámara\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", - "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", - "\n", - "# Estructura de Respuesta (JSON)\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Alias Principal\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\n", - "# Ejemplo de Input\n", - "Contexto: \"...la declaración del Sr. Juan Carlos Ruiz ante este Juzgado. El imputado Ruiz negó los cargos. Por su parte, la Dra. Elena Sosa, fiscal de la causa, solicitó...\"\n", - "Entidades Candidatas:\n", - "[{\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Juan Carlos Ruiz\",\n", - " \"aliases\": [\n", - " \"Juan Carlos Ruiz\",\n", - " \"Ruiz\"\n", - " ]\n", - "},\n", - "{\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Elena Sosa\",\n", - " \"aliases\": [\n", - " \"Elena Sosa\"\n", - " ]\n", - "}]\n", - "\n", - "# Ejemplo de Output\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Juan Carlos Ruiz\",\n", - " \"aliases\": [\n", - " \"Juan Carlos Ruiz\",\n", - " \"Ruiz\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Imputado\"\n", - " }\n", - " },\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Elena Sosa\",\n", - " \"aliases\": [\n", - " \"Elena Sosa\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Fiscal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "40c5f5ae", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_2 = \"\"\"\n", - "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", - "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", - "\n", - "# Material de Trabajo\n", - "Para tu análisis, recibirás:\n", - "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", - "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", - "\n", - "# Tus Tareas\n", - "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", - "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", - "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", - "\n", - "# Reglas de Salida\n", - "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", - "- `canonical_text`: El nombre más completo y formal encontrado.\n", - "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Defensor/a de Cámara\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", - "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", - "\n", - "# Estructura de Respuesta (JSON)\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Alias Principal\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d3f2848b", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template_1 = \"\"\"\n", - "A continuación se proporcionan fragmentos relevantes de un documento judicial y una lista de entidades (personas) pre-clusterizadas por similitud de texto.\n", - "\n", - "# Contexto de la causa, párrafos con alguna mención a las personas:\n", - "{document_text}\n", - "\n", - "# Entidades Pre-clusterizadas a validar:\n", - "{canonical_entities}\n", - "\n", - "# Instrucciones:\n", - "1. **Validación de Aliases:** Analiza si los aliases dentro de cada entidad canónica pertenecen realmente a la misma persona según los párrafos de contexto. \n", - " - Si un alias pertenece a una persona distinta (ej. un familiar con nombre similar), sepáralo en una nueva entidad.\n", - " - Si dos grupos de entidades canónicas refieren a la misma persona, fusiónalos.\n", - "2. **Identificación de Roles:** Extrae el rol procesal de cada persona basándote en el contexto (ej: Juez/a, Fiscal, Denunciante, Imputado/a, Víctima, Abogado/a, Perito/a, Testigo).\n", - "3. **Normalización:** Define el `canonical_text` como el nombre más completo y formal que aparezca en los aliases, si este trabajo ya está bien hecho no lo modifiques.\n", - "4. **Formato:** Devuelve la lista final de entidades en el formato JSON solicitado en el system prompt, asegurándote de no omitir a nadie que sea relevante.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7d9365ca", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_3 = \"\"\"\n", - "Eres un asistente experto en desambiguación de entidades judiciales.\n", - "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", - "\n", - "### Tu Tarea:\n", - "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", - "2. **Limpiar Aliases:** Elimina prefijos (Dr., Sra., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", - "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", - "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - " - **Nota:** No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica rol, usa `null`.\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve exclusivamente un array de objetos:\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Alias Principal\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0f7bf0f7", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_4 = \"\"\"\n", - "Eres un asistente experto en desambiguación de entidades judiciales.\n", - "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", - "\n", - "### Tu Tarea:\n", - "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", - "2. **Limpiar Aliases:** Elimina prefijos (Dr., Dra., Dres., Sra., Sr., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", - "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", - "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - " \n", - " **Instrucciones críticas de rol:**\n", - " - Si una persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y el contexto no indica que es Juez, Fiscal o Defensor oficial, asígnale el rol de **\"Abogado/a\"**.\n", - " - No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica un rol de la lista, usa `null`.\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve exclusivamente un array de objetos:\n", - "[\n", - " {\n", - " \"canonical_text\": \"Nombre Completo Normalizado\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f9bed0ca", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_5 = \"\"\"\n", - "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", - "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", - "4. **Limpiar:** En `canonical_text` y `aliases`, elimina otras palabras que no sean nombres propios.\n", - "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5ac77829", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_6 = \"\"\"\n", - "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", - "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", - "4. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", - "5. No modifiques los `canonical_text` ni los `aliases` originales.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "26f1b81b", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_7 = \"\"\"\n", - "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", - "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", - "4. **Manejo de Siglas e Iniciales:** Ten en cuenta que las personas pueden ser mencionadas por sus iniciales (ej: \"M.L.\" para \"Martín López\"). Si el contexto permite confirmar que unas iniciales refieren a una persona ya identificada, trátalas como un alias de esa misma entidad.\n", - "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona (ya sea por nombre completo, apellido solo o iniciales), devuélvelas como una sola entidad unificada.\n", - "6. **Integridad:** No modifiques los `canonical_text` ni los `aliases` originales; mantén la literalidad de lo extraído por el NER.\n", - "\n", - "Devuelve exclusivamente un array de objetos:\n", - "[\n", - " {\n", - " \"canonical_text\": \"Nombre Completo Normalizado\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f3eec132", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template_2 = \"\"\"\n", - "A continuación se proporcionan fragmentos relevantes de un documento judicial y una lista de entidades (personas) pre-clusterizadas por similitud de texto.\n", - "\n", - "# Contexto de la causa, párrafos con alguna mención a las personas:\n", - "{document_text}\n", - "\n", - "# Entidades Pre-clusterizadas a validar:\n", - "{canonical_entities}\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e07fffe7", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompts = [\n", - " system_prompt_1,\n", - " system_prompt_2,\n", - " system_prompt_3,\n", - " system_prompt_4,\n", - " system_prompt_5,\n", - " system_prompt_6,\n", - " system_prompt_7,\n", - "]\n", - "\n", - "user_prompt_templates = [\n", - " user_prompt_template_1,\n", - " user_prompt_template_2,\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "82835596", - "metadata": {}, - "outputs": [], - "source": [ - "def llm_infer_canonical_entities(\n", - " system_prompt: str,\n", - " user_prompt_template: str,\n", - " model: str,\n", - " document_path: Path,\n", - " pre_cluster_path: Path,\n", - " gold_path: Path,\n", - " context_window_length: int = 120,\n", - " model_context: int = 9_500,\n", - " target_label: str = \"PER\"\n", - ") -> dict:\n", - " \n", - " \"\"\"\n", - " Infers canonical entities using an LLM by providing context windows \n", - " around detected PER entities and pre-clusterization results.\n", - " \"\"\"\n", - "\n", - " # 1. Filename cleaning\n", - " clean_base_name = document_path.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", - " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", - "\n", - " print(f\"Processing document: {target_filename}\")\n", - "\n", - " # 2. Extract document text via API\n", - " session = requests.Session()\n", - " api_response = call_extraction_api(session, Path(document_path))\n", - " document_paragraphs = api_response.get(\"detail\", {}).get(\"document\")\n", - "\n", - " if not document_paragraphs:\n", - " raise ValueError(\"Document text is empty or not found for {target_filename}.\")\n", - "\n", - " # 3. Extract context windows for target label\n", - " context_windows = set()\n", - "\n", - " for paragraph in tqdm(document_paragraphs, desc=\"Extracting context\"):\n", - " preds = get_predictions(paragraph)\n", - " doc_text = preds['document']\n", - " \n", - " for label in preds['labels']:\n", - " label_type = label['attrs'].get('aymurai_label')\n", - " \n", - " # Filter: only PER labels\n", - " if label_type == target_label:\n", - " start = label['start_char']\n", - " end = label['end_char']\n", - " \n", - " # Define window boundaries\n", - " window_start = max(0, start - context_window_length)\n", - " window_end = min(len(doc_text), end + context_window_length)\n", - "\n", - " # Extract and clean the snippet\n", - " snippet = \" \".join(doc_text[window_start:window_end].split())\n", - " context_windows.add(snippet)\n", - "\n", - " context_windows = list(context_windows)\n", - " \n", - " # 4. Prepare Canonical Entities from Pre-cluster\n", - " canonical_entities_pre_cluster = load_json(json_file_path=pre_cluster_path)\n", - "\n", - " # Clean entities to save tokens\n", - " canonical_entities_prompt = [\n", - " {\n", - " k: v\n", - " for k, v in ce.items()\n", - " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", - " }\n", - " for ce in canonical_entities_pre_cluster\n", - " ]\n", - "\n", - " # 5. Build Final User Prompt\n", - " user_prompt = user_prompt_template.format(\n", - " document_text=\"\\n\".join(context_windows).strip(),\n", - " canonical_entities=get_pretty(canonical_entities_prompt),\n", - " )\n", - "\n", - " # 6. LLM Inference\n", - " provider = OllamaLLMProvider(model=model)\n", - " response = provider.generate(\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options={\"temperature\": 0, \"num_ctx\": model_context},\n", - " format=CanonicalEntities.model_json_schema(),\n", - " )\n", - "\n", - " # 7. Parse and Validate Output\n", - " raw_llm_output = [\n", - " output for output in json.loads(response.text)[\"canonical_entities\"]\n", - " ]\n", - "\n", - " canonical_entities_llm = [\n", - " CanonicalEntity.model_validate(canonical_entity)\n", - " for canonical_entity in raw_llm_output\n", - " ]\n", - "\n", - " # 8. Load Gold Standard for reference\n", - " canonical_entities_gold = load_json(json_file_path=gold_path)\n", - "\n", - " print(f\"\\nSummary for {target_filename}:\")\n", - " print(f\"- Pre-cluster entities: {len(canonical_entities_pre_cluster)}\")\n", - " print(f\"- LLM generated entities: {len(canonical_entities_llm)}\")\n", - " print(f\"- Gold standard entities: {len(canonical_entities_gold)}\")\n", - "\n", - " # Return structured results\n", - " return {\n", - " \"pre_cluster_json\": canonical_entities_pre_cluster,\n", - " \"llm_output_json\": canonical_entities_llm,\n", - " \"gold_standard_json\": canonical_entities_gold,\n", - " \"system_prompt\": system_prompt,\n", - " \"user_prompt\": user_prompt\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "586b1ddd", - "metadata": {}, - "outputs": [], - "source": [ - "def get_document_paths(document_check: Path, pre_clusterization_root: Path) -> dict:\n", - " \"\"\"\n", - " Generates the pre-cluster and gold JSON paths for a given document.\n", - " \n", - " Args:\n", - " document_check (Path): The original document Path object.\n", - " pre_clusterization_root (Path): The root directory for pre-clusterization data.\n", - " \n", - " Returns:\n", - " dict: A dictionary containing the 'pre_cluster_path' and 'gold_path'.\n", - " \"\"\"\n", - " # 1. Prepare target filename\n", - " clean_base_name = document_check.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", - " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", - "\n", - " # 2. Define subdirectories\n", - " pre_cluster_dir = pre_clusterization_root / 'best-pre-clusterization-per'\n", - " gold_dir = pre_clusterization_root / 'gold-jsons'\n", - "\n", - " # 3. Build final paths\n", - " pre_cluster_json_path = pre_cluster_dir / f\"{target_filename}-ner-preds-pre-cluster.json\"\n", - " gold_json_path = gold_dir / f\"{target_filename}-canonical-entities-gold.json\"\n", - "\n", - " return {\n", - " \"target_filename\": target_filename,\n", - " \"pre_cluster_path\": pre_cluster_json_path,\n", - " \"gold_path\": gold_json_path\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0c2163a5", - "metadata": {}, - "outputs": [], - "source": [ - "document_check = documents[0]\n", - "PRE_CLUSTERIZATION_ROOT = GOLD_JSON_ROOT.parent / \"pre-clusterization\"\n", - "paths = get_document_paths(document_check, PRE_CLUSTERIZATION_ROOT)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "42211950", - "metadata": {}, - "outputs": [], - "source": [ - "context_window_lengths = list(range(80, 200, 10))\n", - "\n", - "model_context_lengths = [7_500, 8_000, 8_500, 9_000, 9_500]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d5f542f5", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict = llm_infer_canonical_entities(\n", - " system_prompt=system_prompts['system_prompt_7'],\n", - " user_prompt_template=user_prompt_templates['user_prompt_template_2'],\n", - " model=models[0],\n", - " document_path=document_check,\n", - " pre_cluster_path=paths[\"pre_cluster_path\"],\n", - " gold_path=paths[\"gold_path\"],\n", - " context_window_length=120,\n", - " model_context=9_500,\n", - " target_label=\"PER\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3a029e62", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict['llm_output_json']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "027b77cc", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict['pre_cluster_json']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1087e778", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict['gold_standard_json']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5c28436f", - "metadata": {}, - "outputs": [], - "source": [ - "print(llm_response_dict['user_prompt'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b51fc151", - "metadata": {}, - "outputs": [], - "source": [ - "print(llm_response_dict['system_prompt'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "90229978", - "metadata": {}, - "outputs": [], - "source": [ - "import shutil\n", - "\n", - "def get_name(obj):\n", - " \"\"\"Helper to extract a clean string name from a function or object.\"\"\"\n", - " if obj is None:\n", - " return \"None\"\n", - " if hasattr(obj, \"__name__\"):\n", - " return obj.__name__\n", - " # Fallback for complex objects or partials: remove memory addresses\n", - " clean_name = re.sub(r\" at 0x[0-9a-fA-F]+\", \"\", str(obj))\n", - " return clean_name.strip(\"<>\").replace(\"cyfunction \", \"\").replace(\"function \", \"\")\n", - "\n", - "\n", - "def run_llm_grid_search(\n", - " models: list,\n", - " system_prompts: dict,\n", - " user_prompt_templates: dict,\n", - " context_window_lengths: list,\n", - " model_context_lengths: list,\n", - " documents: list[Path],\n", - " target_label: str,\n", - " base_output_path: Path,\n", - "):\n", - " \"\"\"\n", - " Runs a grid search over hyperparameters using nested loops.\n", - " \"\"\"\n", - "\n", - " # To keep track of all results and find the best\n", - " all_combinations_results = []\n", - "\n", - " for model in models:\n", - " for system_prompt_name, system_prompt in system_prompts.items():\n", - " for user_prompt_template_name, user_prompt_template in user_prompt_templates.items():\n", - " for context_window_length in context_window_lengths:\n", - " for model_context in model_context_lengths:\n", - " \n", - " print(\n", - " f\"\\nRunning grid search with model: {model}, \"\n", - " f\"context_window_length: {context_window_length}, \"\n", - " f\"model_context: {model_context}\"\n", - " )\n", - "\n", - " # 1. Create a descriptive folder name with the cleaned names\n", - " combo_name = (\n", - " f\"model-{model}-system_prompt-{system_prompt_name}-\"\n", - " f\"user_prompt_template-{user_prompt_template_name}-context_window-{context_window_length}-\"\n", - " f\"model_context-{model_context}\"\n", - " )\n", - "\n", - " combo_dir = base_output_path / combo_name\n", - " combo_dir.mkdir(parents=True, exist_ok=True)\n", - "\n", - " metrics_results = {}\n", - " metrics_file_path = (\n", - " combo_dir / f\"evaluation_metrics_{target_label}.json\"\n", - " )\n", - "\n", - " # List to collect scores for this specific combination\n", - " current_combo_scores = []\n", - "\n", - " for document in documents:\n", - " \n", - " # Get document paths\n", - " paths = get_document_paths(document, PRE_CLUSTERIZATION_ROOT)\n", - "\n", - " # Run LLM inference\n", - " llm_response_dict = llm_infer_canonical_entities(\n", - " system_prompt=system_prompt,\n", - " user_prompt_template=user_prompt_template,\n", - " model=model,\n", - " document_path=document,\n", - " pre_cluster_path=paths['pre_cluster_path'],\n", - " gold_path=paths['gold_path'],\n", - " context_window_length=context_window_length,\n", - " model_context=model_context,\n", - " target_label=target_label\n", - " )\n", - " # Extract predictions\n", - " ce_llm = llm_response_dict['llm_output_json']\n", - " \n", - " # Validate and prepare for saving\n", - " ce_llm = [\n", - " CanonicalEntity.model_validate(entity)\n", - " for entity in ce_llm\n", - " ]\n", - "\n", - " ce_llm = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in ce_llm\n", - " ]\n", - "\n", - " # Save the result as the llm-pred.json\n", - " target_filename = paths['target_filename']\n", - " llm_filename = f\"{target_filename}-llm-pred.json\"\n", - " llm_output_path = combo_dir / llm_filename\n", - "\n", - " save_json(\n", - " file_path=llm_output_path, json_data=ce_llm\n", - " )\n", - "\n", - " # Extract gold standard\n", - " ce_gold = llm_response_dict['gold_standard_json']\n", - " \n", - " # Validate and prepare for saving\n", - " ce_gold = [\n", - " CanonicalEntity.model_validate(entity)\n", - " for entity in ce_gold\n", - " ]\n", - "\n", - " ce_gold = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in ce_gold\n", - " ]\n", - "\n", - " len_llm = len(ce_llm)\n", - " len_gold = len(ce_gold)\n", - "\n", - " # Evaluate metrics\n", - " score, metrics = aymurai_metrics.evaluate_disambiguation(\n", - " gold_json=ce_gold,\n", - " pred_json=ce_llm,\n", - " target_label=target_label,\n", - " )\n", - " current_combo_scores.append(score)\n", - " doc_id = target_filename\n", - " metrics_results[doc_id] = {\n", - " \"label\": target_label,\n", - " \"metric_value\": score,\n", - " \"detailed_metrics\": metrics,\n", - " \"len_llm_predictions\": len_llm,\n", - " \"len_gold_standard\": len_gold\n", - " }\n", - "\n", - " # --- Calculate Average for this combination ---\n", - " avg_score = (\n", - " np.mean(current_combo_scores) if current_combo_scores else 0.0\n", - " )\n", - "\n", - " # Add average to the results file for this folder\n", - " final_output = {\n", - " \"average_combination_score\": avg_score,\n", - " \"document_details\": metrics_results,\n", - " }\n", - "\n", - " with open(metrics_file_path, \"w\") as f:\n", - " json.dump(final_output, f, indent=4)\n", - "\n", - " # Store combination info for final ranking\n", - " all_combinations_results.append(\n", - " {\n", - " \"name\": combo_name,\n", - " \"score\": avg_score,\n", - " \"params\": {\n", - " \"model\": model,\n", - " \"system_prompt\": system_prompt_name,\n", - " \"user_prompt_template\": user_prompt_template_name,\n", - " \"context_window_length\": context_window_length,\n", - " \"model_context\": model_context\n", - " },\n", - " }\n", - " )\n", - "\n", - " # Save all combinations results in a summary file\n", - " summary_file_path = (\n", - " base_output_path / f\"results_summary_{target_label}.json\"\n", - " )\n", - " with open(summary_file_path, \"w\") as f:\n", - " json.dump(all_combinations_results, f, indent=4)\n", - "\n", - " # --- Find the best combination ---\n", - " best_combo = max(all_combinations_results, key=lambda x: x[\"score\"])\n", - "\n", - " print(f\"\\nGrid Search for {target_label} completed.\")\n", - "\n", - " # We now copy the best combination folder to a new location with a standardized name\n", - " src = Path(base_output_path) / best_combo[\"name\"]\n", - " # Combine the parent destination path with the new folder name\n", - " new_name = f\"best-llm-pred-{target_label.lower()}\"\n", - " dest = Path(base_output_path.parent) / new_name\n", - " \n", - " try:\n", - " # copytree creates the destination directory with the 'new_name'\n", - " shutil.copytree(src, dest)\n", - " print(f\"Successfully copied '{src.name}' to '{dest}'\")\n", - " except FileExistsError:\n", - " print(f\"Error: A folder named '{new_name}' already exists in '{base_output_path.parent}'\")\n", - " except Exception as e:\n", - " print(f\"An error occurred: {e}\") \n", - "\n", - " return best_combo" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5110dc60", - "metadata": {}, - "outputs": [], - "source": [ - "models = [\n", - " \"phi4:14b\",\n", - " \"gpt-oss:20b\",\n", - " \"llama3\",\n", - " \"llama3.1:8b\",\n", - " \"gemma3:270m\",\n", - "]\n", - "\n", - "system_prompts = {\n", - " \"system_prompt_1\": system_prompt_1,\n", - " \"system_prompt_2\": system_prompt_2,\n", - " \"system_prompt_3\": system_prompt_3,\n", - " \"system_prompt_4\": system_prompt_4,\n", - " \"system_prompt_5\": system_prompt_5,\n", - " \"system_prompt_6\": system_prompt_6,\n", - " \"system_prompt_7\": system_prompt_7\n", - "}\n", - "\n", - "\n", - "user_prompt_templates = {\n", - " \"user_prompt_template_1\": user_prompt_template_1,\n", - " \"user_prompt_template_2\": user_prompt_template_2,\n", - "}\n", - "\n", - "context_window_lengths = list(range(80, 200, 10))\n", - "\n", - "model_context_lengths = [7_500, 8_000, 8_500, 9_000, 9_500]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4fe27195", - "metadata": {}, - "outputs": [], - "source": [ - "models = [\n", - " \"phi4:14b\",\n", - "]\n", - "\n", - "system_prompts = {\n", - " \"system_prompt_7\": system_prompt_7\n", - "}\n", - "\n", - "\n", - "user_prompt_templates = {\n", - " \"user_prompt_template_2\": user_prompt_template_2,\n", - "}\n", - "\n", - "context_window_lengths = [120]\n", - "\n", - "model_context_lengths = [9_500]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a32b4244", - "metadata": {}, - "outputs": [], - "source": [ - "top_result = run_llm_grid_search(\n", - " models=models,\n", - " system_prompts=system_prompts,\n", - " user_prompt_templates=user_prompt_templates,\n", - " context_window_lengths=context_window_lengths,\n", - " model_context_lengths=model_context_lengths,\n", - " documents=documents[0:3],\n", - " target_label=\"PER\",\n", - " base_output_path=GOLD_JSON_ROOT.parent / \"llm-grid-search-results\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "86da6a45", - "metadata": {}, - "outputs": [], - "source": [ - "print(\n", - " f\"The best hyperparameter combination is '{top_result['name']}' \"\n", - " f\"with an average score of {top_result['score']:.4f}.\"\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb index 61c88f82..ceaa9f84 100644 --- a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb +++ b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb @@ -13,6 +13,16 @@ "3) disambiguation\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "id": "2edb7397", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich" + ] + }, { "cell_type": "code", "execution_count": null, @@ -26,7 +36,169 @@ "import os\n", "from pathlib import Path\n", "\n", - "import requests\n" + "import requests" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80f525f3", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template_PER = \"\"\"\n", + "Se proporciona la lista de entidades (personas) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su rol y validez.\n", + "\n", + "# Entidades Pre-clusterizadas a validar:\n", + "{canonical_entities}\n", + "\n", + "Procesa la lista siguiendo las instrucciones de filtrado, fusión y asignación de roles.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c8f2ce2", + "metadata": {}, + "outputs": [], + "source": [ + "user_prompt_template_DIR = \"\"\"\n", + "Se proporciona la lista de entidades (direcciones) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su validez y si hay otras entidades de direcciones que corresponden a esa.\n", + "\n", + "# Entidades Pre-clusterizadas a validar:\n", + "{canonical_entities}\n", + "\n", + "Procesa la lista siguiendo las instrucciones de filtrado y fusión.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1aa9140e", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_PER = \"\"\"\n", + "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Asignación de Rol:** Identifica el rol procesal basándote en las ventanas de contexto dentro de cada entidad canónica en la parte de `attributes`['context']\n", + " Elija un rol EXCLUSIVAMENTE en esta lista:\n", + " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", + "2. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", + "3. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", + " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", + " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", + "4. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", + "5. **Limpieza:** Limpiá los `aliases` y el `canonical_text` si los mismos tienen otras palabras, pero respeta que estén escritos de igual manera a que sus ventanas de contexto.\n", + " Te dejo un ejemplo de esta instrucción.\n", + " Vos recibís:\n", + " {\n", + " \"canonical_text\": \"por DREXLER, JORGE\",\n", + " \"aliases\": [\n", + " \"por DREXLER, JORGE\",\n", + " \"Jorge Drexler\"\n", + " ],\n", + " \"attributes\": {\n", + " \"context\": [\n", + " \"Fdo. por DREXLER, JORGE - JUEZ DE CÁMARA el mismo cita en el documento 56 que Juan es culpable\",\n", + " \"es acaso Jorge Drexler el juez designado para esta causa\"\n", + " ]\n", + " }\n", + "\n", + " Debés entregar:\n", + " {\n", + " \"canonical_text\": \"DREXLER, JORGE\",\n", + " \"aliases\": [\n", + " \"DREXLER, JORGE\",\n", + " \"Jorge Drexler\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Juez/a\"\n", + " }\n", + "\n", + "6. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", + "\n", + "### Formato de Salida (JSON):\n", + "Devuelve un array de objetos con esta estructura:\n", + "[\n", + " {\n", + " \"entity_id\": \"optional-unique-id\",\n", + " \"aymurai_label\": \"PER\",\n", + " \"canonical_text\": \"Nombre de la entidad\",\n", + " \"aliases\": [\n", + " \"Nombre de la entidad\",\n", + " \"Alias 1\",\n", + " \"Alias 2\"\n", + " ],\n", + " \"attributes\": {\n", + " \"role\": \"Rol de la lista o null\"\n", + " }\n", + " }\n", + "]\n", + "\n", + "No incluyas el campo 'context' en tu respuesta final.\n", + "\"\"\"" + ] + }, + { + "cell_type": "markdown", + "id": "61fb70d5", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d67ad4f2", + "metadata": {}, + "outputs": [], + "source": [ + "system_prompt_DIR = \"\"\"\n", + "Eres un auditor experto en desambiguación de domicilios y direcciones en documentos judiciales. Tu tarea es validar y consolidar una lista de direcciones pre-agrupadas basándote en su contexto.\n", + "\n", + "### Instrucciones Estrictas:\n", + "1. **Consolidación Geográfica:** - Si dos entidades refieren a la misma ubicación física, fusiónalas en una sola entidad.\n", + " - Considera que una dirección puede estar escrita de forma completa en un alias (ej: \"Av. Rivadavia 123, CABA\") y de forma abreviada en otro (ej: \"Rivadavia 123\").\n", + " - Trata las variantes ortográficas o abreviaturas (Av. vs Avenida, Piso vs P., Dpto vs Departamento) como aliases de la misma ubicación.\n", + "2. **Filtrado:** Elimina entidades que no sean direcciones postales o domicilios físicos (ej: correos electrónicos, URLs, nombres de juzgados o menciones abstractas como \"el domicilio constituido\").\n", + "\n", + "### Formato de Salida (JSON):\n", + "[\n", + " {\n", + " \"entity_id\": \"ID original\",\n", + " \"aymurai_label\": \"DIRECCION\",\n", + " \"canonical_text\": \"Dirección más completa extraída del texto\",\n", + " \"aliases\": [\n", + " \"Dirección más completa (Igual al canonical)\",\n", + " \"Variante 1\",\n", + " \"Variante 2\"\n", + " ],\n", + " \"attributes\": []\n", + " }\n", + "]\n", + "**IMPORTANTE:** No incluyas el campo 'context' en la respuesta.\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43dcd972", + "metadata": {}, + "outputs": [], + "source": [ + "SYSTEM_PROMPTS = {\n", + " \"PER\": system_prompt_PER,\n", + " \"DIRECCION\": system_prompt_DIR,\n", + "}\n", + "\n", + "USER_PROMPT_TEMPLATES = {\n", + " \"PER\": user_prompt_template_PER,\n", + " \"DIRECCION\": user_prompt_template_DIR,\n", + "}" ] }, { @@ -36,35 +208,27 @@ "metadata": {}, "outputs": [], "source": [ - "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8999\")\n", + "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8000\")\n", "DATA_ROOT = Path(\n", " os.getenv(\n", " \"DISAMBIGUATION_DATA_ROOT\",\n", - " \"/resources/data/restricted/disambiguation-eval/documents\",\n", + " \"../../../resources/data/restricted/disambiguation-eval/files\",\n", " )\n", ")\n", "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", "\n", "LIMIT = int(os.getenv(\"DISAMBIGUATION_DOC_LIMIT\", \"0\")) # 0 = no limit\n", - "TARGET_LABELS = os.getenv(\"DISAMBIGUATION_TARGET_LABELS\", \"PER\")\n", - "TARGET_LABELS = [label.strip() for label in TARGET_LABELS.split(\",\") if label.strip()]\n", - "\n", - "FUZZY_THRESHOLD = int(os.getenv(\"DISAMBIGUATION_THRESHOLD\", \"70\"))\n", - "FUZZY_SCORER = os.getenv(\"DISAMBIGUATION_SCORER\", \"token_set_ratio\")\n", - "FUZZY_PROCESSOR = os.getenv(\"DISAMBIGUATION_PROCESSOR\", \"light_normalizer\")\n", + "TARGET_LABELS = os.getenv(\"DISAMBIGUATION_TARGET_LABELS\")\n", "\n", "print(f\"API: {API_BASE_URL}\")\n", "print(f\"Data root: {DATA_ROOT}\")\n", - "print(f\"Target labels: {TARGET_LABELS or 'ALL'}\")\n", - "print(\n", - " f\"Fuzzy params: scorer={FUZZY_SCORER}, threshold={FUZZY_THRESHOLD}, processor={FUZZY_PROCESSOR}\"\n", - ")\n" + "print(f\"Target labels: {TARGET_LABELS or 'All the targets that have the prompt set'}\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "4d3d5787", + "id": "58e9d69e", "metadata": {}, "outputs": [], "source": [ @@ -86,25 +250,55 @@ " endpoint = f\"{API_BASE_URL}/anonymizer/predict\"\n", " predictions = []\n", " for paragraph in paragraphs:\n", - " response = requests.post(endpoint, json={\"text\": paragraph}, timeout=60)\n", + " response = requests.post(\n", + " endpoint, json={\"text\": paragraph}, params={\"use_cache\": False}, timeout=60\n", + " )\n", " response.raise_for_status()\n", " predictions.append(response.json())\n", " return predictions\n", "\n", "\n", - "def disambiguate(predictions: list[dict]) -> dict:\n", + "def disambiguate(\n", + " predictions: list[dict], use_custom_prompts: bool = True\n", + ") -> list[dict]:\n", " endpoint = f\"{API_BASE_URL}/anonymizer/disambiguate\"\n", - " params = {\n", - " \"threshold\": FUZZY_THRESHOLD,\n", - " \"scorer\": FUZZY_SCORER,\n", - " \"processor\": FUZZY_PROCESSOR,\n", - " \"target_labels\": TARGET_LABELS,\n", - " }\n", + "\n", + " payload = {\"paragraphs\": predictions}\n", + "\n", + " if use_custom_prompts:\n", + " custom_prompts_list = []\n", + "\n", + " for label in SYSTEM_PROMPTS.keys():\n", + " custom_prompts_list.append(\n", + " {\n", + " \"label\": label,\n", + " \"system\": SYSTEM_PROMPTS.get(label, \"\"),\n", + " \"user\": USER_PROMPT_TEMPLATES.get(label, \"\"),\n", + " }\n", + " )\n", + "\n", + " payload[\"custom_prompts\"] = custom_prompts_list\n", + "\n", + " else:\n", + " payload[\"custom_prompts\"] = []\n", + "\n", + " params = {\"use_cache\": False}\n", + "\n", " if TARGET_LABELS:\n", " params[\"target_labels\"] = TARGET_LABELS\n", - " response = requests.post(endpoint, params=params, json=predictions, timeout=120)\n", + "\n", + " else:\n", + " params[\"target_labels\"] = []\n", + "\n", + " response = requests.post(\n", + " endpoint,\n", + " params=params,\n", + " json=payload,\n", + " timeout=600,\n", + " )\n", + "\n", " response.raise_for_status()\n", - " return response.json()\n" + " return response.json()" ] }, { @@ -118,21 +312,17 @@ "if LIMIT > 0:\n", " documents = documents[:LIMIT]\n", "\n", - "print(f\"Found {len(documents)} documents\")\n", - "documents[:5]\n" + "print(f\"Found {len(documents)} documents\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "1eb1c141", + "id": "d844f2c8", "metadata": {}, "outputs": [], "source": [ - "from aymurai.experiments.entity_disambiguation.runner import call_extraction_api\n", - "\n", - "\n", - "for doc_path in documents:\n", + "for doc_path in documents[2:3]:\n", " print(f\"\\n=== {doc_path.name} ===\")\n", " session = requests.Session()\n", " document = extract_document(\n", @@ -147,15 +337,55 @@ " predictions = predict_paragraphs(paragraphs)\n", " print(f\"Predictions: {len(predictions)}\")\n", "\n", - " disambiguated = disambiguate(predictions)\n", - " print(f\"Canonical entities: {len(disambiguated.get('canonical_entities', []))}\")\n", - " print(json.dumps(disambiguated, indent=2, ensure_ascii=False))\n" + " disambiguated = disambiguate(predictions=predictions, use_custom_prompts=False)\n", + " print(f\"NER prdictions: {len(disambiguated.get('data', []))}\")\n", + " print(json.dumps(disambiguated, indent=2, ensure_ascii=False))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f65c14ab", + "metadata": {}, + "outputs": [], + "source": [ + "predictions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0eb0561f", + "metadata": {}, + "outputs": [], + "source": [ + "disambiguated" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e7296e8a", + "metadata": {}, + "outputs": [], + "source": [ + "for pred in disambiguated.get(\"data\", []):\n", + " labels = pred.get(\"labels\", [])\n", + " if labels:\n", + " for label in labels:\n", + " attrs = label.get(\"attrs\", {})\n", + " if attrs.get(\"aymurai_label\") == \"FECHA\":\n", + " print(\n", + " label.get(\"text\"),\n", + " attrs.get(\"aymurai_label_subclass\"),\n", + " attrs.get(\"canonical_entity_id\"),\n", + " )" ] }, { "cell_type": "code", "execution_count": null, - "id": "877f5167", + "id": "0f95a791", "metadata": {}, "outputs": [], "source": [] diff --git a/notebooks/experiments/entity-disambiguation/09-date-formatter-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/09-date-formatter-disambiguation.ipynb new file mode 100644 index 00000000..0cefa239 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/09-date-formatter-disambiguation.ipynb @@ -0,0 +1,360 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "185b896a", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6c675263", + "metadata": {}, + "outputs": [], + "source": [ + "# import locale\n", + "# import platform\n", + "\n", + "# locales_a_probar = ['es_AR.UTF-8', 'es_ES.UTF-8', 'es_MX.UTF-8', 'spanish']\n", + "\n", + "# for loc in locales_a_probar:\n", + "# try:\n", + "# locale.setlocale(locale.LC_ALL, loc)\n", + "# break\n", + "# except locale.Error:\n", + "# continue\n", + "\n", + "# print(f\"Sistema: {platform.system()}\")\n", + "# print(f\"Locale actual: {locale.getlocale()}\")\n", + "# print(f\"Default Locale: {locale.getdefaultlocale()}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6640fde2", + "metadata": {}, + "outputs": [], + "source": [ + "# # 1. Forzamos a Python a que crea que \"es_AR.UTF-8\" es lo mismo que el locale básico\n", + "# # Esto intercepta la llamada que falla en patterns.py:4\n", + "# def mock_setlocale(category, value=None):\n", + "# return \"C\" # 'C' es el locale universal que siempre existe\n", + "\n", + "# locale.setlocale = mock_setlocale\n", + "\n", + "# # 2. Opcional: Si quieres ser más preciso, intenta usar el español genérico\n", + "# try:\n", + "# # En Mac a veces es 'es_ES.UTF-8' o solo 'es_AR' (sin .UTF-8)\n", + "# # Aquí intentamos forzar uno que funcione\n", + "# import _locale\n", + "# _locale._setlocale(locale.LC_ALL, 'en_US.UTF-8') \n", + "# except:\n", + "# pass\n", + "\n", + "# print(\"✅ Hack de locale aplicado. Ya puedes importar aymurai.\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "692b5bfe", + "metadata": {}, + "outputs": [], + "source": [ + "from aymurai.transforms.datetime_formatter import DatetimeFormatter\n", + "from aymurai.meta.api_interfaces import DocLabel\n", + "from aymurai.utils.entity_disambiguation.date_formatter import get_canonical_dates" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "54ad952d", + "metadata": {}, + "outputs": [], + "source": [ + "formatter = DatetimeFormatter()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "73946d4a", + "metadata": {}, + "outputs": [], + "source": [ + "ent = DocLabel(\n", + " text= \"el dia 23 de enero de 2024\",\n", + " start_char= 0,\n", + " end_char= 500,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"enero de 2024\",\n", + " \"aymurai_alt_start_char\": 0,\n", + " \"aymurai_alt_end_char\": 400,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.7974909742673238,\n", + " \"aymurai_label_instance\": 2,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": True,\n", + " \"canonical_entity_id\": \"e8a5378d-bbc1-50f0-8da1-27871d5a80a2\"\n", + " }\n", + ")\n", + "\n", + "date_1 = DocLabel(\n", + " text=\"Buenos Aires, 14 de mayo de 2023\",\n", + " start_char=10,\n", + " end_char=42,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"14/05/2023\",\n", + " \"aymurai_alt_start_char\": 24,\n", + " \"aymurai_alt_end_char\": 42,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.9543,\n", + " \"aymurai_label_instance\": 1,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": \"fe54c1a2-b3d4-4e5f-a6b7-c8d9e0f1a2b3\"\n", + " }\n", + ")\n", + "\n", + "date_2 = DocLabel(\n", + " text=\"audiencia del 03 de febrero de 2024\",\n", + " start_char=150,\n", + " end_char=185,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"03/02/2024\",\n", + " \"aymurai_alt_start_char\": 164,\n", + " \"aymurai_alt_end_char\": 185,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.8876,\n", + " \"aymurai_label_instance\": 2,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": \"a1b2c3d4-e5f6-4a5b-8c9d-0e1f2a3b4c5d\"\n", + " }\n", + ")\n", + "\n", + "date_3 = DocLabel(\n", + " text=\"22/10/2023\",\n", + " start_char=402,\n", + " end_char=412,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"22/10/2023\",\n", + " \"aymurai_alt_start_char\": 402,\n", + " \"aymurai_alt_end_char\": 412,\n", + " \"aymurai_method\": \"regex/patterns\",\n", + " \"aymurai_score\": 1.0,\n", + " \"aymurai_label_instance\": 3,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": \"b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e\"\n", + " }\n", + ")\n", + "\n", + "date_4 = DocLabel(\n", + " text=\"notificado el pasado lunes 11\",\n", + " start_char=820,\n", + " end_char=849,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"11\",\n", + " \"aymurai_alt_start_char\": 847,\n", + " \"aymurai_alt_end_char\": 849,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.6124,\n", + " \"aymurai_label_instance\": 4,\n", + " \"aymurai_disambiguation\": \"llm\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": \"c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f\"\n", + " }\n", + ")\n", + "\n", + "date_5 = DocLabel(\n", + " text=\"primero de enero de dos mil veintiuno\",\n", + " start_char=1100,\n", + " end_char=1137,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"01/01/2021\",\n", + " \"aymurai_alt_start_char\": 1100,\n", + " \"aymurai_alt_end_char\": 1137,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.7942,\n", + " \"aymurai_label_instance\": 5,\n", + " \"aymurai_disambiguation\": \"llm\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": \"d4e5f6a7-b8c9-4d0e-1f2a-3b4c5d6e7f8a\"\n", + " }\n", + ")\n", + "\n", + "\n", + "labels_baseline = [ent, date_1, date_2, date_3, date_4, date_5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "417e0719", + "metadata": {}, + "outputs": [], + "source": [ + "date_1 = DocLabel(\n", + " text=\"el dia 23 de enero de 2024\",\n", + " start_char=0,\n", + " end_char=26,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"23 de enero de 2024\",\n", + " \"aymurai_alt_start_char\": 7,\n", + " \"aymurai_alt_end_char\": 26,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.98,\n", + " \"aymurai_label_instance\": 1,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": None\n", + " }\n", + ")\n", + "\n", + "date_2 = DocLabel(\n", + " text=\"hechos del 23/01/24\",\n", + " start_char=150,\n", + " end_char=169,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"23/01/24\",\n", + " \"aymurai_alt_start_char\": 11,\n", + " \"aymurai_alt_end_char\": 19,\n", + " \"aymurai_method\": \"regex/patterns\",\n", + " \"aymurai_score\": 1.0,\n", + " \"aymurai_label_instance\": 2,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": None\n", + " }\n", + ")\n", + "\n", + "date_3 = DocLabel(\n", + " text=\"ocurrido el 23 enero 2024\",\n", + " start_char=300,\n", + " end_char=325,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"23 enero 2024\",\n", + " \"aymurai_alt_start_char\": 12,\n", + " \"aymurai_alt_end_char\": 25,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.91,\n", + " \"aymurai_label_instance\": 3,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": None\n", + " }\n", + ")\n", + "\n", + "date_4 = DocLabel(\n", + " text=\"23-01-2024\",\n", + " start_char=450,\n", + " end_char=460,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"23-01-2024\",\n", + " \"aymurai_alt_start_char\": 450,\n", + " \"aymurai_alt_end_char\": 460,\n", + " \"aymurai_method\": \"regex/patterns\",\n", + " \"aymurai_score\": 1.0,\n", + " \"aymurai_label_instance\": 4,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": None\n", + " }\n", + ")\n", + "\n", + "date_5 = DocLabel(\n", + " text=\"23 de enero\",\n", + " start_char=600,\n", + " end_char=618,\n", + " attrs={\n", + " \"aymurai_label\": \"FECHA\",\n", + " \"aymurai_label_subclass\": [],\n", + " \"aymurai_alt_text\": \"23 de enero\",\n", + " \"aymurai_alt_start_char\": 600,\n", + " \"aymurai_alt_end_char\": 618,\n", + " \"aymurai_method\": \"ner/flair\",\n", + " \"aymurai_score\": 0.99,\n", + " \"aymurai_label_instance\": 5,\n", + " \"aymurai_disambiguation\": \"fuzzy\",\n", + " \"aymurai_anonymize\": False,\n", + " \"canonical_entity_id\": None\n", + " }\n", + ")\n", + "\n", + "batch_dates = [date_1, date_2, date_3, date_4, date_5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b9581fd", + "metadata": {}, + "outputs": [], + "source": [ + "ce = get_canonical_dates(batch_dates)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7b7a58a", + "metadata": {}, + "outputs": [], + "source": [ + "ce" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/resources/llm/entity_disambiguation.yml b/resources/llm/entity_disambiguation.yml new file mode 100644 index 00000000..14615b37 --- /dev/null +++ b/resources/llm/entity_disambiguation.yml @@ -0,0 +1,69 @@ +PER: + system: | + Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas. + + ### Instrucciones Estrictas: + 1. **Asignación de Rol:** Identifica el rol procesal basándote en las ventanas de contexto dentro de cada entidad canónica en la parte de `attributes`['context'] + Elija un rol EXCLUSIVAMENTE en esta lista: + - "Denunciante", "Denunciado/a", "Víctima", "Juez/a", "Defensor/a de Cámara", "Asesor/a Tutelar", "Fiscal", "Abogado/a", "Perito/a", "Testigo". + 2. **Regla "Dr/a":** Si se menciona como "Dr.", "Dra." o "Dres." y no hay otro cargo explícito, asígnale el rol "Abogado/a". + 3. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona. + - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos. + - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo. + 4. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes). + 5. **Limpieza:** Limpiá los `aliases` y el `canonical_text` si los mismos tienen otras palabras, pero respeta que estén escritos de igual manera a que sus ventanas de contexto. + Te dejo un ejemplo de esta instrucción. + Vos recibís: + { + "canonical_text": "por DREXLER, JORGE", + "aliases": [ + "por DREXLER, JORGE", + "Jorge Drexler" + ], + "attributes": { + "context": [ + "Fdo. por DREXLER, JORGE - JUEZ DE CÁMARA el mismo cita en el documento 56 que Juan es culpable", + "es acaso Jorge Drexler el juez designado para esta causa" + ] + } + + Debés entregar: + { + "canonical_text": "DREXLER, JORGE", + "aliases": [ + "DREXLER, JORGE", + "Jorge Drexler" + ], + "attributes": { + "role": "Juez/a" + } + + 6. **Manejo de Iniciales:** Identifica si las siglas (ej: "M.L.") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma. + + ### Formato de Salida (JSON): + Devuelve un array de objetos con esta estructura: + [ + { + "entity_id": "optional-unique-id", + "aymurai_label": "PER", + "canonical_text": "Nombre de la entidad", + "aliases": [ + "Nombre de la entidad", + "Alias 1", + "Alias 2" + ], + "attributes": { + "role": "Rol de la lista o null" + } + } + ] + + No incluyas el campo 'context' en tu respuesta final. + + user: | + Se proporciona la lista de entidades (personas) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su rol y validez. + + # Entidades Pre-clusterizadas a validar: + {canonical_entities} + + Procesa la lista siguiendo las instrucciones de filtrado, fusión y asignación de roles. diff --git a/resources/pipelines/production/flair-anonymizer/pipeline.json b/resources/pipelines/production/flair-anonymizer/pipeline.json index 07e4638e..75302833 100644 --- a/resources/pipelines/production/flair-anonymizer/pipeline.json +++ b/resources/pipelines/production/flair-anonymizer/pipeline.json @@ -20,6 +20,10 @@ [ "aymurai.transforms.anonymization_postprocess.core.AnonymizationEntityCleaner", {} + ], + [ + "aymurai.transforms.datetime_formatter.core.DatetimeFormatter", + {} ] ], "use_cache": false diff --git a/uv.lock b/uv.lock index 9913d119..a903aa6d 100644 --- a/uv.lock +++ b/uv.lock @@ -1,19 +1,22 @@ version = 1 -revision = 3 requires-python = "==3.10.*" resolution-markers = [ - "sys_platform == 'darwin'", - "platform_machine == 'aarch64' and sys_platform == 'linux'", - "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')", + "platform_system == 'Darwin' and sys_platform == 'darwin'", + "platform_system != 'Darwin' and sys_platform == 'darwin'", + "platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", + "platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", + "(platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", + "platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", + "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", ] [[package]] name = "absl-py" version = "2.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" } +sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" }, + { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811 }, ] [[package]] @@ -38,9 +41,9 @@ wheels = [ name = "aiohappyeyeballs" version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265 }, ] [[package]] @@ -86,9 +89,9 @@ dependencies = [ { name = "frozenlist" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490 }, ] [[package]] @@ -101,9 +104,9 @@ dependencies = [ { name = "tomli" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064, upload-time = "2025-11-14T20:35:04.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554, upload-time = "2025-11-14T20:35:05.699Z" }, + { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554 }, ] [[package]] @@ -126,18 +129,18 @@ wheels = [ name = "annotated-doc" version = "0.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303 }, ] [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, ] [[package]] @@ -153,9 +156,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191, upload-time = "2025-02-18T20:35:33.314Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191 } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228, upload-time = "2025-02-18T20:35:28.659Z" }, + { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228 }, ] [[package]] @@ -176,9 +179,9 @@ wheels = [ name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, ] [[package]] @@ -188,9 +191,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, ] [[package]] @@ -200,23 +203,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, - { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549, upload-time = "2025-07-30T10:02:00.101Z" }, - { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539, upload-time = "2025-07-30T10:02:00.929Z" }, - { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467, upload-time = "2025-07-30T10:02:02.08Z" }, - { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355, upload-time = "2025-07-30T10:02:02.867Z" }, - { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187, upload-time = "2025-07-30T10:02:03.674Z" }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, + { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549 }, + { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539 }, + { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467 }, + { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355 }, + { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187 }, ] [[package]] @@ -227,18 +230,18 @@ dependencies = [ { name = "python-dateutil" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797 }, ] [[package]] name = "asttokens" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, ] [[package]] @@ -248,18 +251,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380 } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069 }, ] [[package]] name = "async-timeout" version = "5.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, ] [[package]] @@ -269,23 +272,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217, upload-time = "2024-08-24T23:15:36.449Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209, upload-time = "2024-08-24T23:15:35.317Z" }, + { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209 }, ] [[package]] name = "attrs" version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615 }, ] [[package]] name = "aymurai" -version = "2.0.0a6.dev5" +version = "2.0.0a7.dev37" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -412,9 +415,9 @@ mlops = [ name = "babel" version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, ] [[package]] @@ -425,9 +428,9 @@ dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 }, ] [[package]] @@ -441,9 +444,9 @@ dependencies = [ { name = "lxml" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924, upload-time = "2023-08-15T22:34:59.047Z" } +sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419, upload-time = "2023-08-15T22:34:56.022Z" }, + { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419 }, ] [[package]] @@ -453,9 +456,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437 }, ] [package.optional-dependencies] @@ -467,9 +470,9 @@ css = [ name = "blinker" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, ] [[package]] @@ -525,54 +528,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283 }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504 }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811 }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402 }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217 }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079 }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475 }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829 }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211 }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184 }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790 }, ] [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, ] [[package]] name = "charset-normalizer" version = "3.4.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, - { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, - { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, - { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, - { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, - { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, - { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, - { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, - { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, - { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, - { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709 }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814 }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467 }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280 }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454 }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609 }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586 }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290 }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663 }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964 }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064 }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015 }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792 }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198 }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262 }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, ] [[package]] @@ -580,29 +583,29 @@ name = "click" version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, ] [[package]] name = "cloudpickle" version = "3.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228 }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] [[package]] @@ -610,29 +613,29 @@ name = "colorlog" version = "6.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743 }, ] [[package]] name = "comm" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, ] [[package]] name = "conllu" version = "4.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768, upload-time = "2023-06-19T12:37:49.632Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098, upload-time = "2023-06-19T12:37:47.885Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098 }, ] [[package]] @@ -642,7 +645,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } wheels = [ { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, @@ -707,7 +710,7 @@ wheels = [ name = "cycler" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, ] @@ -773,18 +776,18 @@ wheels = [ name = "decorator" version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, ] [[package]] name = "defusedxml" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, ] [[package]] @@ -794,52 +797,52 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298 }, ] [[package]] name = "dill" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976 } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668 }, ] [[package]] name = "diskcache" version = "5.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" }, + { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550 }, ] [[package]] name = "distlib" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, ] [[package]] name = "distro" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, ] [[package]] name = "dnspython" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251 } wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094 }, ] @@ -862,15 +865,15 @@ wheels = [ name = "docopt" version = "0.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901 } [[package]] name = "docx2txt" version = "0.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613, upload-time = "2025-03-24T20:59:25.21Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025, upload-time = "2025-03-24T20:59:24.394Z" }, + { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025 }, ] [[package]] @@ -906,9 +909,9 @@ wheels = [ name = "einops" version = "0.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805, upload-time = "2025-02-09T03:17:00.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359, upload-time = "2025-02-09T03:17:01.998Z" }, + { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359 }, ] [[package]] @@ -919,9 +922,9 @@ dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238 } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604 }, ] [[package]] @@ -931,18 +934,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, ] [[package]] name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, ] [[package]] @@ -952,9 +955,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644, upload-time = "2023-06-27T15:24:28.075Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644 } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039, upload-time = "2023-06-27T15:24:24.869Z" }, + { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039 }, ] [[package]] @@ -1028,62 +1031,62 @@ wheels = [ name = "fastar" version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524, upload-time = "2025-11-26T02:36:00.72Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536, upload-time = "2025-11-26T02:34:35.236Z" }, - { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235, upload-time = "2025-11-26T02:34:19.367Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386, upload-time = "2025-11-26T02:33:47.613Z" }, - { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955, upload-time = "2025-11-26T02:32:44.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987, upload-time = "2025-11-26T02:32:59.701Z" }, - { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900, upload-time = "2025-11-26T02:33:16.059Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523, upload-time = "2025-11-26T02:33:30.897Z" }, - { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268, upload-time = "2025-11-26T02:34:04.003Z" }, - { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286, upload-time = "2025-11-26T02:34:50.279Z" }, - { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921, upload-time = "2025-11-26T02:35:07.292Z" }, - { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302, upload-time = "2025-11-26T02:35:24.995Z" }, - { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141, upload-time = "2025-11-26T02:35:42.449Z" }, - { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544, upload-time = "2025-11-26T02:36:23.801Z" }, - { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701, upload-time = "2025-11-26T02:36:09.625Z" }, - { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544, upload-time = "2025-11-26T02:34:46.195Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020, upload-time = "2025-11-26T02:34:31.085Z" }, - { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735, upload-time = "2025-11-26T02:34:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779, upload-time = "2025-11-26T02:32:55.109Z" }, - { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755, upload-time = "2025-11-26T02:33:11.595Z" }, - { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732, upload-time = "2025-11-26T02:33:27.122Z" }, - { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571, upload-time = "2025-11-26T02:33:42.986Z" }, - { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440, upload-time = "2025-11-26T02:34:15.439Z" }, - { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424, upload-time = "2025-11-26T02:35:02.742Z" }, - { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675, upload-time = "2025-11-26T02:35:20.252Z" }, - { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098, upload-time = "2025-11-26T02:35:37.643Z" }, - { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397, upload-time = "2025-11-26T02:35:56.215Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536 }, + { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235 }, + { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386 }, + { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955 }, + { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987 }, + { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900 }, + { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523 }, + { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268 }, + { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286 }, + { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921 }, + { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302 }, + { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141 }, + { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544 }, + { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701 }, + { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544 }, + { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020 }, + { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735 }, + { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779 }, + { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755 }, + { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732 }, + { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571 }, + { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440 }, + { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424 }, + { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675 }, + { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098 }, + { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397 }, ] [[package]] name = "fastjsonschema" version = "2.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024 }, ] [[package]] name = "fastuuid" version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760, upload-time = "2025-10-19T22:25:21.509Z" }, - { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748, upload-time = "2025-10-19T22:41:52.873Z" }, - { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537, upload-time = "2025-10-19T22:33:55.603Z" }, - { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994, upload-time = "2025-10-19T22:26:17.631Z" }, - { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003, upload-time = "2025-10-19T22:23:45.415Z" }, - { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583, upload-time = "2025-10-19T22:26:00.756Z" }, - { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955, upload-time = "2025-10-19T22:36:25.196Z" }, - { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763, upload-time = "2025-10-19T22:24:28.451Z" }, - { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613, upload-time = "2025-10-19T22:25:06.827Z" }, - { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045, upload-time = "2025-10-19T22:28:32.732Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122, upload-time = "2025-10-19T22:23:15.59Z" }, + { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760 }, + { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748 }, + { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537 }, + { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994 }, + { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003 }, + { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583 }, + { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955 }, + { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763 }, + { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613 }, + { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045 }, + { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122 }, ] [[package]] @@ -1099,9 +1102,9 @@ wheels = [ name = "filetype" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020, upload-time = "2022-11-02T17:34:04.141Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020 } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970 }, ] [[package]] @@ -1111,9 +1114,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "termcolor" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720, upload-time = "2025-08-16T20:20:24.175Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945, upload-time = "2025-08-16T20:20:22.87Z" }, + { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945 }, ] [[package]] @@ -1147,7 +1150,7 @@ dependencies = [ { name = "transformers", extra = ["sentencepiece"] }, { name = "wikipedia-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607, upload-time = "2025-02-05T14:45:44.322Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607 } wheels = [ { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, ] @@ -1203,43 +1206,43 @@ wheels = [ name = "fqdn" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121 }, ] [[package]] name = "frozenlist" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875 } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230 }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621 }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889 }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464 }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649 }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188 }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748 }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351 }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767 }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887 }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785 }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312 }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650 }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659 }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837 }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989 }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, ] [[package]] name = "fsspec" version = "2025.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285 } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966 }, ] [package.optional-dependencies] @@ -1254,9 +1257,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927, upload-time = "2024-10-26T00:50:35.149Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821, upload-time = "2024-10-26T00:50:33.425Z" }, + { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821 }, ] [[package]] @@ -1290,9 +1293,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "smmap" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794 }, ] [[package]] @@ -1318,9 +1321,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759, upload-time = "2025-10-28T21:34:51.529Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706, upload-time = "2025-10-28T21:34:50.151Z" }, + { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706 }, ] [[package]] @@ -1349,9 +1352,9 @@ dependencies = [ { name = "google-api-core" }, { name = "google-auth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027 } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469 }, ] [[package]] @@ -1412,9 +1415,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-crc32c" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload-time = "2025-11-17T15:38:06.659Z" } +sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload-time = "2025-11-17T15:38:05.594Z" }, + { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340 }, ] [[package]] @@ -1469,7 +1472,7 @@ wheels = [ name = "greenlet" version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651 } wheels = [ { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658 }, { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810 }, @@ -1497,24 +1500,24 @@ wheels = [ name = "h11" version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, ] [[package]] name = "hf-xet" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020 } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099 }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178 }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214 }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054 }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812 }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920 }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735 }, ] [[package]] @@ -1525,24 +1528,24 @@ dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, ] [[package]] name = "httptools" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531, upload-time = "2025-10-10T03:54:20.887Z" }, - { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408, upload-time = "2025-10-10T03:54:22.455Z" }, - { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889, upload-time = "2025-10-10T03:54:23.753Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460, upload-time = "2025-10-10T03:54:25.313Z" }, - { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267, upload-time = "2025-10-10T03:54:26.81Z" }, - { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429, upload-time = "2025-10-10T03:54:28.174Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173, upload-time = "2025-10-10T03:54:29.5Z" }, + { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531 }, + { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408 }, + { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889 }, + { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460 }, + { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267 }, + { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429 }, + { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173 }, ] [[package]] @@ -1555,7 +1558,7 @@ dependencies = [ { name = "httpcore" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, ] @@ -1583,27 +1586,27 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" }, + { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094 }, ] [[package]] name = "identify" version = "2.6.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, + { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183 }, ] [[package]] name = "idna" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, ] [[package]] @@ -1635,7 +1638,7 @@ name = "ipykernel" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "appnope", marker = "(platform_machine != 'aarch64' and platform_system == 'Darwin') or (platform_system == 'Darwin' and sys_platform != 'linux')" }, { name = "comm" }, { name = "debugpy" }, { name = "ipython" }, @@ -1649,9 +1652,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968 }, ] [[package]] @@ -1659,7 +1662,7 @@ name = "ipython" version = "8.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "decorator" }, { name = "exceptiongroup" }, { name = "jedi" }, @@ -1687,9 +1690,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808 }, ] [[package]] @@ -1699,7 +1702,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arrow" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649 } wheels = [ { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, ] @@ -1720,9 +1723,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, ] [[package]] @@ -1732,29 +1735,37 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, ] [[package]] name = "jiter" version = "0.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294, upload-time = "2025-11-09T20:49:23.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652, upload-time = "2025-11-09T20:46:41.021Z" }, - { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829, upload-time = "2025-11-09T20:46:43.281Z" }, - { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568, upload-time = "2025-11-09T20:46:45.075Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052, upload-time = "2025-11-09T20:46:46.818Z" }, - { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585, upload-time = "2025-11-09T20:46:48.319Z" }, - { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541, upload-time = "2025-11-09T20:46:49.643Z" }, - { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423, upload-time = "2025-11-09T20:46:51.731Z" }, - { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958, upload-time = "2025-11-09T20:46:53.432Z" }, - { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084, upload-time = "2025-11-09T20:46:54.848Z" }, - { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054, upload-time = "2025-11-09T20:46:56.487Z" }, - { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368, upload-time = "2025-11-09T20:46:58.638Z" }, - { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847, upload-time = "2025-11-09T20:47:00.295Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652 }, + { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829 }, + { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568 }, + { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052 }, + { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585 }, + { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541 }, + { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423 }, + { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958 }, + { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084 }, + { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054 }, + { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368 }, + { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847 }, + { url = "https://files.pythonhosted.org/packages/fe/54/5339ef1ecaa881c6948669956567a64d2670941925f245c434f494ffb0e5/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8", size = 311144 }, + { url = "https://files.pythonhosted.org/packages/27/74/3446c652bffbd5e81ab354e388b1b5fc1d20daac34ee0ed11ff096b1b01a/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3", size = 305877 }, + { url = "https://files.pythonhosted.org/packages/a1/f4/ed76ef9043450f57aac2d4fbeb27175aa0eb9c38f833be6ef6379b3b9a86/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e", size = 340419 }, + { url = "https://files.pythonhosted.org/packages/21/01/857d4608f5edb0664aa791a3d45702e1a5bcfff9934da74035e7b9803846/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d", size = 347212 }, + { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974 }, + { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233 }, + { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537 }, + { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110 }, ] [[package]] @@ -1765,18 +1776,18 @@ dependencies = [ { name = "click" }, { name = "rapidfuzz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537, upload-time = "2024-11-01T16:18:57.337Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990, upload-time = "2024-11-01T16:18:55.928Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990 }, ] [[package]] name = "jmespath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, ] [[package]] @@ -1813,18 +1824,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359, upload-time = "2023-09-01T12:34:44.187Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701, upload-time = "2023-09-01T12:34:42.563Z" }, + { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701 }, ] [[package]] name = "jsonpointer" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114 } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595 }, ] [[package]] @@ -1862,9 +1873,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437 }, ] [[package]] @@ -1879,9 +1890,9 @@ dependencies = [ { name = "nbconvert" }, { name = "notebook" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657 }, ] [[package]] @@ -1914,9 +1925,9 @@ dependencies = [ { name = "pyzmq" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510 }, ] [[package]] @@ -1927,9 +1938,9 @@ dependencies = [ { name = "platformdirs" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, ] [[package]] @@ -1946,9 +1957,9 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, ] [[package]] @@ -1958,9 +1969,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687 }, ] [[package]] @@ -1980,7 +1991,7 @@ dependencies = [ { name = "overrides" }, { name = "packaging" }, { name = "prometheus-client" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "pyzmq" }, { name = "send2trash" }, { name = "terminado" }, @@ -1988,9 +1999,9 @@ dependencies = [ { name = "traitlets" }, { name = "websocket-client" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221 }, ] [[package]] @@ -1998,12 +2009,12 @@ name = "jupyter-server-terminals" version = "0.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "terminado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, + { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656 }, ] [[package]] @@ -2035,9 +2046,9 @@ wheels = [ name = "jupyterlab-pygments" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, ] [[package]] @@ -2053,44 +2064,44 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830 }, ] [[package]] name = "jupyterlab-widgets" version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, ] [[package]] name = "kiwisolver" version = "1.4.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159, upload-time = "2025-08-10T21:25:35.472Z" }, - { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578, upload-time = "2025-08-10T21:25:36.73Z" }, - { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312, upload-time = "2025-08-10T21:25:37.658Z" }, - { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458, upload-time = "2025-08-10T21:25:39.067Z" }, - { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640, upload-time = "2025-08-10T21:25:40.489Z" }, - { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074, upload-time = "2025-08-10T21:25:42.221Z" }, - { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036, upload-time = "2025-08-10T21:25:43.801Z" }, - { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310, upload-time = "2025-08-10T21:25:45.045Z" }, - { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943, upload-time = "2025-08-10T21:25:46.393Z" }, - { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488, upload-time = "2025-08-10T21:25:48.074Z" }, - { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787, upload-time = "2025-08-10T21:25:49.442Z" }, - { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730, upload-time = "2025-08-10T21:25:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036, upload-time = "2025-08-10T21:25:52.063Z" }, - { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183, upload-time = "2025-08-10T21:27:37.669Z" }, - { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675, upload-time = "2025-08-10T21:27:39.031Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277, upload-time = "2025-08-10T21:27:40.129Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994, upload-time = "2025-08-10T21:27:41.181Z" }, - { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744, upload-time = "2025-08-10T21:27:42.254Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159 }, + { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578 }, + { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312 }, + { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458 }, + { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640 }, + { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074 }, + { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036 }, + { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310 }, + { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943 }, + { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488 }, + { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787 }, + { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730 }, + { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036 }, + { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183 }, + { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675 }, + { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277 }, + { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994 }, + { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744 }, ] [[package]] @@ -2100,7 +2111,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474 } [[package]] name = "langextract" @@ -2124,9 +2135,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029, upload-time = "2025-11-14T22:21:30.511Z" } +sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029 } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592, upload-time = "2025-11-14T22:21:29.044Z" }, + { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592 }, ] [package.optional-dependencies] @@ -2138,9 +2149,9 @@ openai = [ name = "lark" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732 } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, ] [[package]] @@ -2150,9 +2161,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fire" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292, upload-time = "2022-09-06T16:09:06.607Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594, upload-time = "2022-09-06T16:09:04.658Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594 }, ] [[package]] @@ -2173,39 +2184,39 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976, upload-time = "2025-11-16T00:03:51.812Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975, upload-time = "2025-11-16T00:03:49.182Z" }, + { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975 }, ] [[package]] name = "lxml" version = "6.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, - { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, - { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, - { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, - { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, - { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, - { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, - { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, - { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, - { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, - { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, - { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, - { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, - { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, - { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, - { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, - { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589 }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671 }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961 }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087 }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620 }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664 }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397 }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178 }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148 }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035 }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111 }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662 }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973 }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953 }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695 }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051 }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264 }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435 }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913 }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357 }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295 }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913 }, ] [[package]] @@ -2215,9 +2226,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509 }, ] [[package]] @@ -2227,18 +2238,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070 } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321 }, ] [[package]] name = "markdown2" version = "2.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652, upload-time = "2025-07-27T16:16:24.307Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954, upload-time = "2025-07-27T16:16:23.026Z" }, + { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954 }, ] [[package]] @@ -2249,9 +2260,9 @@ dependencies = [ { name = "beautifulsoup4" }, { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816, upload-time = "2025-11-16T19:21:18.565Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816 } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724, upload-time = "2025-11-16T19:21:17.622Z" }, + { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724 }, ] [[package]] @@ -2281,28 +2292,28 @@ dependencies = [ { name = "tqdm" }, { name = "transformers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302, upload-time = "2025-09-30T15:44:59.591Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914, upload-time = "2025-09-30T15:44:58.441Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914 }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631 }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057 }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050 }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681 }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705 }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524 }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282 }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745 }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571 }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056 }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932 }, ] [[package]] @@ -2340,18 +2351,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516 }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] [[package]] @@ -2374,7 +2385,7 @@ dependencies = [ { name = "absl-py" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356, upload-time = "2025-04-17T08:25:02.247Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356 } wheels = [ { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, ] @@ -2401,7 +2412,7 @@ dependencies = [ { name = "scikit-learn" }, { name = "scipy" }, { name = "sqlalchemy" }, - { name = "waitress", marker = "platform_system == 'Windows'" }, + { name = "waitress", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ad/f8/10ccb111ed53732dfceae0369073023f96acd6b00f92fb3c24473938702d/mlflow-3.8.1.tar.gz", hash = "sha256:0823377bedff4d530b0d560bf394daf9f7e9fbba53453add04eadad34de962cc", size = 8550037 } wheels = [ @@ -2461,9 +2472,9 @@ wheels = [ name = "more-itertools" version = "10.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 }, ] [[package]] @@ -2474,18 +2485,18 @@ dependencies = [ { name = "jinja2" }, { name = "matplotlib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433, upload-time = "2025-11-05T18:12:24.183Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051, upload-time = "2025-11-05T18:12:22.527Z" }, + { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, ] [[package]] @@ -2495,27 +2506,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153, upload-time = "2025-10-06T14:48:26.409Z" }, - { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993, upload-time = "2025-10-06T14:48:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607, upload-time = "2025-10-06T14:48:29.581Z" }, - { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847, upload-time = "2025-10-06T14:48:32.107Z" }, - { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616, upload-time = "2025-10-06T14:48:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333, upload-time = "2025-10-06T14:48:35.9Z" }, - { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239, upload-time = "2025-10-06T14:48:37.302Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618, upload-time = "2025-10-06T14:48:38.963Z" }, - { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655, upload-time = "2025-10-06T14:48:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245, upload-time = "2025-10-06T14:48:41.848Z" }, - { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523, upload-time = "2025-10-06T14:48:43.749Z" }, - { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129, upload-time = "2025-10-06T14:48:45.225Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999, upload-time = "2025-10-06T14:48:46.703Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711, upload-time = "2025-10-06T14:48:48.146Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504, upload-time = "2025-10-06T14:48:49.447Z" }, - { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422, upload-time = "2025-10-06T14:48:50.789Z" }, - { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050, upload-time = "2025-10-06T14:48:51.938Z" }, - { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153, upload-time = "2025-10-06T14:48:53.146Z" }, - { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153 }, + { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993 }, + { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607 }, + { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847 }, + { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616 }, + { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333 }, + { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239 }, + { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618 }, + { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655 }, + { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245 }, + { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523 }, + { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129 }, + { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999 }, + { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711 }, + { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504 }, + { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422 }, + { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050 }, + { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153 }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317 }, ] [[package]] @@ -2525,14 +2536,14 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083, upload-time = "2025-04-17T03:11:04.223Z" }, - { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128, upload-time = "2025-04-17T03:11:06.045Z" }, - { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132, upload-time = "2025-04-17T03:11:07.533Z" }, - { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, - { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083 }, + { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128 }, + { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132 }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948 }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636 }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478 }, ] [[package]] @@ -2579,9 +2590,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525 }, ] [[package]] @@ -2594,9 +2605,9 @@ dependencies = [ { name = "jupyter-core" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, ] [[package]] @@ -2606,27 +2617,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nbformat" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747, upload-time = "2025-11-16T17:38:55.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122, upload-time = "2025-11-16T17:38:54.164Z" }, + { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122 }, ] [[package]] name = "nest-asyncio" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, ] [[package]] name = "networkx" version = "3.4.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, ] [[package]] @@ -2661,25 +2672,25 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 }, ] [[package]] name = "numpy" version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, - { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411, upload-time = "2024-02-05T23:48:29.038Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016, upload-time = "2024-02-05T23:48:54.098Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889, upload-time = "2024-02-05T23:49:25.361Z" }, - { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746, upload-time = "2024-02-05T23:49:51.983Z" }, - { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620, upload-time = "2024-02-05T23:50:22.515Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659, upload-time = "2024-02-05T23:50:35.834Z" }, - { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905, upload-time = "2024-02-05T23:51:03.701Z" }, + { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468 }, + { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411 }, + { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016 }, + { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889 }, + { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746 }, + { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620 }, + { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659 }, + { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, ] [[package]] @@ -2687,7 +2698,8 @@ name = "nvidia-cublas-cu12" version = "12.8.4.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, + { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, ] [[package]] @@ -2695,7 +2707,8 @@ name = "nvidia-cuda-cupti-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, ] [[package]] @@ -2703,7 +2716,8 @@ name = "nvidia-cuda-nvrtc-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, + { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, ] [[package]] @@ -2711,7 +2725,8 @@ name = "nvidia-cuda-runtime-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, + { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, ] [[package]] @@ -2722,7 +2737,8 @@ dependencies = [ { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, + { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, ] [[package]] @@ -2733,7 +2749,8 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, + { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, ] [[package]] @@ -2741,7 +2758,8 @@ name = "nvidia-cufile-cu12" version = "1.13.1.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, + { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, ] [[package]] @@ -2749,7 +2767,8 @@ name = "nvidia-curand-cu12" version = "10.3.9.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, + { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, ] [[package]] @@ -2762,7 +2781,8 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, + { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, ] [[package]] @@ -2773,7 +2793,8 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, + { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, ] [[package]] @@ -2781,7 +2802,8 @@ name = "nvidia-cusparselt-cu12" version = "0.7.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, + { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, ] [[package]] @@ -2789,7 +2811,8 @@ name = "nvidia-nccl-cu12" version = "2.27.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, ] [[package]] @@ -2797,7 +2820,8 @@ name = "nvidia-nvjitlink-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, + { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, ] [[package]] @@ -2805,7 +2829,8 @@ name = "nvidia-nvshmem-cu12" version = "3.3.20" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" }, + { url = "https://files.pythonhosted.org/packages/92/9d/3dd98852568fb845ec1f7902c90a22b240fe1cbabda411ccedf2fd737b7b/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0", size = 124484616 }, + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145 }, ] [[package]] @@ -2813,7 +2838,8 @@ name = "nvidia-nvtx-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, ] [[package]] @@ -2823,7 +2849,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "defusedxml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045, upload-time = "2020-01-18T16:55:48.852Z" } +sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045 } [[package]] name = "ollama" @@ -2833,9 +2859,9 @@ dependencies = [ { name = "httpx" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620, upload-time = "2025-11-13T23:02:17.416Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620 } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354, upload-time = "2025-11-13T23:02:16.292Z" }, + { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354 }, ] [[package]] @@ -2852,9 +2878,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133, upload-time = "2025-09-24T13:00:53.075Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627, upload-time = "2025-09-24T13:00:50.754Z" }, + { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627 }, ] [[package]] @@ -2864,7 +2890,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929, upload-time = "2025-01-16T13:53:40.22Z" } +sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929 } wheels = [ { url = "https://files.pythonhosted.org/packages/dc/53/2c50afa0b1e05ecdb4603818e85f7d174e683d874ef63a6abe3ac92220c8/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca", size = 37326460 }, { url = "https://files.pythonhosted.org/packages/3b/43/68555327df94bb9b59a1fd645f63fafb0762515344d2046698762fc19d58/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81", size = 56723330 }, @@ -2939,9 +2965,9 @@ dependencies = [ { name = "sqlalchemy" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444, upload-time = "2025-11-10T05:14:30.151Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444 } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708, upload-time = "2025-11-10T05:14:28.6Z" }, + { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708 }, ] [[package]] @@ -2969,18 +2995,18 @@ wheels = [ name = "overrides" version = "7.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832 }, ] [[package]] name = "packaging" version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, ] [[package]] @@ -3008,18 +3034,18 @@ wheels = [ name = "pandocfilters" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, ] [[package]] name = "parso" version = "0.8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205 } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668 }, ] [[package]] @@ -3032,9 +3058,9 @@ dependencies = [ { name = "pydantic-settings" }, { name = "pypdfium2" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968, upload-time = "2025-06-11T14:42:09.492Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693, upload-time = "2025-06-11T14:42:08.157Z" }, + { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693 }, ] [[package]] @@ -3044,53 +3070,53 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, ] [[package]] name = "pillow" version = "10.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059, upload-time = "2024-07-01T09:48:43.583Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271, upload-time = "2024-07-01T09:45:22.07Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658, upload-time = "2024-07-01T09:45:25.292Z" }, - { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075, upload-time = "2024-07-01T09:45:27.94Z" }, - { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808, upload-time = "2024-07-01T09:45:30.305Z" }, - { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290, upload-time = "2024-07-01T09:45:32.868Z" }, - { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163, upload-time = "2024-07-01T09:45:35.279Z" }, - { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100, upload-time = "2024-07-01T09:45:37.74Z" }, - { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880, upload-time = "2024-07-01T09:45:39.89Z" }, - { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218, upload-time = "2024-07-01T09:45:42.771Z" }, - { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487, upload-time = "2024-07-01T09:45:45.176Z" }, - { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219, upload-time = "2024-07-01T09:45:47.274Z" }, - { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889, upload-time = "2024-07-01T09:48:04.815Z" }, - { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160, upload-time = "2024-07-01T09:48:07.206Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020, upload-time = "2024-07-01T09:48:09.66Z" }, - { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539, upload-time = "2024-07-01T09:48:12.529Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125, upload-time = "2024-07-01T09:48:14.891Z" }, - { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373, upload-time = "2024-07-01T09:48:17.601Z" }, - { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661, upload-time = "2024-07-01T09:48:20.293Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, + { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, + { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, + { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, + { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, + { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, + { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, + { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, + { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, + { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, + { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, + { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, + { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, + { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, + { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, + { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, + { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, + { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, ] [[package]] name = "pip" version = "25.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014 } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622 }, ] [[package]] name = "platformdirs" version = "4.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731 }, ] [[package]] @@ -3102,14 +3128,14 @@ dependencies = [ { name = "pyee" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424, upload-time = "2025-11-11T18:39:10.175Z" }, - { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228, upload-time = "2025-11-11T18:39:13.915Z" }, - { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424, upload-time = "2025-11-11T18:39:17.093Z" }, - { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122, upload-time = "2025-11-11T18:39:20.619Z" }, - { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645, upload-time = "2025-11-11T18:39:24.005Z" }, - { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837, upload-time = "2025-11-11T18:39:27.174Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843, upload-time = "2025-11-11T18:39:30.851Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959, upload-time = "2025-11-11T18:39:33.998Z" }, + { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424 }, + { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228 }, + { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424 }, + { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122 }, + { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645 }, + { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837 }, + { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843 }, + { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959 }, ] [[package]] @@ -3120,16 +3146,16 @@ dependencies = [ { name = "narwhals" }, { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624, upload-time = "2025-11-17T18:39:24.523Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174, upload-time = "2025-11-17T18:39:20.351Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174 }, ] [[package]] name = "pptree" version = "3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043, upload-time = "2020-04-15T18:28:53.362Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043 } [[package]] name = "pre-commit" @@ -3151,9 +3177,9 @@ wheels = [ name = "prometheus-client" version = "0.23.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481, upload-time = "2025-09-18T20:47:25.043Z" } +sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145, upload-time = "2025-09-18T20:47:23.875Z" }, + { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145 }, ] [[package]] @@ -3163,33 +3189,33 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, ] [[package]] name = "propcache" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534 }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526 }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263 }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012 }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491 }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319 }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856 }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241 }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552 }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113 }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778 }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047 }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093 }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638 }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229 }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, ] [[package]] @@ -3223,57 +3249,57 @@ wheels = [ name = "psutil" version = "6.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565, upload-time = "2024-10-17T21:31:45.68Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762, upload-time = "2024-10-17T21:32:05.991Z" }, - { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777, upload-time = "2024-10-17T21:32:07.872Z" }, - { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259, upload-time = "2024-10-17T21:32:10.177Z" }, - { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255, upload-time = "2024-10-17T21:32:11.964Z" }, - { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804, upload-time = "2024-10-17T21:32:13.785Z" }, - { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386, upload-time = "2024-10-17T21:32:21.399Z" }, - { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228, upload-time = "2024-10-17T21:32:23.88Z" }, + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, ] [[package]] name = "pyarrow" version = "22.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, - { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085, upload-time = "2025-10-24T10:03:38.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613, upload-time = "2025-10-24T10:03:46.516Z" }, - { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059, upload-time = "2025-10-24T10:03:55.353Z" }, - { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043, upload-time = "2025-10-24T10:04:05.408Z" }, - { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505, upload-time = "2025-10-24T10:04:15.786Z" }, - { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641, upload-time = "2025-10-24T10:04:22.57Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968 }, + { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085 }, + { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613 }, + { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059 }, + { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043 }, + { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505 }, + { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641 }, ] [[package]] name = "pyasn1" version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135 }, ] [[package]] @@ -3283,18 +3309,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892 } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259 }, ] [[package]] name = "pycparser" version = "2.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, ] [[package]] @@ -3307,9 +3333,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580 }, ] [package.optional-dependencies] @@ -3324,7 +3350,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } wheels = [ { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298 }, { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475 }, @@ -3379,9 +3405,9 @@ dependencies = [ { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880 }, ] [[package]] @@ -3392,9 +3418,9 @@ dependencies = [ { name = "jinja2" }, { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240, upload-time = "2024-05-10T15:36:21.153Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403, upload-time = "2024-05-10T15:36:17.36Z" }, + { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, ] [[package]] @@ -3404,18 +3430,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250, upload-time = "2025-03-17T18:53:15.955Z" } +sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730, upload-time = "2025-03-17T18:53:14.532Z" }, + { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730 }, ] [[package]] name = "pygments" version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, ] [[package]] @@ -3450,9 +3476,9 @@ wheels = [ name = "pypandoc" version = "1.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477, upload-time = "2025-11-13T16:30:29.608Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451, upload-time = "2025-11-13T16:30:07.66Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451 }, ] [[package]] @@ -3468,29 +3494,29 @@ wheels = [ name = "pypdfium2" version = "4.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239, upload-time = "2024-05-09T18:33:17.552Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254, upload-time = "2024-05-09T18:32:48.653Z" }, - { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624, upload-time = "2024-05-09T18:32:51.458Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126, upload-time = "2024-05-09T18:32:53.581Z" }, - { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077, upload-time = "2024-05-09T18:32:55.99Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431, upload-time = "2024-05-09T18:32:57.911Z" }, - { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008, upload-time = "2024-05-09T18:32:59.886Z" }, - { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543, upload-time = "2024-05-09T18:33:02.597Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911, upload-time = "2024-05-09T18:33:05.376Z" }, - { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430, upload-time = "2024-05-09T18:33:08.067Z" }, - { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951, upload-time = "2024-05-09T18:33:10.567Z" }, - { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098, upload-time = "2024-05-09T18:33:13.107Z" }, - { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118, upload-time = "2024-05-09T18:33:15.489Z" }, + { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254 }, + { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624 }, + { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126 }, + { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077 }, + { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431 }, + { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008 }, + { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543 }, + { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911 }, + { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430 }, + { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951 }, + { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098 }, + { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118 }, ] [[package]] name = "pysocks" version = "1.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 }, ] [[package]] @@ -3500,9 +3526,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, ] [[package]] @@ -3513,27 +3539,27 @@ dependencies = [ { name = "lxml" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987 }, ] [[package]] name = "python-dotenv" version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, ] [[package]] name = "python-json-logger" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683 } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548 }, ] [[package]] @@ -3561,9 +3587,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889, upload-time = "2022-11-25T19:33:07.958Z" } +sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949, upload-time = "2022-11-25T19:33:06.093Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949 }, ] [[package]] @@ -3574,18 +3600,18 @@ dependencies = [ { name = "numpy" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086, upload-time = "2021-01-09T17:35:49.131Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564, upload-time = "2021-01-09T17:35:47.543Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564 }, ] [[package]] name = "pytz" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, ] [[package]] @@ -3593,35 +3619,35 @@ name = "pywin32" version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, - { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, - { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, + { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432 }, + { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103 }, + { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557 }, ] [[package]] name = "pywinpty" version = "3.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669, upload-time = "2025-10-03T21:16:29.205Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330, upload-time = "2025-10-03T21:20:15.656Z" }, + { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330 }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, ] [[package]] @@ -3631,52 +3657,52 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, - { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, - { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, - { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, - { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, - { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, - { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, - { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, - { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, - { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, - { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850 }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380 }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421 }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149 }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070 }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441 }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529 }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276 }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208 }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766 }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266 }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206 }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747 }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371 }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862 }, ] [[package]] name = "rapidfuzz" version = "3.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900, upload-time = "2025-11-01T11:54:52.321Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376, upload-time = "2025-11-01T11:52:29.175Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903, upload-time = "2025-11-01T11:52:31.239Z" }, - { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655, upload-time = "2025-11-01T11:52:32.852Z" }, - { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708, upload-time = "2025-11-01T11:52:34.618Z" }, - { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106, upload-time = "2025-11-01T11:52:36.069Z" }, - { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048, upload-time = "2025-11-01T11:52:37.936Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020, upload-time = "2025-11-01T11:52:39.657Z" }, - { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958, upload-time = "2025-11-01T11:52:41.017Z" }, - { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043, upload-time = "2025-11-01T11:52:42.465Z" }, - { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273, upload-time = "2025-11-01T11:52:44.005Z" }, - { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875, upload-time = "2025-11-01T11:52:45.405Z" }, + { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376 }, + { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903 }, + { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655 }, + { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708 }, + { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106 }, + { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048 }, + { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020 }, + { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958 }, + { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043 }, + { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273 }, + { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875 }, ] [[package]] @@ -3688,33 +3714,33 @@ dependencies = [ { name = "rpds-py" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766 }, ] [[package]] name = "regex" version = "2024.11.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, + { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674 }, + { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684 }, + { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589 }, + { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511 }, + { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149 }, + { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707 }, + { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702 }, + { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976 }, + { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397 }, + { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726 }, + { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098 }, + { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325 }, + { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277 }, + { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197 }, + { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714 }, + { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042 }, ] [[package]] @@ -3727,9 +3753,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, ] [package.optional-dependencies] @@ -3744,18 +3770,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490 }, ] [[package]] name = "rfc3986-validator" version = "0.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, ] [[package]] @@ -3765,9 +3791,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046 }, ] [[package]] @@ -3778,9 +3804,9 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393 }, ] [[package]] @@ -3801,56 +3827,56 @@ wheels = [ name = "rignore" version = "0.7.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999, upload-time = "2025-11-05T20:42:38.373Z" }, - { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824, upload-time = "2025-11-05T20:42:22.1Z" }, - { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121, upload-time = "2025-11-05T20:40:48.94Z" }, - { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813, upload-time = "2025-11-05T20:41:04.71Z" }, - { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019, upload-time = "2025-11-05T20:41:20.723Z" }, - { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822, upload-time = "2025-11-05T20:41:36.99Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820, upload-time = "2025-11-05T20:42:06.364Z" }, - { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050, upload-time = "2025-11-05T20:41:51.124Z" }, - { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164, upload-time = "2025-11-05T21:40:10.368Z" }, - { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028, upload-time = "2025-11-05T21:40:27.977Z" }, - { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024, upload-time = "2025-11-05T21:40:45.148Z" }, - { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531, upload-time = "2025-11-05T21:41:02.734Z" }, - { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817, upload-time = "2025-11-05T21:41:47.51Z" }, - { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001, upload-time = "2025-11-05T21:41:32.778Z" }, - { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462, upload-time = "2025-11-05T20:42:50.804Z" }, - { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918, upload-time = "2025-11-05T20:42:33.689Z" }, - { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922, upload-time = "2025-11-05T20:41:00.361Z" }, - { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987, upload-time = "2025-11-05T20:41:16.219Z" }, - { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110, upload-time = "2025-11-05T20:41:32.631Z" }, - { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339, upload-time = "2025-11-05T20:41:47.128Z" }, - { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680, upload-time = "2025-11-05T20:42:18.061Z" }, - { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045, upload-time = "2025-11-05T20:42:02.315Z" }, - { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310, upload-time = "2025-11-05T21:40:23.184Z" }, - { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998, upload-time = "2025-11-05T21:40:40.603Z" }, - { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178, upload-time = "2025-11-05T21:40:57.585Z" }, - { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190, upload-time = "2025-11-05T21:41:16.403Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999 }, + { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824 }, + { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121 }, + { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813 }, + { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019 }, + { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822 }, + { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820 }, + { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050 }, + { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164 }, + { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028 }, + { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024 }, + { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531 }, + { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817 }, + { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001 }, + { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462 }, + { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918 }, + { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922 }, + { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987 }, + { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110 }, + { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339 }, + { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680 }, + { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045 }, + { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310 }, + { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998 }, + { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178 }, + { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190 }, ] [[package]] name = "rpds-py" version = "0.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469 } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, - { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, - { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, - { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, - { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, - { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, - { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, - { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, - { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, - { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, - { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, - { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490 }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751 }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696 }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136 }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699 }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022 }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522 }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579 }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305 }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503 }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322 }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792 }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901 }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823 }, ] [[package]] @@ -3860,9 +3886,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, ] [[package]] @@ -3872,35 +3898,35 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830 }, ] [[package]] name = "safetensors" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781 }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058 }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748 }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881 }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463 }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855 }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152 }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856 }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060 }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715 }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377 }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368 }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423 }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380 }, + { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430 }, + { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890 }, + { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885 }, ] [[package]] @@ -3913,13 +3939,13 @@ dependencies = [ { name = "scipy" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, - { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, - { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, - { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221 }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834 }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938 }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818 }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969 }, ] [[package]] @@ -3929,16 +3955,16 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870, upload-time = "2024-06-24T20:35:18.532Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226, upload-time = "2024-06-24T20:31:50.451Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893, upload-time = "2024-06-24T20:31:57.337Z" }, - { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258, upload-time = "2024-06-24T20:32:02.711Z" }, - { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715, upload-time = "2024-06-24T20:32:07.648Z" }, - { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038, upload-time = "2024-06-24T20:32:17.305Z" }, - { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959, upload-time = "2024-06-24T20:32:25.982Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514, upload-time = "2024-06-24T20:32:32.618Z" }, - { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252, upload-time = "2024-06-24T20:32:45.06Z" }, + { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226 }, + { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893 }, + { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258 }, + { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715 }, + { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038 }, + { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959 }, + { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514 }, + { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252 }, ] [[package]] @@ -3950,9 +3976,9 @@ dependencies = [ { name = "numpy" }, { name = "pandas" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 }, ] [[package]] @@ -3962,9 +3988,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244, upload-time = "2021-12-15T21:56:14.555Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332, upload-time = "2021-12-15T21:56:12.508Z" }, + { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332 }, ] [[package]] @@ -3998,16 +4024,16 @@ wheels = [ name = "sentencepiece" version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106, upload-time = "2024-02-19T17:06:47.428Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979, upload-time = "2024-02-19T17:05:34.651Z" }, - { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845, upload-time = "2024-02-19T17:05:37.371Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472, upload-time = "2024-02-19T17:05:39.775Z" }, - { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151, upload-time = "2024-02-19T17:05:42.594Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931, upload-time = "2024-02-19T17:05:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537, upload-time = "2024-02-19T17:05:46.713Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747, upload-time = "2024-02-19T17:05:48.705Z" }, - { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525, upload-time = "2024-02-19T17:05:55.145Z" }, + { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979 }, + { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845 }, + { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472 }, + { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151 }, + { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931 }, + { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537 }, + { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747 }, + { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525 }, ] [[package]] @@ -4027,54 +4053,54 @@ wheels = [ name = "setuptools" version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 }, ] [[package]] name = "shellingham" version = "1.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] [[package]] name = "smmap" version = "5.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303 }, ] [[package]] name = "sniffio" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] [[package]] name = "sortedcontainers" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] [[package]] @@ -4110,7 +4136,7 @@ wheels = [ name = "sqlitedict" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846, upload-time = "2022-12-03T13:39:13.102Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846 } [[package]] name = "sqlmodel" @@ -4120,7 +4146,7 @@ dependencies = [ { name = "pydantic" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392, upload-time = "2024-08-31T09:43:24.088Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392 } wheels = [ { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, ] @@ -4143,9 +4169,9 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, ] [[package]] @@ -4156,9 +4182,9 @@ dependencies = [ { name = "anyio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033 }, ] [[package]] @@ -4209,9 +4235,9 @@ dependencies = [ { name = "torch" }, { name = "transformers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481, upload-time = "2025-09-23T21:41:37.027Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395, upload-time = "2025-09-23T21:41:35.369Z" }, + { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395 }, ] [[package]] @@ -4221,27 +4247,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, ] [[package]] name = "tabulate" version = "0.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090 } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, ] [[package]] name = "tenacity" version = "9.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 }, ] [[package]] @@ -4273,21 +4299,21 @@ version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, ] [[package]] name = "threadpoolctl" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274 } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638 }, ] [[package]] @@ -4298,15 +4324,15 @@ dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806 } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991, upload-time = "2025-10-06T20:21:34.098Z" }, - { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798, upload-time = "2025-10-06T20:21:35.579Z" }, - { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865, upload-time = "2025-10-06T20:21:36.675Z" }, - { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856, upload-time = "2025-10-06T20:21:37.873Z" }, - { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308, upload-time = "2025-10-06T20:21:39.577Z" }, - { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697, upload-time = "2025-10-06T20:21:41.154Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375, upload-time = "2025-10-06T20:21:43.201Z" }, + { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991 }, + { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798 }, + { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865 }, + { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856 }, + { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308 }, + { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697 }, + { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, ] [[package]] @@ -4316,9 +4342,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, ] [[package]] @@ -4355,18 +4381,18 @@ wheels = [ name = "toml" version = "0.10.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, ] [[package]] name = "tomli" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392 } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408 }, ] [[package]] @@ -4378,30 +4404,30 @@ dependencies = [ { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681, upload-time = "2025-11-12T15:19:56.48Z" }, - { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036, upload-time = "2025-11-12T15:21:01.886Z" }, - { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861, upload-time = "2025-11-12T15:21:30.145Z" }, - { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222, upload-time = "2025-11-12T15:20:46.223Z" }, + { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681 }, + { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036 }, + { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861 }, + { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222 }, ] [[package]] @@ -4413,9 +4439,9 @@ dependencies = [ { name = "packaging" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144, upload-time = "2023-03-10T22:02:20.455Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162, upload-time = "2023-03-10T22:02:18.818Z" }, + { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162 }, ] [[package]] @@ -4442,20 +4468,20 @@ name = "tqdm" version = "4.67.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, ] [[package]] @@ -4466,9 +4492,9 @@ dependencies = [ { name = "torch" }, { name = "transformers", extra = ["sentencepiece", "torch"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754, upload-time = "2025-06-15T13:34:38.522Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073, upload-time = "2025-06-15T13:34:37.468Z" }, + { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073 }, ] [[package]] @@ -4487,9 +4513,9 @@ dependencies = [ { name = "tokenizers" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680, upload-time = "2025-11-25T15:51:30.139Z" } +sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463, upload-time = "2025-11-25T15:51:26.493Z" }, + { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463 }, ] [package.optional-dependencies] @@ -4507,7 +4533,8 @@ name = "triton" version = "3.5.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692, upload-time = "2025-11-11T17:40:46.074Z" }, + { url = "https://files.pythonhosted.org/packages/d9/2e/f95e673222afa2c7f0c687d8913e98fcf2589ef0b1405de76894e37fe18f/triton-3.5.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f63e34dcb32d7bd3a1d0195f60f30d2aee8b08a69a0424189b71017e23dfc3d2", size = 159821655 }, + { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692 }, ] [[package]] @@ -4529,9 +4556,9 @@ wheels = [ name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, ] [[package]] @@ -4541,9 +4568,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, ] [[package]] @@ -4559,18 +4586,18 @@ wheels = [ name = "unidecode" version = "1.3.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701, upload-time = "2024-01-11T11:58:35.609Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494, upload-time = "2024-01-11T11:58:33.012Z" }, + { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494 }, ] [[package]] name = "uri-template" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140 }, ] [[package]] @@ -4598,7 +4625,7 @@ wheels = [ [package.optional-dependencies] standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, { name = "httptools" }, { name = "python-dotenv" }, { name = "pyyaml" }, @@ -4611,14 +4638,14 @@ standard = [ name = "uvloop" version = "0.22.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335, upload-time = "2025-10-16T22:16:11.43Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903, upload-time = "2025-10-16T22:16:12.979Z" }, - { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499, upload-time = "2025-10-16T22:16:14.451Z" }, - { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133, upload-time = "2025-10-16T22:16:16.272Z" }, - { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681, upload-time = "2025-10-16T22:16:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261, upload-time = "2025-10-16T22:16:19.596Z" }, + { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335 }, + { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903 }, + { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499 }, + { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133 }, + { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681 }, + { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261 }, ] [[package]] @@ -4631,7 +4658,7 @@ dependencies = [ { name = "platformdirs" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799 } wheels = [ { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095 }, ] @@ -4649,18 +4676,18 @@ wheels = [ name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, ] [[package]] @@ -4670,67 +4697,67 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318, upload-time = "2025-10-14T15:04:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478, upload-time = "2025-10-14T15:04:20.297Z" }, - { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894, upload-time = "2025-10-14T15:04:21.527Z" }, - { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065, upload-time = "2025-10-14T15:04:22.795Z" }, - { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377, upload-time = "2025-10-14T15:04:24.138Z" }, - { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837, upload-time = "2025-10-14T15:04:25.057Z" }, - { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456, upload-time = "2025-10-14T15:04:26.497Z" }, - { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614, upload-time = "2025-10-14T15:04:27.539Z" }, - { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690, upload-time = "2025-10-14T15:04:28.495Z" }, - { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459, upload-time = "2025-10-14T15:04:29.491Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663, upload-time = "2025-10-14T15:04:30.435Z" }, - { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453, upload-time = "2025-10-14T15:04:31.53Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, - { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, - { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413, upload-time = "2025-10-14T15:06:09.209Z" }, + { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318 }, + { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478 }, + { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894 }, + { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065 }, + { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377 }, + { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837 }, + { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456 }, + { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614 }, + { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690 }, + { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459 }, + { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663 }, + { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453 }, + { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611 }, + { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889 }, + { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616 }, + { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413 }, ] [[package]] name = "wcwidth" version = "0.2.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286 }, ] [[package]] name = "webcolors" version = "25.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905 }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, ] [[package]] name = "websocket-client" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, ] [[package]] name = "websockets" version = "15.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423 }, { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080 }, @@ -4768,9 +4795,9 @@ wheels = [ name = "widgetsnbextension" version = "4.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503 }, ] [[package]] @@ -4780,59 +4807,59 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581480705f912040172f6570cc12e68a245ba9258c32ef/wikipedia_api-0.8.1.tar.gz", hash = "sha256:b31e93b3f5407c1a1ba413ed7326a05379a3c270df6cf6a211aca67a14c5658b", size = 19934, upload-time = "2025-01-19T23:44:33.488Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581480705f912040172f6570cc12e68a245ba9258c32ef/wikipedia_api-0.8.1.tar.gz", hash = "sha256:b31e93b3f5407c1a1ba413ed7326a05379a3c270df6cf6a211aca67a14c5658b", size = 19934 } [[package]] name = "wrapt" version = "2.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481, upload-time = "2025-11-07T00:43:11.103Z" }, - { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692, upload-time = "2025-11-07T00:43:13.697Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574, upload-time = "2025-11-07T00:43:14.967Z" }, - { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688, upload-time = "2025-11-07T00:43:18.275Z" }, - { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698, upload-time = "2025-11-07T00:43:19.407Z" }, - { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096, upload-time = "2025-11-07T00:43:16.5Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878, upload-time = "2025-11-07T00:43:20.81Z" }, - { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298, upload-time = "2025-11-07T00:43:22.229Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361, upload-time = "2025-11-07T00:43:24.301Z" }, - { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035, upload-time = "2025-11-07T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383, upload-time = "2025-11-07T00:43:25.804Z" }, - { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894, upload-time = "2025-11-07T00:43:27.074Z" }, - { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, + { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481 }, + { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692 }, + { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574 }, + { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688 }, + { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698 }, + { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096 }, + { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878 }, + { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298 }, + { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361 }, + { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035 }, + { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383 }, + { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894 }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046 }, ] [[package]] name = "xmltodict" version = "0.14.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942, upload-time = "2024-10-16T06:10:29.683Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981, upload-time = "2024-10-16T06:10:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981 }, ] [[package]] name = "xxhash" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, - { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, - { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, - { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, - { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, - { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, - { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, - { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, - { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, - { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, - { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845 }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807 }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786 }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830 }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606 }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872 }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217 }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139 }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669 }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018 }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058 }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628 }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577 }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487 }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863 }, ] [[package]] @@ -4844,32 +4871,32 @@ dependencies = [ { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, - { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, - { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, - { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, - { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, - { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, - { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, - { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, - { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, - { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, - { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, - { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, - { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, - { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, - { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, - { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517 }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495 }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400 }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545 }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598 }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893 }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240 }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965 }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026 }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637 }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082 }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811 }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223 }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118 }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852 }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012 }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, ] [[package]] name = "zipp" version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, ] From b34374613a0aa8e99272edf8d5a8648d1e3c6c0d Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Tue, 10 Feb 2026 19:42:00 -0300 Subject: [PATCH 033/104] Hotfix: resolve file pathing, logic indentation, and date disambiguation - Update configuration path in llm.py from .yaml to .yml. - Fix indentation in core.py for canonical_entity_id assignment. This ensures all predictions receive an ID even if they lack a canonical match, bypassing the 'aymurai_label_subclass == 0' filter which caused issues with date formatting in NER post-processing. - Add condition in anonymizer.py to trigger 'get_canonical_dates' only when FECHA is present in 'fuzzy_labels'. This prevents unintended date disambiguation when the policy is set to None. --- .../routers/anonymizer/anonymizer.py | 3 +- aymurai/utils/entity_disambiguation/core.py | 18 +- aymurai/utils/entity_disambiguation/llm.py | 2 +- .../08-disambiguation-endpoint-smoke.ipynb | 20 +- uv.lock | 2731 ++++++++--------- 5 files changed, 1363 insertions(+), 1411 deletions(-) diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index dc7f3d56..ec2b481e 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -327,7 +327,8 @@ async def anonymizer_disambiguate( else [] ) - canonical_entities += get_canonical_dates(labels=labels) + if "FECHA" in fuzzy_labels: + canonical_entities += get_canonical_dates(labels) logger.info( "fuzzy clustering produced %d canonical entities", len(canonical_entities) diff --git a/aymurai/utils/entity_disambiguation/core.py b/aymurai/utils/entity_disambiguation/core.py index 085d94de..22982c6c 100644 --- a/aymurai/utils/entity_disambiguation/core.py +++ b/aymurai/utils/entity_disambiguation/core.py @@ -112,15 +112,15 @@ def map_canonical_entities_ner_preds( label.attrs.aymurai_label_subclass.append(role) break - if label.attrs.canonical_entity_id is None: - key = ( - label.attrs.aymurai_label, - str(label.attrs.aymurai_alt_text).strip(), - ) - if key not in new_ids_map: - new_ids_map[key] = uuid.uuid4() - - label.attrs.canonical_entity_id = new_ids_map[key] + elif label.attrs.canonical_entity_id is None: + key = ( + label.attrs.aymurai_label, + str(label.attrs.aymurai_alt_text).strip(), + ) + if key not in new_ids_map: + new_ids_map[key] = uuid.uuid4() + + label.attrs.canonical_entity_id = new_ids_map[key] if include_label_instances: return assign_label_instances(predictions_mapped) diff --git a/aymurai/utils/entity_disambiguation/llm.py b/aymurai/utils/entity_disambiguation/llm.py index f3cc3fb7..6121d40c 100644 --- a/aymurai/utils/entity_disambiguation/llm.py +++ b/aymurai/utils/entity_disambiguation/llm.py @@ -27,7 +27,7 @@ def load_prompts_from_yaml(): Returns: PromptLibrary: The loaded prompt library. """ - path = Path(settings.RESOURCES_BASEPATH) / "llm/entity_disambiguation.yaml" + path = Path(settings.RESOURCES_BASEPATH) / "llm/entity_disambiguation.yml" data = load_yaml(file_path=str(path)) prompts = [] diff --git a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb index ceaa9f84..8ad00ae4 100644 --- a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb +++ b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb @@ -143,12 +143,6 @@ "\"\"\"" ] }, - { - "cell_type": "markdown", - "id": "61fb70d5", - "metadata": {}, - "source": [] - }, { "cell_type": "code", "execution_count": null, @@ -322,7 +316,7 @@ "metadata": {}, "outputs": [], "source": [ - "for doc_path in documents[2:3]:\n", + "for doc_path in documents[1:2]:\n", " print(f\"\\n=== {doc_path.name} ===\")\n", " session = requests.Session()\n", " document = extract_document(\n", @@ -381,19 +375,11 @@ " attrs.get(\"canonical_entity_id\"),\n", " )" ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0f95a791", - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "aymurai (3.10.19)", + "display_name": "aymurai", "language": "python", "name": "python3" }, @@ -407,7 +393,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.19" + "version": "3.10.4" } }, "nbformat": 4, diff --git a/uv.lock b/uv.lock index a903aa6d..2adadb0f 100644 --- a/uv.lock +++ b/uv.lock @@ -1,22 +1,20 @@ version = 1 +revision = 3 requires-python = "==3.10.*" resolution-markers = [ - "platform_system == 'Darwin' and sys_platform == 'darwin'", - "platform_system != 'Darwin' and sys_platform == 'darwin'", - "platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'", - "platform_machine == 'aarch64' and platform_system != 'Linux' and sys_platform == 'linux'", - "(platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux') or (platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')", - "platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'", - "(platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')", + "sys_platform == 'darwin'", + "python_version < '0'", + "platform_machine == 'aarch64' and sys_platform == 'linux'", + "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')", ] [[package]] name = "absl-py" version = "2.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588 } +sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811 }, + { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" }, ] [[package]] @@ -32,18 +30,18 @@ dependencies = [ { name = "safetensors" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/8e/ac2a9566747a93f8be36ee08532eb0160558b07630a081a6056a9f89bf1d/accelerate-1.12.0.tar.gz", hash = "sha256:70988c352feb481887077d2ab845125024b2a137a5090d6d7a32b57d03a45df6", size = 398399 } +sdist = { url = "https://files.pythonhosted.org/packages/4a/8e/ac2a9566747a93f8be36ee08532eb0160558b07630a081a6056a9f89bf1d/accelerate-1.12.0.tar.gz", hash = "sha256:70988c352feb481887077d2ab845125024b2a137a5090d6d7a32b57d03a45df6", size = 398399, upload-time = "2025-11-21T11:27:46.973Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/d2/c581486aa6c4fbd7394c23c47b83fa1a919d34194e16944241daf9e762dd/accelerate-1.12.0-py3-none-any.whl", hash = "sha256:3e2091cd341423207e2f084a6654b1efcd250dc326f2a37d6dde446e07cabb11", size = 380935 }, + { url = "https://files.pythonhosted.org/packages/9f/d2/c581486aa6c4fbd7394c23c47b83fa1a919d34194e16944241daf9e762dd/accelerate-1.12.0-py3-none-any.whl", hash = "sha256:3e2091cd341423207e2f084a6654b1efcd250dc326f2a37d6dde446e07cabb11", size = 380935, upload-time = "2025-11-21T11:27:44.522Z" }, ] [[package]] name = "aiohappyeyeballs" version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760 } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265 }, + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, ] [[package]] @@ -60,25 +58,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556 } +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950 }, - { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099 }, - { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072 }, - { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588 }, - { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334 }, - { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656 }, - { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625 }, - { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604 }, - { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370 }, - { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023 }, - { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680 }, - { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407 }, - { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047 }, - { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264 }, - { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275 }, - { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053 }, - { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687 }, + { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950, upload-time = "2026-01-03T17:29:13.002Z" }, + { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099, upload-time = "2026-01-03T17:29:15.268Z" }, + { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072, upload-time = "2026-01-03T17:29:16.922Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588, upload-time = "2026-01-03T17:29:18.539Z" }, + { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334, upload-time = "2026-01-03T17:29:21.028Z" }, + { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656, upload-time = "2026-01-03T17:29:22.531Z" }, + { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625, upload-time = "2026-01-03T17:29:24.276Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604, upload-time = "2026-01-03T17:29:26.099Z" }, + { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370, upload-time = "2026-01-03T17:29:28.121Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023, upload-time = "2026-01-03T17:29:30.002Z" }, + { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680, upload-time = "2026-01-03T17:29:31.782Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407, upload-time = "2026-01-03T17:29:33.392Z" }, + { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047, upload-time = "2026-01-03T17:29:34.855Z" }, + { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264, upload-time = "2026-01-03T17:29:36.389Z" }, + { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275, upload-time = "2026-01-03T17:29:38.162Z" }, + { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053, upload-time = "2026-01-03T17:29:40.074Z" }, + { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687, upload-time = "2026-01-03T17:29:41.819Z" }, ] [[package]] @@ -89,9 +87,9 @@ dependencies = [ { name = "frozenlist" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007 } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490 }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, ] [[package]] @@ -104,9 +102,9 @@ dependencies = [ { name = "tomli" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064 } +sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064, upload-time = "2025-11-14T20:35:04.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554 }, + { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554, upload-time = "2025-11-14T20:35:05.699Z" }, ] [[package]] @@ -120,27 +118,27 @@ dependencies = [ { name = "packaging" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f7/c0/184a89bd5feba14ff3c41cfaf1dd8a82c05f5ceedbc92145e17042eb08a4/altair-6.0.0.tar.gz", hash = "sha256:614bf5ecbe2337347b590afb111929aa9c16c9527c4887d96c9bc7f6640756b4", size = 763834 } +sdist = { url = "https://files.pythonhosted.org/packages/f7/c0/184a89bd5feba14ff3c41cfaf1dd8a82c05f5ceedbc92145e17042eb08a4/altair-6.0.0.tar.gz", hash = "sha256:614bf5ecbe2337347b590afb111929aa9c16c9527c4887d96c9bc7f6640756b4", size = 763834, upload-time = "2025-11-12T08:59:11.519Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/33/ef2f2409450ef6daa61459d5de5c08128e7d3edb773fefd0a324d1310238/altair-6.0.0-py3-none-any.whl", hash = "sha256:09ae95b53d5fe5b16987dccc785a7af8588f2dca50de1e7a156efa8a461515f8", size = 795410 }, + { url = "https://files.pythonhosted.org/packages/db/33/ef2f2409450ef6daa61459d5de5c08128e7d3edb773fefd0a324d1310238/altair-6.0.0-py3-none-any.whl", hash = "sha256:09ae95b53d5fe5b16987dccc785a7af8588f2dca50de1e7a156efa8a461515f8", size = 795410, upload-time = "2025-11-12T08:59:09.804Z" }, ] [[package]] name = "annotated-doc" version = "0.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288 } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303 }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, ] [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] [[package]] @@ -156,9 +154,9 @@ dependencies = [ { name = "sniffio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191, upload-time = "2025-02-18T20:35:33.314Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228 }, + { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228, upload-time = "2025-02-18T20:35:28.659Z" }, ] [[package]] @@ -170,18 +168,18 @@ dependencies = [ { name = "idna" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685 } +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592 }, + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] [[package]] name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] [[package]] @@ -191,9 +189,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, ] [[package]] @@ -203,23 +201,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, - { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549 }, - { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539 }, - { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467 }, - { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355 }, - { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187 }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, + { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549, upload-time = "2025-07-30T10:02:00.101Z" }, + { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539, upload-time = "2025-07-30T10:02:00.929Z" }, + { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467, upload-time = "2025-07-30T10:02:02.08Z" }, + { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355, upload-time = "2025-07-30T10:02:02.867Z" }, + { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187, upload-time = "2025-07-30T10:02:03.674Z" }, ] [[package]] @@ -230,18 +228,18 @@ dependencies = [ { name = "python-dateutil" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797 }, + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, ] [[package]] name = "asttokens" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, ] [[package]] @@ -251,18 +249,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380 } +sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069 }, + { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, ] [[package]] name = "async-timeout" version = "5.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, ] [[package]] @@ -272,23 +270,22 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217, upload-time = "2024-08-24T23:15:36.449Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209 }, + { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209, upload-time = "2024-08-24T23:15:35.317Z" }, ] [[package]] name = "attrs" version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251 } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615 }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] [[package]] name = "aymurai" -version = "2.0.0a7.dev37" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -415,9 +412,9 @@ mlops = [ name = "babel" version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537 }, + { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, ] [[package]] @@ -428,9 +425,9 @@ dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 }, + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, ] [[package]] @@ -444,9 +441,9 @@ dependencies = [ { name = "lxml" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924 } +sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924, upload-time = "2023-08-15T22:34:59.047Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419 }, + { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419, upload-time = "2023-08-15T22:34:56.022Z" }, ] [[package]] @@ -456,9 +453,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533 } +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437 }, + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, ] [package.optional-dependencies] @@ -470,9 +467,9 @@ css = [ name = "blinker" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460 } +sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458 }, + { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, ] [[package]] @@ -484,9 +481,9 @@ dependencies = [ { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/df/17828670134e56ffca8cf8b017477f16d1a9df7ecfc3870d02aa6d4d2e20/boto3-1.42.23.tar.gz", hash = "sha256:f681a8d43b46b3d8acf0be4f3894eb85e40e75945431d0dfe0542edda7025512", size = 112845 } +sdist = { url = "https://files.pythonhosted.org/packages/0d/df/17828670134e56ffca8cf8b017477f16d1a9df7ecfc3870d02aa6d4d2e20/boto3-1.42.23.tar.gz", hash = "sha256:f681a8d43b46b3d8acf0be4f3894eb85e40e75945431d0dfe0542edda7025512", size = 112845, upload-time = "2026-01-06T20:28:51.006Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/8b/8e028dbf6c4bf36defe899882a00c11a8d22fcb7348e88058900c13b72a0/boto3-1.42.23-py3-none-any.whl", hash = "sha256:2ed797bdb394b08550f6269babf0a31bbeb853684bb2cb67116620df0ed632dc", size = 140574 }, + { url = "https://files.pythonhosted.org/packages/98/8b/8e028dbf6c4bf36defe899882a00c11a8d22fcb7348e88058900c13b72a0/boto3-1.42.23-py3-none-any.whl", hash = "sha256:2ed797bdb394b08550f6269babf0a31bbeb853684bb2cb67116620df0ed632dc", size = 140574, upload-time = "2026-01-06T20:28:48.992Z" }, ] [[package]] @@ -498,27 +495,27 @@ dependencies = [ { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/2c/db33716f86b67c514f895c60694a25cd7428d2137b574b59d09d626b0e2e/botocore-1.42.23.tar.gz", hash = "sha256:453ce449bd1021acd67e75c814aae1b132b1ab3ee0ecff248de863bf19e58be8", size = 14878387 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/2c/db33716f86b67c514f895c60694a25cd7428d2137b574b59d09d626b0e2e/botocore-1.42.23.tar.gz", hash = "sha256:453ce449bd1021acd67e75c814aae1b132b1ab3ee0ecff248de863bf19e58be8", size = 14878387, upload-time = "2026-01-06T20:28:40.151Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e6/114d66f81fc4b77a8c1e45e6fcf0021018d1f4eefca0905b3da8023c9a47/botocore-1.42.23-py3-none-any.whl", hash = "sha256:d5042e0252b81f25ca1152fff9ed25463bab2438fbc4530ba53d5390d00ca1b1", size = 14551561 }, + { url = "https://files.pythonhosted.org/packages/8d/e6/114d66f81fc4b77a8c1e45e6fcf0021018d1f4eefca0905b3da8023c9a47/botocore-1.42.23-py3-none-any.whl", hash = "sha256:d5042e0252b81f25ca1152fff9ed25463bab2438fbc4530ba53d5390d00ca1b1", size = 14551561, upload-time = "2026-01-06T20:28:36.418Z" }, ] [[package]] name = "cachetools" version = "6.2.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/1d/ede8680603f6016887c062a2cf4fc8fdba905866a3ab8831aa8aa651320c/cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607", size = 31731 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/1d/ede8680603f6016887c062a2cf4fc8fdba905866a3ab8831aa8aa651320c/cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607", size = 31731, upload-time = "2025-12-15T18:24:53.744Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/fc/1d7b80d0eb7b714984ce40efc78859c022cd930e402f599d8ca9e39c78a4/cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51", size = 11551 }, + { url = "https://files.pythonhosted.org/packages/2c/fc/1d7b80d0eb7b714984ce40efc78859c022cd930e402f599d8ca9e39c78a4/cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51", size = 11551, upload-time = "2025-12-15T18:24:52.332Z" }, ] [[package]] name = "certifi" version = "2026.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900 }, + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] [[package]] @@ -528,54 +525,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283 }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504 }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811 }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402 }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217 }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079 }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475 }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829 }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211 }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036 }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184 }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790 }, + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, ] [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" version = "3.4.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709 }, - { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814 }, - { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467 }, - { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280 }, - { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454 }, - { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609 }, - { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849 }, - { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586 }, - { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290 }, - { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663 }, - { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964 }, - { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064 }, - { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015 }, - { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792 }, - { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198 }, - { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262 }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, ] [[package]] @@ -583,29 +580,29 @@ name = "click" version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] [[package]] name = "cloudpickle" version = "3.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330 } +sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228 }, + { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] [[package]] @@ -613,29 +610,29 @@ name = "colorlog" version = "6.10.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743 }, + { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, ] [[package]] name = "comm" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, ] [[package]] name = "conllu" version = "4.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768 } +sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768, upload-time = "2023-06-19T12:37:49.632Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098 }, + { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098, upload-time = "2023-06-19T12:37:47.885Z" }, ] [[package]] @@ -645,21 +642,21 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, - { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, - { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061 }, - { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956 }, - { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872 }, - { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027 }, - { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641 }, - { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075 }, - { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534 }, - { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188 }, - { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681 }, - { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101 }, - { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599 }, + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, ] [[package]] @@ -670,49 +667,49 @@ dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004 }, - { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667 }, - { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807 }, - { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615 }, - { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800 }, - { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707 }, - { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541 }, - { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464 }, - { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838 }, - { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596 }, - { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782 }, - { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381 }, - { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988 }, - { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451 }, - { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007 }, - { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248 }, - { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089 }, - { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029 }, - { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222 }, - { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280 }, - { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958 }, - { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714 }, - { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970 }, - { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236 }, - { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642 }, - { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126 }, - { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573 }, - { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695 }, - { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720 }, - { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740 }, - { url = "https://files.pythonhosted.org/packages/d9/cd/1a8633802d766a0fa46f382a77e096d7e209e0817892929655fe0586ae32/cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32", size = 3689163 }, - { url = "https://files.pythonhosted.org/packages/4c/59/6b26512964ace6480c3e54681a9859c974172fb141c38df11eadd8416947/cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c", size = 3429474 }, +sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, + { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, + { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, + { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, + { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, + { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, + { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, + { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, + { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, + { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, + { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, + { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, + { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, + { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, + { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, + { url = "https://files.pythonhosted.org/packages/d9/cd/1a8633802d766a0fa46f382a77e096d7e209e0817892929655fe0586ae32/cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32", size = 3689163, upload-time = "2025-10-15T23:18:13.821Z" }, + { url = "https://files.pythonhosted.org/packages/4c/59/6b26512964ace6480c3e54681a9859c974172fb141c38df11eadd8416947/cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c", size = 3429474, upload-time = "2025-10-15T23:18:15.477Z" }, ] [[package]] name = "cycler" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] [[package]] @@ -724,9 +721,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/54/f2393af72974d8e70bfd44b52f17b917190b4934bab66508f4afec9e9285/databricks_sdk-0.77.0.tar.gz", hash = "sha256:56b6017ae17dc31ee821e49746d2ff627a029127166c702088428527813422bd", size = 827462 } +sdist = { url = "https://files.pythonhosted.org/packages/1e/54/f2393af72974d8e70bfd44b52f17b917190b4934bab66508f4afec9e9285/databricks_sdk-0.77.0.tar.gz", hash = "sha256:56b6017ae17dc31ee821e49746d2ff627a029127166c702088428527813422bd", size = 827462, upload-time = "2026-01-06T13:19:09.432Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/aa/d9186684dbcd338cf51e93621bcf53efa843fe647c0f29f549ebddbf2870/databricks_sdk-0.77.0-py3-none-any.whl", hash = "sha256:42e3211b7dbd53b81a795981149ee08d5b025442a73e464264569edc8c46ee0a", size = 779180 }, + { url = "https://files.pythonhosted.org/packages/03/aa/d9186684dbcd338cf51e93621bcf53efa843fe647c0f29f549ebddbf2870/databricks_sdk-0.77.0-py3-none-any.whl", hash = "sha256:42e3211b7dbd53b81a795981149ee08d5b025442a73e464264569edc8c46ee0a", size = 779180, upload-time = "2026-01-06T13:19:07.757Z" }, ] [[package]] @@ -749,9 +746,9 @@ dependencies = [ { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/54/9359803da96bc65439a28fbb014dc2c90b7d4d8034a93b72362b0d40191f/datasets-4.4.2.tar.gz", hash = "sha256:9de16e415c4ba4713eac0493f7c7dc74f3aa21599297f00cc6ddab409cb7b24b", size = 586474 } +sdist = { url = "https://files.pythonhosted.org/packages/c4/54/9359803da96bc65439a28fbb014dc2c90b7d4d8034a93b72362b0d40191f/datasets-4.4.2.tar.gz", hash = "sha256:9de16e415c4ba4713eac0493f7c7dc74f3aa21599297f00cc6ddab409cb7b24b", size = 586474, upload-time = "2025-12-19T15:03:09.129Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/b5/fefa518c809de7bced5cddb7c21c010da66fa2ae494bda96844a280cc6ce/datasets-4.4.2-py3-none-any.whl", hash = "sha256:6f5ef3417504d9cd663c71c1b90b9a494ff4c2076a2cd6a6e40ceee6ad95befc", size = 512268 }, + { url = "https://files.pythonhosted.org/packages/7b/b5/fefa518c809de7bced5cddb7c21c010da66fa2ae494bda96844a280cc6ce/datasets-4.4.2-py3-none-any.whl", hash = "sha256:6f5ef3417504d9cd663c71c1b90b9a494ff4c2076a2cd6a6e40ceee6ad95befc", size = 512268, upload-time = "2025-12-19T15:03:07.087Z" }, ] [[package]] @@ -763,31 +760,31 @@ source = { git = "https://github.com/jedzill4/datetime_matcher#0e5793e8d1e3653f7 name = "debugpy" version = "1.8.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590 } +sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590, upload-time = "2025-12-15T21:53:28.044Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/98/d57054371887f37d3c959a7a8dc3c76b763acb65f5e78d849d7db7cadc5b/debugpy-1.8.19-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:fce6da15d73be5935b4438435c53adb512326a3e11e4f90793ea87cd9f018254", size = 2098493 }, - { url = "https://files.pythonhosted.org/packages/ee/dd/c517b9aa3500157a30e4f4c4f5149f880026bd039d2b940acd2383a85d8e/debugpy-1.8.19-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:e24b1652a1df1ab04d81e7ead446a91c226de704ff5dde6bd0a0dbaab07aa3f2", size = 3087875 }, - { url = "https://files.pythonhosted.org/packages/d8/57/3d5a5b0da9b63445253107ead151eff29190c6ad7440c68d1a59d56613aa/debugpy-1.8.19-cp310-cp310-win32.whl", hash = "sha256:327cb28c3ad9e17bc925efc7f7018195fd4787c2fe4b7af1eec11f1d19bdec62", size = 5239378 }, - { url = "https://files.pythonhosted.org/packages/a6/36/7f9053c4c549160c87ae7e43800138f2695578c8b65947114c97250983b6/debugpy-1.8.19-cp310-cp310-win_amd64.whl", hash = "sha256:b7dd275cf2c99e53adb9654f5ae015f70415bbe2bacbe24cfee30d54b6aa03c5", size = 5271129 }, - { url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321 }, + { url = "https://files.pythonhosted.org/packages/bf/98/d57054371887f37d3c959a7a8dc3c76b763acb65f5e78d849d7db7cadc5b/debugpy-1.8.19-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:fce6da15d73be5935b4438435c53adb512326a3e11e4f90793ea87cd9f018254", size = 2098493, upload-time = "2025-12-15T21:53:30.149Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dd/c517b9aa3500157a30e4f4c4f5149f880026bd039d2b940acd2383a85d8e/debugpy-1.8.19-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:e24b1652a1df1ab04d81e7ead446a91c226de704ff5dde6bd0a0dbaab07aa3f2", size = 3087875, upload-time = "2025-12-15T21:53:31.511Z" }, + { url = "https://files.pythonhosted.org/packages/d8/57/3d5a5b0da9b63445253107ead151eff29190c6ad7440c68d1a59d56613aa/debugpy-1.8.19-cp310-cp310-win32.whl", hash = "sha256:327cb28c3ad9e17bc925efc7f7018195fd4787c2fe4b7af1eec11f1d19bdec62", size = 5239378, upload-time = "2025-12-15T21:53:32.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/36/7f9053c4c549160c87ae7e43800138f2695578c8b65947114c97250983b6/debugpy-1.8.19-cp310-cp310-win_amd64.whl", hash = "sha256:b7dd275cf2c99e53adb9654f5ae015f70415bbe2bacbe24cfee30d54b6aa03c5", size = 5271129, upload-time = "2025-12-15T21:53:35.085Z" }, + { url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321, upload-time = "2025-12-15T21:54:16.024Z" }, ] [[package]] name = "decorator" version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] [[package]] name = "defusedxml" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, ] [[package]] @@ -797,54 +794,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523 } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298 }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, ] [[package]] name = "dill" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976 } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668 }, + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, ] [[package]] name = "diskcache" version = "5.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916 } +sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550 }, + { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" }, ] [[package]] name = "distlib" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "distro" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, ] [[package]] name = "dnspython" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251 } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094 }, + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, ] [[package]] @@ -852,28 +849,28 @@ name = "docker" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywin32", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, { name = "requests" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834 } +sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834, upload-time = "2024-05-23T11:13:57.216Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774 }, + { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774, upload-time = "2024-05-23T11:13:55.01Z" }, ] [[package]] name = "docopt" version = "0.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } [[package]] name = "docx2txt" version = "0.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613 } +sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613, upload-time = "2025-03-24T20:59:25.21Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025 }, + { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025, upload-time = "2025-03-24T20:59:24.394Z" }, ] [[package]] @@ -900,18 +897,18 @@ dependencies = [ { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/bd/339e1d949aa24e50b6edca8574cf8afbff005a1dfadc2d5b82a0003fa7da/dspy-3.1.0.tar.gz", hash = "sha256:3c1660cb687411f064509cd7ac47ed0231761f50ed92823cbbb59b3af2885702", size = 242611 } +sdist = { url = "https://files.pythonhosted.org/packages/d9/bd/339e1d949aa24e50b6edca8574cf8afbff005a1dfadc2d5b82a0003fa7da/dspy-3.1.0.tar.gz", hash = "sha256:3c1660cb687411f064509cd7ac47ed0231761f50ed92823cbbb59b3af2885702", size = 242611, upload-time = "2026-01-06T18:50:18.655Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/34/64e900657cad3c4df8a417fccbc4370ca851864edbd0f468210f1b57d084/dspy-3.1.0-py3-none-any.whl", hash = "sha256:b9f4d42cad9ac32b13fdf085dd3246c8ee8339c759cb291c5e7b7f9f5fb5dd72", size = 291317 }, + { url = "https://files.pythonhosted.org/packages/ca/34/64e900657cad3c4df8a417fccbc4370ca851864edbd0f468210f1b57d084/dspy-3.1.0-py3-none-any.whl", hash = "sha256:b9f4d42cad9ac32b13fdf085dd3246c8ee8339c759cb291c5e7b7f9f5fb5dd72", size = 291317, upload-time = "2026-01-06T18:50:17.559Z" }, ] [[package]] name = "einops" version = "0.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805 } +sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805, upload-time = "2025-02-09T03:17:00.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359 }, + { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359, upload-time = "2025-02-09T03:17:01.998Z" }, ] [[package]] @@ -922,9 +919,9 @@ dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238 } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604 }, + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, ] [[package]] @@ -934,18 +931,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] [[package]] name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, ] [[package]] @@ -955,9 +952,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644, upload-time = "2023-06-27T15:24:28.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039 }, + { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039, upload-time = "2023-06-27T15:24:24.869Z" }, ] [[package]] @@ -970,9 +967,9 @@ dependencies = [ { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/08/8c8508db6c7b9aae8f7175046af41baad690771c9bcde676419965e338c7/fastapi-0.128.0.tar.gz", hash = "sha256:1cc179e1cef10a6be60ffe429f79b829dce99d8de32d7acb7e6c8dfdf7f2645a", size = 365682 } +sdist = { url = "https://files.pythonhosted.org/packages/52/08/8c8508db6c7b9aae8f7175046af41baad690771c9bcde676419965e338c7/fastapi-0.128.0.tar.gz", hash = "sha256:1cc179e1cef10a6be60ffe429f79b829dce99d8de32d7acb7e6c8dfdf7f2645a", size = 365682, upload-time = "2025-12-27T15:21:13.714Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094 }, + { url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094, upload-time = "2025-12-27T15:21:12.154Z" }, ] [package.optional-dependencies] @@ -997,9 +994,9 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d3/ca/d90fb3bfbcbd6e56c77afd9d114dd6ce8955d8bb90094399d1c70e659e40/fastapi_cli-0.0.20.tar.gz", hash = "sha256:d17c2634f7b96b6b560bc16b0035ed047d523c912011395f49f00a421692bc3a", size = 19786 } +sdist = { url = "https://files.pythonhosted.org/packages/d3/ca/d90fb3bfbcbd6e56c77afd9d114dd6ce8955d8bb90094399d1c70e659e40/fastapi_cli-0.0.20.tar.gz", hash = "sha256:d17c2634f7b96b6b560bc16b0035ed047d523c912011395f49f00a421692bc3a", size = 19786, upload-time = "2025-12-22T17:13:33.794Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/89/5c4eef60524d0fd704eb0706885b82cd5623a43396b94e4a5b17d3a3f516/fastapi_cli-0.0.20-py3-none-any.whl", hash = "sha256:e58b6a0038c0b1532b7a0af690656093dee666201b6b19d3c87175b358e9f783", size = 12390 }, + { url = "https://files.pythonhosted.org/packages/08/89/5c4eef60524d0fd704eb0706885b82cd5623a43396b94e4a5b17d3a3f516/fastapi_cli-0.0.20-py3-none-any.whl", hash = "sha256:e58b6a0038c0b1532b7a0af690656093dee666201b6b19d3c87175b358e9f783", size = 12390, upload-time = "2025-12-22T17:13:31.708Z" }, ] [package.optional-dependencies] @@ -1022,89 +1019,89 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/51/5d/3b33438de35521fab4968b232caa9a4bd568a5078f2b2dfb7bb8a4528603/fastapi_cloud_cli-0.8.0.tar.gz", hash = "sha256:cf07c502528bfd9e6b184776659f05d9212811d76bbec9fbb6bf34bed4c7456f", size = 30257 } +sdist = { url = "https://files.pythonhosted.org/packages/51/5d/3b33438de35521fab4968b232caa9a4bd568a5078f2b2dfb7bb8a4528603/fastapi_cloud_cli-0.8.0.tar.gz", hash = "sha256:cf07c502528bfd9e6b184776659f05d9212811d76bbec9fbb6bf34bed4c7456f", size = 30257, upload-time = "2025-12-23T12:08:33.904Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/8e/abb95ef59e91bb5adaa2d18fbf9ea70fd524010bb03f406a2dd2a4775ef9/fastapi_cloud_cli-0.8.0-py3-none-any.whl", hash = "sha256:e9f40bee671d985fd25d7a5409b56d4f103777bf8a0c6d746ea5fbf97a8186d9", size = 22306 }, + { url = "https://files.pythonhosted.org/packages/dd/8e/abb95ef59e91bb5adaa2d18fbf9ea70fd524010bb03f406a2dd2a4775ef9/fastapi_cloud_cli-0.8.0-py3-none-any.whl", hash = "sha256:e9f40bee671d985fd25d7a5409b56d4f103777bf8a0c6d746ea5fbf97a8186d9", size = 22306, upload-time = "2025-12-23T12:08:32.68Z" }, ] [[package]] name = "fastar" version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536 }, - { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235 }, - { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386 }, - { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955 }, - { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987 }, - { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900 }, - { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523 }, - { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268 }, - { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286 }, - { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921 }, - { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302 }, - { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141 }, - { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544 }, - { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701 }, - { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544 }, - { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020 }, - { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735 }, - { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779 }, - { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755 }, - { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732 }, - { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571 }, - { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440 }, - { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424 }, - { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675 }, - { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098 }, - { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397 }, +sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524, upload-time = "2025-11-26T02:36:00.72Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536, upload-time = "2025-11-26T02:34:35.236Z" }, + { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235, upload-time = "2025-11-26T02:34:19.367Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386, upload-time = "2025-11-26T02:33:47.613Z" }, + { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955, upload-time = "2025-11-26T02:32:44.279Z" }, + { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987, upload-time = "2025-11-26T02:32:59.701Z" }, + { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900, upload-time = "2025-11-26T02:33:16.059Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523, upload-time = "2025-11-26T02:33:30.897Z" }, + { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268, upload-time = "2025-11-26T02:34:04.003Z" }, + { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286, upload-time = "2025-11-26T02:34:50.279Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921, upload-time = "2025-11-26T02:35:07.292Z" }, + { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302, upload-time = "2025-11-26T02:35:24.995Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141, upload-time = "2025-11-26T02:35:42.449Z" }, + { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544, upload-time = "2025-11-26T02:36:23.801Z" }, + { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701, upload-time = "2025-11-26T02:36:09.625Z" }, + { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544, upload-time = "2025-11-26T02:34:46.195Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020, upload-time = "2025-11-26T02:34:31.085Z" }, + { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735, upload-time = "2025-11-26T02:34:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779, upload-time = "2025-11-26T02:32:55.109Z" }, + { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755, upload-time = "2025-11-26T02:33:11.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732, upload-time = "2025-11-26T02:33:27.122Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571, upload-time = "2025-11-26T02:33:42.986Z" }, + { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440, upload-time = "2025-11-26T02:34:15.439Z" }, + { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424, upload-time = "2025-11-26T02:35:02.742Z" }, + { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675, upload-time = "2025-11-26T02:35:20.252Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098, upload-time = "2025-11-26T02:35:37.643Z" }, + { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397, upload-time = "2025-11-26T02:35:56.215Z" }, ] [[package]] name = "fastjsonschema" version = "2.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130 } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024 }, + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, ] [[package]] name = "fastuuid" version = "0.14.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760 }, - { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748 }, - { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537 }, - { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994 }, - { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003 }, - { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583 }, - { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955 }, - { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763 }, - { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613 }, - { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045 }, - { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122 }, + { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760, upload-time = "2025-10-19T22:25:21.509Z" }, + { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748, upload-time = "2025-10-19T22:41:52.873Z" }, + { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537, upload-time = "2025-10-19T22:33:55.603Z" }, + { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994, upload-time = "2025-10-19T22:26:17.631Z" }, + { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003, upload-time = "2025-10-19T22:23:45.415Z" }, + { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583, upload-time = "2025-10-19T22:26:00.756Z" }, + { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955, upload-time = "2025-10-19T22:36:25.196Z" }, + { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763, upload-time = "2025-10-19T22:24:28.451Z" }, + { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613, upload-time = "2025-10-19T22:25:06.827Z" }, + { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045, upload-time = "2025-10-19T22:28:32.732Z" }, + { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122, upload-time = "2025-10-19T22:23:15.59Z" }, ] [[package]] name = "filelock" version = "3.20.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c1/e0/a75dbe4bca1e7d41307323dad5ea2efdd95408f74ab2de8bd7dba9b51a1a/filelock-3.20.2.tar.gz", hash = "sha256:a2241ff4ddde2a7cebddf78e39832509cb045d18ec1a09d7248d6bfc6bfbbe64", size = 19510 } +sdist = { url = "https://files.pythonhosted.org/packages/c1/e0/a75dbe4bca1e7d41307323dad5ea2efdd95408f74ab2de8bd7dba9b51a1a/filelock-3.20.2.tar.gz", hash = "sha256:a2241ff4ddde2a7cebddf78e39832509cb045d18ec1a09d7248d6bfc6bfbbe64", size = 19510, upload-time = "2026-01-02T15:33:32.582Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697 }, + { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697, upload-time = "2026-01-02T15:33:31.133Z" }, ] [[package]] name = "filetype" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020 } +sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020, upload-time = "2022-11-02T17:34:04.141Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970 }, + { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, ] [[package]] @@ -1114,9 +1111,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "termcolor" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720 } +sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720, upload-time = "2025-08-16T20:20:24.175Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945 }, + { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945, upload-time = "2025-08-16T20:20:22.87Z" }, ] [[package]] @@ -1150,9 +1147,9 @@ dependencies = [ { name = "transformers", extra = ["sentencepiece"] }, { name = "wikipedia-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607 } +sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607, upload-time = "2025-02-05T14:45:44.322Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, + { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604, upload-time = "2025-02-05T14:45:41.788Z" }, ] [[package]] @@ -1167,9 +1164,9 @@ dependencies = [ { name = "markupsafe" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dc/6d/cfe3c0fcc5e477df242b98bfe186a4c34357b4847e87ecaef04507332dab/flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87", size = 720160 } +sdist = { url = "https://files.pythonhosted.org/packages/dc/6d/cfe3c0fcc5e477df242b98bfe186a4c34357b4847e87ecaef04507332dab/flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87", size = 720160, upload-time = "2025-08-19T21:03:21.205Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308 }, + { url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308, upload-time = "2025-08-19T21:03:19.499Z" }, ] [[package]] @@ -1180,69 +1177,69 @@ dependencies = [ { name = "flask" }, { name = "werkzeug" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/74/0fc0fa68d62f21daef41017dafab19ef4b36551521260987eb3a5394c7ba/flask_cors-6.0.2.tar.gz", hash = "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", size = 13472 } +sdist = { url = "https://files.pythonhosted.org/packages/70/74/0fc0fa68d62f21daef41017dafab19ef4b36551521260987eb3a5394c7ba/flask_cors-6.0.2.tar.gz", hash = "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", size = 13472, upload-time = "2025-12-12T20:31:42.861Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257 }, + { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257, upload-time = "2025-12-12T20:31:41.3Z" }, ] [[package]] name = "fonttools" version = "4.61.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756 } +sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799 }, - { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032 }, - { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863 }, - { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076 }, - { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623 }, - { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327 }, - { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180 }, - { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654 }, - { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996 }, + { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799, upload-time = "2025-12-12T17:29:27.5Z" }, + { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032, upload-time = "2025-12-12T17:29:30.115Z" }, + { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863, upload-time = "2025-12-12T17:29:32.535Z" }, + { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076, upload-time = "2025-12-12T17:29:34.907Z" }, + { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623, upload-time = "2025-12-12T17:29:37.33Z" }, + { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327, upload-time = "2025-12-12T17:29:39.781Z" }, + { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180, upload-time = "2025-12-12T17:29:42.217Z" }, + { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654, upload-time = "2025-12-12T17:29:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" }, ] [[package]] name = "fqdn" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015 } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121 }, + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, ] [[package]] name = "frozenlist" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875 } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230 }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621 }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889 }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464 }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649 }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188 }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748 }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351 }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767 }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887 }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785 }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312 }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650 }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659 }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837 }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989 }, - { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] [[package]] name = "fsspec" version = "2025.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285 } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966 }, + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, ] [package.optional-dependencies] @@ -1257,9 +1254,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927 } +sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927, upload-time = "2024-10-26T00:50:35.149Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821 }, + { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821, upload-time = "2024-10-26T00:50:33.425Z" }, ] [[package]] @@ -1272,18 +1269,18 @@ dependencies = [ { name = "requests", extra = ["socks"] }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/6a/37e6b70c5bda3161e40265861e63b64a86bfc6ca6a8f1c35328a675c84fd/gdown-5.2.0.tar.gz", hash = "sha256:2145165062d85520a3cd98b356c9ed522c5e7984d408535409fd46f94defc787", size = 284647 } +sdist = { url = "https://files.pythonhosted.org/packages/09/6a/37e6b70c5bda3161e40265861e63b64a86bfc6ca6a8f1c35328a675c84fd/gdown-5.2.0.tar.gz", hash = "sha256:2145165062d85520a3cd98b356c9ed522c5e7984d408535409fd46f94defc787", size = 284647, upload-time = "2024-05-12T06:45:12.725Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/70/e07c381e6488a77094f04c85c9caf1c8008cdc30778f7019bc52e5285ef0/gdown-5.2.0-py3-none-any.whl", hash = "sha256:33083832d82b1101bdd0e9df3edd0fbc0e1c5f14c9d8c38d2a35bf1683b526d6", size = 18235 }, + { url = "https://files.pythonhosted.org/packages/54/70/e07c381e6488a77094f04c85c9caf1c8008cdc30778f7019bc52e5285ef0/gdown-5.2.0-py3-none-any.whl", hash = "sha256:33083832d82b1101bdd0e9df3edd0fbc0e1c5f14c9d8c38d2a35bf1683b526d6", size = 18235, upload-time = "2024-05-12T06:45:10.017Z" }, ] [[package]] name = "gepa" version = "0.0.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/be/9a4c31c65c4910e73bd4a316df99347681bce4f2ef6d10877cc1ed8d57da/gepa-0.0.22.tar.gz", hash = "sha256:0b13a644efd2af52186e456eaad2ae28fcf88c6f796a9c999910c587863d4315", size = 116337 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/be/9a4c31c65c4910e73bd4a316df99347681bce4f2ef6d10877cc1ed8d57da/gepa-0.0.22.tar.gz", hash = "sha256:0b13a644efd2af52186e456eaad2ae28fcf88c6f796a9c999910c587863d4315", size = 116337, upload-time = "2025-11-10T21:39:27.044Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/0e/d41272b28f2163f5bf840b508cbaf4a0bc01eaeaa6e5d447558d1050eb3b/gepa-0.0.22-py3-none-any.whl", hash = "sha256:ff57ee0442399a5cc62d01411935476bc80cfa8f1c318bed82e3db4c2c834665", size = 119666 }, + { url = "https://files.pythonhosted.org/packages/b3/0e/d41272b28f2163f5bf840b508cbaf4a0bc01eaeaa6e5d447558d1050eb3b/gepa-0.0.22-py3-none-any.whl", hash = "sha256:ff57ee0442399a5cc62d01411935476bc80cfa8f1c318bed82e3db4c2c834665", size = 119666, upload-time = "2025-11-10T21:39:26.028Z" }, ] [[package]] @@ -1293,9 +1290,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "smmap" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684 } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794 }, + { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, ] [[package]] @@ -1305,9 +1302,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "gitdb" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371 } +sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620 }, + { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" }, ] [[package]] @@ -1321,9 +1318,9 @@ dependencies = [ { name = "protobuf" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759 } +sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759, upload-time = "2025-10-28T21:34:51.529Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706 }, + { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706, upload-time = "2025-10-28T21:34:50.151Z" }, ] [[package]] @@ -1334,9 +1331,9 @@ dependencies = [ { name = "pyasn1-modules" }, { name = "rsa" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/3c/ec64b9a275ca22fa1cd3b6e77fefcf837b0732c890aa32d2bd21313d9b33/google_auth-2.47.0.tar.gz", hash = "sha256:833229070a9dfee1a353ae9877dcd2dec069a8281a4e72e72f77d4a70ff945da", size = 323719 } +sdist = { url = "https://files.pythonhosted.org/packages/60/3c/ec64b9a275ca22fa1cd3b6e77fefcf837b0732c890aa32d2bd21313d9b33/google_auth-2.47.0.tar.gz", hash = "sha256:833229070a9dfee1a353ae9877dcd2dec069a8281a4e72e72f77d4a70ff945da", size = 323719, upload-time = "2026-01-06T21:55:31.045Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/18/79e9008530b79527e0d5f79e7eef08d3b179b7f851cfd3a2f27822fbdfa9/google_auth-2.47.0-py3-none-any.whl", hash = "sha256:c516d68336bfde7cf0da26aab674a36fedcf04b37ac4edd59c597178760c3498", size = 234867 }, + { url = "https://files.pythonhosted.org/packages/db/18/79e9008530b79527e0d5f79e7eef08d3b179b7f851cfd3a2f27822fbdfa9/google_auth-2.47.0-py3-none-any.whl", hash = "sha256:c516d68336bfde7cf0da26aab674a36fedcf04b37ac4edd59c597178760c3498", size = 234867, upload-time = "2026-01-06T21:55:28.6Z" }, ] [package.optional-dependencies] @@ -1352,9 +1349,9 @@ dependencies = [ { name = "google-api-core" }, { name = "google-auth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469 }, + { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, ] [[package]] @@ -1369,22 +1366,22 @@ dependencies = [ { name = "google-resumable-media" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d2/8e/fab2de1a0ab7fdbd452eaae5a9a5c933d0911c26b04efa0c76ddfd921259/google_cloud_storage-3.7.0.tar.gz", hash = "sha256:9ce59c65f4d6e372effcecc0456680a8d73cef4f2dc9212a0704799cb3d69237", size = 17258914 } +sdist = { url = "https://files.pythonhosted.org/packages/d2/8e/fab2de1a0ab7fdbd452eaae5a9a5c933d0911c26b04efa0c76ddfd921259/google_cloud_storage-3.7.0.tar.gz", hash = "sha256:9ce59c65f4d6e372effcecc0456680a8d73cef4f2dc9212a0704799cb3d69237", size = 17258914, upload-time = "2025-12-09T18:24:48.97Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/80/6e5c7c83cea15ed4dfc4843b9df9db0716bc551ac938f7b5dd18a72bd5e4/google_cloud_storage-3.7.0-py3-none-any.whl", hash = "sha256:469bc9540936e02f8a4bfd1619e9dca1e42dec48f95e4204d783b36476a15093", size = 303364 }, + { url = "https://files.pythonhosted.org/packages/2d/80/6e5c7c83cea15ed4dfc4843b9df9db0716bc551ac938f7b5dd18a72bd5e4/google_cloud_storage-3.7.0-py3-none-any.whl", hash = "sha256:469bc9540936e02f8a4bfd1619e9dca1e42dec48f95e4204d783b36476a15093", size = 303364, upload-time = "2025-12-09T18:24:47.343Z" }, ] [[package]] name = "google-crc32c" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192 } +sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/ac/6f7bc93886a823ab545948c2dd48143027b2355ad1944c7cf852b338dc91/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff", size = 31296 }, - { url = "https://files.pythonhosted.org/packages/f7/97/a5accde175dee985311d949cfcb1249dcbb290f5ec83c994ea733311948f/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288", size = 30870 }, - { url = "https://files.pythonhosted.org/packages/3d/63/bec827e70b7a0d4094e7476f863c0dbd6b5f0f1f91d9c9b32b76dcdfeb4e/google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d", size = 33214 }, - { url = "https://files.pythonhosted.org/packages/63/bc/11b70614df04c289128d782efc084b9035ef8466b3d0a8757c1b6f5cf7ac/google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092", size = 33589 }, - { url = "https://files.pythonhosted.org/packages/3e/00/a08a4bc24f1261cc5b0f47312d8aebfbe4b53c2e6307f1b595605eed246b/google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733", size = 34437 }, + { url = "https://files.pythonhosted.org/packages/95/ac/6f7bc93886a823ab545948c2dd48143027b2355ad1944c7cf852b338dc91/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff", size = 31296, upload-time = "2025-12-16T00:19:07.261Z" }, + { url = "https://files.pythonhosted.org/packages/f7/97/a5accde175dee985311d949cfcb1249dcbb290f5ec83c994ea733311948f/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288", size = 30870, upload-time = "2025-12-16T00:29:17.669Z" }, + { url = "https://files.pythonhosted.org/packages/3d/63/bec827e70b7a0d4094e7476f863c0dbd6b5f0f1f91d9c9b32b76dcdfeb4e/google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d", size = 33214, upload-time = "2025-12-16T00:40:19.618Z" }, + { url = "https://files.pythonhosted.org/packages/63/bc/11b70614df04c289128d782efc084b9035ef8466b3d0a8757c1b6f5cf7ac/google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092", size = 33589, upload-time = "2025-12-16T00:40:20.7Z" }, + { url = "https://files.pythonhosted.org/packages/3e/00/a08a4bc24f1261cc5b0f47312d8aebfbe4b53c2e6307f1b595605eed246b/google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733", size = 34437, upload-time = "2025-12-16T00:35:19.437Z" }, ] [[package]] @@ -1403,9 +1400,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "websockets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/ad/d3ac5a102135bd3f1e4b1475ca65d2bd4bcc22eb2e9348ac40fe3fadb1d6/google_genai-1.56.0.tar.gz", hash = "sha256:0491af33c375f099777ae207d9621f044e27091fafad4c50e617eba32165e82f", size = 340451 } +sdist = { url = "https://files.pythonhosted.org/packages/70/ad/d3ac5a102135bd3f1e4b1475ca65d2bd4bcc22eb2e9348ac40fe3fadb1d6/google_genai-1.56.0.tar.gz", hash = "sha256:0491af33c375f099777ae207d9621f044e27091fafad4c50e617eba32165e82f", size = 340451, upload-time = "2025-12-17T12:35:05.412Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/93/94bc7a89ef4e7ed3666add55cd859d1483a22737251df659bf1aa46e9405/google_genai-1.56.0-py3-none-any.whl", hash = "sha256:9e6b11e0c105ead229368cb5849a480e4d0185519f8d9f538d61ecfcf193b052", size = 426563 }, + { url = "https://files.pythonhosted.org/packages/84/93/94bc7a89ef4e7ed3666add55cd859d1483a22737251df659bf1aa46e9405/google_genai-1.56.0-py3-none-any.whl", hash = "sha256:9e6b11e0c105ead229368cb5849a480e4d0185519f8d9f538d61ecfcf193b052", size = 426563, upload-time = "2025-12-17T12:35:03.717Z" }, ] [[package]] @@ -1415,9 +1412,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "google-crc32c" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265 } +sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload-time = "2025-11-17T15:38:06.659Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340 }, + { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload-time = "2025-11-17T15:38:05.594Z" }, ] [[package]] @@ -1427,9 +1424,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433 } +sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515 }, + { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, ] [[package]] @@ -1442,18 +1439,18 @@ dependencies = [ { name = "python-dateutil" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/cc/f6/bf62ff950c317ed03e77f3f6ddd7e34aaa98fe89d79ebd660c55343d8054/graphene-3.4.3.tar.gz", hash = "sha256:2a3786948ce75fe7e078443d37f609cbe5bb36ad8d6b828740ad3b95ed1a0aaa", size = 44739 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/f6/bf62ff950c317ed03e77f3f6ddd7e34aaa98fe89d79ebd660c55343d8054/graphene-3.4.3.tar.gz", hash = "sha256:2a3786948ce75fe7e078443d37f609cbe5bb36ad8d6b828740ad3b95ed1a0aaa", size = 44739, upload-time = "2024-11-09T20:44:25.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl", hash = "sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71", size = 114894 }, + { url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl", hash = "sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71", size = 114894, upload-time = "2024-11-09T20:44:23.851Z" }, ] [[package]] name = "graphql-core" version = "3.2.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/9b/037a640a2983b09aed4a823f9cf1729e6d780b0671f854efa4727a7affbe/graphql_core-3.2.7.tar.gz", hash = "sha256:27b6904bdd3b43f2a0556dad5d579bdfdeab1f38e8e8788e555bdcb586a6f62c", size = 513484 } +sdist = { url = "https://files.pythonhosted.org/packages/ac/9b/037a640a2983b09aed4a823f9cf1729e6d780b0671f854efa4727a7affbe/graphql_core-3.2.7.tar.gz", hash = "sha256:27b6904bdd3b43f2a0556dad5d579bdfdeab1f38e8e8788e555bdcb586a6f62c", size = 513484, upload-time = "2025-11-01T22:30:40.436Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/14/933037032608787fb92e365883ad6a741c235e0ff992865ec5d904a38f1e/graphql_core-3.2.7-py3-none-any.whl", hash = "sha256:17fc8f3ca4a42913d8e24d9ac9f08deddf0a0b2483076575757f6c412ead2ec0", size = 207262 }, + { url = "https://files.pythonhosted.org/packages/0a/14/933037032608787fb92e365883ad6a741c235e0ff992865ec5d904a38f1e/graphql_core-3.2.7-py3-none-any.whl", hash = "sha256:17fc8f3ca4a42913d8e24d9ac9f08deddf0a0b2483076575757f6c412ead2ec0", size = 207262, upload-time = "2025-11-01T22:30:38.912Z" }, ] [[package]] @@ -1463,25 +1460,25 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "graphql-core" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d1/13/98fbf8d67552f102488ffc16c6f559ce71ea15f6294728d33928ab5ff14d/graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c", size = 50027 } +sdist = { url = "https://files.pythonhosted.org/packages/d1/13/98fbf8d67552f102488ffc16c6f559ce71ea15f6294728d33928ab5ff14d/graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c", size = 50027, upload-time = "2022-04-16T11:03:45.447Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5", size = 16940 }, + { url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5", size = 16940, upload-time = "2022-04-16T11:03:43.895Z" }, ] [[package]] name = "greenlet" version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658 }, - { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810 }, - { url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248 }, - { url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403 }, - { url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910 }, - { url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206 }, - { url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359 }, - { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740 }, + { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658, upload-time = "2025-12-04T14:23:37.494Z" }, + { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810, upload-time = "2025-12-04T14:50:04.154Z" }, + { url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248, upload-time = "2025-12-04T14:57:39.35Z" }, + { url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403, upload-time = "2025-12-04T15:07:10.831Z" }, + { url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910, upload-time = "2025-12-04T14:25:59.705Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206, upload-time = "2025-12-04T15:04:21.027Z" }, + { url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359, upload-time = "2025-12-04T14:27:26.548Z" }, + { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740, upload-time = "2025-12-04T14:47:52.773Z" }, ] [[package]] @@ -1491,33 +1488,33 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031 } +sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031, upload-time = "2024-08-10T20:25:27.378Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029 }, + { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" }, ] [[package]] name = "h11" version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] [[package]] name = "hf-xet" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099 }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178 }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214 }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054 }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812 }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920 }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735 }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, ] [[package]] @@ -1528,24 +1525,24 @@ dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, ] [[package]] name = "httptools" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531 }, - { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408 }, - { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889 }, - { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460 }, - { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267 }, - { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429 }, - { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173 }, + { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531, upload-time = "2025-10-10T03:54:20.887Z" }, + { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408, upload-time = "2025-10-10T03:54:22.455Z" }, + { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889, upload-time = "2025-10-10T03:54:23.753Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460, upload-time = "2025-10-10T03:54:25.313Z" }, + { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267, upload-time = "2025-10-10T03:54:26.81Z" }, + { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429, upload-time = "2025-10-10T03:54:28.174Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173, upload-time = "2025-10-10T03:54:29.5Z" }, ] [[package]] @@ -1558,18 +1555,18 @@ dependencies = [ { name = "httpcore" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] [[package]] name = "huey" version = "2.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/29/3428d52eb8e85025e264a291641a9f9d6407cc1e51d1b630f6ac5815999a/huey-2.6.0.tar.gz", hash = "sha256:8d11f8688999d65266af1425b831f6e3773e99415027177b8734b0ffd5e251f6", size = 221068 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/29/3428d52eb8e85025e264a291641a9f9d6407cc1e51d1b630f6ac5815999a/huey-2.6.0.tar.gz", hash = "sha256:8d11f8688999d65266af1425b831f6e3773e99415027177b8734b0ffd5e251f6", size = 221068, upload-time = "2026-01-06T03:01:02.055Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/34/fae9ac8f1c3a552fd3f7ff652b94c78d219dedc5fce0c0a4232457760a00/huey-2.6.0-py3-none-any.whl", hash = "sha256:1b9df9d370b49c6d5721ba8a01ac9a787cf86b3bdc584e4679de27b920395c3f", size = 76951 }, + { url = "https://files.pythonhosted.org/packages/1a/34/fae9ac8f1c3a552fd3f7ff652b94c78d219dedc5fce0c0a4232457760a00/huey-2.6.0-py3-none-any.whl", hash = "sha256:1b9df9d370b49c6d5721ba8a01ac9a787cf86b3bdc584e4679de27b920395c3f", size = 76951, upload-time = "2026-01-06T03:01:00.808Z" }, ] [[package]] @@ -1586,27 +1583,27 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358 } +sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094 }, + { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" }, ] [[package]] name = "identify" version = "2.6.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311 } +sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183 }, + { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, ] [[package]] name = "idna" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] [[package]] @@ -1616,9 +1613,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865 }, + { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, ] [[package]] @@ -1628,9 +1625,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531 } +sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531, upload-time = "2025-12-24T04:25:06.773Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929 }, + { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929, upload-time = "2025-12-24T04:25:05.298Z" }, ] [[package]] @@ -1638,7 +1635,7 @@ name = "ipykernel" version = "7.1.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "appnope", marker = "(platform_machine != 'aarch64' and platform_system == 'Darwin') or (platform_system == 'Darwin' and sys_platform != 'linux')" }, + { name = "appnope", marker = "sys_platform == 'darwin'" }, { name = "comm" }, { name = "debugpy" }, { name = "ipython" }, @@ -1652,9 +1649,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968 }, + { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, ] [[package]] @@ -1662,7 +1659,7 @@ name = "ipython" version = "8.38.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "decorator" }, { name = "exceptiongroup" }, { name = "jedi" }, @@ -1674,9 +1671,9 @@ dependencies = [ { name = "traitlets" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996 } +sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996, upload-time = "2026-01-05T10:59:06.901Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813 }, + { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813, upload-time = "2026-01-05T10:59:04.239Z" }, ] [[package]] @@ -1690,9 +1687,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808 }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, ] [[package]] @@ -1702,18 +1699,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arrow" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649 } +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, ] [[package]] name = "itsdangerous" version = "2.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410 } +sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234 }, + { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, ] [[package]] @@ -1723,9 +1720,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, ] [[package]] @@ -1735,37 +1732,29 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] name = "jiter" version = "0.12.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652 }, - { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829 }, - { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568 }, - { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052 }, - { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585 }, - { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541 }, - { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423 }, - { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958 }, - { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084 }, - { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054 }, - { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368 }, - { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847 }, - { url = "https://files.pythonhosted.org/packages/fe/54/5339ef1ecaa881c6948669956567a64d2670941925f245c434f494ffb0e5/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:4739a4657179ebf08f85914ce50332495811004cc1747852e8b2041ed2aab9b8", size = 311144 }, - { url = "https://files.pythonhosted.org/packages/27/74/3446c652bffbd5e81ab354e388b1b5fc1d20daac34ee0ed11ff096b1b01a/jiter-0.12.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:41da8def934bf7bec16cb24bd33c0ca62126d2d45d81d17b864bd5ad721393c3", size = 305877 }, - { url = "https://files.pythonhosted.org/packages/a1/f4/ed76ef9043450f57aac2d4fbeb27175aa0eb9c38f833be6ef6379b3b9a86/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c44ee814f499c082e69872d426b624987dbc5943ab06e9bbaa4f81989fdb79e", size = 340419 }, - { url = "https://files.pythonhosted.org/packages/21/01/857d4608f5edb0664aa791a3d45702e1a5bcfff9934da74035e7b9803846/jiter-0.12.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd2097de91cf03eaa27b3cbdb969addf83f0179c6afc41bbc4513705e013c65d", size = 347212 }, - { url = "https://files.pythonhosted.org/packages/cb/f5/12efb8ada5f5c9edc1d4555fe383c1fb2eac05ac5859258a72d61981d999/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:e8547883d7b96ef2e5fe22b88f8a4c8725a56e7f4abafff20fd5272d634c7ecb", size = 309974 }, - { url = "https://files.pythonhosted.org/packages/85/15/d6eb3b770f6a0d332675141ab3962fd4a7c270ede3515d9f3583e1d28276/jiter-0.12.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:89163163c0934854a668ed783a2546a0617f71706a2551a4a0666d91ab365d6b", size = 304233 }, - { url = "https://files.pythonhosted.org/packages/8c/3e/e7e06743294eea2cf02ced6aa0ff2ad237367394e37a0e2b4a1108c67a36/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d96b264ab7d34bbb2312dedc47ce07cd53f06835eacbc16dde3761f47c3a9e7f", size = 338537 }, - { url = "https://files.pythonhosted.org/packages/2f/9c/6753e6522b8d0ef07d3a3d239426669e984fb0eba15a315cdbc1253904e4/jiter-0.12.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c24e864cb30ab82311c6425655b0cdab0a98c5d973b065c66a3f020740c2324c", size = 346110 }, +sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294, upload-time = "2025-11-09T20:49:23.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652, upload-time = "2025-11-09T20:46:41.021Z" }, + { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829, upload-time = "2025-11-09T20:46:43.281Z" }, + { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568, upload-time = "2025-11-09T20:46:45.075Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052, upload-time = "2025-11-09T20:46:46.818Z" }, + { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585, upload-time = "2025-11-09T20:46:48.319Z" }, + { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541, upload-time = "2025-11-09T20:46:49.643Z" }, + { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423, upload-time = "2025-11-09T20:46:51.731Z" }, + { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958, upload-time = "2025-11-09T20:46:53.432Z" }, + { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084, upload-time = "2025-11-09T20:46:54.848Z" }, + { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054, upload-time = "2025-11-09T20:46:56.487Z" }, + { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368, upload-time = "2025-11-09T20:46:58.638Z" }, + { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847, upload-time = "2025-11-09T20:47:00.295Z" }, ] [[package]] @@ -1776,45 +1765,45 @@ dependencies = [ { name = "click" }, { name = "rapidfuzz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537 } +sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537, upload-time = "2024-11-01T16:18:57.337Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990 }, + { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990, upload-time = "2024-11-01T16:18:55.928Z" }, ] [[package]] name = "jmespath" version = "1.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843 } +sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256 }, + { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, ] [[package]] name = "joblib" version = "1.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603 } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071 }, + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, ] [[package]] name = "json-repair" version = "0.55.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/74/0f39677fa7c0127129c3f1a37c94d05c30a968ba3047200e54dea375b09a/json_repair-0.55.0.tar.gz", hash = "sha256:9fafb47d92582ef4bdd3520656bdb0fcb37b46cf6aa99c1926b7895abc0a3a4b", size = 38828 } +sdist = { url = "https://files.pythonhosted.org/packages/96/74/0f39677fa7c0127129c3f1a37c94d05c30a968ba3047200e54dea375b09a/json_repair-0.55.0.tar.gz", hash = "sha256:9fafb47d92582ef4bdd3520656bdb0fcb37b46cf6aa99c1926b7895abc0a3a4b", size = 38828, upload-time = "2026-01-01T20:29:02.684Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/00/d7d6b6b3257f9b1f997a558b6f7087b8af7c0a2f525f4fbd864c267a88ab/json_repair-0.55.0-py3-none-any.whl", hash = "sha256:bcf4880f5e6ad21a0f70ab034e3d1d398c2ae9698dc5717d7015afbac77b8ed7", size = 29570 }, + { url = "https://files.pythonhosted.org/packages/bc/00/d7d6b6b3257f9b1f997a558b6f7087b8af7c0a2f525f4fbd864c267a88ab/json_repair-0.55.0-py3-none-any.whl", hash = "sha256:bcf4880f5e6ad21a0f70ab034e3d1d398c2ae9698dc5717d7015afbac77b8ed7", size = 29570, upload-time = "2026-01-01T20:29:01.042Z" }, ] [[package]] name = "json5" version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441 } +sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441, upload-time = "2026-01-01T19:42:14.99Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163 }, + { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163, upload-time = "2026-01-01T19:42:13.962Z" }, ] [[package]] @@ -1824,18 +1813,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359 } +sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359, upload-time = "2023-09-01T12:34:44.187Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701 }, + { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701, upload-time = "2023-09-01T12:34:42.563Z" }, ] [[package]] name = "jsonpointer" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114 } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595 }, + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, ] [[package]] @@ -1848,9 +1837,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583 } +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630 }, + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, ] [package.optional-dependencies] @@ -1873,9 +1862,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855 } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437 }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] [[package]] @@ -1890,9 +1879,9 @@ dependencies = [ { name = "nbconvert" }, { name = "notebook" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959 } +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657 }, + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, ] [[package]] @@ -1906,9 +1895,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/27/d10de45e8ad4ce872372c4a3a37b7b35b6b064f6f023a5c14ffcced4d59d/jupyter_client-8.7.0.tar.gz", hash = "sha256:3357212d9cbe01209e59190f67a3a7e1f387a4f4e88d1e0433ad84d7b262531d", size = 344691 } +sdist = { url = "https://files.pythonhosted.org/packages/a6/27/d10de45e8ad4ce872372c4a3a37b7b35b6b064f6f023a5c14ffcced4d59d/jupyter_client-8.7.0.tar.gz", hash = "sha256:3357212d9cbe01209e59190f67a3a7e1f387a4f4e88d1e0433ad84d7b262531d", size = 344691, upload-time = "2025-12-09T18:37:01.953Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/f5/fddaec430367be9d62a7ed125530e133bfd4a1c0350fe221149ee0f2b526/jupyter_client-8.7.0-py3-none-any.whl", hash = "sha256:3671a94fd25e62f5f2f554f5e95389c2294d89822378a5f2dd24353e1494a9e0", size = 106215 }, + { url = "https://files.pythonhosted.org/packages/bb/f5/fddaec430367be9d62a7ed125530e133bfd4a1c0350fe221149ee0f2b526/jupyter_client-8.7.0-py3-none-any.whl", hash = "sha256:3671a94fd25e62f5f2f554f5e95389c2294d89822378a5f2dd24353e1494a9e0", size = 106215, upload-time = "2025-12-09T18:37:00.024Z" }, ] [[package]] @@ -1925,9 +1914,9 @@ dependencies = [ { name = "pyzmq" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510 }, + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, ] [[package]] @@ -1938,9 +1927,9 @@ dependencies = [ { name = "platformdirs" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, ] [[package]] @@ -1957,9 +1946,9 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, ] [[package]] @@ -1969,9 +1958,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687 }, + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, ] [[package]] @@ -1991,7 +1980,7 @@ dependencies = [ { name = "overrides" }, { name = "packaging" }, { name = "prometheus-client" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "pyzmq" }, { name = "send2trash" }, { name = "terminado" }, @@ -1999,9 +1988,9 @@ dependencies = [ { name = "traitlets" }, { name = "websocket-client" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221 }, + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, ] [[package]] @@ -2009,12 +1998,12 @@ name = "jupyter-server-terminals" version = "0.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "terminado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430 } +sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656 }, + { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, ] [[package]] @@ -2037,18 +2026,18 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/21/413d142686a4e8f4268d985becbdb4daf060524726248e73be4773786987/jupyterlab-4.5.1.tar.gz", hash = "sha256:09da1ddfbd9eec18b5101dbb8515612aa1e47443321fb99503725a88e93d20d9", size = 23992251 } +sdist = { url = "https://files.pythonhosted.org/packages/09/21/413d142686a4e8f4268d985becbdb4daf060524726248e73be4773786987/jupyterlab-4.5.1.tar.gz", hash = "sha256:09da1ddfbd9eec18b5101dbb8515612aa1e47443321fb99503725a88e93d20d9", size = 23992251, upload-time = "2025-12-15T16:58:59.361Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/c3/acced767eecc11a70c65c45295db5396c4f0c1937874937d5a76d7b177b6/jupyterlab-4.5.1-py3-none-any.whl", hash = "sha256:31b059de96de0754ff1f2ce6279774b6aab8c34d7082e9752db58207c99bd514", size = 12384821 }, + { url = "https://files.pythonhosted.org/packages/af/c3/acced767eecc11a70c65c45295db5396c4f0c1937874937d5a76d7b177b6/jupyterlab-4.5.1-py3-none-any.whl", hash = "sha256:31b059de96de0754ff1f2ce6279774b6aab8c34d7082e9752db58207c99bd514", size = 12384821, upload-time = "2025-12-15T16:58:55.563Z" }, ] [[package]] name = "jupyterlab-pygments" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, ] [[package]] @@ -2064,44 +2053,44 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830 }, + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, ] [[package]] name = "jupyterlab-widgets" version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423 } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, ] [[package]] name = "kiwisolver" version = "1.4.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159 }, - { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578 }, - { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312 }, - { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458 }, - { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640 }, - { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074 }, - { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036 }, - { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310 }, - { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943 }, - { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488 }, - { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787 }, - { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730 }, - { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036 }, - { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183 }, - { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675 }, - { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277 }, - { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994 }, - { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744 }, +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159, upload-time = "2025-08-10T21:25:35.472Z" }, + { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578, upload-time = "2025-08-10T21:25:36.73Z" }, + { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312, upload-time = "2025-08-10T21:25:37.658Z" }, + { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458, upload-time = "2025-08-10T21:25:39.067Z" }, + { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640, upload-time = "2025-08-10T21:25:40.489Z" }, + { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074, upload-time = "2025-08-10T21:25:42.221Z" }, + { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036, upload-time = "2025-08-10T21:25:43.801Z" }, + { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310, upload-time = "2025-08-10T21:25:45.045Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943, upload-time = "2025-08-10T21:25:46.393Z" }, + { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488, upload-time = "2025-08-10T21:25:48.074Z" }, + { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787, upload-time = "2025-08-10T21:25:49.442Z" }, + { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730, upload-time = "2025-08-10T21:25:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036, upload-time = "2025-08-10T21:25:52.063Z" }, + { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183, upload-time = "2025-08-10T21:27:37.669Z" }, + { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675, upload-time = "2025-08-10T21:27:39.031Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277, upload-time = "2025-08-10T21:27:40.129Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994, upload-time = "2025-08-10T21:27:41.181Z" }, + { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744, upload-time = "2025-08-10T21:27:42.254Z" }, ] [[package]] @@ -2111,7 +2100,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } [[package]] name = "langextract" @@ -2135,9 +2124,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029 } +sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029, upload-time = "2025-11-14T22:21:30.511Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592 }, + { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592, upload-time = "2025-11-14T22:21:29.044Z" }, ] [package.optional-dependencies] @@ -2149,9 +2138,9 @@ openai = [ name = "lark" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732 } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, ] [[package]] @@ -2161,9 +2150,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fire" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292, upload-time = "2022-09-06T16:09:06.607Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594 }, + { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594, upload-time = "2022-09-06T16:09:04.658Z" }, ] [[package]] @@ -2184,39 +2173,39 @@ dependencies = [ { name = "tiktoken" }, { name = "tokenizers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976, upload-time = "2025-11-16T00:03:51.812Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975 }, + { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975, upload-time = "2025-11-16T00:03:49.182Z" }, ] [[package]] name = "lxml" version = "6.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589 }, - { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671 }, - { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961 }, - { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087 }, - { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620 }, - { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664 }, - { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397 }, - { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178 }, - { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148 }, - { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035 }, - { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111 }, - { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662 }, - { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973 }, - { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953 }, - { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695 }, - { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051 }, - { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264 }, - { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435 }, - { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913 }, - { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357 }, - { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295 }, - { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913 }, +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, ] [[package]] @@ -2226,9 +2215,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509 }, + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, ] [[package]] @@ -2238,18 +2227,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321 }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] [[package]] name = "markdown2" version = "2.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652 } +sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652, upload-time = "2025-07-27T16:16:24.307Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954 }, + { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954, upload-time = "2025-07-27T16:16:23.026Z" }, ] [[package]] @@ -2260,9 +2249,9 @@ dependencies = [ { name = "beautifulsoup4" }, { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816 } +sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816, upload-time = "2025-11-16T19:21:18.565Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724 }, + { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724, upload-time = "2025-11-16T19:21:17.622Z" }, ] [[package]] @@ -2292,28 +2281,28 @@ dependencies = [ { name = "tqdm" }, { name = "transformers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302 } +sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302, upload-time = "2025-09-30T15:44:59.591Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914 }, + { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914, upload-time = "2025-09-30T15:44:58.441Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631 }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057 }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050 }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681 }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705 }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524 }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282 }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745 }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571 }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056 }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932 }, + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, ] [[package]] @@ -2331,17 +2320,17 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828 }, - { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050 }, - { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452 }, - { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928 }, - { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377 }, - { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127 }, - { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252 }, - { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693 }, - { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205 }, + { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828, upload-time = "2025-12-10T22:55:02.313Z" }, + { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050, upload-time = "2025-12-10T22:55:04.997Z" }, + { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452, upload-time = "2025-12-10T22:55:07.47Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928, upload-time = "2025-12-10T22:55:10.566Z" }, + { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377, upload-time = "2025-12-10T22:55:12.362Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127, upload-time = "2025-12-10T22:55:14.436Z" }, + { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252, upload-time = "2025-12-10T22:56:39.529Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693, upload-time = "2025-12-10T22:56:41.758Z" }, + { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205, upload-time = "2025-12-10T22:56:43.415Z" }, ] [[package]] @@ -2351,18 +2340,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516 }, + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] [[package]] @@ -2372,9 +2361,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598 }, + { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, ] [[package]] @@ -2385,9 +2374,9 @@ dependencies = [ { name = "absl-py" }, { name = "pyyaml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356 } +sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356, upload-time = "2025-04-17T08:25:02.247Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707 }, + { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707, upload-time = "2025-04-17T08:24:59.038Z" }, ] [[package]] @@ -2401,7 +2390,7 @@ dependencies = [ { name = "flask" }, { name = "flask-cors" }, { name = "graphene" }, - { name = "gunicorn", marker = "platform_system != 'Windows'" }, + { name = "gunicorn", marker = "sys_platform != 'win32'" }, { name = "huey" }, { name = "matplotlib" }, { name = "mlflow-skinny" }, @@ -2412,11 +2401,11 @@ dependencies = [ { name = "scikit-learn" }, { name = "scipy" }, { name = "sqlalchemy" }, - { name = "waitress", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "waitress", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ad/f8/10ccb111ed53732dfceae0369073023f96acd6b00f92fb3c24473938702d/mlflow-3.8.1.tar.gz", hash = "sha256:0823377bedff4d530b0d560bf394daf9f7e9fbba53453add04eadad34de962cc", size = 8550037 } +sdist = { url = "https://files.pythonhosted.org/packages/ad/f8/10ccb111ed53732dfceae0369073023f96acd6b00f92fb3c24473938702d/mlflow-3.8.1.tar.gz", hash = "sha256:0823377bedff4d530b0d560bf394daf9f7e9fbba53453add04eadad34de962cc", size = 8550037, upload-time = "2025-12-26T16:46:49.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/d5/a20b87c6cd99395fee04d6034686512305530c71ceaabe3a151eeaa25ed7/mlflow-3.8.1-py3-none-any.whl", hash = "sha256:42f26b52438fdb615588e150407c6516d0f64d417436dfc75599c525a464f210", size = 9062281 }, + { url = "https://files.pythonhosted.org/packages/d5/d5/a20b87c6cd99395fee04d6034686512305530c71ceaabe3a151eeaa25ed7/mlflow-3.8.1-py3-none-any.whl", hash = "sha256:42f26b52438fdb615588e150407c6516d0f64d417436dfc75599c525a464f210", size = 9062281, upload-time = "2025-12-26T16:46:46.528Z" }, ] [[package]] @@ -2444,9 +2433,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "uvicorn" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7e/00/18486d9072739e63471c1e441e78cdb6a10c641312d98f6699715406451e/mlflow_skinny-3.8.1.tar.gz", hash = "sha256:0c0aade08187030a4653e267bcd63de2f12cbfebf4c6737832cba45d6fb3594d", size = 2082226 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/00/18486d9072739e63471c1e441e78cdb6a10c641312d98f6699715406451e/mlflow_skinny-3.8.1.tar.gz", hash = "sha256:0c0aade08187030a4653e267bcd63de2f12cbfebf4c6737832cba45d6fb3594d", size = 2082226, upload-time = "2025-12-26T16:30:11.171Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/24/42e52320636fcbabeaf50704f9269a328acc995e1b8a44df6fea33130a0a/mlflow_skinny-3.8.1-py3-none-any.whl", hash = "sha256:3a6ee27f5ac1e67c1d565fa0e12c070b27129b03e669dcaf88ff841176429142", size = 2506002 }, + { url = "https://files.pythonhosted.org/packages/8d/24/42e52320636fcbabeaf50704f9269a328acc995e1b8a44df6fea33130a0a/mlflow_skinny-3.8.1-py3-none-any.whl", hash = "sha256:3a6ee27f5ac1e67c1d565fa0e12c070b27129b03e669dcaf88ff841176429142", size = 2506002, upload-time = "2025-12-26T16:30:09.357Z" }, ] [[package]] @@ -2463,18 +2452,18 @@ dependencies = [ { name = "protobuf" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/e5/9cdca5a91afd71e15943f3dbe00e788bd36479637e9b2e0625224027ff01/mlflow_tracing-3.8.1.tar.gz", hash = "sha256:c032ba715994a4580323f3045fa2700a6323033d87e564bbcbda37e6ab993071", size = 1130700 } +sdist = { url = "https://files.pythonhosted.org/packages/52/e5/9cdca5a91afd71e15943f3dbe00e788bd36479637e9b2e0625224027ff01/mlflow_tracing-3.8.1.tar.gz", hash = "sha256:c032ba715994a4580323f3045fa2700a6323033d87e564bbcbda37e6ab993071", size = 1130700, upload-time = "2025-12-26T16:31:39.314Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/e3/ddbe3e2d1219fa9235559ab88ebf98e1e4f48c62672f0dfb8f1eb07276dc/mlflow_tracing-3.8.1-py3-none-any.whl", hash = "sha256:12d9b5b7177b4152979d003e0d967b280c4252758639aebdfd672734283b17bf", size = 1359007 }, + { url = "https://files.pythonhosted.org/packages/fd/e3/ddbe3e2d1219fa9235559ab88ebf98e1e4f48c62672f0dfb8f1eb07276dc/mlflow_tracing-3.8.1-py3-none-any.whl", hash = "sha256:12d9b5b7177b4152979d003e0d967b280c4252758639aebdfd672734283b17bf", size = 1359007, upload-time = "2025-12-26T16:31:37.514Z" }, ] [[package]] name = "more-itertools" version = "10.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431 } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 }, + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, ] [[package]] @@ -2485,18 +2474,18 @@ dependencies = [ { name = "jinja2" }, { name = "matplotlib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433, upload-time = "2025-11-05T18:12:24.183Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, + { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051, upload-time = "2025-11-05T18:12:22.527Z" }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, ] [[package]] @@ -2506,27 +2495,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153 }, - { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993 }, - { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607 }, - { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847 }, - { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616 }, - { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333 }, - { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239 }, - { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618 }, - { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655 }, - { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245 }, - { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523 }, - { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129 }, - { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999 }, - { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711 }, - { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504 }, - { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422 }, - { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050 }, - { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153 }, - { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317 }, +sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153, upload-time = "2025-10-06T14:48:26.409Z" }, + { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993, upload-time = "2025-10-06T14:48:28.4Z" }, + { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607, upload-time = "2025-10-06T14:48:29.581Z" }, + { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847, upload-time = "2025-10-06T14:48:32.107Z" }, + { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616, upload-time = "2025-10-06T14:48:34.054Z" }, + { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333, upload-time = "2025-10-06T14:48:35.9Z" }, + { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239, upload-time = "2025-10-06T14:48:37.302Z" }, + { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618, upload-time = "2025-10-06T14:48:38.963Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655, upload-time = "2025-10-06T14:48:40.312Z" }, + { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245, upload-time = "2025-10-06T14:48:41.848Z" }, + { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523, upload-time = "2025-10-06T14:48:43.749Z" }, + { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129, upload-time = "2025-10-06T14:48:45.225Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999, upload-time = "2025-10-06T14:48:46.703Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711, upload-time = "2025-10-06T14:48:48.146Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504, upload-time = "2025-10-06T14:48:49.447Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422, upload-time = "2025-10-06T14:48:50.789Z" }, + { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050, upload-time = "2025-10-06T14:48:51.938Z" }, + { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153, upload-time = "2025-10-06T14:48:53.146Z" }, + { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, ] [[package]] @@ -2536,23 +2525,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503 } +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083 }, - { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128 }, - { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132 }, - { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948 }, - { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636 }, - { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478 }, + { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083, upload-time = "2025-04-17T03:11:04.223Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128, upload-time = "2025-04-17T03:11:06.045Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132, upload-time = "2025-04-17T03:11:07.533Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, ] [[package]] name = "narwhals" version = "2.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/6d/b57c64e5038a8cf071bce391bb11551657a74558877ac961e7fa905ece27/narwhals-2.15.0.tar.gz", hash = "sha256:a9585975b99d95084268445a1fdd881311fa26ef1caa18020d959d5b2ff9a965", size = 603479 } +sdist = { url = "https://files.pythonhosted.org/packages/47/6d/b57c64e5038a8cf071bce391bb11551657a74558877ac961e7fa905ece27/narwhals-2.15.0.tar.gz", hash = "sha256:a9585975b99d95084268445a1fdd881311fa26ef1caa18020d959d5b2ff9a965", size = 603479, upload-time = "2026-01-06T08:10:13.27Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/2e/cf2ffeb386ac3763526151163ad7da9f1b586aac96d2b4f7de1eaebf0c61/narwhals-2.15.0-py3-none-any.whl", hash = "sha256:cbfe21ca19d260d9fd67f995ec75c44592d1f106933b03ddd375df7ac841f9d6", size = 432856 }, + { url = "https://files.pythonhosted.org/packages/3d/2e/cf2ffeb386ac3763526151163ad7da9f1b586aac96d2b4f7de1eaebf0c61/narwhals-2.15.0-py3-none-any.whl", hash = "sha256:cbfe21ca19d260d9fd67f995ec75c44592d1f106933b03ddd375df7ac841f9d6", size = 432856, upload-time = "2026-01-06T08:10:11.511Z" }, ] [[package]] @@ -2565,9 +2554,9 @@ dependencies = [ { name = "nbformat" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554 } +sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465 }, + { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, ] [[package]] @@ -2590,9 +2579,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715 } +sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525 }, + { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, ] [[package]] @@ -2605,9 +2594,9 @@ dependencies = [ { name = "jupyter-core" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, ] [[package]] @@ -2617,36 +2606,36 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nbformat" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747 } +sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747, upload-time = "2025-11-16T17:38:55.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122 }, + { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122, upload-time = "2025-11-16T17:38:54.164Z" }, ] [[package]] name = "nest-asyncio" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, ] [[package]] name = "networkx" version = "3.4.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, ] [[package]] name = "nodeenv" version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611 } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438 }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] [[package]] @@ -2660,9 +2649,9 @@ dependencies = [ { name = "notebook-shim" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/a9/882707b0aa639e6d7d3e7df4bfbe07479d832e9a8f02d8471002a4ea6d65/notebook-7.5.1.tar.gz", hash = "sha256:b2fb4cef4d47d08c33aecce1c6c6e84be05436fbd791f88fce8df9fbca088b75", size = 14058696 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/a9/882707b0aa639e6d7d3e7df4bfbe07479d832e9a8f02d8471002a4ea6d65/notebook-7.5.1.tar.gz", hash = "sha256:b2fb4cef4d47d08c33aecce1c6c6e84be05436fbd791f88fce8df9fbca088b75", size = 14058696, upload-time = "2025-12-16T07:38:59.223Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/86/ca516cb58ad2cb2064124d31cf0fd8b012fca64bebeb26da2d2ddf03fc79/notebook-7.5.1-py3-none-any.whl", hash = "sha256:f4e2451c19910c33b88709b84537e11f6368c1cdff1aa0c43db701aea535dd44", size = 14468080 }, + { url = "https://files.pythonhosted.org/packages/d1/86/ca516cb58ad2cb2064124d31cf0fd8b012fca64bebeb26da2d2ddf03fc79/notebook-7.5.1-py3-none-any.whl", hash = "sha256:f4e2451c19910c33b88709b84537e11f6368c1cdff1aa0c43db701aea535dd44", size = 14468080, upload-time = "2025-12-16T07:38:55.644Z" }, ] [[package]] @@ -2672,25 +2661,25 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167 } +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 }, + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, ] [[package]] name = "numpy" version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129 } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468 }, - { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411 }, - { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016 }, - { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889 }, - { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746 }, - { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620 }, - { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659 }, - { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, + { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411, upload-time = "2024-02-05T23:48:29.038Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016, upload-time = "2024-02-05T23:48:54.098Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889, upload-time = "2024-02-05T23:49:25.361Z" }, + { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746, upload-time = "2024-02-05T23:49:51.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620, upload-time = "2024-02-05T23:50:22.515Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659, upload-time = "2024-02-05T23:50:35.834Z" }, + { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905, upload-time = "2024-02-05T23:51:03.701Z" }, ] [[package]] @@ -2698,8 +2687,7 @@ name = "nvidia-cublas-cu12" version = "12.8.4.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, ] [[package]] @@ -2707,8 +2695,7 @@ name = "nvidia-cuda-cupti-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, ] [[package]] @@ -2716,8 +2703,7 @@ name = "nvidia-cuda-nvrtc-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, - { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, ] [[package]] @@ -2725,8 +2711,7 @@ name = "nvidia-cuda-runtime-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, ] [[package]] @@ -2737,8 +2722,7 @@ dependencies = [ { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, ] [[package]] @@ -2749,8 +2733,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, ] [[package]] @@ -2758,8 +2741,7 @@ name = "nvidia-cufile-cu12" version = "1.13.1.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, - { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, ] [[package]] @@ -2767,8 +2749,7 @@ name = "nvidia-curand-cu12" version = "10.3.9.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, ] [[package]] @@ -2781,8 +2762,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, ] [[package]] @@ -2793,8 +2773,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, ] [[package]] @@ -2802,8 +2781,7 @@ name = "nvidia-cusparselt-cu12" version = "0.7.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, ] [[package]] @@ -2811,8 +2789,7 @@ name = "nvidia-nccl-cu12" version = "2.27.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, ] [[package]] @@ -2820,8 +2797,7 @@ name = "nvidia-nvjitlink-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, - { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, ] [[package]] @@ -2829,8 +2805,7 @@ name = "nvidia-nvshmem-cu12" version = "3.3.20" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/9d/3dd98852568fb845ec1f7902c90a22b240fe1cbabda411ccedf2fd737b7b/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b0b960da3842212758e4fa4696b94f129090b30e5122fea3c5345916545cff0", size = 124484616 }, - { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145 }, + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" }, ] [[package]] @@ -2838,8 +2813,7 @@ name = "nvidia-nvtx-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, ] [[package]] @@ -2849,7 +2823,7 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "defusedxml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045 } +sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045, upload-time = "2020-01-18T16:55:48.852Z" } [[package]] name = "ollama" @@ -2859,9 +2833,9 @@ dependencies = [ { name = "httpx" }, { name = "pydantic" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620, upload-time = "2025-11-13T23:02:17.416Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354 }, + { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354, upload-time = "2025-11-13T23:02:16.292Z" }, ] [[package]] @@ -2878,9 +2852,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133 } +sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133, upload-time = "2025-09-24T13:00:53.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627 }, + { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627, upload-time = "2025-09-24T13:00:50.754Z" }, ] [[package]] @@ -2890,14 +2864,14 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929 } +sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929, upload-time = "2025-01-16T13:53:40.22Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/53/2c50afa0b1e05ecdb4603818e85f7d174e683d874ef63a6abe3ac92220c8/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca", size = 37326460 }, - { url = "https://files.pythonhosted.org/packages/3b/43/68555327df94bb9b59a1fd645f63fafb0762515344d2046698762fc19d58/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81", size = 56723330 }, - { url = "https://files.pythonhosted.org/packages/45/be/1438ce43ebe65317344a87e4b150865c5585f4c0db880a34cdae5ac46881/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efabcaa9df731f29e5ea9051776715b1bdd1845d7c9530065c7951d2a2899eb", size = 29487060 }, - { url = "https://files.pythonhosted.org/packages/dd/5c/c139a7876099916879609372bfa513b7f1257f7f1a908b0bdc1c2328241b/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0a27c19dd1f40ddff94976cfe43066fbbe9dfbb2ec1907d66c19caef42a57b", size = 49969856 }, - { url = "https://files.pythonhosted.org/packages/95/dd/ed1191c9dc91abcc9f752b499b7928aacabf10567bb2c2535944d848af18/opencv_python_headless-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:f447d8acbb0b6f2808da71fddd29c1cdd448d2bc98f72d9bb78a7a898fc9621b", size = 29324425 }, - { url = "https://files.pythonhosted.org/packages/86/8a/69176a64335aed183529207ba8bc3d329c2999d852b4f3818027203f50e6/opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca", size = 39402386 }, + { url = "https://files.pythonhosted.org/packages/dc/53/2c50afa0b1e05ecdb4603818e85f7d174e683d874ef63a6abe3ac92220c8/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca", size = 37326460, upload-time = "2025-01-16T13:52:57.015Z" }, + { url = "https://files.pythonhosted.org/packages/3b/43/68555327df94bb9b59a1fd645f63fafb0762515344d2046698762fc19d58/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81", size = 56723330, upload-time = "2025-01-16T13:55:45.731Z" }, + { url = "https://files.pythonhosted.org/packages/45/be/1438ce43ebe65317344a87e4b150865c5585f4c0db880a34cdae5ac46881/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efabcaa9df731f29e5ea9051776715b1bdd1845d7c9530065c7951d2a2899eb", size = 29487060, upload-time = "2025-01-16T13:51:59.625Z" }, + { url = "https://files.pythonhosted.org/packages/dd/5c/c139a7876099916879609372bfa513b7f1257f7f1a908b0bdc1c2328241b/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0a27c19dd1f40ddff94976cfe43066fbbe9dfbb2ec1907d66c19caef42a57b", size = 49969856, upload-time = "2025-01-16T13:53:29.654Z" }, + { url = "https://files.pythonhosted.org/packages/95/dd/ed1191c9dc91abcc9f752b499b7928aacabf10567bb2c2535944d848af18/opencv_python_headless-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:f447d8acbb0b6f2808da71fddd29c1cdd448d2bc98f72d9bb78a7a898fc9621b", size = 29324425, upload-time = "2025-01-16T13:52:49.048Z" }, + { url = "https://files.pythonhosted.org/packages/86/8a/69176a64335aed183529207ba8bc3d329c2999d852b4f3818027203f50e6/opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca", size = 39402386, upload-time = "2025-01-16T13:52:56.418Z" }, ] [[package]] @@ -2908,9 +2882,9 @@ dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767 } +sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356 }, + { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, ] [[package]] @@ -2920,9 +2894,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152 } +sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535 }, + { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, ] [[package]] @@ -2934,9 +2908,9 @@ dependencies = [ { name = "opentelemetry-semantic-conventions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565 }, + { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, ] [[package]] @@ -2947,9 +2921,9 @@ dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935 } +sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982 }, + { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, ] [[package]] @@ -2965,48 +2939,48 @@ dependencies = [ { name = "sqlalchemy" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444 } +sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444, upload-time = "2025-11-10T05:14:30.151Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708 }, + { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708, upload-time = "2025-11-10T05:14:28.6Z" }, ] [[package]] name = "orjson" version = "3.11.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347 } +sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719 }, - { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467 }, - { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702 }, - { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907 }, - { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935 }, - { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541 }, - { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031 }, - { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622 }, - { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800 }, - { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198 }, - { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984 }, - { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272 }, - { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360 }, + { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719, upload-time = "2025-12-06T15:53:43.877Z" }, + { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467, upload-time = "2025-12-06T15:53:45.379Z" }, + { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702, upload-time = "2025-12-06T15:53:46.659Z" }, + { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907, upload-time = "2025-12-06T15:53:48.487Z" }, + { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935, upload-time = "2025-12-06T15:53:49.88Z" }, + { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541, upload-time = "2025-12-06T15:53:51.226Z" }, + { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031, upload-time = "2025-12-06T15:53:52.309Z" }, + { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622, upload-time = "2025-12-06T15:53:53.606Z" }, + { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800, upload-time = "2025-12-06T15:53:54.866Z" }, + { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198, upload-time = "2025-12-06T15:53:56.383Z" }, + { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984, upload-time = "2025-12-06T15:53:57.746Z" }, + { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272, upload-time = "2025-12-06T15:53:59.769Z" }, + { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360, upload-time = "2025-12-06T15:54:01.25Z" }, ] [[package]] name = "overrides" version = "7.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812 } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832 }, + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, ] [[package]] name = "packaging" version = "25.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, ] [[package]] @@ -3019,33 +2993,33 @@ dependencies = [ { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223 } +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763 }, - { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217 }, - { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791 }, - { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373 }, - { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444 }, - { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459 }, - { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086 }, + { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, + { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, + { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, + { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, + { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, ] [[package]] name = "pandocfilters" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, ] [[package]] name = "parso" version = "0.8.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205 } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668 }, + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] [[package]] @@ -3058,9 +3032,9 @@ dependencies = [ { name = "pydantic-settings" }, { name = "pypdfium2" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968, upload-time = "2025-06-11T14:42:09.492Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693 }, + { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693, upload-time = "2025-06-11T14:42:08.157Z" }, ] [[package]] @@ -3070,53 +3044,53 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] [[package]] name = "pillow" version = "10.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271 }, - { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658 }, - { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075 }, - { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808 }, - { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290 }, - { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163 }, - { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100 }, - { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880 }, - { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218 }, - { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487 }, - { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219 }, - { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889 }, - { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160 }, - { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020 }, - { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539 }, - { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125 }, - { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373 }, - { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661 }, +sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059, upload-time = "2024-07-01T09:48:43.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271, upload-time = "2024-07-01T09:45:22.07Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658, upload-time = "2024-07-01T09:45:25.292Z" }, + { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075, upload-time = "2024-07-01T09:45:27.94Z" }, + { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808, upload-time = "2024-07-01T09:45:30.305Z" }, + { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290, upload-time = "2024-07-01T09:45:32.868Z" }, + { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163, upload-time = "2024-07-01T09:45:35.279Z" }, + { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100, upload-time = "2024-07-01T09:45:37.74Z" }, + { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880, upload-time = "2024-07-01T09:45:39.89Z" }, + { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218, upload-time = "2024-07-01T09:45:42.771Z" }, + { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487, upload-time = "2024-07-01T09:45:45.176Z" }, + { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219, upload-time = "2024-07-01T09:45:47.274Z" }, + { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889, upload-time = "2024-07-01T09:48:04.815Z" }, + { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160, upload-time = "2024-07-01T09:48:07.206Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020, upload-time = "2024-07-01T09:48:09.66Z" }, + { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539, upload-time = "2024-07-01T09:48:12.529Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125, upload-time = "2024-07-01T09:48:14.891Z" }, + { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373, upload-time = "2024-07-01T09:48:17.601Z" }, + { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661, upload-time = "2024-07-01T09:48:20.293Z" }, ] [[package]] name = "pip" version = "25.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622 }, + { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, ] [[package]] name = "platformdirs" version = "4.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715 } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731 }, + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] [[package]] @@ -3128,14 +3102,14 @@ dependencies = [ { name = "pyee" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424 }, - { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228 }, - { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424 }, - { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122 }, - { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645 }, - { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837 }, - { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843 }, - { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959 }, + { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424, upload-time = "2025-11-11T18:39:10.175Z" }, + { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228, upload-time = "2025-11-11T18:39:13.915Z" }, + { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424, upload-time = "2025-11-11T18:39:17.093Z" }, + { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122, upload-time = "2025-11-11T18:39:20.619Z" }, + { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645, upload-time = "2025-11-11T18:39:24.005Z" }, + { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837, upload-time = "2025-11-11T18:39:27.174Z" }, + { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843, upload-time = "2025-11-11T18:39:30.851Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959, upload-time = "2025-11-11T18:39:33.998Z" }, ] [[package]] @@ -3146,16 +3120,16 @@ dependencies = [ { name = "narwhals" }, { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624 } +sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624, upload-time = "2025-11-17T18:39:24.523Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174 }, + { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174, upload-time = "2025-11-17T18:39:20.351Z" }, ] [[package]] name = "pptree" version = "3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043 } +sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043, upload-time = "2020-04-15T18:28:53.362Z" } [[package]] name = "pre-commit" @@ -3168,18 +3142,18 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232 } +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437 }, + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, ] [[package]] name = "prometheus-client" version = "0.23.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481 } +sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481, upload-time = "2025-09-18T20:47:25.043Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145 }, + { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145, upload-time = "2025-09-18T20:47:23.875Z" }, ] [[package]] @@ -3189,33 +3163,33 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, ] [[package]] name = "propcache" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534 }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526 }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263 }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012 }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491 }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319 }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856 }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241 }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552 }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113 }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778 }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047 }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093 }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638 }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229 }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] [[package]] @@ -3225,81 +3199,81 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/01/89/9cbe2f4bba860e149108b683bc2efec21f14d5f7ed6e25562ad86acbc373/proto_plus-1.27.0.tar.gz", hash = "sha256:873af56dd0d7e91836aee871e5799e1c6f1bda86ac9a983e0bb9f0c266a568c4", size = 56158 } +sdist = { url = "https://files.pythonhosted.org/packages/01/89/9cbe2f4bba860e149108b683bc2efec21f14d5f7ed6e25562ad86acbc373/proto_plus-1.27.0.tar.gz", hash = "sha256:873af56dd0d7e91836aee871e5799e1c6f1bda86ac9a983e0bb9f0c266a568c4", size = 56158, upload-time = "2025-12-16T13:46:25.729Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/24/3b7a0818484df9c28172857af32c2397b6d8fcd99d9468bd4684f98ebf0a/proto_plus-1.27.0-py3-none-any.whl", hash = "sha256:1baa7f81cf0f8acb8bc1f6d085008ba4171eaf669629d1b6d1673b21ed1c0a82", size = 50205 }, + { url = "https://files.pythonhosted.org/packages/cd/24/3b7a0818484df9c28172857af32c2397b6d8fcd99d9468bd4684f98ebf0a/proto_plus-1.27.0-py3-none-any.whl", hash = "sha256:1baa7f81cf0f8acb8bc1f6d085008ba4171eaf669629d1b6d1673b21ed1c0a82", size = 50205, upload-time = "2025-12-16T13:46:24.76Z" }, ] [[package]] name = "protobuf" version = "6.33.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/34/44/e49ecff446afeec9d1a66d6bbf9adc21e3c7cea7803a920ca3773379d4f6/protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4", size = 444296 } +sdist = { url = "https://files.pythonhosted.org/packages/34/44/e49ecff446afeec9d1a66d6bbf9adc21e3c7cea7803a920ca3773379d4f6/protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4", size = 444296, upload-time = "2025-12-06T00:17:53.311Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/91/1e3a34881a88697a7354ffd177e8746e97a722e5e8db101544b47e84afb1/protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d", size = 425603 }, - { url = "https://files.pythonhosted.org/packages/64/20/4d50191997e917ae13ad0a235c8b42d8c1ab9c3e6fd455ca16d416944355/protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4", size = 436930 }, - { url = "https://files.pythonhosted.org/packages/b2/ca/7e485da88ba45c920fb3f50ae78de29ab925d9e54ef0de678306abfbb497/protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43", size = 427621 }, - { url = "https://files.pythonhosted.org/packages/7d/4f/f743761e41d3b2b2566748eb76bbff2b43e14d5fcab694f494a16458b05f/protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e", size = 324460 }, - { url = "https://files.pythonhosted.org/packages/b1/fa/26468d00a92824020f6f2090d827078c09c9c587e34cbfd2d0c7911221f8/protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872", size = 339168 }, - { url = "https://files.pythonhosted.org/packages/56/13/333b8f421738f149d4fe5e49553bc2a2ab75235486259f689b4b91f96cec/protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f", size = 323270 }, - { url = "https://files.pythonhosted.org/packages/0e/15/4f02896cc3df04fc465010a4c6a0cd89810f54617a32a70ef531ed75d61c/protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c", size = 170501 }, + { url = "https://files.pythonhosted.org/packages/bc/91/1e3a34881a88697a7354ffd177e8746e97a722e5e8db101544b47e84afb1/protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d", size = 425603, upload-time = "2025-12-06T00:17:41.114Z" }, + { url = "https://files.pythonhosted.org/packages/64/20/4d50191997e917ae13ad0a235c8b42d8c1ab9c3e6fd455ca16d416944355/protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4", size = 436930, upload-time = "2025-12-06T00:17:43.278Z" }, + { url = "https://files.pythonhosted.org/packages/b2/ca/7e485da88ba45c920fb3f50ae78de29ab925d9e54ef0de678306abfbb497/protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43", size = 427621, upload-time = "2025-12-06T00:17:44.445Z" }, + { url = "https://files.pythonhosted.org/packages/7d/4f/f743761e41d3b2b2566748eb76bbff2b43e14d5fcab694f494a16458b05f/protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e", size = 324460, upload-time = "2025-12-06T00:17:45.678Z" }, + { url = "https://files.pythonhosted.org/packages/b1/fa/26468d00a92824020f6f2090d827078c09c9c587e34cbfd2d0c7911221f8/protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872", size = 339168, upload-time = "2025-12-06T00:17:46.813Z" }, + { url = "https://files.pythonhosted.org/packages/56/13/333b8f421738f149d4fe5e49553bc2a2ab75235486259f689b4b91f96cec/protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f", size = 323270, upload-time = "2025-12-06T00:17:48.253Z" }, + { url = "https://files.pythonhosted.org/packages/0e/15/4f02896cc3df04fc465010a4c6a0cd89810f54617a32a70ef531ed75d61c/protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c", size = 170501, upload-time = "2025-12-06T00:17:52.211Z" }, ] [[package]] name = "psutil" version = "6.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } +sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565, upload-time = "2024-10-17T21:31:45.68Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, - { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, - { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, - { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, - { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, - { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, - { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762, upload-time = "2024-10-17T21:32:05.991Z" }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777, upload-time = "2024-10-17T21:32:07.872Z" }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259, upload-time = "2024-10-17T21:32:10.177Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255, upload-time = "2024-10-17T21:32:11.964Z" }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804, upload-time = "2024-10-17T21:32:13.785Z" }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386, upload-time = "2024-10-17T21:32:21.399Z" }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228, upload-time = "2024-10-17T21:32:23.88Z" }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] [[package]] name = "pyarrow" version = "22.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151 } +sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968 }, - { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085 }, - { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613 }, - { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059 }, - { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043 }, - { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505 }, - { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641 }, + { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, + { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085, upload-time = "2025-10-24T10:03:38.146Z" }, + { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613, upload-time = "2025-10-24T10:03:46.516Z" }, + { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059, upload-time = "2025-10-24T10:03:55.353Z" }, + { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043, upload-time = "2025-10-24T10:04:05.408Z" }, + { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505, upload-time = "2025-10-24T10:04:15.786Z" }, + { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641, upload-time = "2025-10-24T10:04:22.57Z" }, ] [[package]] name = "pyasn1" version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135 }, + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, ] [[package]] @@ -3309,18 +3283,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892 } +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259 }, + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, ] [[package]] name = "pycparser" version = "2.23" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140 }, + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, ] [[package]] @@ -3333,9 +3307,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591 } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580 }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, ] [package.optional-dependencies] @@ -3350,37 +3324,29 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298 }, - { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475 }, - { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815 }, - { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567 }, - { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442 }, - { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956 }, - { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253 }, - { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050 }, - { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178 }, - { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833 }, - { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156 }, - { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378 }, - { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622 }, - { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441 }, - { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291 }, - { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632 }, - { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905 }, - { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495 }, - { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388 }, - { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879 }, - { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017 }, - { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351 }, - { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363 }, - { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615 }, - { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369 }, - { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218 }, - { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951 }, - { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428 }, - { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009 }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, ] [[package]] @@ -3391,9 +3357,9 @@ dependencies = [ { name = "pydantic" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226 } +sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226, upload-time = "2025-12-31T16:18:27.944Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296 }, + { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296, upload-time = "2025-12-31T16:18:26.38Z" }, ] [[package]] @@ -3405,9 +3371,9 @@ dependencies = [ { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184 } +sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880 }, + { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] [[package]] @@ -3418,9 +3384,9 @@ dependencies = [ { name = "jinja2" }, { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240, upload-time = "2024-05-10T15:36:21.153Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403 }, + { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403, upload-time = "2024-05-10T15:36:17.36Z" }, ] [[package]] @@ -3430,33 +3396,33 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250 } +sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250, upload-time = "2025-03-17T18:53:15.955Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730 }, + { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730, upload-time = "2025-03-17T18:53:14.532Z" }, ] [[package]] name = "pygments" version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] [[package]] name = "pymupdf" version = "1.26.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/d6/09b28f027b510838559f7748807192149c419b30cb90e6d5f0cf916dc9dc/pymupdf-1.26.7.tar.gz", hash = "sha256:71add8bdc8eb1aaa207c69a13400693f06ad9b927bea976f5d5ab9df0bb489c3", size = 84327033 } +sdist = { url = "https://files.pythonhosted.org/packages/48/d6/09b28f027b510838559f7748807192149c419b30cb90e6d5f0cf916dc9dc/pymupdf-1.26.7.tar.gz", hash = "sha256:71add8bdc8eb1aaa207c69a13400693f06ad9b927bea976f5d5ab9df0bb489c3", size = 84327033, upload-time = "2025-12-11T21:48:50.694Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/35/cd74cea1787b2247702ef8522186bdef32e9cb30a099e6bb864627ef6045/pymupdf-1.26.7-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:07085718dfdae5ab83b05eb5eb397f863bcc538fe05135318a01ea353e7a1353", size = 23179369 }, - { url = "https://files.pythonhosted.org/packages/72/74/448b6172927c829c6a3fba80078d7b0a016ebbe2c9ee528821f5ea21677a/pymupdf-1.26.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:31aa9c8377ea1eea02934b92f4dcf79fb2abba0bf41f8a46d64c3e31546a3c02", size = 22470101 }, - { url = "https://files.pythonhosted.org/packages/65/e7/47af26f3ac76be7ac3dd4d6cc7ee105948a8355d774e5ca39857bf91c11c/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e419b609996434a14a80fa060adec72c434a1cca6a511ec54db9841bc5d51b3c", size = 23502486 }, - { url = "https://files.pythonhosted.org/packages/2a/6b/3de1714d734ff949be1e90a22375d0598d3540b22ae73eb85c2d7d1f36a9/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:69dfc78f206a96e5b3ac22741263ebab945fdf51f0dbe7c5757c3511b23d9d72", size = 24115727 }, - { url = "https://files.pythonhosted.org/packages/62/9b/f86224847949577a523be2207315ae0fd3155b5d909cd66c274d095349a3/pymupdf-1.26.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1d5106f46e1ca0d64d46bd51892372a4f82076bdc14a9678d33d630702abca36", size = 24324386 }, - { url = "https://files.pythonhosted.org/packages/85/8e/a117d39092ca645fde8b903f4a941d9aa75b370a67b4f1f435f56393dc5a/pymupdf-1.26.7-cp310-abi3-win32.whl", hash = "sha256:7c9645b6f5452629c747690190350213d3e5bbdb6b2eca227d82702b327f6eee", size = 17203888 }, - { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952 }, + { url = "https://files.pythonhosted.org/packages/94/35/cd74cea1787b2247702ef8522186bdef32e9cb30a099e6bb864627ef6045/pymupdf-1.26.7-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:07085718dfdae5ab83b05eb5eb397f863bcc538fe05135318a01ea353e7a1353", size = 23179369, upload-time = "2025-12-11T21:47:21.587Z" }, + { url = "https://files.pythonhosted.org/packages/72/74/448b6172927c829c6a3fba80078d7b0a016ebbe2c9ee528821f5ea21677a/pymupdf-1.26.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:31aa9c8377ea1eea02934b92f4dcf79fb2abba0bf41f8a46d64c3e31546a3c02", size = 22470101, upload-time = "2025-12-11T21:47:37.105Z" }, + { url = "https://files.pythonhosted.org/packages/65/e7/47af26f3ac76be7ac3dd4d6cc7ee105948a8355d774e5ca39857bf91c11c/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e419b609996434a14a80fa060adec72c434a1cca6a511ec54db9841bc5d51b3c", size = 23502486, upload-time = "2025-12-12T09:51:25.824Z" }, + { url = "https://files.pythonhosted.org/packages/2a/6b/3de1714d734ff949be1e90a22375d0598d3540b22ae73eb85c2d7d1f36a9/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:69dfc78f206a96e5b3ac22741263ebab945fdf51f0dbe7c5757c3511b23d9d72", size = 24115727, upload-time = "2025-12-11T21:47:51.274Z" }, + { url = "https://files.pythonhosted.org/packages/62/9b/f86224847949577a523be2207315ae0fd3155b5d909cd66c274d095349a3/pymupdf-1.26.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1d5106f46e1ca0d64d46bd51892372a4f82076bdc14a9678d33d630702abca36", size = 24324386, upload-time = "2025-12-12T14:58:45.483Z" }, + { url = "https://files.pythonhosted.org/packages/85/8e/a117d39092ca645fde8b903f4a941d9aa75b370a67b4f1f435f56393dc5a/pymupdf-1.26.7-cp310-abi3-win32.whl", hash = "sha256:7c9645b6f5452629c747690190350213d3e5bbdb6b2eca227d82702b327f6eee", size = 17203888, upload-time = "2025-12-12T13:59:57.613Z" }, + { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952, upload-time = "2025-12-11T21:48:02.947Z" }, ] [[package]] @@ -3467,56 +3433,56 @@ dependencies = [ { name = "pymupdf" }, { name = "tabulate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/ff/d2e856ff5db5fa57ebf13ae04de4da6c203f5fb17507c0dd21ffd0ae4a17/pymupdf4llm-0.2.8.tar.gz", hash = "sha256:c4f9815cff210cef45123e93ae3a6f802e0dc1d1ad4534a4a463c000aaec98fd", size = 66867 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/ff/d2e856ff5db5fa57ebf13ae04de4da6c203f5fb17507c0dd21ffd0ae4a17/pymupdf4llm-0.2.8.tar.gz", hash = "sha256:c4f9815cff210cef45123e93ae3a6f802e0dc1d1ad4534a4a463c000aaec98fd", size = 66867, upload-time = "2026-01-04T16:38:30.015Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/d5/47e14346b6f57cbc7456cc24ded697b4037b399ff56ed12afccbd202361d/pymupdf4llm-0.2.8-py3-none-any.whl", hash = "sha256:e60587d151223fc9e118661a9c7bb04b04ae928187c201a14d60ac8a42963591", size = 68637 }, + { url = "https://files.pythonhosted.org/packages/58/d5/47e14346b6f57cbc7456cc24ded697b4037b399ff56ed12afccbd202361d/pymupdf4llm-0.2.8-py3-none-any.whl", hash = "sha256:e60587d151223fc9e118661a9c7bb04b04ae928187c201a14d60ac8a42963591", size = 68637, upload-time = "2026-01-04T16:38:32.412Z" }, ] [[package]] name = "pypandoc" version = "1.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477, upload-time = "2025-11-13T16:30:29.608Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451 }, + { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451, upload-time = "2025-11-13T16:30:07.66Z" }, ] [[package]] name = "pyparsing" version = "3.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512 } +sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512, upload-time = "2025-12-23T03:14:04.391Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793 }, + { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793, upload-time = "2025-12-23T03:14:02.103Z" }, ] [[package]] name = "pypdfium2" version = "4.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239, upload-time = "2024-05-09T18:33:17.552Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254 }, - { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624 }, - { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126 }, - { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077 }, - { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431 }, - { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008 }, - { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543 }, - { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911 }, - { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430 }, - { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951 }, - { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098 }, - { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118 }, + { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254, upload-time = "2024-05-09T18:32:48.653Z" }, + { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624, upload-time = "2024-05-09T18:32:51.458Z" }, + { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126, upload-time = "2024-05-09T18:32:53.581Z" }, + { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077, upload-time = "2024-05-09T18:32:55.99Z" }, + { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431, upload-time = "2024-05-09T18:32:57.911Z" }, + { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008, upload-time = "2024-05-09T18:32:59.886Z" }, + { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543, upload-time = "2024-05-09T18:33:02.597Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911, upload-time = "2024-05-09T18:33:05.376Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430, upload-time = "2024-05-09T18:33:08.067Z" }, + { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951, upload-time = "2024-05-09T18:33:10.567Z" }, + { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098, upload-time = "2024-05-09T18:33:13.107Z" }, + { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118, upload-time = "2024-05-09T18:33:15.489Z" }, ] [[package]] name = "pysocks" version = "1.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 }, + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, ] [[package]] @@ -3526,9 +3492,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] [[package]] @@ -3539,36 +3505,36 @@ dependencies = [ { name = "lxml" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987 }, + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, ] [[package]] name = "python-dotenv" version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] [[package]] name = "python-json-logger" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683 } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548 }, + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, ] [[package]] name = "python-multipart" version = "0.0.21" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196 } +sdist = { url = "https://files.pythonhosted.org/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196, upload-time = "2025-12-17T09:24:22.446Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541 }, + { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" }, ] [[package]] @@ -3587,9 +3553,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889 } +sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889, upload-time = "2022-11-25T19:33:07.958Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949 }, + { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949, upload-time = "2022-11-25T19:33:06.093Z" }, ] [[package]] @@ -3600,18 +3566,18 @@ dependencies = [ { name = "numpy" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086 } +sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086, upload-time = "2021-01-09T17:35:49.131Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564 }, + { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564, upload-time = "2021-01-09T17:35:47.543Z" }, ] [[package]] name = "pytz" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] [[package]] @@ -3619,35 +3585,35 @@ name = "pywin32" version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432 }, - { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103 }, - { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557 }, + { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, + { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, ] [[package]] name = "pywinpty" version = "3.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669, upload-time = "2025-10-03T21:16:29.205Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330 }, + { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330, upload-time = "2025-10-03T21:20:15.656Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, ] [[package]] @@ -3657,52 +3623,52 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850 }, - { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380 }, - { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421 }, - { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149 }, - { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070 }, - { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441 }, - { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529 }, - { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276 }, - { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208 }, - { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766 }, - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, - { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266 }, - { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206 }, - { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747 }, - { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371 }, - { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862 }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, ] [[package]] name = "rapidfuzz" version = "3.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900 } +sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900, upload-time = "2025-11-01T11:54:52.321Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376 }, - { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903 }, - { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655 }, - { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708 }, - { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106 }, - { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048 }, - { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020 }, - { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958 }, - { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043 }, - { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273 }, - { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875 }, + { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376, upload-time = "2025-11-01T11:52:29.175Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903, upload-time = "2025-11-01T11:52:31.239Z" }, + { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655, upload-time = "2025-11-01T11:52:32.852Z" }, + { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708, upload-time = "2025-11-01T11:52:34.618Z" }, + { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106, upload-time = "2025-11-01T11:52:36.069Z" }, + { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048, upload-time = "2025-11-01T11:52:37.936Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020, upload-time = "2025-11-01T11:52:39.657Z" }, + { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958, upload-time = "2025-11-01T11:52:41.017Z" }, + { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043, upload-time = "2025-11-01T11:52:42.465Z" }, + { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273, upload-time = "2025-11-01T11:52:44.005Z" }, + { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875, upload-time = "2025-11-01T11:52:45.405Z" }, ] [[package]] @@ -3714,33 +3680,33 @@ dependencies = [ { name = "rpds-py" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036 } +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766 }, + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, ] [[package]] name = "regex" version = "2024.11.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674 }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684 }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589 }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511 }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149 }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707 }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702 }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976 }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397 }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726 }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098 }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325 }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277 }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197 }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714 }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042 }, + { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, + { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, + { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, + { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, + { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, + { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, + { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, + { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, + { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, + { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, + { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, + { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, + { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, + { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, + { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, + { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, ] [[package]] @@ -3753,9 +3719,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [package.optional-dependencies] @@ -3770,18 +3736,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513 } +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490 }, + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, ] [[package]] name = "rfc3986-validator" version = "0.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760 } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, ] [[package]] @@ -3791,9 +3757,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046 }, + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, ] [[package]] @@ -3804,9 +3770,9 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990 } +sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393 }, + { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, ] [[package]] @@ -3818,65 +3784,65 @@ dependencies = [ { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/09/3f9b8d9daaf235195c626f21e03604c05b987404ee3bcacee0c1f67f2a8e/rich_toolkit-0.17.1.tar.gz", hash = "sha256:5af54df8d1dd9c8530e462e1bdcaed625c9b49f5a55b035aa0ba1c17bdb87c9a", size = 187925 } +sdist = { url = "https://files.pythonhosted.org/packages/97/09/3f9b8d9daaf235195c626f21e03604c05b987404ee3bcacee0c1f67f2a8e/rich_toolkit-0.17.1.tar.gz", hash = "sha256:5af54df8d1dd9c8530e462e1bdcaed625c9b49f5a55b035aa0ba1c17bdb87c9a", size = 187925, upload-time = "2025-12-17T10:49:22.583Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/7b/15e55fa8a76d0d41bf34d965af78acdaf80a315907adb30de8b63c272694/rich_toolkit-0.17.1-py3-none-any.whl", hash = "sha256:96d24bb921ecd225ffce7c526a9149e74006410c05e6d405bd74ffd54d5631ed", size = 31412 }, + { url = "https://files.pythonhosted.org/packages/7f/7b/15e55fa8a76d0d41bf34d965af78acdaf80a315907adb30de8b63c272694/rich_toolkit-0.17.1-py3-none-any.whl", hash = "sha256:96d24bb921ecd225ffce7c526a9149e74006410c05e6d405bd74ffd54d5631ed", size = 31412, upload-time = "2025-12-17T10:49:21.793Z" }, ] [[package]] name = "rignore" version = "0.7.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999 }, - { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824 }, - { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121 }, - { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813 }, - { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019 }, - { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822 }, - { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820 }, - { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050 }, - { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164 }, - { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028 }, - { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024 }, - { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531 }, - { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817 }, - { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001 }, - { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462 }, - { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918 }, - { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922 }, - { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987 }, - { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110 }, - { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339 }, - { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680 }, - { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045 }, - { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310 }, - { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998 }, - { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178 }, - { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190 }, +sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999, upload-time = "2025-11-05T20:42:38.373Z" }, + { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824, upload-time = "2025-11-05T20:42:22.1Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121, upload-time = "2025-11-05T20:40:48.94Z" }, + { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813, upload-time = "2025-11-05T20:41:04.71Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019, upload-time = "2025-11-05T20:41:20.723Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822, upload-time = "2025-11-05T20:41:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820, upload-time = "2025-11-05T20:42:06.364Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050, upload-time = "2025-11-05T20:41:51.124Z" }, + { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164, upload-time = "2025-11-05T21:40:10.368Z" }, + { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028, upload-time = "2025-11-05T21:40:27.977Z" }, + { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024, upload-time = "2025-11-05T21:40:45.148Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531, upload-time = "2025-11-05T21:41:02.734Z" }, + { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817, upload-time = "2025-11-05T21:41:47.51Z" }, + { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001, upload-time = "2025-11-05T21:41:32.778Z" }, + { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462, upload-time = "2025-11-05T20:42:50.804Z" }, + { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918, upload-time = "2025-11-05T20:42:33.689Z" }, + { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922, upload-time = "2025-11-05T20:41:00.361Z" }, + { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987, upload-time = "2025-11-05T20:41:16.219Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110, upload-time = "2025-11-05T20:41:32.631Z" }, + { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339, upload-time = "2025-11-05T20:41:47.128Z" }, + { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680, upload-time = "2025-11-05T20:42:18.061Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045, upload-time = "2025-11-05T20:42:02.315Z" }, + { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310, upload-time = "2025-11-05T21:40:23.184Z" }, + { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998, upload-time = "2025-11-05T21:40:40.603Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178, upload-time = "2025-11-05T21:40:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190, upload-time = "2025-11-05T21:41:16.403Z" }, ] [[package]] name = "rpds-py" version = "0.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469 } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490 }, - { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751 }, - { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696 }, - { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136 }, - { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699 }, - { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022 }, - { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522 }, - { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579 }, - { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305 }, - { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503 }, - { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322 }, - { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792 }, - { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901 }, - { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823 }, + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, ] [[package]] @@ -3886,9 +3852,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pyasn1" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034 } +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696 }, + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, ] [[package]] @@ -3898,35 +3864,35 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827 } +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830 }, + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, ] [[package]] name = "safetensors" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781 }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058 }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748 }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881 }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463 }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855 }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152 }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856 }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060 }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715 }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377 }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368 }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423 }, - { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380 }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430 }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977 }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890 }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885 }, +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, + { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, + { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, ] [[package]] @@ -3939,13 +3905,13 @@ dependencies = [ { name = "scipy" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136 } +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221 }, - { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834 }, - { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938 }, - { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818 }, - { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969 }, + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, ] [[package]] @@ -3955,16 +3921,16 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870, upload-time = "2024-06-24T20:35:18.532Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226 }, - { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893 }, - { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258 }, - { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715 }, - { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038 }, - { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959 }, - { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514 }, - { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252 }, + { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226, upload-time = "2024-06-24T20:31:50.451Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893, upload-time = "2024-06-24T20:31:57.337Z" }, + { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258, upload-time = "2024-06-24T20:32:02.711Z" }, + { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715, upload-time = "2024-06-24T20:32:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038, upload-time = "2024-06-24T20:32:17.305Z" }, + { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959, upload-time = "2024-06-24T20:32:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514, upload-time = "2024-06-24T20:32:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252, upload-time = "2024-06-24T20:32:45.06Z" }, ] [[package]] @@ -3976,9 +3942,9 @@ dependencies = [ { name = "numpy" }, { name = "pandas" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 }, + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, ] [[package]] @@ -3988,18 +3954,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244 } +sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244, upload-time = "2021-12-15T21:56:14.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332 }, + { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332, upload-time = "2021-12-15T21:56:12.508Z" }, ] [[package]] name = "send2trash" version = "2.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/62/6e/421803dec0c0dfbf5a27e66491ebe6643a461e4f90422f00ea4c68ae24aa/send2trash-2.0.0.tar.gz", hash = "sha256:1761421da3f9930bfe51ed7c45343948573383ad4c27e3acebc91be324e7770d", size = 17206 } +sdist = { url = "https://files.pythonhosted.org/packages/62/6e/421803dec0c0dfbf5a27e66491ebe6643a461e4f90422f00ea4c68ae24aa/send2trash-2.0.0.tar.gz", hash = "sha256:1761421da3f9930bfe51ed7c45343948573383ad4c27e3acebc91be324e7770d", size = 17206, upload-time = "2025-12-31T04:12:48.664Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/5a/f2f2e5eda25579f754acd83399c522ee03d6acbe001dfe53c8a1ec928b44/send2trash-2.0.0-py3-none-any.whl", hash = "sha256:e70d5ce41dbb890882cc78bc25d137478330b39a391e756fadf82e34da4d85b8", size = 17642 }, + { url = "https://files.pythonhosted.org/packages/1b/5a/f2f2e5eda25579f754acd83399c522ee03d6acbe001dfe53c8a1ec928b44/send2trash-2.0.0-py3-none-any.whl", hash = "sha256:e70d5ce41dbb890882cc78bc25d137478330b39a391e756fadf82e34da4d85b8", size = 17642, upload-time = "2025-12-31T04:12:45.336Z" }, ] [[package]] @@ -4015,25 +3981,25 @@ dependencies = [ { name = "transformers" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/a1/64e7b111e753307ffb7c5b6d039c52d4a91a47fa32a7f5bc377a49b22402/sentence_transformers-5.2.0.tar.gz", hash = "sha256:acaeb38717de689f3dab45d5e5a02ebe2f75960a4764ea35fea65f58a4d3019f", size = 381004 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/a1/64e7b111e753307ffb7c5b6d039c52d4a91a47fa32a7f5bc377a49b22402/sentence_transformers-5.2.0.tar.gz", hash = "sha256:acaeb38717de689f3dab45d5e5a02ebe2f75960a4764ea35fea65f58a4d3019f", size = 381004, upload-time = "2025-12-11T14:12:31.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/d0/3b2897ef6a0c0c801e9fecca26bcc77081648e38e8c772885ebdd8d7d252/sentence_transformers-5.2.0-py3-none-any.whl", hash = "sha256:aa57180f053687d29b08206766ae7db549be5074f61849def7b17bf0b8025ca2", size = 493748 }, + { url = "https://files.pythonhosted.org/packages/40/d0/3b2897ef6a0c0c801e9fecca26bcc77081648e38e8c772885ebdd8d7d252/sentence_transformers-5.2.0-py3-none-any.whl", hash = "sha256:aa57180f053687d29b08206766ae7db549be5074f61849def7b17bf0b8025ca2", size = 493748, upload-time = "2025-12-11T14:12:29.516Z" }, ] [[package]] name = "sentencepiece" version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106, upload-time = "2024-02-19T17:06:47.428Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979 }, - { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845 }, - { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472 }, - { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151 }, - { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931 }, - { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537 }, - { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747 }, - { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525 }, + { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979, upload-time = "2024-02-19T17:05:34.651Z" }, + { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845, upload-time = "2024-02-19T17:05:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472, upload-time = "2024-02-19T17:05:39.775Z" }, + { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151, upload-time = "2024-02-19T17:05:42.594Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931, upload-time = "2024-02-19T17:05:44.695Z" }, + { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537, upload-time = "2024-02-19T17:05:46.713Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747, upload-time = "2024-02-19T17:05:48.705Z" }, + { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525, upload-time = "2024-02-19T17:05:55.145Z" }, ] [[package]] @@ -4044,72 +4010,72 @@ dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/f0/0e9dc590513d5e742d7799e2038df3a05167cba084c6ca4f3cdd75b55164/sentry_sdk-2.48.0.tar.gz", hash = "sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473", size = 384828 } +sdist = { url = "https://files.pythonhosted.org/packages/40/f0/0e9dc590513d5e742d7799e2038df3a05167cba084c6ca4f3cdd75b55164/sentry_sdk-2.48.0.tar.gz", hash = "sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473", size = 384828, upload-time = "2025-12-16T14:55:41.722Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/19/8d77f9992e5cbfcaa9133c3bf63b4fbbb051248802e1e803fed5c552fbb2/sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172", size = 414555 }, + { url = "https://files.pythonhosted.org/packages/4d/19/8d77f9992e5cbfcaa9133c3bf63b4fbbb051248802e1e803fed5c552fbb2/sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172", size = 414555, upload-time = "2025-12-16T14:55:40.152Z" }, ] [[package]] name = "setuptools" version = "80.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958 } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486 }, + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, ] [[package]] name = "shellingham" version = "1.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "smmap" version = "5.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329 } +sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303 }, + { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, ] [[package]] name = "sniffio" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] [[package]] name = "sortedcontainers" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, ] [[package]] name = "soupsieve" version = "2.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856 } +sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710 }, + { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, ] [[package]] @@ -4120,23 +4086,23 @@ dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/f9/5e4491e5ccf42f5d9cfc663741d261b3e6e1683ae7812114e7636409fcc6/sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", size = 9869912 } +sdist = { url = "https://files.pythonhosted.org/packages/be/f9/5e4491e5ccf42f5d9cfc663741d261b3e6e1683ae7812114e7636409fcc6/sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", size = 9869912, upload-time = "2025-12-09T21:05:16.737Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/70/75b1387d72e2847220441166c5eb4e9846dd753895208c13e6d66523b2d9/sqlalchemy-2.0.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c64772786d9eee72d4d3784c28f0a636af5b0a29f3fe26ff11f55efe90c0bd85", size = 2154148 }, - { url = "https://files.pythonhosted.org/packages/d8/a4/7805e02323c49cb9d1ae5cd4913b28c97103079765f520043f914fca4cb3/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ae64ebf7657395824a19bca98ab10eb9a3ecb026bf09524014f1bb81cb598d4", size = 3233051 }, - { url = "https://files.pythonhosted.org/packages/d7/ec/32ae09139f61bef3de3142e85c47abdee8db9a55af2bb438da54a4549263/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f02325709d1b1a1489f23a39b318e175a171497374149eae74d612634b234c0", size = 3232781 }, - { url = "https://files.pythonhosted.org/packages/ad/bd/bf7b869b6f5585eac34222e1cf4405f4ba8c3b85dd6b1af5d4ce8bca695f/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2c3684fca8a05f0ac1d9a21c1f4a266983a7ea9180efb80ffeb03861ecd01a0", size = 3182096 }, - { url = "https://files.pythonhosted.org/packages/21/6a/c219720a241bb8f35c88815ccc27761f5af7fdef04b987b0e8a2c1a6dcaa/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040f6f0545b3b7da6b9317fc3e922c9a98fc7243b2a1b39f78390fc0942f7826", size = 3205109 }, - { url = "https://files.pythonhosted.org/packages/bd/c4/6ccf31b2bc925d5d95fab403ffd50d20d7c82b858cf1a4855664ca054dce/sqlalchemy-2.0.45-cp310-cp310-win32.whl", hash = "sha256:830d434d609fe7bfa47c425c445a8b37929f140a7a44cdaf77f6d34df3a7296a", size = 2114240 }, - { url = "https://files.pythonhosted.org/packages/de/29/a27a31fca07316def418db6f7c70ab14010506616a2decef1906050a0587/sqlalchemy-2.0.45-cp310-cp310-win_amd64.whl", hash = "sha256:0209d9753671b0da74da2cfbb9ecf9c02f72a759e4b018b3ab35f244c91842c7", size = 2137615 }, - { url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672 }, + { url = "https://files.pythonhosted.org/packages/fe/70/75b1387d72e2847220441166c5eb4e9846dd753895208c13e6d66523b2d9/sqlalchemy-2.0.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c64772786d9eee72d4d3784c28f0a636af5b0a29f3fe26ff11f55efe90c0bd85", size = 2154148, upload-time = "2025-12-10T20:03:21.023Z" }, + { url = "https://files.pythonhosted.org/packages/d8/a4/7805e02323c49cb9d1ae5cd4913b28c97103079765f520043f914fca4cb3/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ae64ebf7657395824a19bca98ab10eb9a3ecb026bf09524014f1bb81cb598d4", size = 3233051, upload-time = "2025-12-09T22:06:04.768Z" }, + { url = "https://files.pythonhosted.org/packages/d7/ec/32ae09139f61bef3de3142e85c47abdee8db9a55af2bb438da54a4549263/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f02325709d1b1a1489f23a39b318e175a171497374149eae74d612634b234c0", size = 3232781, upload-time = "2025-12-09T22:09:54.435Z" }, + { url = "https://files.pythonhosted.org/packages/ad/bd/bf7b869b6f5585eac34222e1cf4405f4ba8c3b85dd6b1af5d4ce8bca695f/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2c3684fca8a05f0ac1d9a21c1f4a266983a7ea9180efb80ffeb03861ecd01a0", size = 3182096, upload-time = "2025-12-09T22:06:06.169Z" }, + { url = "https://files.pythonhosted.org/packages/21/6a/c219720a241bb8f35c88815ccc27761f5af7fdef04b987b0e8a2c1a6dcaa/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040f6f0545b3b7da6b9317fc3e922c9a98fc7243b2a1b39f78390fc0942f7826", size = 3205109, upload-time = "2025-12-09T22:09:55.969Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c4/6ccf31b2bc925d5d95fab403ffd50d20d7c82b858cf1a4855664ca054dce/sqlalchemy-2.0.45-cp310-cp310-win32.whl", hash = "sha256:830d434d609fe7bfa47c425c445a8b37929f140a7a44cdaf77f6d34df3a7296a", size = 2114240, upload-time = "2025-12-09T21:29:54.007Z" }, + { url = "https://files.pythonhosted.org/packages/de/29/a27a31fca07316def418db6f7c70ab14010506616a2decef1906050a0587/sqlalchemy-2.0.45-cp310-cp310-win_amd64.whl", hash = "sha256:0209d9753671b0da74da2cfbb9ecf9c02f72a759e4b018b3ab35f244c91842c7", size = 2137615, upload-time = "2025-12-09T21:29:55.85Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672, upload-time = "2025-12-09T21:54:52.608Z" }, ] [[package]] name = "sqlitedict" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846 } +sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846, upload-time = "2022-12-03T13:39:13.102Z" } [[package]] name = "sqlmodel" @@ -4146,18 +4112,18 @@ dependencies = [ { name = "pydantic" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392, upload-time = "2024-08-31T09:43:24.088Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, + { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276, upload-time = "2024-08-31T09:43:22.358Z" }, ] [[package]] name = "sqlparse" version = "0.5.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815 } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138 }, + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, ] [[package]] @@ -4169,9 +4135,9 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] [[package]] @@ -4182,9 +4148,9 @@ dependencies = [ { name = "anyio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985 } +sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033 }, + { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, ] [[package]] @@ -4209,11 +4175,11 @@ dependencies = [ { name = "toml" }, { name = "tornado" }, { name = "typing-extensions" }, - { name = "watchdog", marker = "platform_system != 'Darwin'" }, + { name = "watchdog", marker = "sys_platform != 'darwin'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/20/434aaceccc6e1912671d869926103051330437adba72d538d787a07727ef/streamlit-1.52.2.tar.gz", hash = "sha256:64a4dda8bc5cdd37bfd490e93bb53da35aaef946fcfc283a7980dacdf165108b", size = 8584178 } +sdist = { url = "https://files.pythonhosted.org/packages/43/20/434aaceccc6e1912671d869926103051330437adba72d538d787a07727ef/streamlit-1.52.2.tar.gz", hash = "sha256:64a4dda8bc5cdd37bfd490e93bb53da35aaef946fcfc283a7980dacdf165108b", size = 8584178, upload-time = "2025-12-17T17:07:59.642Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/95/6b7873f0267973ebd55ba9cd33a690b35a116f2779901ef6185a0e21864d/streamlit-1.52.2-py3-none-any.whl", hash = "sha256:a16bb4fbc9781e173ce9dfbd8ffb189c174f148f9ca4fb8fa56423e84e193fc8", size = 9025937 }, + { url = "https://files.pythonhosted.org/packages/c0/95/6b7873f0267973ebd55ba9cd33a690b35a116f2779901ef6185a0e21864d/streamlit-1.52.2-py3-none-any.whl", hash = "sha256:a16bb4fbc9781e173ce9dfbd8ffb189c174f148f9ca4fb8fa56423e84e193fc8", size = 9025937, upload-time = "2025-12-17T17:07:57.67Z" }, ] [[package]] @@ -4235,9 +4201,9 @@ dependencies = [ { name = "torch" }, { name = "transformers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481 } +sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481, upload-time = "2025-09-23T21:41:37.027Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395 }, + { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395, upload-time = "2025-09-23T21:41:35.369Z" }, ] [[package]] @@ -4247,27 +4213,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, ] [[package]] name = "tabulate" version = "0.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090 } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, ] [[package]] name = "tenacity" version = "9.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036 } +sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248 }, + { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, ] [[package]] @@ -4279,18 +4245,18 @@ dependencies = [ { name = "packaging" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2b/c5/d4cc6e293fb837aaf9f76dd7745476aeba8ef7ef5146c3b3f9ee375fe7a5/tensorboardx-2.6.4.tar.gz", hash = "sha256:b163ccb7798b31100b9f5fa4d6bc22dad362d7065c2f24b51e50731adde86828", size = 4769801 } +sdist = { url = "https://files.pythonhosted.org/packages/2b/c5/d4cc6e293fb837aaf9f76dd7745476aeba8ef7ef5146c3b3f9ee375fe7a5/tensorboardx-2.6.4.tar.gz", hash = "sha256:b163ccb7798b31100b9f5fa4d6bc22dad362d7065c2f24b51e50731adde86828", size = 4769801, upload-time = "2025-06-10T22:37:07.419Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl", hash = "sha256:5970cf3a1f0a6a6e8b180ccf46f3fe832b8a25a70b86e5a237048a7c0beb18e2", size = 87201 }, + { url = "https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl", hash = "sha256:5970cf3a1f0a6a6e8b180ccf46f3fe832b8a25a70b86e5a237048a7c0beb18e2", size = 87201, upload-time = "2025-06-10T22:37:05.44Z" }, ] [[package]] name = "termcolor" version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434 } +sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734 }, + { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, ] [[package]] @@ -4299,21 +4265,21 @@ version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'linux') or (os_name == 'nt' and platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux') or (os_name == 'nt' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, ] [[package]] name = "threadpoolctl" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274 } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638 }, + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, ] [[package]] @@ -4324,15 +4290,15 @@ dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991 }, - { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798 }, - { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865 }, - { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856 }, - { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308 }, - { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697 }, - { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375 }, + { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991, upload-time = "2025-10-06T20:21:34.098Z" }, + { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798, upload-time = "2025-10-06T20:21:35.579Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865, upload-time = "2025-10-06T20:21:36.675Z" }, + { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856, upload-time = "2025-10-06T20:21:37.873Z" }, + { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308, upload-time = "2025-10-06T20:21:39.577Z" }, + { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697, upload-time = "2025-10-06T20:21:41.154Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375, upload-time = "2025-10-06T20:21:43.201Z" }, ] [[package]] @@ -4342,9 +4308,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, ] [[package]] @@ -4354,45 +4320,45 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275 }, - { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472 }, - { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736 }, - { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835 }, - { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673 }, - { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818 }, - { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195 }, - { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982 }, - { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245 }, - { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069 }, - { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263 }, - { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429 }, - { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363 }, - { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786 }, - { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133 }, - { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301 }, - { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308 }, - { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964 }, - { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542 }, +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, + { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301, upload-time = "2026-01-05T10:40:34.858Z" }, + { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308, upload-time = "2026-01-05T10:40:40.737Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964, upload-time = "2026-01-05T10:40:46.56Z" }, + { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" }, ] [[package]] name = "toml" version = "0.10.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253 } +sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588 }, + { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, ] [[package]] name = "tomli" version = "2.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392 } +sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408 }, + { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, ] [[package]] @@ -4404,30 +4370,30 @@ dependencies = [ { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux' and sys_platform != 'darwin'" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681 }, - { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036 }, - { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861 }, - { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222 }, + { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681, upload-time = "2025-11-12T15:19:56.48Z" }, + { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036, upload-time = "2025-11-12T15:21:01.886Z" }, + { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861, upload-time = "2025-11-12T15:21:30.145Z" }, + { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222, upload-time = "2025-11-12T15:20:46.223Z" }, ] [[package]] @@ -4439,28 +4405,28 @@ dependencies = [ { name = "packaging" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144, upload-time = "2023-03-10T22:02:20.455Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162 }, + { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162, upload-time = "2023-03-10T22:02:18.818Z" }, ] [[package]] name = "tornado" version = "6.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632 } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909 }, - { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163 }, - { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746 }, - { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083 }, - { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315 }, - { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003 }, - { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412 }, - { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392 }, - { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481 }, - { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886 }, - { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910 }, + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, ] [[package]] @@ -4468,20 +4434,20 @@ name = "tqdm" version = "4.67.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Windows' and sys_platform == 'linux') or (platform_system == 'Windows' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 } +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540 }, + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, ] [[package]] @@ -4492,9 +4458,9 @@ dependencies = [ { name = "torch" }, { name = "transformers", extra = ["sentencepiece", "torch"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754 } +sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754, upload-time = "2025-06-15T13:34:38.522Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073 }, + { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073, upload-time = "2025-06-15T13:34:37.468Z" }, ] [[package]] @@ -4513,9 +4479,9 @@ dependencies = [ { name = "tokenizers" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680 } +sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680, upload-time = "2025-11-25T15:51:30.139Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463 }, + { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463, upload-time = "2025-11-25T15:51:26.493Z" }, ] [package.optional-dependencies] @@ -4533,8 +4499,7 @@ name = "triton" version = "3.5.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/2e/f95e673222afa2c7f0c687d8913e98fcf2589ef0b1405de76894e37fe18f/triton-3.5.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f63e34dcb32d7bd3a1d0195f60f30d2aee8b08a69a0424189b71017e23dfc3d2", size = 159821655 }, - { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692 }, + { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692, upload-time = "2025-11-11T17:40:46.074Z" }, ] [[package]] @@ -4547,18 +4512,18 @@ dependencies = [ { name = "shellingham" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371 } +sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371, upload-time = "2026-01-06T11:21:10.989Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381 }, + { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, ] [[package]] name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] @@ -4568,45 +4533,45 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] name = "tzdata" version = "2025.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521 }, + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, ] [[package]] name = "unidecode" version = "1.3.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701 } +sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701, upload-time = "2024-01-11T11:58:35.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494 }, + { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494, upload-time = "2024-01-11T11:58:33.012Z" }, ] [[package]] name = "uri-template" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678 } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140 }, + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, ] [[package]] name = "urllib3" version = "2.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930 } +sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182 }, + { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" }, ] [[package]] @@ -4618,14 +4583,14 @@ dependencies = [ { name = "h11" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502 }, + { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, ] [package.optional-dependencies] standard = [ - { name = "colorama", marker = "(platform_machine != 'aarch64' and platform_system == 'Linux' and sys_platform == 'win32') or (platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'win32')" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "httptools" }, { name = "python-dotenv" }, { name = "pyyaml" }, @@ -4638,14 +4603,14 @@ standard = [ name = "uvloop" version = "0.22.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250 } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335 }, - { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903 }, - { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499 }, - { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133 }, - { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681 }, - { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261 }, + { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335, upload-time = "2025-10-16T22:16:11.43Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903, upload-time = "2025-10-16T22:16:12.979Z" }, + { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499, upload-time = "2025-10-16T22:16:14.451Z" }, + { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133, upload-time = "2025-10-16T22:16:16.272Z" }, + { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681, upload-time = "2025-10-16T22:16:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261, upload-time = "2025-10-16T22:16:19.596Z" }, ] [[package]] @@ -4658,36 +4623,36 @@ dependencies = [ { name = "platformdirs" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799 } +sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095 }, + { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, ] [[package]] name = "waitress" version = "3.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bf/cb/04ddb054f45faa306a230769e868c28b8065ea196891f09004ebace5b184/waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", size = 179901 } +sdist = { url = "https://files.pythonhosted.org/packages/bf/cb/04ddb054f45faa306a230769e868c28b8065ea196891f09004ebace5b184/waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", size = 179901, upload-time = "2024-11-16T20:02:35.195Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/57/a27182528c90ef38d82b636a11f606b0cbb0e17588ed205435f8affe3368/waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", size = 56232 }, + { url = "https://files.pythonhosted.org/packages/8d/57/a27182528c90ef38d82b636a11f606b0cbb0e17588ed205435f8affe3368/waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", size = 56232, upload-time = "2024-11-16T20:02:33.858Z" }, ] [[package]] name = "watchdog" version = "6.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220 } +sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079 }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076 }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077 }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078 }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065 }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070 }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067 }, + { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, + { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, + { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, + { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, + { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, + { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, + { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, ] [[package]] @@ -4697,86 +4662,86 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318 }, - { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478 }, - { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894 }, - { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065 }, - { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377 }, - { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837 }, - { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456 }, - { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614 }, - { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690 }, - { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459 }, - { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663 }, - { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453 }, - { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611 }, - { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889 }, - { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616 }, - { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413 }, + { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318, upload-time = "2025-10-14T15:04:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478, upload-time = "2025-10-14T15:04:20.297Z" }, + { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894, upload-time = "2025-10-14T15:04:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065, upload-time = "2025-10-14T15:04:22.795Z" }, + { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377, upload-time = "2025-10-14T15:04:24.138Z" }, + { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837, upload-time = "2025-10-14T15:04:25.057Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456, upload-time = "2025-10-14T15:04:26.497Z" }, + { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614, upload-time = "2025-10-14T15:04:27.539Z" }, + { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690, upload-time = "2025-10-14T15:04:28.495Z" }, + { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459, upload-time = "2025-10-14T15:04:29.491Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663, upload-time = "2025-10-14T15:04:30.435Z" }, + { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453, upload-time = "2025-10-14T15:04:31.53Z" }, + { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, + { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413, upload-time = "2025-10-14T15:06:09.209Z" }, ] [[package]] name = "wcwidth" version = "0.2.14" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293 } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286 }, + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, ] [[package]] name = "webcolors" version = "25.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491 } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, ] [[package]] name = "websocket-client" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, ] [[package]] name = "websockets" version = "15.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423 }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080 }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329 }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312 }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319 }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631 }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016 }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426 }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360 }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388 }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830 }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109 }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343 }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599 }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207 }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155 }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884 }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743 }, +sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, + { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, + { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, + { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, + { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, + { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, + { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, + { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, + { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, + { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, + { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, + { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] [[package]] @@ -4786,18 +4751,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687 } +sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687, upload-time = "2025-11-29T02:15:22.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960 }, + { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960, upload-time = "2025-11-29T02:15:21.13Z" }, ] [[package]] name = "widgetsnbextension" version = "4.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503 }, + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, ] [[package]] @@ -4807,59 +4772,59 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581480705f912040172f6570cc12e68a245ba9258c32ef/wikipedia_api-0.8.1.tar.gz", hash = "sha256:b31e93b3f5407c1a1ba413ed7326a05379a3c270df6cf6a211aca67a14c5658b", size = 19934 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581480705f912040172f6570cc12e68a245ba9258c32ef/wikipedia_api-0.8.1.tar.gz", hash = "sha256:b31e93b3f5407c1a1ba413ed7326a05379a3c270df6cf6a211aca67a14c5658b", size = 19934, upload-time = "2025-01-19T23:44:33.488Z" } [[package]] name = "wrapt" version = "2.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040 } +sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481 }, - { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692 }, - { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574 }, - { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688 }, - { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698 }, - { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096 }, - { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878 }, - { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298 }, - { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361 }, - { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035 }, - { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383 }, - { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894 }, - { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046 }, + { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481, upload-time = "2025-11-07T00:43:11.103Z" }, + { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692, upload-time = "2025-11-07T00:43:13.697Z" }, + { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574, upload-time = "2025-11-07T00:43:14.967Z" }, + { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688, upload-time = "2025-11-07T00:43:18.275Z" }, + { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698, upload-time = "2025-11-07T00:43:19.407Z" }, + { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096, upload-time = "2025-11-07T00:43:16.5Z" }, + { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878, upload-time = "2025-11-07T00:43:20.81Z" }, + { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298, upload-time = "2025-11-07T00:43:22.229Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361, upload-time = "2025-11-07T00:43:24.301Z" }, + { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035, upload-time = "2025-11-07T00:43:28.96Z" }, + { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383, upload-time = "2025-11-07T00:43:25.804Z" }, + { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894, upload-time = "2025-11-07T00:43:27.074Z" }, + { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, ] [[package]] name = "xmltodict" version = "0.14.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942 } +sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942, upload-time = "2024-10-16T06:10:29.683Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981 }, + { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981, upload-time = "2024-10-16T06:10:27.649Z" }, ] [[package]] name = "xxhash" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160 } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845 }, - { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807 }, - { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786 }, - { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830 }, - { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606 }, - { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872 }, - { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217 }, - { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139 }, - { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669 }, - { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018 }, - { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058 }, - { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628 }, - { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577 }, - { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487 }, - { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863 }, + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, ] [[package]] @@ -4871,32 +4836,32 @@ dependencies = [ { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169 } +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517 }, - { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495 }, - { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400 }, - { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545 }, - { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598 }, - { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893 }, - { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240 }, - { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965 }, - { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026 }, - { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637 }, - { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082 }, - { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811 }, - { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223 }, - { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118 }, - { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852 }, - { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012 }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] [[package]] name = "zipp" version = "3.23.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547 } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276 }, + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, ] From bdec740dc306f51fef7a639eefe8d7f1fc35cc75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Fri, 13 Feb 2026 19:03:31 -0300 Subject: [PATCH 034/104] Feature/anonymize document refactor (#73) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add render policy support and refactor anonymization logic for improved token rendering * 📝Update anonymization docs * ♻️ Refactor: modularize document anonymization * 📝 Rename notebook for document anonymization with render policy * FECHA disambiguation bug fixed, label and render policies changed and whole code reviewed for PR --- .../routers/anonymizer/anonymizer.py | 161 +++- aymurai/meta/api_interfaces.py | 11 +- aymurai/settings.py | 14 +- aymurai/text/anonymization.py | 766 ------------------ aymurai/text/anonymization/__init__.py | 7 + aymurai/text/anonymization/alignment.py | 396 +++++++++ aymurai/text/anonymization/doc_anonymizer.py | 88 ++ aymurai/text/anonymization/watermarks.py | 197 +++++ aymurai/text/anonymization/xml_docx.py | 172 ++++ aymurai/transforms/datetime_formatter/core.py | 2 +- docs/anonymization/README.md | 61 +- .../08-disambiguation-endpoint-smoke.ipynb | 2 - .../10-anonymize-document-render-policy.ipynb | 266 ++++++ 13 files changed, 1357 insertions(+), 786 deletions(-) delete mode 100644 aymurai/text/anonymization.py create mode 100644 aymurai/text/anonymization/__init__.py create mode 100644 aymurai/text/anonymization/alignment.py create mode 100644 aymurai/text/anonymization/doc_anonymizer.py create mode 100644 aymurai/text/anonymization/watermarks.py create mode 100644 aymurai/text/anonymization/xml_docx.py create mode 100644 notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index ec2b481e..9d963ab1 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -28,10 +28,11 @@ DocumentInformation, LabelPolicy, PromptLibrary, + RenderPolicy, TextRequest, ) from aymurai.settings import settings -from aymurai.text.anonymization import DocAnonymizer +from aymurai.text.anonymization import DocAnonymizer, replace_labels_in_text from aymurai.text.extraction import MIMETYPE_EXTENSION_MAPPER from aymurai.utils.entity_disambiguation import ( build_canonical_entities, @@ -105,6 +106,10 @@ def _merge_label_policies( current.disambiguation = incoming.disambiguation if incoming.anonymize is not None: current.anonymize = incoming.anonymize + if incoming.use_subclass_when_available is not None: + current.use_subclass_when_available = ( + incoming.use_subclass_when_available + ) policies[label] = current if request_policies: @@ -115,11 +120,131 @@ def _merge_label_policies( current.disambiguation = incoming.disambiguation if incoming.anonymize is not None: current.anonymize = incoming.anonymize + if incoming.use_subclass_when_available is not None: + current.use_subclass_when_available = ( + incoming.use_subclass_when_available + ) policies[label] = current return policies +def _merge_render_policy( + request_policy: RenderPolicy | None, +) -> RenderPolicy: + """ + Merges render policies from settings and request, with request policy taking precedence. + + Args: + request_policy (RenderPolicy | None): Render policy from request. + + Returns: + RenderPolicy: Effective render policy. + """ + policy = RenderPolicy( + suffix_mode="auto", + suffix_threshold=1, + ) + + def apply(incoming: RenderPolicy) -> None: + nonlocal policy + if incoming.suffix_mode is not None: + policy.suffix_mode = incoming.suffix_mode + if incoming.suffix_threshold is not None: + policy.suffix_threshold = incoming.suffix_threshold + + if settings.RENDER_POLICY: + apply(RenderPolicy.model_validate(settings.RENDER_POLICY)) + + if request_policy: + apply(RenderPolicy.model_validate(request_policy)) + + return policy + + +def _resolve_token_base( + label: DocLabel, + label_policy: LabelPolicy, +) -> str: + """ + Resolves the base token label for rendering. + + Args: + label (DocLabel): Label to render. + label_policy (LabelPolicy): Label policy rules. + + Returns: + str: Base token label (e.g., PER, DENUNCIANTE). + """ + attrs = label.attrs + if attrs is None: + return label.text + + subclass = None + if attrs.aymurai_label_subclass: + subclass = attrs.aymurai_label_subclass[0] + + if label_policy.use_subclass_when_available and subclass: + return subclass.upper() + + return attrs.aymurai_label + + +def _build_render_context( + annotations: list[DocumentInformation], + render_policy: RenderPolicy, + label_policies: dict[str, LabelPolicy], +) -> dict: + """ + Builds render context with per-entity indices and counts. + + Args: + annotations (list[DocumentInformation]): Document annotations. + render_policy (RenderPolicy): Render policy rules. + label_policies (dict[str, LabelPolicy]): Per-label policies. + + Returns: + dict: Render context with policy, indices, and counts. + """ + occurrences: list[tuple[int, int, str, str]] = [] + + for p_idx, paragraph in enumerate(annotations): + for label in paragraph.labels or []: + label_policy = label_policies.get( + label.attrs.aymurai_label + if label.attrs and label.attrs.aymurai_label + else None, + LabelPolicy(), + ) + base = _resolve_token_base(label, label_policy) + entity_id = ( + str(label.attrs.canonical_entity_id) + if label.attrs and label.attrs.canonical_entity_id + else label.text + ) + occurrences.append((p_idx, label.start_char, base, entity_id)) + + occurrences.sort(key=lambda item: (item[0], item[1])) + + index_by_entity: dict[tuple[str, str], int] = {} + next_index_by_base: dict[str, int] = {} + + for _, _, base, entity_id in occurrences: + key = (base, entity_id) + if key not in index_by_entity: + next_index_by_base[base] = next_index_by_base.get(base, 0) + 1 + index_by_entity[key] = next_index_by_base[base] + + count_by_base = {base: count for base, count in next_index_by_base.items()} + + return { + "render_policy": render_policy, + "label_policies": label_policies, + "index_by_entity": index_by_entity, + "count_by_base": count_by_base, + } + + def _should_anonymize_label( label: DocLabel, label_policies: dict[str, LabelPolicy], @@ -137,7 +262,11 @@ def _should_anonymize_label( if label.attrs and label.attrs.aymurai_anonymize is not None: return bool(label.attrs.aymurai_anonymize) - policy = label_policies.get(label.attrs.aymurai_label) if label.attrs else None + policy = ( + label_policies.get(str(label.attrs.aymurai_label).strip().upper()) + if label.attrs and label.attrs.aymurai_label + else None + ) if policy is None: return True @@ -265,7 +394,7 @@ async def anonymizer_disambiguate( ) labels = [label for paragraph in paragraphs for label in (paragraph.labels or [])] - effective_policies = _merge_label_policies(label_policies) + effective_label_policies = _merge_label_policies(label_policies) logger.info("disambiguation labels: %d", len(labels)) prompt_library = load_prompts_from_yaml() @@ -273,7 +402,10 @@ async def anonymizer_disambiguate( all_detected_labels = { label.attrs.aymurai_label for label in labels - if label.attrs and label.attrs.aymurai_label + if label.attrs + and label.attrs.aymurai_label + and effective_label_policies.get(label.attrs.aymurai_label) + and effective_label_policies.get(label.attrs.aymurai_label).anonymize } default_llm_labels = ( @@ -284,7 +416,7 @@ async def anonymizer_disambiguate( fuzzy_labels: set[str] = set() for label in all_detected_labels: - policy = effective_policies.get(label) + policy = effective_label_policies.get(label) if policy and policy.disambiguation == "llm": llm_labels.append(label) fuzzy_labels.add(label) @@ -407,7 +539,7 @@ async def anonymizer_disambiguate( label.attrs.aymurai_label, "fuzzy" ) - policy = effective_policies.get(label.attrs.aymurai_label) + policy = effective_label_policies.get(label.attrs.aymurai_label) label.attrs.aymurai_anonymize = ( policy.anonymize if policy and policy.anonymize is not None else True ) @@ -427,7 +559,7 @@ async def anonymizer_disambiguate( return DocumentAnnotations( data=predictions, - label_policies=effective_policies if effective_policies else None, + label_policies=effective_label_policies if effective_label_policies else None, ) @@ -503,7 +635,8 @@ async def anonymizer_compile_document( annots_json = json.loads(annotations) annots = DocumentAnnotations.model_validate(annots_json) logger.info(f"processing annotations => {annots}") - effective_policies = _merge_label_policies(annots.label_policies) + effective_label_policies = _merge_label_policies(annots.label_policies) + effective_render_policy = _merge_render_policy(annots.render_policy) # Add paragraphs to the database # validation MUST be at least an empty list, to remember user feedback @@ -534,7 +667,7 @@ async def anonymizer_compile_document( filtered_labels = [ label for label in (paragraph.labels or []) - if _should_anonymize_label(label, effective_policies) + if _should_anonymize_label(label, effective_label_policies) ] filtered_annotations.append( DocumentInformation( @@ -543,8 +676,13 @@ async def anonymizer_compile_document( ) ) + render_context = _build_render_context( + filtered_annotations, effective_render_policy, effective_label_policies + ) + if suffix == ".docx": item = {"path": tmp_filename} + doc_anonymizer.render_context = render_context doc_anonymizer( item, [ @@ -558,7 +696,10 @@ async def anonymizer_compile_document( else: # Export as raw document anonymized_doc = [ - doc_anonymizer.replace_labels_in_text(document_information.model_dump()) + replace_labels_in_text( + document_information.model_dump(), + render_context=render_context, + ) .replace("<", "<") .replace(">", ">") for document_information in filtered_annotations diff --git a/aymurai/meta/api_interfaces.py b/aymurai/meta/api_interfaces.py index 9fd601ce..1caa6509 100644 --- a/aymurai/meta/api_interfaces.py +++ b/aymurai/meta/api_interfaces.py @@ -48,8 +48,16 @@ class DocumentInformation(BaseModel): class LabelPolicy(BaseModel): """Per-label policy for disambiguation and anonymization.""" - disambiguation: Literal["none", "fuzzy", "llm"] | None = None anonymize: bool | None = None + disambiguation: Literal["none", "fuzzy", "llm"] | None = None + use_subclass_when_available: bool | None = None + + +class RenderPolicy(BaseModel): + """Render policy for anonymized tokens.""" + + suffix_mode: Literal["auto", "always", "never"] | None = None + suffix_threshold: int | None = None class DocumentAnnotations(BaseModel): @@ -57,6 +65,7 @@ class DocumentAnnotations(BaseModel): data: list[DocumentInformation] label_policies: dict[str, LabelPolicy] | None = None + render_policy: RenderPolicy | None = None class DataPublicDocumentAnnotations(RootModel): diff --git a/aymurai/settings.py b/aymurai/settings.py index cfaee728..85fe08e4 100644 --- a/aymurai/settings.py +++ b/aymurai/settings.py @@ -3,8 +3,8 @@ from pathlib import Path from dotenv import load_dotenv +from pydantic import ConfigDict, FilePath, field_validator from pydantic_settings import BaseSettings -from pydantic import FilePath, ConfigDict, field_validator import aymurai @@ -88,6 +88,18 @@ def parse_label_policies(cls, v): return json.loads(v) return v + # Render policy (JSON dict) + RENDER_POLICY: dict | None = None + + @field_validator("RENDER_POLICY", mode="before") + @classmethod + def parse_render_policy(cls, v): + if v is None or v == "": + return None + if isinstance(v, str): + return json.loads(v) + return v + load_env() settings = Settings() diff --git a/aymurai/text/anonymization.py b/aymurai/text/anonymization.py deleted file mode 100644 index fe6fb14f..00000000 --- a/aymurai/text/anonymization.py +++ /dev/null @@ -1,766 +0,0 @@ -import os -import re -import tempfile -import xml.sax.saxutils -import zipfile -from copy import deepcopy -from glob import glob -from unicodedata import normalize - -import numpy as np -import pandas as pd -from docx import Document -from docx.enum.text import WD_ALIGN_PARAGRAPH -from docx.opc.constants import RELATIONSHIP_TYPE -from docx.oxml.shared import OxmlElement, qn -from docx.shared import Inches, Pt, RGBColor -from jiwer import cer -from joblib import hash -from lxml import etree -from more_itertools import flatten - -from aymurai.logger import get_logger -from aymurai.meta.pipeline_interfaces import Transform -from aymurai.models.flair.utils import FlairTextNormalize -from aymurai.utils.alignment.core import align_text, tokenize -from aymurai.utils.cache import cache_load, cache_save, get_cache_key - -logger = get_logger(__file__) - - -REGEX_PARAGRAPH = r"((?.*?)(\/w:p\b)" -REGEX_FRAGMENT = r"(?(?P.*?)(<.*?\/w:t)" - - -class DocAnonymizer(Transform): - """ - Anonymize document by replacing sensitive data with label tokens - """ - - def __init__(self, use_cache: bool = False, **kwargs): - self.use_cache = use_cache - self.kwargs = kwargs - - def unzip_document(self, doc_path: str, output_dir: str) -> None: - """ - Unzips the document file to the specified output directory. - - Args: - doc_path (str): The path to the document file. - output_dir (str): The directory where the contents of the document - file will be extracted. - """ - # Ensure the output directory exists - os.makedirs(output_dir, exist_ok=True) - - # Open the doc file as a zip file - with zipfile.ZipFile(doc_path, "r") as doc_zip: - # Extract all the contents to the output directory - doc_zip.extractall(output_dir) - logger.info(f"unzipped {doc_path} to {output_dir}") - - def index_paragraphs(self, file: str) -> list[dict]: - """ - Indexes the paragraphs of an XML file. - - Args: - file (str): The path to the XML file to be indexed. - - Returns: - list[dict]: A list of dictionaries representing the indexed paragraphs. - """ - # Read the XML file - with open(file) as f: - xml = f.read() - - paragraphs = [] - paragraph_index = 0 - - # Find all paragraphs in the XML file - for match in re.finditer(REGEX_PARAGRAPH, xml): - paragraph = match.group("paragraph") - paragraph_start = match.start("paragraph") - paragraph_end = match.end("paragraph") - fragments = [] - fragment_index = 0 - - # Find all text fragments in the paragraph - for fragment in re.finditer(REGEX_FRAGMENT, paragraph): - text = fragment.group("text") - start = fragment.start("text") - end = fragment.end("text") - - fragment_dict = { - "text": text, - "normalized_text": FlairTextNormalize.normalize_text(text), - "start": start, - "end": end, - "fragment_index": fragment_index, - "paragraph_index": paragraph_index, - } - fragments.append(fragment_dict) - fragment_index += 1 - - # Join all fragments as plain text - plain_text = "".join( - [fragment["normalized_text"] for fragment in fragments] - ) - - paragraphs.append( - { - "plain_text": plain_text, - "metadata": { - "start": paragraph_start, - "end": paragraph_end, - "fragments": fragments, - "xml_file": os.path.basename(file), - }, - } - ) - paragraph_index += 1 - - return paragraphs - - def match_paragraphs_with_predictions( - self, - paragraphs: list[dict], - predictions: list[dict], - ) -> list[dict]: - """ - Matches each paragraph with its corresponding predictions. - - Args: - paragraphs (list[dict]): A list of dictionaries representing the paragraphs. - predictions (list[dict]): A list of dictionaries representing - the predictions. - - Returns: - list[dict]: A list of dictionaries representing - the matched paragraphs with predictions. - """ - - paragraphs = deepcopy(paragraphs) - - # Hash prediction documents - pred_hashes = [hash(prediction["document"]) for prediction in predictions] - idx2hash = {i: _hash for i, _hash in enumerate(pred_hashes)} - - # Hash paragraphs - paragraphs = [ - paragraph - | {"hash": hash(normalize("NFKC", paragraph["plain_text"].strip()))} - for paragraph in paragraphs - ] - - # Assign prediction indices to each paragraph by hash - hash2idx = { - paragraph["hash"]: np.where(np.array(pred_hashes) == paragraph["hash"])[ - 0 - ].tolist() - for paragraph in paragraphs - } - - paragraphs = [ - paragraph | {"pred_indices": hash2idx[paragraph["hash"]]} - for paragraph in paragraphs - ] - - # Identify missing indices - missing_indices = list( - set(idx2hash.keys()) - set(flatten(list(hash2idx.values()))) - ) - - if missing_indices: - # Assign prediction indices to each paragraph by lowest CER - target_texts = np.array( - [prediction["document"] for prediction in predictions] - )[missing_indices] - - missing_paragraphs = [ - paragraph for paragraph in paragraphs if not paragraph["pred_indices"] - ] - - for missing_paragraph in missing_paragraphs: - source_text = missing_paragraph["plain_text"] - min_cer_idx = np.argmin( - [cer(source_text, target_text) for target_text in target_texts] - ) - missing_paragraph["pred_indices"] = [missing_indices[min_cer_idx]] - - # Assign document text and labels - paragraphs = [ - paragraph - | { - "document": predictions[paragraph["pred_indices"][0]]["document"], - "labels": predictions[paragraph["pred_indices"][0]]["labels"], - } - for paragraph in paragraphs - ] - - return paragraphs - - def unify_consecutive_labels( - self, sample: dict, text_key: str = "document" - ) -> list[dict]: - """ - Unifies consecutive labels in a sample. - - Args: - sample (dict): A dictionary representing the sample. - text_key (str, optional): The key for the text in the sample dictionary. - Defaults to "document". - - Returns: - list[dict]: A list of dictionaries representing the unified labels. - """ - sample = deepcopy(sample) - - # Extract labels and document text - labels = sample["labels"] - document = sample[text_key] - - # Reorder labels based on start indices - labels = sorted(labels, key=lambda x: x["start_char"]) - - unified_labels = [] - current_group = None - - # Iterate over labels - for label in labels: - # Get attributes - text = label["attrs"]["aymurai_alt_text"] or label["text"] - start_char = label["attrs"]["aymurai_alt_start_char"] or label["start_char"] - end_char = label["attrs"]["aymurai_alt_end_char"] or label["end_char"] - aymurai_label = label["attrs"]["aymurai_label"] - - if current_group is None: - # Start a new group with the current label - current_group = { - "text": text, - "start_char": start_char, - "end_char": end_char, - "aymurai_label": aymurai_label, - } - elif ( - current_group["aymurai_label"] == aymurai_label - and (start_char - current_group["end_char"]) <= 1 - ): - # Extend the current group with the current label - current_group["end_char"] = end_char - else: - # Finish the current group and start a new one - current_group["text"] = document[ - current_group["start_char"] : current_group["end_char"] + 1 - ] - unified_labels.append(current_group) - current_group = { - "text": text, - "start_char": start_char, - "end_char": end_char, - "aymurai_label": aymurai_label, - } - - # Finish the last group - if current_group is not None: - current_group["text"] = document[ - current_group["start_char"] : current_group["end_char"] + 1 - ] - unified_labels.append(current_group) - - return unified_labels - - def replace_labels_in_text(self, pred: dict, text_key: str = "document") -> str: - """ - Replaces labels in the text with anonymized tokens. - - Args: - pred (dict): A dictionary representing the prediction. - text_key (str, optional): The key for the text in the prediction dictionary. - Defaults to "document". - - Returns: - str: The text with replaced labels. - """ - pred = deepcopy(pred) - doc = pred[text_key] - - # Unify consecutive labels - unified_labels = self.unify_consecutive_labels(pred, text_key) - - # Initialize the offset - offset = 0 - - # Replace labels in the text - for unified_label in unified_labels: - # Adjust start and end character indices of the label - start_char = unified_label["start_char"] + offset - end_char = unified_label["end_char"] + offset - len_text_to_replace = end_char - start_char - - # Replace the text with the anonymized token - aymurai_label = f" <{unified_label['aymurai_label']}>" - len_aymurai_label = len(aymurai_label) - - doc = doc[:start_char] + aymurai_label + doc[end_char:] - - # Update the offset - offset += len_aymurai_label - len_text_to_replace - - return re.sub(r" +", " ", doc).strip() - - def erase_duplicates_justseen(self, series: pd.Series) -> pd.Series: - """ - Erases duplicates that were just seen between two consecutive rows. - - Args: - series (pd.Series): The pandas Series to be processed. - - Returns: - pd.Series: The processed pandas Series. - """ - return pd.Series( - [ - ( - "" - if (i > 0 and series.iloc[i] == series.iloc[i - 1]) - else series.iloc[i] - ) - for i in range(len(series)) - ] - ) - - def parse_token_indices(self, sample: dict) -> pd.DataFrame: - """ - Parses the token indices from a sample. - - Args: - sample (dict): A dictionary representing the sample. - - Returns: - pd.DataFrame: A pandas DataFrame representing the parsed token indices. - """ - original_text = " ".join( - [fragment["text"] for fragment in sample["metadata"]["fragments"]] - ) - anonymized_text = self.replace_labels_in_text(sample) - - aligned = align_text( - " " + original_text + " ", - " " + anonymized_text + " ", - ) - aligned["target"] = self.erase_duplicates_justseen(aligned["target"]) - - xml_file = sample["metadata"]["xml_file"] - - tokens = [] - for i, fragment in enumerate(sample["metadata"]["fragments"]): - text = fragment["text"] - tokenized_text = tokenize(text) - paragraph_index = fragment["paragraph_index"] - - # Use re.finditer to locate each instance of tokens in the text - token_matches = list( - re.finditer(r"\S+", text) - ) # \S+ matches any non-whitespace sequence - - # Loop over tokenized text and token_matches in parallel - for j, (token, match) in enumerate(zip(tokenized_text, token_matches)): - start = sample["metadata"]["start"] + fragment["start"] + match.start() - end = start + len(token) - - tokens.append((xml_file, paragraph_index, i, j, token, start, end)) - - tokens = pd.DataFrame( - tokens, - columns=[ - "xml_file", - "paragraph_index", - "fragment_index", - "token_index", - "token", - "start_char", - "end_char", - ], - ) - - tokens = pd.concat( - [tokens, aligned["target"].iloc[1:-1].reset_index(drop=True)], axis=1 - ) - - tokens["target"] = tokens["target"].fillna("") - - return tokens - - def normalize_document(self, xml_content: str) -> str: - """ - Normalizes the XML document by removing extra spaces, preserving line breaks, - and removing hyperlinks while preserving text content. - - Args: - xml_content (str): The XML content to be normalized. - - Returns: - str: The normalized XML content. - """ - # Parse the XML content - parser = etree.XMLParser(ns_clean=True) - root = etree.fromstring(xml_content.encode("utf-8"), parser) - - # Extract namespaces - namespaces = {k: v for k, v in root.nsmap.items() if k} - - # Remove hyperlinks but preserve the text content - for hyperlink in root.xpath("//w:hyperlink", namespaces=namespaces): - parent = hyperlink.getparent() - index = list(parent).index(hyperlink) - - # Move all text-containing children (e.g., w:r elements) outside the hyperlink tag - for child in hyperlink: - parent.insert(index, child) - index += 1 - parent.remove(hyperlink) # Remove the element itself - - # Process each paragraph - for wp in root.xpath("//w:p", namespaces=namespaces): - first = True - - # Find all w:r elements containing w:t elements - for wr in wp.xpath(".//w:r", namespaces=namespaces): - wt = wr.find(".//w:t", namespaces) - if wt is not None and wt.text: - # Normalize spaces within the text, preserving new line breaks - wt.text = re.sub(r"[^\S\r\n]+", " ", wt.text) - - # Add a leading space if not the first fragment in the paragraph - if not first: - wt.text = " " + wt.text.lstrip() - else: - wt.text = wt.text.lstrip() - first = False - - # Remove trailing spaces from all fragments - wt.text = wt.text.rstrip() - - # Set the xml:space attribute to preserve - wt.set( - "{http://www.w3.org/XML/1998/namespace}space", - "preserve", - ) - - # Check if the text is empty after normalization - if not wt.text or wt.text.strip() == "": - # Remove the w:r element from its parent - wr.getparent().remove(wr) - - # Write back the XML content to a string - xml_str = etree.tostring(root, encoding="unicode", pretty_print=True) - - return xml_str - - def replace_text_in_xml(self, paragraphs: list[dict], base_dir: str) -> None: - """ - Replaces text in XML files based on the provided paragraphs - and saves the modified files. - - Args: - paragraphs (list[dict]): A list of dictionaries representing - the paragraphs to be replaced. - base_dir (str): The base directory where the XML files are located. - """ - tokens = pd.concat( - [self.parse_token_indices(sample) for sample in paragraphs], - ignore_index=True, - ) - - fragments = ( - tokens.groupby(["xml_file", "paragraph_index", "fragment_index"]) - .agg({"target": " ".join, "start_char": "min", "end_char": "max"}) - .reset_index() - ) - - for xml_file, group in fragments.groupby("xml_file"): - group = group.sort_values("end_char", ascending=False) - - with open(f"{base_dir}/word/{xml_file}", "r+") as file: - content = file.read() - - for _, r in group.iterrows(): - start_char = r["start_char"] - end_char = r["end_char"] - - target = r["target"] - target = re.sub(r"[^\S\r\n]+", " ", target) - - # Escape XML special characters - target = xml.sax.saxutils.escape(target) - - content = content[:start_char] + target + content[end_char:] - - # MUST be at the end to dont screw up the indexes - content = self.normalize_document(content) - - file.seek(0) - file.write(content) - file.truncate() - - def add_files_to_zip(self, zip_file: zipfile.ZipFile, directory: str) -> None: - """ - Adds all files in the specified directory to a zip file. - - Args: - zip_file (zipfile.ZipFile): The zip file to add the files to. - directory (str): The directory containing the files to be added. - """ - for root, _, files in os.walk(directory): - for file in files: - file_path = os.path.join(root, file) - zip_file.write(file_path, os.path.relpath(file_path, directory)) - - def add_hyperlink( - self, - paragraph, - text, - url, - font_name="Archivo", - size=10, - color=RGBColor(115, 190, 250), - italic=False, - bold=True, - underline=True, - ) -> None: - """ - Adds a formatted hyperlink to a given paragraph in a Word document. - - Notes: - - This method directly manipulates the underlying XML of the paragraph to insert a hyperlink, - as python-docx does not natively support hyperlinks. - - The hyperlink will be appended to the end of the given paragraph. - - Formatting options (font, size, color, italic, bold, underline) are applied to the hyperlink text. - - Args: - paragraph: The python-docx paragraph object to which the hyperlink will be added. - text (str): The display text for the hyperlink. - url (str): The URL that the hyperlink points to. - font_name (str, optional): The font name to use for the hyperlink text. Defaults to "Archivo". - size (int, optional): The font size (in points) for the hyperlink text. Defaults to 10. - color (RGBColor, optional): The font color as an RGBColor tuple. Defaults to RGBColor(115, 190, 250). - italic (bool, optional): Whether the hyperlink text should be italicized. Defaults to False. - bold (bool, optional): Whether the hyperlink text should be bold. Defaults to True. - underline (bool, optional): Whether the hyperlink text should be underlined. Defaults to True. - - Raises: - ValueError: If the paragraph is not a valid python-docx paragraph object. - """ # noqa: E501 - # Create the hyperlink relationship - part = paragraph.part - r_id = part.relate_to(url, RELATIONSHIP_TYPE.HYPERLINK, is_external=True) - - # Create the hyperlink element - hyperlink = OxmlElement("w:hyperlink") - hyperlink.set(qn("r:id"), r_id) - - # Create a new run - new_run = OxmlElement("w:r") - - # Set run properties (formatting) - rPr = OxmlElement("w:rPr") - - # Set font - if font_name: - font = OxmlElement("w:rFonts") - font.set(qn("w:ascii"), font_name) - font.set(qn("w:hAnsi"), font_name) - rPr.append(font) - - # Set color - if color: - c = OxmlElement("w:color") - c.set(qn("w:val"), f"{color[0]:02x}{color[1]:02x}{color[2]:02x}") - rPr.append(c) - - # Set italic - if italic: - i = OxmlElement("w:i") - rPr.append(i) - - # Set bold - if bold: - b = OxmlElement("w:b") - rPr.append(b) - - # Set underline - added for links - if underline: - u = OxmlElement("w:u") - u.set(qn("w:val"), "single") # single underline - rPr.append(u) - - # Set size - sz = OxmlElement("w:sz") - sz.set(qn("w:val"), str(size * 2)) # Word uses half-points - rPr.append(sz) - - # Add properties to run - new_run.append(rPr) - - # Set text - t = OxmlElement("w:t") - t.text = text - new_run.append(t) - - # Add run to hyperlink - hyperlink.append(new_run) - - # Add hyperlink to paragraph - paragraph._p.append(hyperlink) - - def _add_watermark_to_footer( - self, - footer, - alignment, - font_name="Archivo", - hyperlink_text="AymurAI", - hyperlink_url="https://www.aymurai.info/", - watermark_text="Documento anonimizado por AymurAI", - ) -> None: - """ - Adds a watermark text to the footer of a document. - - Args: - footer: The footer object to which the watermark will be added. - alignment: The alignment setting for the paragraph (e.g., left, center, right). - font_name (str, optional): The font name to use for the watermark text. Defaults to "Archivo". - hyperlink_text (str, optional): The text to be hyperlinked. Defaults to "AymurAI". - hyperlink_url (str, optional): The URL to link "AymurAI" to. Defaults to "https://www.aymurai.info/". - watermark_text (str): The text to be used as the watermark. Defaults to "Documento anonimizado por AymurAI". - """ # noqa: E501 - paragraph = footer.add_paragraph() - paragraph.alignment = alignment - - if hyperlink_url and hyperlink_text in watermark_text: - parts = watermark_text.split(hyperlink_text, 1) - before_text = parts[0] - after_text = parts[1] if len(parts) > 1 else "" - - # Add text before the hyperlink - if before_text: - run = paragraph.add_run(before_text) - run.font.name = "Archivo" - run.font.color.rgb = RGBColor(192, 192, 192) - run.font.size = Pt(10) - - # Add hyperlink - self.add_hyperlink(paragraph, hyperlink_text, hyperlink_url) - - # Add text after the hyperlink - if after_text: - run = paragraph.add_run(after_text) - run.font.name = font_name - run.font.color.rgb = RGBColor(192, 192, 192) - run.font.size = Pt(10) - - else: - # Just add the full text without a hyperlink - run = paragraph.add_run(watermark_text) - run.font.name = font_name - run.font.color.rgb = RGBColor(192, 192, 192) - run.font.size = Pt(10) - - def add_footer_watermark(self, doc_path) -> None: - """ - Adds a watermark to the footer of each section in a Word document. - - Args: - doc_path: Path to the document - """ - document = Document(doc_path) - processed_footers = set() - - for section in document.sections: - section.footer_distance = Inches(0.1) - - # List of (footer_obj, alignment) tuples - footers = [(section.footer, WD_ALIGN_PARAGRAPH.RIGHT)] # Odd/default - if section.even_page_footer is not None: - footers.append((section.even_page_footer, WD_ALIGN_PARAGRAPH.LEFT)) - if section.different_first_page_header_footer: - footers.append((section.first_page_footer, WD_ALIGN_PARAGRAPH.RIGHT)) - - for footer, alignment in footers: - if id(footer) not in processed_footers: - self._add_watermark_to_footer(footer, alignment) - processed_footers.add(id(footer)) - - document.save(doc_path) - - def create_docx(self, xml_directory, output_file) -> None: - """ - Creates a new DOCX file by adding XML components from the specified directory. - - Args: - xml_directory (str): The directory containing the XML components. - output_file (str): The path to the output DOCX file. - """ - # Create a new zip file - with zipfile.ZipFile(output_file, "w") as docx: - # Add XML components - self.add_files_to_zip(docx, xml_directory) - - def __call__(self, item: dict, preds: list[dict], output_dir: str = ".") -> None: - """ - Performs the anonymization process on a document. - - Args: - item (dict): The document item to be anonymized. - preds (list[dict]): The list of predictions for the document. - output_dir (str, optional): The directory to save the anonymized document. - Defaults to ".". - - Raises: - ValueError: If the document has an extension other than `.docx`. - """ - item_path = item["path"] - - if not os.path.splitext(item_path)[-1] == ".docx": - raise ValueError("Only `.docx` extension is allowed.") - - if not item.get("data"): - item["data"] = {} - - cache_key = get_cache_key(item_path, self.__name__) - if self.use_cache and (cache_data := cache_load(key=cache_key)): - paragraphs = cache_data - else: - # Unzip document into a temporary directory - with tempfile.TemporaryDirectory() as tempdir: - self.unzip_document(item_path, tempdir) - - # Parse XML files - xml_files = glob(f"{tempdir}/**/*.xml", recursive=True) - paragraphs = (self.index_paragraphs(file) for file in xml_files) - paragraphs = list(flatten(paragraphs)) - - # Filter out empty paragraphs - paragraphs = [ - paragraph - for paragraph in paragraphs - if paragraph["plain_text"].strip() - ] - - # Matching - paragraphs = self.match_paragraphs_with_predictions(paragraphs, preds) - - # Edit XML filess - self.replace_text_in_xml(paragraphs, tempdir) - - # Recreate anonymized document - os.makedirs(output_dir, exist_ok=True) - self.create_docx( - tempdir, - f"{output_dir}/{os.path.basename(item_path)}", - ) - - # Add watermark to the footer - self.add_footer_watermark(f"{output_dir}/{os.path.basename(item_path)}") - - if self.use_cache: - cache_save(paragraphs, key=cache_key) diff --git a/aymurai/text/anonymization/__init__.py b/aymurai/text/anonymization/__init__.py new file mode 100644 index 00000000..7f839a95 --- /dev/null +++ b/aymurai/text/anonymization/__init__.py @@ -0,0 +1,7 @@ +from aymurai.text.anonymization.alignment import replace_labels_in_text +from aymurai.text.anonymization.doc_anonymizer import DocAnonymizer + +__all__ = [ + "DocAnonymizer", + "replace_labels_in_text", +] diff --git a/aymurai/text/anonymization/alignment.py b/aymurai/text/anonymization/alignment.py new file mode 100644 index 00000000..3a6386b3 --- /dev/null +++ b/aymurai/text/anonymization/alignment.py @@ -0,0 +1,396 @@ +import os +import re +from copy import deepcopy +from unicodedata import normalize + +import numpy as np +import pandas as pd +from jiwer import cer +from joblib import hash +from more_itertools import flatten + +from aymurai.models.flair.utils import FlairTextNormalize +from aymurai.utils.alignment.core import align_text, tokenize +from aymurai.meta.api_interfaces import LabelPolicy + +REGEX_PARAGRAPH = r"((?.*?)(\/w:p\b)" +REGEX_FRAGMENT = r"(?(?P.*?)(<.*?\/w:t)" + + +def resolve_render_token(label: dict, render_context: dict | None = None) -> str: + """ + Resolves the render token for a label using the current render context. + + Args: + label (dict): Label dictionary with attrs. + + Returns: + str: Render token to insert in the document. + """ + if not render_context: + return label["attrs"]["aymurai_label"] + + render_policy = render_context["render_policy"] + label_policies = render_context["label_policies"] + count_by_base = render_context["count_by_base"] + index_by_entity = render_context["index_by_entity"] + + attrs = label.get("attrs") or {} + base = attrs.get("aymurai_label") + + label_policy = label_policies.get(base.upper(), LabelPolicy()) + + subclasses = attrs.get("aymurai_label_subclass") or [] + if label_policy.use_subclass_when_available and subclasses: + base = subclasses[0].upper() + + if not base: + base = label.get("label") or label.get("text") or "ENT" + + entity_id = attrs.get("canonical_entity_id") or label.get("text") + key = (base, str(entity_id)) + index = index_by_entity.get(key) + + if render_policy.suffix_mode == "never" or index is None: + return base + + if render_policy.suffix_mode == "auto": + if count_by_base.get(base, 0) <= render_policy.suffix_threshold: + return base + + return f"{base}_{index}" + + +def unify_consecutive_labels( + sample: dict, + text_key: str = "document", + render_context: dict | None = None, +) -> list[dict]: + """ + Unifies consecutive labels in a sample. + + Args: + sample (dict): A dictionary representing the sample. + text_key (str, optional): The key for the text in the sample dictionary. + Defaults to "document". + render_context (dict | None, optional): The context for rendering labels. Defaults to None. + + Returns: + list[dict]: A list of dictionaries representing the unified labels. + """ + sample = deepcopy(sample) + + # Extract labels and document text + labels = sample["labels"] + document = sample[text_key] + + # Reorder labels based on start indices + labels = sorted(labels, key=lambda x: x["start_char"]) + + unified_labels = [] + current_group = None + + # Iterate over labels + for label in labels: + # Get attributes + text = label["attrs"]["aymurai_alt_text"] or label["text"] + start_char = label["attrs"]["aymurai_alt_start_char"] or label["start_char"] + end_char = label["attrs"]["aymurai_alt_end_char"] or label["end_char"] + aymurai_label = resolve_render_token(label, render_context) + + if current_group is None: + # Start a new group with the current label + current_group = { + "text": text, + "start_char": start_char, + "end_char": end_char, + "aymurai_label": aymurai_label, + } + elif ( + current_group["aymurai_label"] == aymurai_label + and (start_char - current_group["end_char"]) <= 1 + ): + # Extend the current group with the current label + current_group["end_char"] = end_char + else: + # Finish the current group and start a new one + current_group["text"] = document[ + current_group["start_char"] : current_group["end_char"] + 1 + ] + unified_labels.append(current_group) + current_group = { + "text": text, + "start_char": start_char, + "end_char": end_char, + "aymurai_label": aymurai_label, + } + + # Finish the last group + if current_group is not None: + current_group["text"] = document[ + current_group["start_char"] : current_group["end_char"] + 1 + ] + unified_labels.append(current_group) + + return unified_labels + + +def replace_labels_in_text( + pred: dict, + text_key: str = "document", + render_context: dict | None = None, +) -> str: + """ + Replaces labels in the text with anonymized tokens. + + Args: + pred (dict): A dictionary representing the prediction. + text_key (str, optional): The key for the text in the prediction dictionary. + Defaults to "document". + render_context (dict | None, optional): The context for rendering labels. Defaults to None. + Returns: + str: The text with replaced labels. + """ + pred = deepcopy(pred) + doc = pred[text_key] + + # Unify consecutive labels + unified_labels = unify_consecutive_labels( + pred, render_context=render_context, text_key=text_key + ) + + # Initialize the offset + offset = 0 + + # Replace labels in the text + for unified_label in unified_labels: + # Adjust start and end character indices of the label + start_char = unified_label["start_char"] + offset + end_char = unified_label["end_char"] + offset + len_text_to_replace = end_char - start_char + + # Replace the text with the anonymized token + aymurai_label = f" <{unified_label['aymurai_label']}>" + len_aymurai_label = len(aymurai_label) + + doc = doc[:start_char] + aymurai_label + doc[end_char:] + + # Update the offset + offset += len_aymurai_label - len_text_to_replace + + return re.sub(r" +", " ", doc).strip() + + +def erase_duplicates_justseen(series: pd.Series) -> pd.Series: + """ + Replaces consecutive duplicate values in a pandas Series with an empty string, keeping only the first occurrence. + + Args: + series (pd.Series): The input pandas Series. + + Returns: + pd.Series: A pandas Series with consecutive duplicates replaced by an empty string. + """ + return series.where(series.ne(series.shift(), fill_value=None), "") + + +def parse_token_indices( + sample: dict, render_context: dict | None = None +) -> pd.DataFrame: + """ + Parses the token indices from a sample. + + Args: + sample (dict): A dictionary representing the sample. + render_context (dict | None, optional): The context for rendering labels. Defaults to None. + + Returns: + pd.DataFrame: A pandas DataFrame representing the parsed token indices. + """ + original_text = " ".join( + [fragment["text"] for fragment in sample["metadata"]["fragments"]] + ) + anonymized_text = replace_labels_in_text(sample, render_context=render_context) + + aligned = align_text( + " " + original_text + " ", + " " + anonymized_text + " ", + ) + aligned["target"] = erase_duplicates_justseen(aligned["target"]) + + xml_file = sample["metadata"]["xml_file"] + + tokens = [] + for i, fragment in enumerate(sample["metadata"]["fragments"]): + text = fragment["text"] + tokenized_text = tokenize(text) + paragraph_index = fragment["paragraph_index"] + + # Use re.finditer to locate each instance of tokens in the text + token_matches = list( + re.finditer(r"\S+", text) + ) # \S+ matches any non-whitespace sequence + + # Loop over tokenized text and token_matches in parallel + for j, (token, match) in enumerate(zip(tokenized_text, token_matches)): + start = sample["metadata"]["start"] + fragment["start"] + match.start() + end = start + len(token) + + tokens.append((xml_file, paragraph_index, i, j, token, start, end)) + + tokens = pd.DataFrame( + tokens, + columns=[ + "xml_file", + "paragraph_index", + "fragment_index", + "token_index", + "token", + "start_char", + "end_char", + ], + ) + + tokens = pd.concat( + [tokens, aligned["target"].iloc[1:-1].reset_index(drop=True)], axis=1 + ) + + tokens["target"] = tokens["target"].fillna("") + + return tokens + + +def index_paragraphs(file: str) -> list[dict]: + """ + Indexes the paragraphs of an XML file. + + Args: + file (str): The path to the XML file to be indexed. + + Returns: + list[dict]: A list of dictionaries representing the indexed paragraphs. + """ + # Read the XML file + with open(file) as f: + xml = f.read() + + paragraphs = [] + paragraph_index = 0 + + # Find all paragraphs in the XML file + for match in re.finditer(REGEX_PARAGRAPH, xml): + paragraph = match.group("paragraph") + paragraph_start = match.start("paragraph") + paragraph_end = match.end("paragraph") + fragments = [] + fragment_index = 0 + + # Find all text fragments in the paragraph + for fragment in re.finditer(REGEX_FRAGMENT, paragraph): + text = fragment.group("text") + start = fragment.start("text") + end = fragment.end("text") + + fragment_dict = { + "text": text, + "normalized_text": FlairTextNormalize.normalize_text(text), + "start": start, + "end": end, + "fragment_index": fragment_index, + "paragraph_index": paragraph_index, + } + fragments.append(fragment_dict) + fragment_index += 1 + + # Join all fragments as plain text + plain_text = "".join([fragment["normalized_text"] for fragment in fragments]) + + paragraphs.append( + { + "plain_text": plain_text, + "metadata": { + "start": paragraph_start, + "end": paragraph_end, + "fragments": fragments, + "xml_file": os.path.basename(file), + }, + } + ) + paragraph_index += 1 + + return paragraphs + + +def match_paragraphs_with_predictions( + paragraphs: list[dict], + predictions: list[dict], +) -> list[dict]: + """ + Matches each paragraph with its corresponding predictions. + + Args: + paragraphs (list[dict]): A list of dictionaries representing the paragraphs. + predictions (list[dict]): A list of dictionaries representing + the predictions. + + Returns: + list[dict]: A list of dictionaries representing + the matched paragraphs with predictions. + """ + + paragraphs = deepcopy(paragraphs) + + # Hash prediction documents + pred_hashes = [hash(prediction["document"]) for prediction in predictions] + idx2hash = {i: _hash for i, _hash in enumerate(pred_hashes)} + + # Hash paragraphs + paragraphs = [ + paragraph | {"hash": hash(normalize("NFKC", paragraph["plain_text"].strip()))} + for paragraph in paragraphs + ] + + # Assign prediction indices to each paragraph by hash + hash2idx = { + paragraph["hash"]: np.where(np.array(pred_hashes) == paragraph["hash"])[ + 0 + ].tolist() + for paragraph in paragraphs + } + + paragraphs = [ + paragraph | {"pred_indices": hash2idx[paragraph["hash"]]} + for paragraph in paragraphs + ] + + # Identify missing indices + missing_indices = list(set(idx2hash.keys()) - set(flatten(list(hash2idx.values())))) + + if missing_indices: + # Assign prediction indices to each paragraph by lowest CER + target_texts = np.array([prediction["document"] for prediction in predictions])[ + missing_indices + ] + + missing_paragraphs = [ + paragraph for paragraph in paragraphs if not paragraph["pred_indices"] + ] + + for missing_paragraph in missing_paragraphs: + source_text = missing_paragraph["plain_text"] + min_cer_idx = np.argmin( + [cer(source_text, target_text) for target_text in target_texts] + ) + missing_paragraph["pred_indices"] = [missing_indices[min_cer_idx]] + + # Assign document text and labels + paragraphs = [ + paragraph + | { + "document": predictions[paragraph["pred_indices"][0]]["document"], + "labels": predictions[paragraph["pred_indices"][0]]["labels"], + } + for paragraph in paragraphs + ] + + return paragraphs diff --git a/aymurai/text/anonymization/doc_anonymizer.py b/aymurai/text/anonymization/doc_anonymizer.py new file mode 100644 index 00000000..7feb6f3a --- /dev/null +++ b/aymurai/text/anonymization/doc_anonymizer.py @@ -0,0 +1,88 @@ +import os +import tempfile +from glob import glob + +from more_itertools import flatten + +from aymurai.meta.pipeline_interfaces import Transform +from aymurai.text.anonymization.alignment import ( + index_paragraphs, + match_paragraphs_with_predictions, +) +from aymurai.text.anonymization.watermarks import add_footer_watermark +from aymurai.text.anonymization.xml_docx import ( + create_docx, + replace_text_in_xml, + unzip_document, +) +from aymurai.utils.cache import cache_load, cache_save, get_cache_key + + +class DocAnonymizer(Transform): + """ + Anonymize document by replacing sensitive data with label tokens + """ + + def __init__(self, use_cache: bool = False): + self.use_cache = use_cache + self.render_context = None + + def __call__(self, item: dict, preds: list[dict], output_dir: str = ".") -> None: + """ + Performs the anonymization process on a document. + + Args: + item (dict): The document item to be anonymized. + preds (list[dict]): The list of predictions for the document. + output_dir (str, optional): The directory to save the anonymized document. + Defaults to ".". + + Raises: + ValueError: If the document has an extension other than `.docx`. + """ + item_path = item["path"] + + if not os.path.splitext(item_path)[-1] == ".docx": + raise ValueError("Only `.docx` extension is allowed.") + + if not item.get("data"): + item["data"] = {} + + cache_key = get_cache_key(item_path, self.__name__) + if self.use_cache and (cache_data := cache_load(key=cache_key)): + paragraphs = cache_data + else: + # Unzip document into a temporary directory + with tempfile.TemporaryDirectory() as tempdir: + unzip_document(item_path, tempdir) + + # Parse XML files + xml_files = glob(f"{tempdir}/**/*.xml", recursive=True) + paragraphs = (index_paragraphs(file) for file in xml_files) + paragraphs = list(flatten(paragraphs)) + + # Filter out empty paragraphs + paragraphs = [ + paragraph + for paragraph in paragraphs + if paragraph["plain_text"].strip() + ] + + # Matching + paragraphs = match_paragraphs_with_predictions(paragraphs, preds) + + # Edit XML filess + replace_text_in_xml(paragraphs, tempdir, self.render_context) + + # Recreate anonymized document + os.makedirs(output_dir, exist_ok=True) + create_docx( + tempdir, + f"{output_dir}/{os.path.basename(item_path)}", + ) + + # Add watermark to the footer + add_footer_watermark(f"{output_dir}/{os.path.basename(item_path)}") + + if self.use_cache: + cache_save(paragraphs, key=cache_key) diff --git a/aymurai/text/anonymization/watermarks.py b/aymurai/text/anonymization/watermarks.py new file mode 100644 index 00000000..3199bb9e --- /dev/null +++ b/aymurai/text/anonymization/watermarks.py @@ -0,0 +1,197 @@ +from docx import Document +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.opc.constants import RELATIONSHIP_TYPE +from docx.oxml.shared import OxmlElement, qn +from docx.shared import Inches, Pt, RGBColor + + +def _add_hyperlink( + paragraph, + text: str, + url: str, + font_name: str = "Archivo", + size: int = 10, + color: RGBColor = RGBColor(115, 190, 250), + italic: bool = False, + bold: bool = True, + underline: bool = True, +) -> None: + """ + Adds a formatted hyperlink to a given paragraph in a Word document. + + Notes: + - This method directly manipulates the underlying XML of the paragraph to insert a hyperlink, + as python-docx does not natively support hyperlinks. + - The hyperlink will be appended to the end of the given paragraph. + - Formatting options (font, size, color, italic, bold, underline) are applied to the hyperlink text. + + Args: + paragraph: The python-docx paragraph object to which the hyperlink will be added. + text (str): The display text for the hyperlink. + url (str): The URL that the hyperlink points to. + font_name (str, optional): The font name to use for the hyperlink text. Defaults to "Archivo". + size (int, optional): The font size (in points) for the hyperlink text. Defaults to 10. + color (RGBColor, optional): The font color as an RGBColor tuple. Defaults to RGBColor(115, 190, 250). + italic (bool, optional): Whether the hyperlink text should be italicized. Defaults to False. + bold (bool, optional): Whether the hyperlink text should be bold. Defaults to True. + underline (bool, optional): Whether the hyperlink text should be underlined. Defaults to True. + + Raises: + ValueError: If the paragraph is not a valid python-docx paragraph object. + """ + # Create the hyperlink relationship + part = paragraph.part + r_id = part.relate_to(url, RELATIONSHIP_TYPE.HYPERLINK, is_external=True) + + # Create the hyperlink element + hyperlink = OxmlElement("w:hyperlink") + hyperlink.set(qn("r:id"), r_id) + + # Create a new run + new_run = OxmlElement("w:r") + + # Set run properties (formatting) + r_pr = OxmlElement("w:rPr") + + # Set font + if font_name: + font = OxmlElement("w:rFonts") + font.set(qn("w:ascii"), font_name) + font.set(qn("w:hAnsi"), font_name) + r_pr.append(font) + + # Set color + if color: + color_el = OxmlElement("w:color") + color_el.set(qn("w:val"), f"{color[0]:02x}{color[1]:02x}{color[2]:02x}") + r_pr.append(color_el) + + # Set italic + if italic: + r_pr.append(OxmlElement("w:i")) + + # Set bold + if bold: + r_pr.append(OxmlElement("w:b")) + + # Set underline - added for links + if underline: + underline_el = OxmlElement("w:u") + underline_el.set(qn("w:val"), "single") # single underline + r_pr.append(underline_el) + + # Set size + sz = OxmlElement("w:sz") + sz.set(qn("w:val"), str(size * 2)) # Word uses half-points + r_pr.append(sz) + + # Add properties to run + new_run.append(r_pr) + + # Set text + text_el = OxmlElement("w:t") + text_el.text = text + new_run.append(text_el) + + # Add run to hyperlink + hyperlink.append(new_run) + + # Add hyperlink to paragraph + paragraph._p.append(hyperlink) + + +def _add_watermark_to_footer( + footer, + alignment, + font_name: str = "Archivo", + hyperlink_text: str = "AymurAI", + hyperlink_url: str = "https://www.aymurai.info/", + watermark_text: str = "Documento anonimizado por AymurAI", +) -> None: + """ + Adds a watermark text to the footer of a document. + + Args: + footer: The footer object to which the watermark will be added. + alignment: The alignment setting for the paragraph (e.g., left, center, right). + font_name (str, optional): The font name to use for the watermark text. Defaults to "Archivo". + hyperlink_text (str, optional): The text to be hyperlinked. Defaults to "AymurAI". + hyperlink_url (str, optional): The URL to link "AymurAI" to. Defaults to "https://www.aymurai.info/". + watermark_text (str): The text to be used as the watermark. Defaults to "Documento anonimizado por AymurAI". + """ + paragraph = footer.add_paragraph() + paragraph.alignment = alignment + + if hyperlink_url and hyperlink_text in watermark_text: + parts = watermark_text.split(hyperlink_text, 1) + before_text = parts[0] + after_text = parts[1] if len(parts) > 1 else "" + + # Add text before the hyperlink + if before_text: + run = paragraph.add_run(before_text) + run.font.name = "Archivo" + run.font.color.rgb = RGBColor(192, 192, 192) + run.font.size = Pt(10) + + # Add hyperlink + _add_hyperlink(paragraph, hyperlink_text, hyperlink_url) + + # Add text after the hyperlink + if after_text: + run = paragraph.add_run(after_text) + run.font.name = font_name + run.font.color.rgb = RGBColor(192, 192, 192) + run.font.size = Pt(10) + + else: + # Just add the full text without a hyperlink + run = paragraph.add_run(watermark_text) + run.font.name = font_name + run.font.color.rgb = RGBColor(192, 192, 192) + run.font.size = Pt(10) + + +def add_footer_watermark( + doc_path: str, + font_name: str = "Archivo", + hyperlink_text: str = "AymurAI", + hyperlink_url: str = "https://www.aymurai.info/", + watermark_text: str = "Documento anonimizado por AymurAI", +) -> None: + """ + Adds a watermark to the footer of each section in a Word document. + + Args: + doc_path (str): Path to the document. + font_name (str, optional): The font name to use for the watermark text. Defaults to "Archivo". + hyperlink_text (str, optional): The text to be hyperlinked. Defaults to "AymurAI". + hyperlink_url (str, optional): The URL to link "AymurAI" to. Defaults to "https://www.aymurai.info/". + watermark_text (str, optional): The text to be used as the watermark. Defaults to "Documento anonimizado por AymurAI". + """ + document = Document(doc_path) + processed_footers = set() + + for section in document.sections: + section.footer_distance = Inches(0.1) + + # List of (footer_obj, alignment) tuples + footers = [(section.footer, WD_ALIGN_PARAGRAPH.RIGHT)] # Odd/default + if section.even_page_footer is not None: + footers.append((section.even_page_footer, WD_ALIGN_PARAGRAPH.LEFT)) + if section.different_first_page_header_footer: + footers.append((section.first_page_footer, WD_ALIGN_PARAGRAPH.RIGHT)) + + for footer, alignment in footers: + if id(footer) not in processed_footers: + _add_watermark_to_footer( + footer, + alignment, + font_name=font_name, + hyperlink_text=hyperlink_text, + hyperlink_url=hyperlink_url, + watermark_text=watermark_text, + ) + processed_footers.add(id(footer)) + + document.save(doc_path) diff --git a/aymurai/text/anonymization/xml_docx.py b/aymurai/text/anonymization/xml_docx.py new file mode 100644 index 00000000..1ae9f50e --- /dev/null +++ b/aymurai/text/anonymization/xml_docx.py @@ -0,0 +1,172 @@ +import os +import re +import xml.sax.saxutils +import zipfile + +import pandas as pd +from lxml import etree + +from aymurai.text.anonymization.alignment import parse_token_indices + + +def unzip_document(doc_path: str, output_dir: str) -> None: + """ + Unzips the document file to the specified output directory. + + Args: + doc_path (str): The path to the document file. + output_dir (str): The directory where the contents of the document + file will be extracted. + """ + # Ensure the output directory exists + os.makedirs(output_dir, exist_ok=True) + + # Open the doc file as a zip file + with zipfile.ZipFile(doc_path, "r") as doc_zip: + # Extract all the contents to the output directory + doc_zip.extractall(output_dir) + + +def normalize_document(xml_content: str) -> str: + """ + Normalizes the XML document by removing extra spaces, preserving line breaks, + and removing hyperlinks while preserving text content. + + Args: + xml_content (str): The XML content to be normalized. + + Returns: + str: The normalized XML content. + """ + # Parse the XML content + parser = etree.XMLParser(ns_clean=True) + root = etree.fromstring(xml_content.encode("utf-8"), parser) + + # Extract namespaces + namespaces = {k: v for k, v in root.nsmap.items() if k} + + # Remove hyperlinks but preserve the text content + for hyperlink in root.xpath("//w:hyperlink", namespaces=namespaces): + parent = hyperlink.getparent() + index = list(parent).index(hyperlink) + + # Move all text-containing children (e.g., w:r elements) outside the hyperlink tag + for child in hyperlink: + parent.insert(index, child) + index += 1 + parent.remove(hyperlink) # Remove the element itself + + # Process each paragraph + for wp in root.xpath("//w:p", namespaces=namespaces): + first = True + + # Find all w:r elements containing w:t elements + for wr in wp.xpath(".//w:r", namespaces=namespaces): + wt = wr.find(".//w:t", namespaces) + if wt is not None and wt.text: + # Normalize spaces within the text, preserving new line breaks + wt.text = re.sub(r"[^\S\r\n]+", " ", wt.text) + + # Add a leading space if not the first fragment in the paragraph + if not first: + wt.text = " " + wt.text.lstrip() + else: + wt.text = wt.text.lstrip() + first = False + + # Remove trailing spaces from all fragments + wt.text = wt.text.rstrip() + + # Set the xml:space attribute to preserve + wt.set( + "{http://www.w3.org/XML/1998/namespace}space", + "preserve", + ) + + # Check if the text is empty after normalization + if not wt.text or wt.text.strip() == "": + # Remove the w:r element from its parent + wr.getparent().remove(wr) + + # Write back the XML content to a string + xml_str = etree.tostring(root, encoding="unicode", pretty_print=True) + + return xml_str + + +def replace_text_in_xml( + paragraphs: list[dict], base_dir: str, render_context: dict | None = None +) -> None: + """ + Replaces text in XML files based on the provided paragraphs + and saves the modified files. + + Args: + paragraphs (list[dict]): A list of dictionaries representing + the paragraphs to be replaced. + base_dir (str): The base directory where the XML files are located. + render_context (dict | None, optional): The context for rendering labels. Defaults to None. + """ + tokens = pd.concat( + [parse_token_indices(sample, render_context) for sample in paragraphs], + ignore_index=True, + ) + + fragments = ( + tokens.groupby(["xml_file", "paragraph_index", "fragment_index"]) + .agg({"target": " ".join, "start_char": "min", "end_char": "max"}) + .reset_index() + ) + + for xml_file, group in fragments.groupby("xml_file"): + group = group.sort_values("end_char", ascending=False) + + with open(f"{base_dir}/word/{xml_file}", "r+") as file: + content = file.read() + + for _, r in group.iterrows(): + start_char = r["start_char"] + end_char = r["end_char"] + + target = r["target"] + target = re.sub(r"[^\S\r\n]+", " ", target) + + # Escape XML special characters + target = xml.sax.saxutils.escape(target) + + content = content[:start_char] + target + content[end_char:] + + # MUST be at the end to dont screw up the indexes + content = normalize_document(content) + + file.seek(0) + file.write(content) + file.truncate() + + +def add_files_to_zip(zip_file: zipfile.ZipFile, directory: str) -> None: + """ + Adds all files in the specified directory to a zip file. + + Args: + zip_file (zipfile.ZipFile): The zip file to add the files to. + directory (str): The directory containing the files to be added. + """ + for root, _, files in os.walk(directory): + for file in files: + file_path = os.path.join(root, file) + zip_file.write(file_path, os.path.relpath(file_path, directory)) + + +def create_docx(xml_directory: str, output_file: str) -> None: + """ + Creates a new DOCX file by adding XML components from the specified directory. + + Args: + xml_directory (str): The directory containing the XML components. + output_file (str): The path to the output DOCX file. + """ + # Create a new zip file + with zipfile.ZipFile(output_file, "w") as docx: + # Add XML components + add_files_to_zip(docx, xml_directory) diff --git a/aymurai/transforms/datetime_formatter/core.py b/aymurai/transforms/datetime_formatter/core.py index fbdab7e1..e98c0d76 100644 --- a/aymurai/transforms/datetime_formatter/core.py +++ b/aymurai/transforms/datetime_formatter/core.py @@ -2,9 +2,9 @@ from datetime_matcher import DatetimeMatcher +from aymurai.meta.pipeline_interfaces import Transform from aymurai.meta.types import DataItem from aymurai.utils.misc import get_element -from aymurai.meta.pipeline_interfaces import Transform from .patterns import patterns diff --git a/docs/anonymization/README.md b/docs/anonymization/README.md index 899a2081..9beee13d 100644 --- a/docs/anonymization/README.md +++ b/docs/anonymization/README.md @@ -10,13 +10,64 @@ 1. `/misc/document-extract` recibe el DOCX/PDF y devuelve el payload estructurado (`document_id`, lista de párrafos) tal como hoy. 2. Se procesa cada párrafo con `/anonymizer/predict`, obteniendo los resultados de NER (`aymurai_label`, texto, offsets, contexto previo y posterior y otros atributos). 3. Se consolida la inferencia: agrupamos todas las menciones detectadas y armamos un paquete enriquecido con contexto circundante (párrafo u oraciones vecinas). -4. Módulo de fuzzy-matching cruza cada mención extraida para sugerir candidatos de `CanonicalEntities` (`canonical_text` y `aliases`). +4. Módulo de fuzzy-matching cruza cada mención extraída para sugerir candidatos de `CanonicalEntities` (`canonical_text` y `aliases`). 5. El contexto del paso 3 más las sugerencias del paso 4 son insumo para el servicio de desambiguación (LLM); el modelo se encarga de validar los `CanonicalEntities` sugeridos o proponer nuevos, al tiempo que infiere atributos adicionales (rol procesal), devolviendo una lista refinada de `CanonicalEntities`. -6. Con esa lista se ejecuta el mapeo de `Entity` a `CanonicalEntity`: cada mención NER queda anotada con un `canonical_entity_id` y un `aymurai_label_suffix` y cualquier atributo inferido, generando la desambiguación de entidades. +6. Con esa lista se ejecuta el mapeo de `Entity` a `CanonicalEntity`: cada mención NER queda anotada con un `canonical_entity_id` y un `aymurai_label_instance` (índice entero por orden de aparición) y cualquier atributo inferido, generando la desambiguación de entidades. 7. El frontend consume esos outputs y muestra el texto original con dos niveles de revisión: etiquetas NER y asignación canónica. -8. Tras la validación manual, el cliente invoca `/anonymizer/anonymize-document`, que ahora utiliza el `aymurai_label_suffix` para aplicar reemplazos consistentes y generar el documento anonimizado final. +8. Tras la validación manual, el cliente invoca `/anonymizer/anonymize-document`, que ahora utiliza políticas de render (`render_policy`) para aplicar reemplazos consistentes (etiqueta o subclase con sufijos opcionales) y generar el documento anonimizado final. 9. El documento anonimizado queda disponible para descarga y se registran en la base de datos las decisiones finales (etiquetas y canónicos). +## Cambios principales en el modelo de datos + +### Nuevos campos en `EntityAttributes` + +- `canonical_entity_id`: UUID de la entidad canónica asignada a cada mención. +- `aymurai_label_instance`: índice entero por orden de aparición del `canonical_entity_id` dentro de un mismo label (1, 2, 3...). +- `aymurai_label_subclass`: lista de roles inferidos por LLM (p. ej. "Denunciante", "Juez/a"). +- `aymurai_disambiguation`: método aplicado para la desambiguación efectiva del label (`llm`, `fuzzy`, `none`). +- `aymurai_anonymize`: flag efectivo de anonimización (True/False). + +### Políticas por label (nueva interfaz) + +Se incorpora un esquema de políticas por etiqueta que permite decidir: + +- `anonymize`: `true | false` +- `disambiguation`: `"none" | "fuzzy" | "llm"` +- `use_subclass_when_available`: `true | false` + +Estas políticas pueden venir de: + +1. Configuración del servidor (variable de entorno `DISAMBIGUATION_LABEL_POLICIES`). +2. Request del usuario (campo `label_policies` en `/anonymizer/disambiguate` y `/anonymizer/anonymize-document`). + +## Render Policy (integración con frontend) + +Para evitar sumar flags adicionales en cada entidad, el comportamiento de render se controla con un objeto `render_policy` (a nivel request/documento), que define: + +- `suffix_mode`: `"auto" | "always" | "never"`. +- `suffix_threshold`: umbral para agregar sufijo en modo `auto`. + +Esto permite generar tokens como: + +- `` si hay un solo juez. +- ``, `` si hay múltiples. +- `` si `use_subclass_when_available` es `false` ó `use_subclass_when_available` es `true` pero no hay subclase disponible para esa entidad. + +El `render_policy` puede definirse por entorno (`RENDER_POLICY`) o por request y se aplica al momento de exportar el documento con `/anonymizer/anonymize-document`. + +## Cambios en la API + +### `/anonymizer/disambiguate` + +- **Nuevo input opcional**: `label_policies`. +- **Nuevo output**: `label_policies` y metadatos efectivos en cada `DocLabel` (`aymurai_disambiguation`, `aymurai_anonymize`). +- La selección de labels para LLM/fuzzy se define por políticas, no por un modo global. + +### `/anonymizer/anonymize-document` + +- **Input**: `DocumentAnnotations` incluye `label_policies` y `render_policy`. +- **Render**: los tokens se generan según `render_policy` y respetan `aymurai_anonymize`. + ## Plan de evaluación incremental El objetivo general es optimizar la extracción y desambiguación de entidades. Para avanzar con criterio orientado a métricas mediremos cada capa y el sistema end-to-end. @@ -29,5 +80,5 @@ Finalmente consolidaremos una evaluación integrada combinando el mejor NER disp ## Consideraciones de integración con frontend -- Necesitamos habilitar una lista configurable de entidades a excluir de la anonimización. El frontend deberá permitir que la persona usuaria decida, por ejemplo, mantener visibles o no entidades específicas o menciones a funcionariaos públicos según su rol procesal. -- Las exclusiones y la edición manual posterior impactan directamente en el ordenamiento de los `aymurai_label_suffix`. Habrá que recalcular los sufijos luego de aplicar exclusiones y validaciones para evitar huecos o inconsistencias entre el texto mostrado y los reemplazos finales. +- Necesitamos habilitar una lista configurable de entidades a excluir de la anonimización. El frontend deberá permitir que la persona usuaria decida, por ejemplo, mantener visibles o no entidades específicas o menciones a funcionarios públicos según su rol procesal. +- Las exclusiones y la edición manual posterior impactan directamente en el ordenamiento de los `aymurai_label_instance`. Habrá que recalcular los sufijos luego de aplicar exclusiones y validaciones para evitar huecos o inconsistencias entre el texto mostrado y los reemplazos finales. diff --git a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb index 8ad00ae4..6eed83f1 100644 --- a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb +++ b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb @@ -230,7 +230,6 @@ " call_extraction_api as extract_document,\n", ")\n", "\n", - "\n", "def discover_documents(root: Path, extensions: set[str]) -> list[Path]:\n", " extensions = {ext.lower() for ext in extensions}\n", " return sorted(\n", @@ -239,7 +238,6 @@ " if path.is_file() and path.suffix.lower() in extensions\n", " )\n", "\n", - "\n", "def predict_paragraphs(paragraphs: list[str]) -> list[dict]:\n", " endpoint = f\"{API_BASE_URL}/anonymizer/predict\"\n", " predictions = []\n", diff --git a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb new file mode 100644 index 00000000..1b3566f9 --- /dev/null +++ b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb @@ -0,0 +1,266 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "from pathlib import Path\n", + "\n", + "import requests\n", + "from tqdm import tqdm\n", + "\n", + "from aymurai.experiments.entity_disambiguation.runner import (\n", + " call_extraction_api as extract_document,\n", + ")\n", + "\n", + "API_URL = \"http://localhost:8000\" # Url for debugger. change it to your own\n", + "DATA_ROOT = Path(\n", + " os.getenv(\n", + " \"DISAMBIGUATION_DATA_ROOT\",\n", + " \"../../../resources/data/restricted/disambiguation-eval/files\",\n", + " )\n", + ")\n", + "DOC_EXTENSIONS = {\".pdf\", \".docx\"}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sample document\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def discover_documents(root: Path, extensions: set[str]) -> list[Path]:\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", + "\n", + "print(f\"Found {len(documents)} documents\")\n", + "\n", + "doc_path = documents[16]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## /document-extract endpoint output\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# /document-extract endpoint output\n", + "session = requests.Session()\n", + "document = extract_document(\n", + " session,\n", + " endpoint=f\"{API_URL}/misc/document-extract\",\n", + " file_path=doc_path,\n", + " timeout_s=300,\n", + ")\n", + "paragraphs = document[\"detail\"][\"document\"]\n", + "document" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "len(paragraphs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Inference\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Function to make inference using the API\n", + "def get_predictions(sample: str) -> dict:\n", + " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample}, params={\"use_cache\": False})\n", + " response.raise_for_status()\n", + " return response.json()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "predictions = [get_predictions(paragraph) for paragraph in tqdm(paragraphs)]\n", + "predictions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Export variants\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def disambiguate_and_export(\n", + " variant_name: str, label_policies: dict, render_policy: dict\n", + "):\n", + " response = requests.post(\n", + " url=f\"{API_URL}/anonymizer/disambiguate\",\n", + " json={\n", + " \"paragraphs\": predictions,\n", + " # \"custom_prompts\": {\"root\": []},\n", + " \"label_policies\": label_policies,\n", + " },\n", + " )\n", + " response.raise_for_status()\n", + " disambiguated = response.json()\n", + "\n", + " json_prediction = json.dumps(\n", + " {\n", + " \"data\": disambiguated[\"data\"],\n", + " \"label_policies\": label_policies,\n", + " \"render_policy\": render_policy,\n", + " }\n", + " )\n", + "\n", + " with open(doc_path, \"rb\") as file:\n", + " files = {\"file\": file}\n", + "\n", + " response = requests.post(\n", + " url=f\"{API_URL}/anonymizer/anonymize-document\",\n", + " data={\"annotations\": json_prediction},\n", + " files=files,\n", + " )\n", + " response.raise_for_status()\n", + "\n", + " output_dir = \"output\"\n", + " os.makedirs(output_dir, exist_ok=True)\n", + "\n", + " filename = os.path.basename(doc_path)\n", + " filename, ext = os.path.splitext(filename)\n", + " out_path = f\"{output_dir}/{filename}-{variant_name}.odt\"\n", + "\n", + " with open(out_path, \"wb\") as file:\n", + " file.write(response.content)\n", + "\n", + " return out_path" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "render_policy = {\n", + " \"suffix_mode\": \"auto\",\n", + " \"suffix_threshold\": 1,\n", + "}\n", + "\n", + "# 1) everything fuzzy\n", + "label_policies_all_fuzzy = {\n", + " \"PER\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": True},\n", + " \"DNI\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"LOC\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"FECHA\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + "}\n", + "out_all_fuzzy = disambiguate_and_export(\n", + " \"all-fuzzy\", label_policies_all_fuzzy, render_policy\n", + ")\n", + "\n", + "# 2) FECHAs excluded\n", + "label_policies_no_fecha = {\n", + " \"PER\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": True},\n", + " \"DNI\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"LOC\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"FECHA\": {\"disambiguation\": \"none\", \"anonymize\": False, \"use_subclass_when_available\": False},\n", + "}\n", + "out_no_fecha = disambiguate_and_export(\n", + " \"no-fecha\", label_policies_no_fecha, render_policy\n", + ")\n", + "\n", + "# 3) PER llm-disambiguated\n", + "label_policies_per_llm = {\n", + " \"PER\": {\"disambiguation\": \"llm\", \"anonymize\": False, \"use_subclass_when_available\": True},\n", + " \"DNI\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"LOC\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"FECHA\": {\"disambiguation\": \"none\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + "}\n", + "out_per_llm = disambiguate_and_export(\"per-llm\", label_policies_per_llm, render_policy)\n", + "\n", + "out_all_fuzzy, out_no_fecha, out_per_llm" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 96a88ef2fafbb386331f29c18014ef7dbece88f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= Date: Thu, 30 Jan 2025 21:54:41 +0000 Subject: [PATCH 035/104] =?UTF-8?q?=E2=8F=AA=20Revert=20entrypoint.sh=20to?= =?UTF-8?q?=201ac2776?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .devcontainer/entrypoint.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/entrypoint.sh b/.devcontainer/entrypoint.sh index 214ac9f6..000c3360 100644 --- a/.devcontainer/entrypoint.sh +++ b/.devcontainer/entrypoint.sh @@ -1,7 +1,7 @@ #!/bin/sh # install dependencies -uv sync --frozen --all-extras --group mlops +uv sync --frozen --all-extras # configure precommit uv run pre-commit install From 20f9e9236803c1d0b8e5c0a7697fbacee2dc9cc4 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 18 Feb 2026 18:31:48 -0300 Subject: [PATCH 036/104] =?UTF-8?q?=E2=8F=AA=20Revert=20.dockerignore=20to?= =?UTF-8?q?=205af5814?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .dockerignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index e84e738a..9b91c7d3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,6 @@ resources/ !resources/api !resources/pipelines -!resources/llm !resources/cache/aymurai !resources/cache/tfhub_modules notebooks/ From 04f33432193adeb5c9f2ff1aabfb5449c06dfe56 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 18 Feb 2026 18:50:35 -0300 Subject: [PATCH 037/104] =?UTF-8?q?=E2=8F=AA=20Revert=20.env.common=20to?= =?UTF-8?q?=2090f7369?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.common | 9 --------- 1 file changed, 9 deletions(-) diff --git a/.env.common b/.env.common index 25d41bb8..1eec416e 100644 --- a/.env.common +++ b/.env.common @@ -8,12 +8,3 @@ TESSDATA_PREFIX=/usr/local/share/tessdata AYMURAI_RESTRICTED_DOCUMENT_PDFS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO-pdf" AYMURAI_RESTRICTED_DOCUMENT_DOCS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO" - -API_BASE_URL=http://localhost:8899 -REQUEST_TIMEOUT=300 - -MLFLOW_TRACKING_URI=http://localhost:5000 -MLFLOW_S3_ENDPOINT_URL=http://localhost:9002 -MLFLOW_S3_IGNORE_TLS=true -MLFLOW_EXPERIMENT_NAME=entity-disambiguation -MLFLOW_ARTIFACT_ROOT=s3://mlflow/artifacts \ No newline at end of file From 1dbd24c303cb04542c395b0f8c0357cf82816e87 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 18 Feb 2026 19:29:09 -0300 Subject: [PATCH 038/104] =?UTF-8?q?=E2=8F=AA=20Revert=20.vscode/launch.jso?= =?UTF-8?q?n=20to=20f366690?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index d6348f6f..00fd92d6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,8 +19,7 @@ ], "subProcess": false, "envFile": "${workspaceFolder}/.env", - "python": "${workspaceFolder}/.venv/bin/python", - "preLaunchTask": "Start Ollama service" + "python": "${workspaceFolder}/.venv/bin/python" }, ] } \ No newline at end of file From f645881a3482a6e2f1ab6fde13bfc89a22dfd883 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 18 Feb 2026 19:36:53 -0300 Subject: [PATCH 039/104] =?UTF-8?q?=E2=8F=AA=20Revert=20Makefile=20to=20cb?= =?UTF-8?q?3df05?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 124 ++++--------------------------------------------------- 1 file changed, 7 insertions(+), 117 deletions(-) diff --git a/Makefile b/Makefile index b49053fd..0f132348 100644 --- a/Makefile +++ b/Makefile @@ -3,131 +3,21 @@ export $(shell sed 's/=.*//' .env) include .env.common export $(shell sed 's/=.*//' .env.common) -# Select which Ollama service to control (ollama or ollama-gpu) -OLLAMA_SERVICE ?= ollama -OLLAMA_CONTAINER := $(shell docker ps -q -f name=^$(OLLAMA_SERVICE)$$) -# Select which API service to control (override with API_SERVICE=aymurai-api-gpu) -API_SERVICE ?= aymurai-api -# Select which full API service to control (override with API_FULL_SERVICE=aymurai-api-full-gpu) -API_FULL_SERVICE ?= aymurai-api-full api-build: - docker compose build $(API_SERVICE) + docker compose build aymurai-api-dev api-run: - @if [ "$(API_SERVICE)" = "aymurai-api-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose run --service-ports $(API_SERVICE) -api-up: - @if [ "$(API_SERVICE)" = "aymurai-api-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose up -d $(API_SERVICE) -api-stop: - docker compose stop $(API_SERVICE) -api-logs: - docker compose logs -f $(API_SERVICE) + docker compose run --service-ports aymurai-api-dev api-pull: - docker compose pull $(API_SERVICE) + docker compose pull aymurai-api api-full-build: - docker compose build $(API_FULL_SERVICE) + docker compose build aymurai-api-full api-full-run: - @if [ "$(API_FULL_SERVICE)" = "aymurai-api-full-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose run --service-ports $(API_FULL_SERVICE) -api-full-up: - @if [ "$(API_FULL_SERVICE)" = "aymurai-api-full-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose up -d $(API_FULL_SERVICE) -api-full-stop: - docker compose stop $(API_FULL_SERVICE) -api-full-logs: - docker compose logs -f $(API_FULL_SERVICE) + docker compose run aymurai-api-full api-full-pull: - docker compose pull $(API_FULL_SERVICE) - -ollama-up: - @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose up -d --no-recreate $(OLLAMA_SERVICE) - -ollama-stop: - docker compose stop $(OLLAMA_SERVICE) - -ollama-restart: - docker compose restart $(OLLAMA_SERVICE) - -ollama-pull: -ifndef MODEL - $(error MODEL variable is required, e.g. make ollama-pull MODEL=llama3) -endif -ifndef OLLAMA_CONTAINER - $(error Ollama container '$(OLLAMA_SERVICE)' is not running. Start it first with 'make ollama-up OLLAMA_SERVICE=$(OLLAMA_SERVICE)') -endif - docker exec $(OLLAMA_SERVICE) ollama pull $(MODEL) - -ollama-run: -ifndef MODEL - $(error MODEL variable is required, e.g. make ollama-run MODEL=llama3) -endif - @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose up -d --no-recreate $(OLLAMA_SERVICE) - docker compose exec -it $(OLLAMA_SERVICE) ollama run $(MODEL) - -ollama-list: - @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose up -d --no-recreate $(OLLAMA_SERVICE) - docker compose exec $(OLLAMA_SERVICE) ollama list - -ollama-rm: -ifndef MODEL - $(error MODEL variable is required, e.g. make ollama-rm MODEL=llama3) -endif - @if [ "$(OLLAMA_SERVICE)" = "ollama-gpu" ]; then \ - docker compose stop ollama || true; \ - else \ - docker compose stop ollama-gpu || true; \ - fi - docker compose up -d --no-recreate $(OLLAMA_SERVICE) - docker compose exec $(OLLAMA_SERVICE) ollama rm $(MODEL) - -mlops-up: - docker compose up -d postgres minio minio-mc mlflow - -mlops-stop: - docker compose stop mlflow minio minio-mc postgres - -mlops-logs: - docker compose logs -f mlflow - -exp-run: -ifndef CONFIG - $(error CONFIG variable is required, e.g. make exp-run CONFIG=resources/experiments/entity-disambiguation/exp-gemma3-pv1.yaml) -endif - uv run --group mlops -- python -m aymurai.experiments.entity_disambiguation.runner --config $(CONFIG) + docker compose pull aymurai-api-full stress-test: locust -f locustfile.py --host http://localhost:8899 @@ -137,4 +27,4 @@ alembic-regenerate: rm -rvf aymurai/database/versions/* && \ cd aymurai && \ uv run alembic revision --autogenerate -m "Create database" && \ - uv run alembic upgrade head + uv run alembic upgrade head \ No newline at end of file From 8983156a02de1100ff91f662868c69a83d40d154 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 18 Feb 2026 19:40:09 -0300 Subject: [PATCH 040/104] =?UTF-8?q?=E2=8F=AA=20Revert=20aymurai/api.core.p?= =?UTF-8?q?y=20to=2019a9ca8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/api/core.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/aymurai/api/core.py b/aymurai/api/core.py index fe955b4b..c9223455 100644 --- a/aymurai/api/core.py +++ b/aymurai/api/core.py @@ -3,7 +3,6 @@ from .endpoints.routers.anonymizer import anonymizer from .endpoints.routers.anonymizer import database as anonymizer_database from .endpoints.routers.datapublic import datapublic -from .endpoints.routers.llm import summarization from .endpoints.routers.misc import convert, document_extract from .endpoints.routers.server import stats @@ -37,13 +36,6 @@ tags=["datapublic/model"], ) -# LLM -router.include_router( - summarization.router, - prefix="/llm", - tags=["llm/summarization"], -) - # Misc router.include_router(document_extract.router, tags=["document"], deprecated=True) From 8ca5420062b0a1cfd14cfac6b7bec4e77b506f7c Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 18 Feb 2026 19:59:52 -0300 Subject: [PATCH 041/104] =?UTF-8?q?=F0=9F=A6=96=20Changed=20aymurai/api/en?= =?UTF-8?q?dpoints/routers/anonymizer/anonymizer.py=20for=20release/v1.5.0?= =?UTF-8?q?=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routers/anonymizer/anonymizer.py | 63 +------------------ 1 file changed, 3 insertions(+), 60 deletions(-) diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 9d963ab1..5b3690bd 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -37,7 +37,6 @@ from aymurai.utils.entity_disambiguation import ( build_canonical_entities, get_canonical_dates, - llm_canonical_entities_inference, load_prompts_from_yaml, map_canonical_entities_ner_preds, ) @@ -466,70 +465,14 @@ async def anonymizer_disambiguate( "fuzzy clustering produced %d canonical entities", len(canonical_entities) ) - # --- LLM REFINEMENT (policy-driven) --- - canonical_entities_llm = [] - - for label in llm_labels: - logger.info("llm refinement: label=%s", label) - prompt_set = custom_prompts.get(label) or prompt_library.get(label) - - if ( - not prompt_set - or not prompt_set.system.strip() - or not prompt_set.user.strip() - ): - logger.info("llm refinement skipped: missing prompt for label=%s", label) - continue - - entities_for_this_label = [ - e for e in canonical_entities if e.aymurai_label == label - ] - - if not entities_for_this_label: - logger.info("llm refinement skipped: no entities for label=%s", label) - continue - logger.info( - "llm refinement input: label=%s entities=%d", - label, - len(entities_for_this_label), - ) - - llm_response = llm_canonical_entities_inference( - paragraphs=paragraphs, - canonical_entities_pre_cluster=entities_for_this_label, - system_prompt=prompt_set.system, - user_prompt_template=prompt_set.user, - model=settings.MODEL, - context_window_length=settings.CONTEXT_WINDOW_LENGTH, - model_context=settings.MODEL_CONTEXT, - token_limit_frac=settings.TOKEN_LIMIT_FRAC, - tokenizer_model=settings.TOKENIZER_MODEL, - target_label=label, - temperature=settings.TEMPERATURE, - decompose_by=settings.DECOMPOSE_BY, - ) - - if llm_response: - canonical_entities_llm.extend(llm_response) - logger.info( - "llm refinement output: label=%s entities=%d", - label, - len(llm_response), - ) - - canonical_entities_merged = canonical_entities_llm + [ - ce for ce in canonical_entities if ce.aymurai_label not in set(llm_labels) - ] logger.info( - "disambiguation merge: llm=%d fuzzy_only=%d total=%d", - len(canonical_entities_llm), - len(canonical_entities_merged) - len(canonical_entities_llm), - len(canonical_entities_merged), + "disambiguation merge: total=%d", + len(canonical_entities), ) predictions = map_canonical_entities_ner_preds( predictions=paragraphs, - canonical_entities=canonical_entities_merged, + canonical_entities=canonical_entities, force_labels=set(llm_labels), ) From 6933321ee723b274bb7643f67f1136d2182b1591 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 18 Feb 2026 20:09:55 -0300 Subject: [PATCH 042/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20aymurai/api/en?= =?UTF-8?q?dpoints/routers/llm=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/api/endpoints/routers/llm/__init__.py | 1 - .../endpoints/routers/llm/summarization.py | 580 ------------------ 2 files changed, 581 deletions(-) delete mode 100644 aymurai/api/endpoints/routers/llm/__init__.py delete mode 100644 aymurai/api/endpoints/routers/llm/summarization.py diff --git a/aymurai/api/endpoints/routers/llm/__init__.py b/aymurai/api/endpoints/routers/llm/__init__.py deleted file mode 100644 index 8b137891..00000000 --- a/aymurai/api/endpoints/routers/llm/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/aymurai/api/endpoints/routers/llm/summarization.py b/aymurai/api/endpoints/routers/llm/summarization.py deleted file mode 100644 index a681f594..00000000 --- a/aymurai/api/endpoints/routers/llm/summarization.py +++ /dev/null @@ -1,580 +0,0 @@ -from __future__ import annotations - -import json -from pathlib import Path -from typing import Any, AsyncIterator - -import tiktoken -from fastapi import APIRouter, HTTPException -from fastapi.responses import StreamingResponse -from pydantic import BaseModel, ConfigDict, Field - -from aymurai.llm_providers import OllamaLLMProvider -from aymurai.logger import get_logger -from aymurai.settings import settings -from aymurai.utils.yaml_data import load_yaml - -logger = get_logger(__name__) - -router = APIRouter() - -DEFAULT_MODEL = "gpt-oss:20b" -DEFAULT_OPTIONS = {"num_ctx": 16_384, "num_predict": 4096} -DEFAULT_TOKENIZER = "o200k_harmony" -PROMPT_TEMPLATE_PATH = Path(settings.RESOURCES_BASEPATH) / "llm" / "summarization.yml" - - -def _load_prompt_defaults(path: Path) -> tuple[str, str]: - """ - Load default placeholders from the YAML template, - ensuring both required fields are present. - - Args: - path: Path to the summarization YAML file. - - Returns: - tuple[str, str]: Defaults for `information_to_extract` and `entities_to_identify`. - - Raises: - FileNotFoundError: If the YAML file cannot be located. - RuntimeError: If the defaults block is missing or incomplete. - """ - content = load_yaml(str(path)) - defaults = content.get("defaults", {}) - info = (defaults.get("information-to-extract") or "").strip() - entities = (defaults.get("entities-to-identify") or "").strip() - if not info or not entities: - raise RuntimeError("summarization defaults missing in YAML") - return info, entities - - -DEFAULT_INFORMATION_TO_EXTRACT, DEFAULT_ENTITIES_TO_IDENTIFY = _load_prompt_defaults( - PROMPT_TEMPLATE_PATH -) - - -class SummarizationRequest(BaseModel): - model_config = ConfigDict( - json_schema_extra={ - "example": { - "text": "Texto de entrada a resumir.", - "model": DEFAULT_MODEL, - "tokenizer": DEFAULT_TOKENIZER, - "options": DEFAULT_OPTIONS, - } - } - ) - - text: str = Field(..., description="Raw document to summarize.") - model: str = Field( - default=DEFAULT_MODEL, - description="Model name for Ollama. Defaults to gpt-oss:20b.", - ) - tokenizer: str | None = Field( - default=DEFAULT_TOKENIZER, - description="Tokenizer name (tiktoken). Falls back to whitespace if unavailable.", - ) - system_prompt: str | None = Field( - default=None, - description="Optional system prompt override. Defaults to the template in /resources/llm/summarization.yml.", - ) - information_to_extract: str | None = Field( - default=DEFAULT_INFORMATION_TO_EXTRACT, - description="Template variable information_to_extract.", - ) - entities_to_identify: str | None = Field( - default=DEFAULT_ENTITIES_TO_IDENTIFY, - description="Template variable entities_to_identify.", - ) - options: dict[str, Any] = Field( - default_factory=lambda: DEFAULT_OPTIONS.copy(), - description="Ollama chat options. Defaults to num_ctx=16_384 and num_predict=4096.", - ) - - -class SummarizationStep(BaseModel): - chunk_index: int - input_tokens: int - source: str - - -class SummarizationResponse(BaseModel): - summary: str - model: str - system_prompt: str - options: dict[str, Any] - chunks_used: int - steps: list[SummarizationStep] - - -def _load_template_prompt( - *, - information_to_extract: str | None, - entities_to_identify: str | None, -) -> str: - """ - Load and format the summarization prompt template. - - Args: - information_to_extract: Template placeholder describing what to extract. - entities_to_identify: Template placeholder listing entities to detect. - - Returns: - str: Formatted system prompt for summarization. - - Raises: - HTTPException: If the template file is missing or cannot be parsed. - """ - path = PROMPT_TEMPLATE_PATH - try: - content = load_yaml(str(path)) - template = content["system-prompts"]["template"] - - except FileNotFoundError as exc: - logger.exception(f"Summarization prompt template not found at {path}") - raise HTTPException( - status_code=500, - detail="Summarization prompt template not found.", - ) from exc - except Exception as exc: - logger.exception("Error loading summarization prompt template.") - raise HTTPException( - status_code=500, - detail="Unable to load summarization prompt template.", - ) from exc - - info = information_to_extract or DEFAULT_INFORMATION_TO_EXTRACT - entities = entities_to_identify or DEFAULT_ENTITIES_TO_IDENTIFY - - return template.format( - information_to_extract=info, - entities_to_identify=entities, - ) - - -def _load_tokenizer(tokenizer_name: str | None) -> tiktoken.Encoding | None: - """ - Load a tiktoken tokenizer by name. - - Args: - tokenizer_name (str | None): Name of the tokenizer to load. - - Returns: - tiktoken.Encoding | None: The loaded tokenizer encoding or None if unavailable. - """ - if not tokenizer_name: - return None - - try: - return tiktoken.get_encoding(tokenizer_name) - - except Exception: - logger.warning( - f"Tokenizer {tokenizer_name} is not available. Falling back to whitespace." - ) - return None - - -def _count_tokens(text: str, tokenizer: Any) -> int: - """ - Count the number of tokens in the given text using the provided tokenizer. - - Args: - text (str): The input text to count tokens for. - tokenizer (Any): The tokenizer to use for counting tokens. - - Returns: - int: The number of tokens in the input text. - """ - if tokenizer is None: - return len(text.split()) - try: - return len(tokenizer.encode(text)) - except Exception: - return len(text.split()) - - -def _build_provider( - model_name: str, - *, - tokenizer_name: str | None, - system_prompt: str, - context_limit: int, -) -> OllamaLLMProvider: - """ - Build an Ollama provider, adjusting available context for the system prompt. - - Args: - model_name: Name of the model to use. - tokenizer_name: Tokenizer name to attempt loading. - system_prompt: System prompt to set and budget for. - context_limit: Maximum number of context tokens. - - Returns: - OllamaLLMProvider: Configured OllamaLLMProvider instance. - """ - encoding = _load_tokenizer(tokenizer_name) - available_context = max(context_limit - _count_tokens(system_prompt, encoding), 1) - - return OllamaLLMProvider( - model=model_name, - tokenizer=encoding, - system_prompt=system_prompt, - max_context_tokens=available_context, - ) - - -async def _summarize_once( - provider: OllamaLLMProvider, - *, - text: str, - options: dict[str, Any], -) -> str: - """ - Run a single summarization call on the provider. - - Args: - provider: Initialized OllamaLLMProvider instance. - text: Chunk or combined text to summarize. - options: Provider options forwarded to the model. - - Returns: - str: The model's text output for the given input. - """ - response = await provider.async_generate(prompt=text, options=options) - return response.text - - -async def _rolling_summarize( - provider: OllamaLLMProvider, - *, - text: str, - options: dict[str, Any], -) -> tuple[str, list[SummarizationStep], int]: - """ - Summarize potentially long text by chunking and rolling summaries forward. - - Args: - provider: Initialized OllamaLLMProvider instance. - text: Full document text to summarize. - options: Provider options forwarded to the model. - - Returns: - tuple[str, list[SummarizationStep], int]: A tuple of (final_summary, steps_metadata, chunk_count). - """ - chunks = provider.chunk_text(text, max_tokens=provider.max_context_tokens) - if not chunks: - return "", [], 0 - - steps = [] - summary = await _summarize_once(provider, text=chunks[0].text, options=options) - steps.append( - SummarizationStep( - chunk_index=chunks[0].index, - input_tokens=chunks[0].token_count, - source="chunk", - ) - ) - - for chunk in chunks[1:]: - combined_text = f"{summary}\n\n{chunk.text}" - combined_tokens = provider.count_tokens(combined_text) - - if ( - provider.max_context_tokens - and combined_tokens > provider.max_context_tokens - ): - chunk_summary = await _summarize_once( - provider, - text=chunk.text, - options=options, - ) - steps.append( - SummarizationStep( - chunk_index=chunk.index, - input_tokens=chunk.token_count, - source="chunk", - ) - ) - combined_text = f"{summary}\n\n{chunk_summary}" - combined_tokens = provider.count_tokens(combined_text) - - if ( - provider.max_context_tokens - and combined_tokens > provider.max_context_tokens - ): - trimmed_parts = [] - for part in provider.chunk_text( - combined_text, max_tokens=provider.max_context_tokens - ): - tentative = " ".join(trimmed_parts + [part.text]) - if ( - provider.max_context_tokens - and provider.count_tokens(tentative) - > provider.max_context_tokens - ): - break - trimmed_parts.append(part.text) - combined_text = " ".join(trimmed_parts) - combined_tokens = provider.count_tokens(combined_text) - - summary = await _summarize_once( - provider, - text=combined_text, - options=options, - ) - steps.append( - SummarizationStep( - chunk_index=chunk.index, - input_tokens=combined_tokens, - source="summary+chunk", - ) - ) - - return summary, steps, len(chunks) - - -def _build_sse_message(payload: dict[str, Any]) -> str: - """ - Format a payload as an SSE data message. - - Args: - payload: Dictionary to serialize into the SSE data field. - - Returns: - str: Serialized SSE message string. - """ - return f"data: {json.dumps(payload)}\n\n" - - -def _trim_to_context(provider: OllamaLLMProvider, text: str) -> str: - """ - Trim combined text to respect the provider's context window. - - Args: - provider: Provider with a configured max_context_tokens. - text: Concatenated summary and chunk text. - - Returns: - str: Text trimmed to fit within the context limit. - """ - if not provider.max_context_tokens: - return text - - trimmed_parts: list[str] = [] - for part in provider.chunk_text(text, max_tokens=provider.max_context_tokens): - tentative = " ".join(trimmed_parts + [part.text]) - if ( - provider.max_context_tokens - and provider.count_tokens(tentative) > provider.max_context_tokens - ): - break - trimmed_parts.append(part.text) - - return " ".join(trimmed_parts) - - -@router.post("/summarize", response_model=SummarizationResponse) -async def summarize_document(payload: SummarizationRequest) -> SummarizationResponse: - """ - Summarize a document using a local Ollama model. - - The endpoint chunks inputs above the context limit and performs a rolling - summarization that keeps the interim summary in context for subsequent chunks. - """ - if not payload.text.strip(): - raise HTTPException(status_code=400, detail="Input text cannot be empty.") - - system_prompt = payload.system_prompt or _load_template_prompt( - information_to_extract=payload.information_to_extract, - entities_to_identify=payload.entities_to_identify, - ) - model_name = payload.model or DEFAULT_MODEL - options = {**DEFAULT_OPTIONS, **(payload.options or {})} - - try: - context_limit = int(options.get("num_ctx", DEFAULT_OPTIONS["num_ctx"])) - - except (TypeError, ValueError) as exc: - raise HTTPException( - status_code=400, - detail="num_ctx option must be an integer.", - ) from exc - - if context_limit <= 0: - raise HTTPException(status_code=400, detail="num_ctx must be greater than 0.") - - provider = _build_provider( - model_name, - tokenizer_name=payload.tokenizer, - system_prompt=system_prompt, - context_limit=context_limit, - ) - - summary, steps, chunk_count = await _rolling_summarize( - provider, - text=payload.text, - options=options, - ) - - return SummarizationResponse( - summary=summary, - model=provider.model_name, - system_prompt=system_prompt, - options=options, - chunks_used=chunk_count or 1, - steps=steps, - ) - - -@router.post("/summarize/stream") -async def stream_summarize_document( - payload: SummarizationRequest, -) -> StreamingResponse: - """ - Stream a document summary using server-sent events (text/event-stream). - - Emits: - - data: {"type": "meta", ...} - - data: {"type": "token", "chunk_index": int, "source": str, "text": str} - - data: {"type": "summary", "summary": str, "chunks_used": int, "steps": [...], "model": str} - """ - if not payload.text.strip(): - raise HTTPException(status_code=400, detail="Input text cannot be empty.") - - system_prompt = payload.system_prompt or _load_template_prompt( - information_to_extract=payload.information_to_extract, - entities_to_identify=payload.entities_to_identify, - ) - model_name = payload.model or DEFAULT_MODEL - options = {**DEFAULT_OPTIONS, **(payload.options or {})} - - try: - context_limit = int(options.get("num_ctx", DEFAULT_OPTIONS["num_ctx"])) - - except (TypeError, ValueError) as exc: - raise HTTPException( - status_code=400, - detail="num_ctx option must be an integer.", - ) from exc - - if context_limit <= 0: - raise HTTPException(status_code=400, detail="num_ctx must be greater than 0.") - - provider = _build_provider( - model_name, - tokenizer_name=payload.tokenizer, - system_prompt=system_prompt, - context_limit=context_limit, - ) - - async def event_stream() -> AsyncIterator[str]: - yield _build_sse_message( - { - "type": "meta", - "model": provider.model_name, - "system_prompt": system_prompt, - "options": options, - } - ) - - chunks = provider.chunk_text( - payload.text, - max_tokens=provider.max_context_tokens, - ) - - if not chunks: - yield _build_sse_message( - { - "type": "summary", - "summary": "", - "chunks_used": 0, - "steps": [], - "model": provider.model_name, - } - ) - return - - steps: list[dict[str, Any]] = [] - summary = "" - - for chunk in chunks: - source = "chunk" if not summary else "summary+chunk" - combined_text = f"{summary}\n\n{chunk.text}" if summary else chunk.text - combined_tokens = provider.count_tokens(combined_text) - - if ( - provider.max_context_tokens - and combined_tokens > provider.max_context_tokens - and summary - ): - # Summarize the current chunk alone when the combined context would overflow. - chunk_summary = "" - async for resp in provider.async_stream( - prompt=chunk.text, - options=options, - ): - token = resp.text - if not token: - continue - chunk_summary += token - yield _build_sse_message( - { - "type": "token", - "chunk_index": chunk.index, - "source": "chunk", - "text": token, - } - ) - - steps.append( - { - "chunk_index": chunk.index, - "input_tokens": chunk.token_count, - "source": "chunk", - } - ) - - combined_text = f"{summary}\n\n{chunk_summary}" - combined_text = _trim_to_context(provider, combined_text) - source = "summary+chunk" - combined_tokens = provider.count_tokens(combined_text) - - updated_summary = "" - async for resp in provider.async_stream( - prompt=combined_text, - options=options, - ): - token = resp.text - if not token: - continue - updated_summary += token - yield _build_sse_message( - { - "type": "token", - "chunk_index": chunk.index, - "source": source, - "text": token, - } - ) - - steps.append( - { - "chunk_index": chunk.index, - "input_tokens": combined_tokens, - "source": source, - } - ) - summary = updated_summary - - yield _build_sse_message( - { - "type": "summary", - "summary": summary, - "chunks_used": len(chunks), - "steps": steps, - "model": provider.model_name, - } - ) - - return StreamingResponse(event_stream(), media_type="text/event-stream") From 3c55d8e9240f70330036a5be33708688841ce7a8 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 07:57:56 -0300 Subject: [PATCH 043/104] =?UTF-8?q?=F0=9F=A6=96=20Changed=20aymurai/api/en?= =?UTF-8?q?dpoints/routers/misc/document=5Fextract.py=20for=20release/v1.5?= =?UTF-8?q?.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🦖 Changed aymurai/text/extractors/pdf.py for release/v1.5.0 compatibility 🦖 Changed aymurai/text/extractors/utils.py for release/v1.5.0 compatibility --- .../routers/misc/document_extract.py | 27 +-- aymurai/text/extractors/pdf.py | 26 +-- aymurai/text/extractors/utils.py | 218 +++++++----------- 3 files changed, 84 insertions(+), 187 deletions(-) diff --git a/aymurai/api/endpoints/routers/misc/document_extract.py b/aymurai/api/endpoints/routers/misc/document_extract.py index 7322b07a..11354a0e 100644 --- a/aymurai/api/endpoints/routers/misc/document_extract.py +++ b/aymurai/api/endpoints/routers/misc/document_extract.py @@ -77,14 +77,7 @@ def run_safe_text_extraction( def plain_text_extractor( file: UploadFile, use_cache: bool = True, - layout_batch_size: int = 8, - detection_batch_size: int = 8, - table_rec_batch_size: int = 8, - recognition_batch_size: int = 8, - ocr_error_batch_size: int = 8, - force_ocr: bool = False, - strip_existing_ocr: bool = True, - torch_device: str | None = None, + y_tolerance: float | None = None, debug: bool | None = None, ) -> Document: """ @@ -93,14 +86,7 @@ def plain_text_extractor( Args: file (UploadFile): Incoming document upload. use_cache (bool): Whether to use caching for the extraction. Defaults to True. - layout_batch_size (int): Batch size for layout model inference. Defaults to 8. - detection_batch_size (int): Batch size for detection model inference. Defaults to 8. - table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. - recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. - ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. - force_ocr (bool): Force OCR even if text is detected. Defaults to False. - strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. - torch_device (str | None): Optional override for the torch device. Defaults to None. + y_tolerance (float | None): Optional vertical tolerance for PDF paragraph merging. Defaults to None. debug (bool | None): Optional override for marker debug mode. Defaults to None. Returns: @@ -126,14 +112,7 @@ def plain_text_extractor( document = run_safe_text_extraction( tmp_filename, use_cache=use_cache, - layout_batch_size=layout_batch_size, - detection_batch_size=detection_batch_size, - table_rec_batch_size=table_rec_batch_size, - recognition_batch_size=recognition_batch_size, - ocr_error_batch_size=ocr_error_batch_size, - force_ocr=force_ocr, - strip_existing_ocr=strip_existing_ocr, - torch_device=torch_device, + y_tolerance=y_tolerance, debug=debug, ) diff --git a/aymurai/text/extractors/pdf.py b/aymurai/text/extractors/pdf.py index c4b273c2..19cec025 100644 --- a/aymurai/text/extractors/pdf.py +++ b/aymurai/text/extractors/pdf.py @@ -16,16 +16,9 @@ class PdfExtractor(BaseExtractor): def extract( self, path: Path, + y_tolerance: float | None = None, *, use_cache: bool = True, - layout_batch_size: int = 8, - detection_batch_size: int = 8, - table_rec_batch_size: int = 8, - recognition_batch_size: int = 8, - ocr_error_batch_size: int = 8, - force_ocr: bool = False, - strip_existing_ocr: bool = True, - torch_device: str | None = None, debug: bool | None = None, ) -> str: """ @@ -34,14 +27,6 @@ def extract( Args: path (Path): Input document path. use_cache (bool): Toggle extractor-level caching. Defaults to True. - layout_batch_size (int): Batch size for layout model inference. Defaults to 8. - detection_batch_size (int): Batch size for detection model inference. Defaults to 8. - table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. - recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. - ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. - force_ocr (bool): Force OCR even if text is detected. Defaults to False. - strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. - torch_device (str | None): Optional override for the torch device. Defaults to None. debug (bool | None): Optional override for marker debug mode. Defaults to None. Returns: @@ -60,14 +45,7 @@ def extract( try: text = pdf_to_text( file_path, - layout_batch_size=layout_batch_size, - detection_batch_size=detection_batch_size, - table_rec_batch_size=table_rec_batch_size, - recognition_batch_size=recognition_batch_size, - ocr_error_batch_size=ocr_error_batch_size, - force_ocr=force_ocr, - strip_existing_ocr=strip_existing_ocr, - torch_device=torch_device, + y_tolerance=y_tolerance, debug=debug, ) except (OSError, ValueError) as exc: diff --git a/aymurai/text/extractors/utils.py b/aymurai/text/extractors/utils.py index 6a98ba30..9c449fe0 100644 --- a/aymurai/text/extractors/utils.py +++ b/aymurai/text/extractors/utils.py @@ -1,20 +1,17 @@ -import os import unicodedata import xml.etree.ElementTree as ET import zipfile -from functools import cache from pathlib import Path from typing import Any -import markdown2 import xmltodict -from bs4 import BeautifulSoup from lxml import etree -from marker.converters.pdf import PdfConverter -from marker.models import create_model_dict -from marker.renderers.markdown import MarkdownRenderer from more_itertools import flatten +import pymupdf +import statistics +import numpy as np + from aymurai.logger import get_logger from aymurai.utils.misc import get_element, get_recursively @@ -23,12 +20,11 @@ BLOCK_TAGS = {"h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "blockquote", "pre"} -MarkerPdfConfig = dict[str, int | str | bool] ODT_NS = {"text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0"} -def normalize_text(text: str) -> str: +def _normalize_text(text: str) -> str: """ Normalize Unicode output consistently across extractors. @@ -41,127 +37,87 @@ def normalize_text(text: str) -> str: return unicodedata.normalize("NFKC", text) -def markdown_to_text(md: str) -> str: +def _compute_median_margin_between_blocks(pdf_path: str) -> float: """ - Convert Markdown content to plain text by extracting relevant blocks. - + Computes the median vertical margin between text blocks in a PDF. Args: - md (str): Markdown content produced by the renderer. - + pdf_path (str): Path to the PDF file. Returns: - str: Plain text representation stripped of nested blocks. + float: Median margin between text blocks (in points). """ - html = markdown2.markdown(md, extras=["tables"]) - soup = BeautifulSoup(html, "html.parser") - - chunks: list[str] = [] - for block in soup.find_all(BLOCK_TAGS): - if block.find_parent(BLOCK_TAGS): - continue - chunks.append(block.get_text(" ", strip=True)) - - return "\n\n".join(filter(None, chunks)) - - -def _build_marker_pdf_config( - layout_batch_size: int = 8, - detection_batch_size: int = 8, - table_rec_batch_size: int = 8, - recognition_batch_size: int = 8, - ocr_error_batch_size: int = 8, - force_ocr: bool = False, - strip_existing_ocr: bool = True, - torch_device: str | None = None, - debug: bool | None = None, -) -> MarkerPdfConfig: - """ - Build marker configuration factoring in environment overrides. + margins = [] - Args: - layout_batch_size (int): Batch size for layout model inference. Defaults to 8. - detection_batch_size (int): Batch size for detection model inference. Defaults to 8. - table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. - recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. - ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. - force_ocr (bool): Force OCR even if text is detected. Defaults to False. - strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. - torch_device (str | None): Optional override for the torch device. Defaults to None. - debug (bool | None): Optional override for marker debug mode. Defaults to None. + with pymupdf.open(pdf_path) as doc: + for page in doc: + # Extract all text blocks from the page + blocks = page.get_text("blocks") - Returns: - dict[str, int | str | bool]: Effective configuration for marker-pdf. - """ - config: MarkerPdfConfig = { - "layout_batch_size": layout_batch_size, - "detection_batch_size": detection_batch_size, - "table_rec_batch_size": table_rec_batch_size, - "recognition_batch_size": recognition_batch_size, - "ocr_error_batch_size": ocr_error_batch_size, - "force_ocr": force_ocr, - "strip_existing_ocr": strip_existing_ocr, - } - - if torch_device is None: - torch_device = os.getenv("TORCH_DEVICE") - if torch_device: - config["TORCH_DEVICE"] = torch_device - - if debug is None: - log_level = os.getenv("LOG_LEVEL", "").lower() - debug = log_level == "debug" - - if debug: - config["debug"] = True - - return config - - -@cache -def get_marker_pdf_converter_and_md_renderer( - config_items: tuple[tuple[str, int | str | bool], ...], -) -> tuple[PdfConverter, MarkdownRenderer]: - """ - Provide cached marker PDF converter and Markdown renderer instances. + # Sort blocks by their top y-coordinate (y0) + blocks_sorted = sorted(blocks, key=lambda b: b[1]) - Args: - config_items (tuple[tuple[str, int | str | bool], ...]): Sorted config items - to build a stable cache key. + # Compute vertical margins between consecutive blocks + for i in range(1, len(blocks_sorted)): + previous_block = blocks_sorted[i - 1] + current_block = blocks_sorted[i] + + # Calculate the vertical margin + previous_y1 = previous_block[3] # Bottom of the previous block + current_y0 = current_block[1] # Top of the current block + margin = current_y0 - previous_y1 + + if margin > 0: # Ignore overlapping blocks + margins.append(margin) + + # Compute and return the median margin + if margins: + return statistics.median(margins) + else: + return 0.0 # Return 0 if no margins were found + +def _extract_and_merge_paragraphs(pdf_path: str, y_tolerance=5) -> list[str]: + """ + Extracts and merges paragraphs from a PDF by grouping close text blocks. + Args: + pdf_path (str): Path to the PDF file. + y_tolerance (float): Maximum vertical gap (in points) to consider blocks part of the same paragraph. Returns: - tuple[PdfConverter, MarkdownRenderer]: Ready-to-use converter and renderer. + list[str]: A list of merged paragraphs as strings. """ - pdf_converter = PdfConverter( - artifact_dict=create_model_dict(), - config=dict(config_items), - ) + paragraphs = [] + current_paragraph = [] + last_y1 = None - markdown_renderer = MarkdownRenderer( - { - "keep_pageheader_in_output": True, - "keep_pagefooter_in_output": True, - } - ) + with pymupdf.open(pdf_path) as doc: + for page in doc: + # Extract all text blocks from the page + blocks = page.get_text("blocks") + + # Sort blocks by their top y-coordinate (y0) + blocks_sorted = sorted(blocks, key=lambda b: b[1]) + + for block in blocks_sorted: + x0, y0, x1, y1, text, *_ = block - return pdf_converter, markdown_renderer + if last_y1 is not None and (y0 - last_y1) > y_tolerance: + # If the gap between blocks is too large, start a new paragraph + if current_paragraph: + paragraphs.append(" ".join(current_paragraph)) + current_paragraph = [] + current_paragraph.append(text) + last_y1 = y1 -def _marker_config_key( - config: MarkerPdfConfig, -) -> tuple[tuple[str, int | str | bool], ...]: - return tuple(sorted(config.items())) + if current_paragraph: + paragraphs.append(" ".join(current_paragraph)) + current_paragraph = [] + + return paragraphs def pdf_to_text( - file_path: Path, - *, - layout_batch_size: int = 8, - detection_batch_size: int = 8, - table_rec_batch_size: int = 8, - recognition_batch_size: int = 8, - ocr_error_batch_size: int = 8, - force_ocr: bool = False, - strip_existing_ocr: bool = True, - torch_device: str | None = None, + file_path: Path | str, + y_tolerance: float | None = None, debug: bool | None = None, ) -> str: """ @@ -169,38 +125,22 @@ def pdf_to_text( Args: file_path (Path): Path to the PDF document. - layout_batch_size (int): Batch size for layout model inference. Defaults to 8. - detection_batch_size (int): Batch size for detection model inference. Defaults to 8. - table_rec_batch_size (int): Batch size for table recognition. Defaults to 8. - recognition_batch_size (int): Batch size for OCR recognition. Defaults to 8. - ocr_error_batch_size (int): Batch size for OCR error correction. Defaults to 8. - force_ocr (bool): Force OCR even if text is detected. Defaults to False. - strip_existing_ocr (bool): Remove embedded OCR layers before re-OCR. Defaults to True. - torch_device (str | None): Optional override for the torch device. Defaults to None. + y_tolerance (float, optional): + Maximum vertical gap (in points) to consider blocks part of the same paragraph. debug (bool | None): Optional override for marker debug mode. Defaults to None. Returns: str: Cleaned textual content extracted from the PDF. """ logger.info("Extracting text from PDF: %s", file_path) - config = _build_marker_pdf_config( - layout_batch_size=layout_batch_size, - detection_batch_size=detection_batch_size, - table_rec_batch_size=table_rec_batch_size, - recognition_batch_size=recognition_batch_size, - ocr_error_batch_size=ocr_error_batch_size, - force_ocr=force_ocr, - strip_existing_ocr=strip_existing_ocr, - torch_device=torch_device, - debug=debug, - ) - pdf_converter, markdown_renderer = get_marker_pdf_converter_and_md_renderer( - _marker_config_key(config) - ) - document = pdf_converter.build_document(filepath=file_path.as_posix()) - markdown_output = markdown_renderer(document) - plain_text = markdown_to_text(markdown_output.markdown) - return normalize_text(plain_text) + + if y_tolerance is None: + y_tolerance = _compute_median_margin_between_blocks(file_path) + + paragraphs = _extract_and_merge_paragraphs(file_path, np.ceil(y_tolerance)) + docu = "\n\n".join(paragraphs) + + return _normalize_text(docu) def load_xml_from_docx(path: Path, xmlfile: str = "word/footnotes.xml") -> Any | None: From 60ba41422bd0fc923b7ee9975a31c7f92e86bf26 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 08:39:36 -0300 Subject: [PATCH 044/104] =?UTF-8?q?=E2=8F=AA=20Revert=20aymurai/api/main.p?= =?UTF-8?q?y=20to=20a801bf4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/api/main.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/aymurai/api/main.py b/aymurai/api/main.py index fbd5bdad..d814a3f6 100644 --- a/aymurai/api/main.py +++ b/aymurai/api/main.py @@ -6,15 +6,14 @@ from alembic import command from alembic.config import Config from fastapi import FastAPI, Request -from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import RedirectResponse +from fastapi.middleware.cors import CORSMiddleware from aymurai.api import core -from aymurai.api.startup.database import check_db_connection -from aymurai.api.startup.marker import warm_marker_models from aymurai.logger import get_logger -from aymurai.pipeline import AymurAIPipeline from aymurai.settings import settings +from aymurai.pipeline import AymurAIPipeline +from aymurai.api.startup.database import check_db_connection try: from aymurai.version import __version__ @@ -105,11 +104,10 @@ def healthcheck(): if __name__ == "__main__": # download the necessary data - logger.info("Loading pipelines") + logger.info("Loading pipelines and exit.") AymurAIPipeline.load( os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "flair-anonymizer") ) AymurAIPipeline.load( os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "full-paragraph") ) - warm_marker_models() From 596d3b19e06ce8cae93c74cb25d4e95fe1dc55b0 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 08:42:12 -0300 Subject: [PATCH 045/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20aymurai/api/st?= =?UTF-8?q?artup/marker.py=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/api/startup/marker.py | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 aymurai/api/startup/marker.py diff --git a/aymurai/api/startup/marker.py b/aymurai/api/startup/marker.py deleted file mode 100644 index fa40aa48..00000000 --- a/aymurai/api/startup/marker.py +++ /dev/null @@ -1,18 +0,0 @@ -from aymurai.logger import get_logger -from aymurai.text.extractors.utils import ( - _build_marker_pdf_config, - _marker_config_key, - get_marker_pdf_converter_and_md_renderer, -) - -logger = get_logger(__name__) - - -def warm_marker_models() -> None: - """Download marker-pdf artifacts at startup to avoid first-request latency.""" - try: - config = _build_marker_pdf_config() - get_marker_pdf_converter_and_md_renderer(_marker_config_key(config)) - logger.info("marker-pdf models are ready") - except Exception as exc: - logger.warning("marker-pdf warmup failed: %s", exc) From 994aca42aae80e3663dda8534730328abf186f1a Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 08:51:58 -0300 Subject: [PATCH 046/104] =?UTF-8?q?=F0=9F=94=A5=20=20aymurai/experiments/e?= =?UTF-8?q?ntity=5Fdisambiguation=20folder=20for=20release/v1.5.0=20compat?= =?UTF-8?q?ibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity_disambiguation/__init__.py | 1 - .../entity_disambiguation/config.py | 176 ------- .../entity_disambiguation/manifest.py | 51 -- .../entity_disambiguation/mlflow_logging.py | 111 ----- .../entity_disambiguation/runner.py | 468 ------------------ 5 files changed, 807 deletions(-) delete mode 100644 aymurai/experiments/entity_disambiguation/__init__.py delete mode 100644 aymurai/experiments/entity_disambiguation/config.py delete mode 100644 aymurai/experiments/entity_disambiguation/manifest.py delete mode 100644 aymurai/experiments/entity_disambiguation/mlflow_logging.py delete mode 100644 aymurai/experiments/entity_disambiguation/runner.py diff --git a/aymurai/experiments/entity_disambiguation/__init__.py b/aymurai/experiments/entity_disambiguation/__init__.py deleted file mode 100644 index 17dc9d09..00000000 --- a/aymurai/experiments/entity_disambiguation/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Entity disambiguation experiment helpers.""" diff --git a/aymurai/experiments/entity_disambiguation/config.py b/aymurai/experiments/entity_disambiguation/config.py deleted file mode 100644 index 68f54534..00000000 --- a/aymurai/experiments/entity_disambiguation/config.py +++ /dev/null @@ -1,176 +0,0 @@ -import os -from datetime import datetime, timezone -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field - -from aymurai.utils.yaml_data import load_yaml - - -class ExperimentConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - name: str - run_name: str - - -class ModelConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - provider: str - name: str - temperature: float | None = None - max_tokens: int | None = None - - -class PromptSpec(BaseModel): - model_config = ConfigDict(extra="forbid") - - id: str - text: str | None = None - - -class PromptsConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - system: PromptSpec - user: PromptSpec - - -class DataManifestConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - enabled: bool = True - mode: Literal["metadata_only"] = "metadata_only" - - -class DataConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - ground_truth_dir: str - input_dir: str - dataset_id: str | None = None - manifest: DataManifestConfig = DataManifestConfig() - - -class PredictionsConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - output_base_dir: str - dir_name_template: str - - -class MLflowConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - tracking_uri: str - experiment_name: str - - -class LoggingPrivacyConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - log_prompt_text: bool = True - log_data_manifest: bool = False - log_per_doc_scores: bool = True - - -class PerDocScoresConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - id_strategy: str = "anon_filename" - - -class LoggingConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - mlflow: MLflowConfig - privacy: LoggingPrivacyConfig = LoggingPrivacyConfig() - per_doc_scores: PerDocScoresConfig = PerDocScoresConfig() - - -class EvaluationConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - function: str = "evaluate_disambiguation" - weights: dict[str, float] = Field( - default_factory=lambda: { - "w_ent": 0.4, - "w_alias": 0.35, - "w_label": 0.2, - "w_role": 0.05, - } - ) - per_doc_scores: bool = True - sim_threshold: float | None = None - normalize: bool = True - - -class ExperimentRunConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - experiment: ExperimentConfig - model: ModelConfig - prompts: PromptsConfig - data: DataConfig - predictions: PredictionsConfig - logging: LoggingConfig - evaluation: EvaluationConfig - - -def load_experiment_config(path: str) -> ExperimentRunConfig: - """ - Load an experiment configuration from a YAML file. - - Args: - path (str): Path to the YAML configuration file. - - Raises: - ValueError: If the MLflow tracking URI is not set in the environment or configuration. - - Returns: - ExperimentRunConfig: The loaded experiment configuration. - """ - data = load_yaml(path) - tracking_uri = os.getenv("MLFLOW_TRACKING_URI") - if tracking_uri: - logging_cfg = data.setdefault("logging", {}) - mlflow_cfg = logging_cfg.setdefault("mlflow", {}) - mlflow_cfg["tracking_uri"] = tracking_uri - else: - mlflow_cfg = data.get("logging", {}).get("mlflow", {}) - if "tracking_uri" not in mlflow_cfg: - raise ValueError( - "MLFLOW_TRACKING_URI is required but was not set in the environment." - ) - return ExperimentRunConfig.model_validate(data) - - -def render_run_name( - template: str, - model_name: str, - system_id: str, - user_id: str, - *, - timestamp: str | None = None, -) -> str: - """ - Render a run name based on a template and provided identifiers. - - Args: - template (str): The template string for the run name. - model_name (str): The name of the model. - system_id (str): The system identifier. - user_id (str): The user identifier. - timestamp (str | None, optional): The timestamp string. Defaults to None. - - Returns: - str: The rendered run name. - """ - timestamp = timestamp or datetime.now(timezone.utc).strftime("%y%m%d_%H%M") - return template.format( - model=model_name, - system_id=system_id, - user_id=user_id, - timestamp=timestamp, - ) diff --git a/aymurai/experiments/entity_disambiguation/manifest.py b/aymurai/experiments/entity_disambiguation/manifest.py deleted file mode 100644 index 2e2c37fa..00000000 --- a/aymurai/experiments/entity_disambiguation/manifest.py +++ /dev/null @@ -1,51 +0,0 @@ -import hashlib -import json -from dataclasses import dataclass -from pathlib import Path - - -@dataclass(frozen=True) -class DatasetInfo: - dataset_hash: str - dataset_count: int - dataset_bytes_total: int - manifest: dict | None = None - - -def build_metadata_manifest(root_dir: Path) -> DatasetInfo: - """ - Build a metadata manifest for the dataset located at the given root directory. - - Args: - root_dir (Path): The root directory of the dataset. - - Returns: - DatasetInfo: An object containing dataset hash, count, total bytes, and manifest. - """ - files = [] - total_bytes = 0 - - for path in sorted(root_dir.rglob("*")): - if not path.is_file(): - continue - stat = path.stat() - rel_path = path.relative_to(root_dir).as_posix() - files.append( - { - "path": rel_path, - "size_bytes": stat.st_size, - "mtime": int(stat.st_mtime), - } - ) - total_bytes += stat.st_size - - manifest = {"files": files, "summary": {"count": len(files), "bytes": total_bytes}} - manifest_bytes = json.dumps(files, sort_keys=True).encode("utf-8") - dataset_hash = hashlib.sha256(manifest_bytes).hexdigest() - - return DatasetInfo( - dataset_hash=dataset_hash, - dataset_count=len(files), - dataset_bytes_total=total_bytes, - manifest=manifest, - ) diff --git a/aymurai/experiments/entity_disambiguation/mlflow_logging.py b/aymurai/experiments/entity_disambiguation/mlflow_logging.py deleted file mode 100644 index b9e0a799..00000000 --- a/aymurai/experiments/entity_disambiguation/mlflow_logging.py +++ /dev/null @@ -1,111 +0,0 @@ -import json -import tempfile -from pathlib import Path - -import mlflow - -from aymurai.experiments.entity_disambiguation.config import ExperimentRunConfig -from aymurai.experiments.entity_disambiguation.manifest import DatasetInfo -from aymurai.utils.yaml_data import save_yaml - - -def configure_mlflow(config: ExperimentRunConfig) -> None: - """ - Configure MLflow tracking URI and experiment name. - - Args: - config (ExperimentRunConfig): Experiment run configuration. - """ - mlflow.set_tracking_uri(config.logging.mlflow.tracking_uri) - mlflow.set_experiment(config.logging.mlflow.experiment_name) - - -def log_run_metadata( - config: ExperimentRunConfig, - *, - run_name: str | None = None, - preds_dir_name: str | None = None, - dataset_info: DatasetInfo | None = None, - metrics: dict[str, float] | None = None, - per_doc_scores: dict[str, object] | None = None, -) -> None: - """ - Log run metadata to MLflow. - - Args: - config (ExperimentRunConfig): Experiment run configuration. - run_name (str | None, optional): Run name. Defaults to None. - preds_dir_name (str | None, optional): Predictions directory name. Defaults to None. - dataset_info (DatasetInfo | None, optional): Dataset information. Defaults to None. - metrics (dict[str, float] | None, optional): Metrics to log. Defaults to None. - per_doc_scores (dict[str, object] | None, optional): Per-document scores to log. Defaults to None. - """ - params = { - "model_provider": config.model.provider, - "model_name": config.model.name, - "system_prompt_id": config.prompts.system.id, - "user_prompt_id": config.prompts.user.id, - "preds_dir_template": config.predictions.dir_name_template, - } - if run_name: - params["run_name"] = run_name - if preds_dir_name: - params["preds_dir_name"] = preds_dir_name - if config.model.temperature is not None: - params["temperature"] = config.model.temperature - if config.model.max_tokens is not None: - params["max_tokens"] = config.model.max_tokens - if config.data.dataset_id: - params["dataset_id"] = config.data.dataset_id - - if dataset_info: - params.update( - { - "dataset_hash": dataset_info.dataset_hash, - "dataset_count": dataset_info.dataset_count, - "dataset_bytes_total": dataset_info.dataset_bytes_total, - } - ) - - mlflow.log_params(params) - - if metrics: - mlflow.log_metrics(metrics) - - with tempfile.TemporaryDirectory() as tmp_dir: - tmp_path = Path(tmp_dir) - config_payload = config.model_dump(mode="json") - if not config.logging.privacy.log_prompt_text: - config_payload["prompts"]["system"]["text"] = "" - config_payload["prompts"]["user"]["text"] = "" - config_path = tmp_path / "config.yaml" - save_yaml(config_payload, str(config_path)) - mlflow.log_artifact(str(config_path), artifact_path="config") - - if config.logging.privacy.log_prompt_text: - system_path = tmp_path / "system_prompt.txt" - user_path = tmp_path / "user_prompt.txt" - system_path.write_text(config.prompts.system.text or "", encoding="utf-8") - user_path.write_text(config.prompts.user.text or "", encoding="utf-8") - mlflow.log_artifact(str(system_path), artifact_path="prompts") - mlflow.log_artifact(str(user_path), artifact_path="prompts") - - if ( - config.logging.privacy.log_data_manifest - and dataset_info - and dataset_info.manifest - ): - manifest_path = tmp_path / "manifest.json" - manifest_path.write_text( - json.dumps(dataset_info.manifest, indent=2, sort_keys=True), - encoding="utf-8", - ) - mlflow.log_artifact(str(manifest_path), artifact_path="data") - - if config.logging.privacy.log_per_doc_scores and per_doc_scores: - scores_path = tmp_path / "per_doc_scores.json" - scores_path.write_text( - json.dumps(per_doc_scores, indent=2, sort_keys=True), - encoding="utf-8", - ) - mlflow.log_artifact(str(scores_path), artifact_path="metrics") diff --git a/aymurai/experiments/entity_disambiguation/runner.py b/aymurai/experiments/entity_disambiguation/runner.py deleted file mode 100644 index 2cc372ce..00000000 --- a/aymurai/experiments/entity_disambiguation/runner.py +++ /dev/null @@ -1,468 +0,0 @@ -import argparse -import json -import mimetypes -import os -import re -import time -from pathlib import Path -from typing import Any, Iterable - -import mlflow -import requests -from more_itertools import unique_everseen -from tqdm import tqdm - -from aymurai.evaluation.metrics import evaluate_disambiguation -from aymurai.experiments.entity_disambiguation.config import ( - load_experiment_config, - render_run_name, -) -from aymurai.experiments.entity_disambiguation.manifest import build_metadata_manifest -from aymurai.experiments.entity_disambiguation.mlflow_logging import ( - configure_mlflow, - log_run_metadata, -) -from aymurai.llm_providers import OllamaLLMProvider -from aymurai.logger import get_logger -from aymurai.meta.entities import CanonicalEntities, CanonicalEntity -from aymurai.utils.json_data import get_pretty, load_json, save_json -from aymurai.utils.paths import prediction_filename_for_test, test_id_from_filename - -logger = get_logger(__name__) - -DOC_EXTENSIONS = {".pdf", ".docx"} - - -def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]: - """ - Discover documents in a directory with given extensions. - - Args: - root (Path): Root directory to search for documents. - extensions (Iterable[str]): File extensions to include. - - Returns: - list[Path]: List of discovered document paths with the specified extensions. - """ - extensions = {ext.lower() for ext in extensions} - return sorted( - path - for path in root.rglob("*") - if path.is_file() and path.suffix.lower() in extensions - ) - - -def call_extraction_api( - session: requests.Session, endpoint: str, file_path: Path, timeout_s: float -) -> dict[str, object]: - """ - Call the extraction API with a document file. - - Args: - session (requests.Session): HTTP session for making requests. - endpoint (str): URL of the extraction API endpoint. - file_path (Path): Path to the document file to be processed. - timeout_s (float): Request timeout in seconds. - - Returns: - dict[str, object]: Payload containing the response details. - """ - payload: dict[str, object] = { - "path": str(file_path), - "status": "failure", - "status_code": None, - "elapsed_s": None, - "detail": None, - } - - if not file_path.exists(): - payload["detail"] = "File does not exist" - return payload - - mime_type = mimetypes.guess_type(file_path.name)[0] or "application/octet-stream" - files = { - "file": (file_path.name, file_path.open("rb"), mime_type), - } - - try: - start = time.perf_counter() - response = session.post( - endpoint, - files=files, - timeout=timeout_s, - ) - elapsed = time.perf_counter() - start - except requests.RequestException as exc: - payload["detail"] = f"Request failed: {exc}" - return payload - finally: - files["file"][1].close() - - payload["status_code"] = response.status_code - payload["elapsed_s"] = elapsed - - try: - response_body = response.json() - except ValueError: - response_body = {"raw": response.text[:500]} - - if response.ok: - payload["status"] = "success" - payload["detail"] = { - "document_id": response_body.get("document_id"), - "document": response_body.get("document", []), - } - else: - payload["detail"] = response_body - - return payload - - -def get_predictions( - session: requests.Session, endpoint: str, sample: str, timeout_s: float -) -> dict: - """ - Get predictions from the prediction API for a given text sample. - - Args: - session (requests.Session): HTTP session for making requests. - endpoint (str): URL of the prediction API endpoint. - sample (str): Text sample to be predicted. - timeout_s (float): Request timeout in seconds. - - Returns: - dict: Prediction response as a dictionary. - """ - response = session.post(url=endpoint, json={"text": sample}, timeout=timeout_s) - response.raise_for_status() - return response.json() - - -def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]: - """ - Parse prediction labels to extract unique aymurai labels and their alternative texts. - - Args: - predictions (list[dict[str, Any]]): List of prediction dictionaries. - - Returns: - list[dict[str, str]]: List of dictionaries containing unique aymurai labels and their alternative texts. - """ - attrs_stream = ( - label.get("attrs") or {} - for label in (label for pred in predictions for label in pred.get("labels", ())) - ) - - unique_pairs = unique_everseen( - ( - attrs.get("aymurai_label"), - attrs.get("aymurai_alt_text"), - ) - for attrs in attrs_stream - if attrs.get("aymurai_label") and attrs.get("aymurai_alt_text") - ) - - return sorted( - ({"aymurai_label": label, "text": text} for label, text in unique_pairs), - key=lambda item: (item["aymurai_label"], item["text"]), - ) - - -def sanitize_filename(path: Path) -> str: - """ - Sanitize a filename by replacing spaces and underscores with hyphens and collapsing multiple hyphens. - - Args: - path (Path): Path object representing the file. - - Returns: - str: Sanitized filename as a string. - """ - base = os.path.splitext(path.name)[0] - target = re.sub(r"\s+|_", "-", base) - target = re.sub(r"-{2,}", "-", target) - return target - - -def extract_canonical_entities( - *, - session: requests.Session, - doc_path: Path, - extract_endpoint: str, - predict_endpoint: str, - timeout_s: float, - model_name: str, - system_prompt: str, - user_prompt_template: str, - temperature: float | None, - max_tokens: int | None, -) -> list[CanonicalEntity]: - """ - Extract canonical entities from a document using extraction and prediction APIs. - - Args: - session (requests.Session): HTTP session for making requests. - doc_path (Path): Path to the document file. - extract_endpoint (str): URL of the extraction API endpoint. - predict_endpoint (str): URL of the prediction API endpoint. - timeout_s (float): Request timeout in seconds. - model_name (str): Name of the LLM model to use. - system_prompt (str): System prompt text. - user_prompt_template (str): User prompt template text. - temperature (float | None): Temperature setting for the LLM. - max_tokens (int | None): Maximum tokens setting for the LLM. - - Raises: - ValueError: If the document text is empty or not found. - - Returns: - list[CanonicalEntity]: List of extracted canonical entities. - """ - document_payload = call_extraction_api( - session, - extract_endpoint, - doc_path, - timeout_s, - ) - document = document_payload.get("detail", {}).get("document") - - if not document: - raise ValueError("Document text is empty or not found.") - - ner_predictions = [ - get_predictions(session, predict_endpoint, paragraph, timeout_s) - for paragraph in tqdm(document, desc=f"NER {doc_path.name}") - ] - parsed_ner_labels = parse_prediction_labels(ner_predictions) - ner_output_json = get_pretty(parsed_ner_labels) - - user_prompt = user_prompt_template.format( - document_text="\n".join(document).strip(), - ner_output_json=ner_output_json, - ) - - provider = OllamaLLMProvider(model=model_name) - options: dict[str, object] = {} - if temperature is not None: - options["temperature"] = temperature - if max_tokens is not None: - options["num_predict"] = max_tokens - - generate_kwargs: dict[str, object] = { - "messages": [ - {"role": "system", "content": system_prompt}, - {"role": "user", "content": user_prompt}, - ], - "format": CanonicalEntities.model_json_schema(), - } - if options: - generate_kwargs["options"] = options - - response = provider.generate(**generate_kwargs) - - payload = json.loads(response.text) - canonical_entities = [ - CanonicalEntity.model_validate(output) - for output in payload.get("canonical_entities", []) - ] - - return canonical_entities - - -def run_experiment(config_path: str) -> None: - """ - Run the entity disambiguation experiment based on the provided configuration. - - Args: - config_path (str): Path to the experiment configuration file. - - Raises: - FileNotFoundError: If the input directory is not found. - FileNotFoundError: If the ground truth directory is not found. - RuntimeError: If no documents are found in the input directory. - ValueError: If there is an error in processing the documents. - """ - config = load_experiment_config(config_path) - - input_dir = Path(config.data.input_dir) - ground_truth_dir = Path(config.data.ground_truth_dir) - - if not input_dir.exists(): - raise FileNotFoundError(f"Input directory not found: {input_dir}") - if not ground_truth_dir.exists(): - raise FileNotFoundError(f"Ground truth directory not found: {ground_truth_dir}") - - documents = discover_documents(input_dir, DOC_EXTENSIONS) - if not documents: - raise RuntimeError(f"No documents found under {input_dir}") - - timestamp = time.strftime("%y%m%d_%H%M") - run_name = render_run_name( - config.experiment.run_name, - config.model.name, - config.prompts.system.id, - config.prompts.user.id, - timestamp=timestamp, - ) - preds_dir_name = render_run_name( - config.predictions.dir_name_template, - config.model.name, - config.prompts.system.id, - config.prompts.user.id, - timestamp=timestamp, - ) - output_dir = Path(config.predictions.output_base_dir) / preds_dir_name - output_dir.mkdir(parents=True, exist_ok=False) - - dataset_info = ( - build_metadata_manifest(ground_truth_dir) - if config.data.manifest.enabled - else None - ) - - api_base_url = os.getenv("API_BASE_URL", "http://localhost:8899") - extract_endpoint = f"{api_base_url}/misc/document-extract" - predict_endpoint = f"{api_base_url}/anonymizer/predict" - timeout_s = float(os.getenv("REQUEST_TIMEOUT", "30")) - - logger.info(f"Processing {len(documents)} documents from {input_dir}") - logger.info(f"Predictions will be stored in {output_dir}") - - configure_mlflow(config) - - per_doc_scores: dict[str, object] = {} - metrics_summary: dict[str, float] = {} - - with mlflow.start_run(run_name=run_name): - session = requests.Session() - - processed = 0 - failed = 0 - - for doc_path in documents: - logger.info(f"Processing document: {doc_path.name}") - try: - canonical_entities = extract_canonical_entities( - session=session, - doc_path=doc_path, - extract_endpoint=extract_endpoint, - predict_endpoint=predict_endpoint, - timeout_s=timeout_s, - model_name=config.model.name, - system_prompt=config.prompts.system.text or "", - user_prompt_template=config.prompts.user.text or "", - temperature=config.model.temperature, - max_tokens=config.model.max_tokens, - ) - target_filename = sanitize_filename(doc_path) - target_path = output_dir / f"{target_filename}.json" - save_json( - [ - entity.model_dump() - | { - "entity_id": entity.entity_id.hex - if entity.entity_id - else None - } - for entity in canonical_entities - ], - str(target_path), - ) - processed += 1 - except Exception as exc: - failed += 1 - logger.warning(f"Error processing {doc_path.name}: {exc}") - - if config.evaluation.function != "evaluate_disambiguation": - raise ValueError( - f"Unsupported evaluation function: {config.evaluation.function}" - ) - - results = [] - if output_dir.exists(): - for test_path in sorted(ground_truth_dir.glob("*.json")): - doc_id = test_id_from_filename(test_path) - pred_path = output_dir / prediction_filename_for_test(test_path) - - if not pred_path.exists(): - logger.warning( - f"Prediction for {test_path.name} was not found; skipping." - ) - continue - - gold_data = load_json(str(test_path)) - pred_data = load_json(str(pred_path)) - - score, metrics = evaluate_disambiguation( - gold_data, - pred_data, - w_ent=config.evaluation.weights.get("w_ent", 0.4), - w_alias=config.evaluation.weights.get("w_alias", 0.35), - w_label=config.evaluation.weights.get("w_label", 0.2), - w_role=config.evaluation.weights.get("w_role", 0.05), - sim_threshold=config.evaluation.sim_threshold or 0.3, - normalize=config.evaluation.normalize, - ) - results.append((doc_id, score, metrics)) - - average = ( - sum(score for _, score, _ in results) / len(results) - if results - else float("nan") - ) - - if results: - metrics_summary["score_avg"] = average - metrics_summary["doc_count"] = float(len(results)) - - metric_names = set(results[0][2].keys()) - for metric_name in metric_names: - metrics_summary[f"{metric_name}_avg"] = sum( - metrics.get(metric_name, 0.0) for _, _, metrics in results - ) / len(results) - - for doc_id, score, metrics in results: - per_doc_scores[doc_id] = {"score": score, **metrics} - - metrics_summary["docs_processed"] = float(processed) - metrics_summary["docs_failed"] = float(failed) - - log_run_metadata( - config, - run_name=run_name, - preds_dir_name=preds_dir_name, - dataset_info=dataset_info, - metrics=metrics_summary if metrics_summary else None, - per_doc_scores=per_doc_scores if per_doc_scores else None, - ) - - -def build_arg_parser() -> argparse.ArgumentParser: - """ - Build the argument parser for the entity disambiguation experiment. - - Returns: - argparse.ArgumentParser: The configured argument parser. - """ - parser = argparse.ArgumentParser( - description="Run entity disambiguation experiment from a YAML config.", - ) - parser.add_argument( - "--config", - required=True, - help="Path to the experiment YAML config.", - ) - return parser - - -def main() -> None: - """ - Main entry point for the entity disambiguation experiment script. - Parses command-line arguments and runs the experiment. - """ - args = build_arg_parser().parse_args() - run_experiment(args.config) - - -if __name__ == "__main__": - main() From 55de08685d1f497b7a32deed4b5867ed8ee3273c Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 08:54:33 -0300 Subject: [PATCH 047/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20aymurai/llm=5F?= =?UTF-8?q?providers=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/llm_providers/__init__.py | 9 - aymurai/llm_providers/ollama_provider.py | 254 ---------------------- aymurai/llm_providers/provider.py | 256 ----------------------- 3 files changed, 519 deletions(-) delete mode 100644 aymurai/llm_providers/__init__.py delete mode 100644 aymurai/llm_providers/ollama_provider.py delete mode 100644 aymurai/llm_providers/provider.py diff --git a/aymurai/llm_providers/__init__.py b/aymurai/llm_providers/__init__.py deleted file mode 100644 index c63aaaac..00000000 --- a/aymurai/llm_providers/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from aymurai.llm_providers.ollama_provider import OllamaLLMProvider -from aymurai.llm_providers.provider import DocumentChunk, LLMProvider, LLMResponse - -__all__ = [ - "DocumentChunk", - "LLMProvider", - "LLMResponse", - "OllamaLLMProvider", -] diff --git a/aymurai/llm_providers/ollama_provider.py b/aymurai/llm_providers/ollama_provider.py deleted file mode 100644 index b3e9ef80..00000000 --- a/aymurai/llm_providers/ollama_provider.py +++ /dev/null @@ -1,254 +0,0 @@ -from __future__ import annotations - -from typing import Any, AsyncIterator, Iterator - -import ollama -from ollama import AsyncClient - -from aymurai.llm_providers.provider import LLMProvider, LLMResponse - - -class OllamaLLMProvider(LLMProvider): - """Adapter that wraps `ollama.chat` preserving the common interface.""" - - def __init__( - self, - model: str, - *, - system_prompt: str | None = None, - keep_alive: int | str | None = None, - **kwargs, - ) -> None: - super().__init__(model=model, **kwargs) - self.system_prompt = system_prompt - self.keep_alive = keep_alive - - def generate( - self, - prompt: str | None = None, - *, - messages: list[dict[str, str]] | None = None, - **kwargs, - ) -> LLMResponse: - """ - Generate text using the configured Ollama model. - - Args: - prompt (str | None, optional): Optional single prompt string to be transformed into a chat message. Defaults to None. - messages (list[dict[str, str]] | None, optional): Optional list of pre-formatted chat messages to send. Defaults to None. - - Returns: - LLMResponse: Response containing the generated text, metadata about the request, and the raw payload. - """ - # Build the message payload - payload = self._build_messages(prompt=prompt, messages=messages) - - # Call ollama.chat - response = ollama.chat( - model=self.model_name, - messages=payload, - keep_alive=self.keep_alive, - **kwargs, - ) - - return self._build_llm_response( - response, - extra_metadata={ - "eval_count": response.get("eval_count"), - "eval_duration": response.get("eval_duration"), - }, - ) - - async def async_generate( - self, - prompt: str | None = None, - *, - messages: list[dict[str, str]] | None = None, - **kwargs, - ) -> LLMResponse: - """ - Asynchronously generate text using the configured Ollama model. - - Args: - prompt (str | None): Optional single prompt string to be transformed into a chat message. Defaults to None. - messages (list[dict[str, str]] | None): Optional list of pre-formatted chat messages to send. Defaults to None. - **kwargs: Additional keyword arguments forwarded to the Ollama AsyncClient chat endpoint. - - Returns: - LLMResponse: Response containing the generated text, metadata about the request, and the raw payload. - """ - # Build the message payload - payload = self._build_messages(prompt=prompt, messages=messages) - - # Call ollama.chat asynchronously - client = self._get_async_client() - response = await client.chat( - model=self.model_name, - messages=payload, - keep_alive=self.keep_alive, - **kwargs, - ) - - return self._build_llm_response( - response, - extra_metadata={ - "eval_count": response.get("eval_count"), - "eval_duration": response.get("eval_duration"), - }, - ) - - def stream( - self, - prompt: str | None = None, - *, - messages: list[dict[str, str]] | None = None, - **kwargs, - ) -> Iterator[LLMResponse]: - """ - Stream the response from the model using the provided prompt or messages. - - Args: - prompt (str | None, optional): Optional single prompt string to be transformed into a chat message. Defaults to None. - messages (list[dict[str, str]] | None, optional): Optional list of pre-formatted chat messages to send. Defaults to None. - - Yields: - Iterator[LLMResponse]: Response chunks containing generated text, metadata, and raw payloads. - """ - # Build the message payload - payload = self._build_messages(prompt=prompt, messages=messages) - - # Call ollama.chat with streaming enabled - stream_kwargs = {**kwargs, "stream": True} - - # Iterate over the streamed responses - for chunk in ollama.chat( - model=self.model_name, - messages=payload, - keep_alive=self.keep_alive, - **stream_kwargs, - ): - yield self._build_stream_response(chunk) - - async def async_stream( - self, - prompt: str | None = None, - *, - messages: list[dict[str, str]] | None = None, - **kwargs, - ) -> AsyncIterator[LLMResponse]: - """ - Asynchronously stream the response from the model using the provided prompt or messages. - - Args: - prompt (str | None, optional): Optional single prompt string to be transformed into a chat message. Defaults to None. - messages (list[dict[str, str]] | None, optional): Optional list of pre-formatted chat messages to send. Defaults to None. - - Yields: - AsyncIterator[LLMResponse]: Asynchronous iterator yielding response chunks containing generated text, metadata, and raw payloads. - """ - # Build the message payload - payload = self._build_messages(prompt=prompt, messages=messages) - - # Call ollama.chat with streaming enabled - stream_kwargs = {**kwargs, "stream": True} - - # Iterate over the streamed responses asynchronously - client = self._get_async_client() - stream = await client.chat( - model=self.model_name, - messages=payload, - keep_alive=self.keep_alive, - **stream_kwargs, - ) - async for chunk in stream: - yield self._build_stream_response(chunk) - - def _build_messages( - self, - *, - prompt: str | None, - messages: list[dict[str, str]] | None = None, - ) -> list[dict[str, str]]: - """ - Build the message payload for `ollama.chat`. - - Args: - prompt (str | None): The user prompt to be sent to the model. - messages (list[dict[str, str]] | None, optional): A list of message dictionaries to be sent to the model. - Defaults to None. - - Raises: - ValueError: If neither prompt nor messages are provided. - - Returns: - list[dict[str, str]]: The message payload to be sent to `ollama.chat`. - """ - if messages is not None: - return list(messages) - - if prompt is None: - raise ValueError("Either prompt or messages must be provided.") - - payload = [] - - if self.system_prompt: - payload.append({"role": "system", "content": self.system_prompt}) - - payload.append({"role": "user", "content": prompt}) - - return payload - - def _get_async_client(self) -> AsyncClient: - """ - Create a fresh AsyncClient instance. - - Returns: - AsyncClient: A new AsyncClient instance for making asynchronous requests. - """ - return AsyncClient() - - def _build_llm_response( - self, response: dict[str, Any], *, extra_metadata: dict[str, Any] | None = None - ) -> LLMResponse: - """ - Build an LLMResponse with consistent metadata from the response payload. - - Args: - response (dict[str, Any]): The response payload from the Ollama model. - extra_metadata (dict[str, Any] | None, optional): Additional metadata to include in the response. Defaults to None. - - Returns: - LLMResponse: The constructed LLMResponse object containing text, metadata, and raw response. - """ - # Extract the generated text - text = response.get("message", {}).get("content", "") - - # Build metadata - metadata = { - "model": self.model_name, - "provider": "ollama", - } - - # Include any extra metadata - if extra_metadata: - metadata.update(extra_metadata) - - return LLMResponse(text=text, metadata=metadata, raw=response) - - def _build_stream_response(self, chunk: dict[str, Any]) -> LLMResponse: - """ - Build stream responses with consistent metadata from chunk payloads. - - Args: - chunk (dict[str, Any]): The chunk payload from the Ollama model. - - Returns: - LLMResponse: The constructed LLMResponse object containing text, metadata, and raw chunk. - """ - return self._build_llm_response( - chunk, - extra_metadata={"done": chunk.get("done")}, - ) - - -__all__ = ["OllamaLLMProvider"] diff --git a/aymurai/llm_providers/provider.py b/aymurai/llm_providers/provider.py deleted file mode 100644 index 89e3750d..00000000 --- a/aymurai/llm_providers/provider.py +++ /dev/null @@ -1,256 +0,0 @@ -from __future__ import annotations - -import abc -from typing import Any, Sequence - -from pydantic import BaseModel, Field - - -class LLMResponse(BaseModel): - """Standard response wrapper for any LLM provider.""" - - text: str - metadata: dict[str, Any] = Field(default_factory=dict) - raw: Any | None = None - - -class DocumentChunk(BaseModel): - """Represents a chunked portion of a larger document.""" - - text: str - token_count: int - index: int - - -TokenizerType = Any - - -class LLMProvider(abc.ABC): - """Base class with shared utilities for concrete LLM providers.""" - - def __init__( - self, - model: str, - *, - tokenizer: TokenizerType | None = None, - max_context_tokens: int | None = None, - chunk_overlap: int = 0, - ) -> None: - self.model_name = model - self._tokenizer = tokenizer - self.max_context_tokens = max_context_tokens - self.chunk_overlap = max(chunk_overlap, 0) - - @abc.abstractmethod - def generate(self, prompt: str, **kwargs) -> LLMResponse: - """ - Generate a response from the model using the provided prompt. - - Args: - prompt (str): The input prompt to generate a response for. - **kwargs: Additional provider-specific parameters. - - Returns: - LLMResponse: The generated response wrapped in an LLMResponse object. - """ - pass - - @abc.abstractmethod - def stream(self, prompt: str, **kwargs): - """ - Stream the response from the model using the provided prompt. - - Args: - prompt (str): The input prompt to generate a response for. - **kwargs: Additional provider-specific parameters. - - Raises: - NotImplementedError: If the provider does not support streaming. - """ - raise NotImplementedError("This provider does not support streaming.") - - def count_tokens(self, text: str) -> int: - """ - Count the number of tokens in the given text. - - Args: - text (str): The input text to count tokens for. - - Returns: - int: The number of tokens in the input text. - """ - tokens = self._tokenize(text) - return len(tokens) - - def chunk_text( - self, - text: str, - *, - max_tokens: int | None = None, - overlap: int | None = None, - ) -> list[DocumentChunk]: - """ - Chunk text ensuring every piece respects the token budget. - - Args: - text (str): The input text to chunk. - max_tokens (int | None): Optional maximum tokens per chunk. - overlap (int | None): Optional token overlap between chunks. - - Returns: - list[DocumentChunk]: A list of document chunks. - """ - cleaned_text = text.strip() - if not cleaned_text: - return [] - - limit = max_tokens or self.max_context_tokens - if limit is None: - total_tokens = self.count_tokens(cleaned_text) - return [DocumentChunk(text=cleaned_text, token_count=total_tokens, index=0)] - - words = cleaned_text.split() - if not words: - return [] - - chunks = [] - overlap_tokens = overlap if overlap is not None else self.chunk_overlap - current_words = [] - current_tokens = 0 - - for word in words: - if not current_words: - current_words = [word] - current_tokens = self.count_tokens(" ".join(current_words)) - if current_tokens > limit: - self._append_chunk( - chunks=chunks, - text=current_words[0], - token_count=current_tokens, - ) - current_words = [] - current_tokens = 0 - continue - - tentative_words = current_words + [word] - tentative_text = " ".join(tentative_words) - tentative_tokens = self.count_tokens(tentative_text) - - if tentative_tokens <= limit: - current_words = tentative_words - current_tokens = tentative_tokens - continue - - chunk_text = " ".join(current_words) - self._append_chunk( - chunks=chunks, - text=chunk_text, - token_count=current_tokens, - ) - - carry_over = self._overlap_tail(current_words, overlap_tokens) - current_words = carry_over + [word] - current_tokens = self.count_tokens(" ".join(current_words)) - - if current_tokens > limit: - chunk_text = " ".join(current_words) - self._append_chunk( - chunks=chunks, - text=chunk_text, - token_count=current_tokens, - ) - current_words = [] - current_tokens = 0 - - if current_words: - chunk_text = " ".join(current_words) - self._append_chunk( - chunks=chunks, - text=chunk_text, - token_count=current_tokens, - fallback_count=True, - ) - - return chunks - - def _tokenize(self, text: str) -> Sequence[Any]: - """ - Tokenize text using the configured tokenizer or fallback to whitespace. - - Args: - text (str): The input text to tokenize. - - Returns: - Sequence[Any]: The sequence of tokens. - """ - if self._tokenizer is None: - return text.split() - - tokenizer = self._tokenizer - if hasattr(tokenizer, "encode"): - return tokenizer.encode(text) - - if callable(tokenizer): - tokens = tokenizer(text) - if isinstance(tokens, dict): - return tokens.get("input_ids", []) - return tokens - - return text.split() - - def _overlap_tail(self, words: list[str], overlap_tokens: int) -> list[str]: - """ - Get the tail overlap of words based on the token budget. - - Args: - words (list[str]): The list of words to consider for overlap. - overlap_tokens (int): The token budget for the overlap. Must be non-negative. - - Returns: - list[str]: The list of words representing the tail overlap. - """ - assert overlap_tokens >= 0, "`overlap_tokens` must be non-negative." - - if not words or overlap_tokens == 0: - return [] - - tail = [] - - for word in reversed(words): - tail.insert(0, word) - token_budget = self.count_tokens(" ".join(tail)) - if token_budget >= overlap_tokens: - break - - return tail - - def _append_chunk( - self, - *, - chunks: list[DocumentChunk], - text: str, - token_count: int, - fallback_count: bool = False, - ) -> None: - """ - Append a chunk with consistent indexing, optionally recomputing token count if missing. - - Args: - chunks (list[DocumentChunk]): Accumulated chunk list. - text (str): Chunk text. - token_count (int): Token count for the chunk. - fallback_count (bool): Recompute token count when provided count is falsy. Defaults to False. - """ - count = token_count or ( - self.count_tokens(text) if fallback_count else token_count - ) - chunks.append( - DocumentChunk( - text=text, - token_count=count, - index=len(chunks), - ) - ) - - -__all__ = ["DocumentChunk", "LLMProvider", "LLMResponse"] From 0c478a905ebef556e424efec7aa1bd298e6913c4 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 09:04:30 -0300 Subject: [PATCH 048/104] =?UTF-8?q?=F0=9F=A6=96=20Changed=20aymurai/settin?= =?UTF-8?q?gs.py=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/settings.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/aymurai/settings.py b/aymurai/settings.py index 85fe08e4..51036fe8 100644 --- a/aymurai/settings.py +++ b/aymurai/settings.py @@ -67,15 +67,6 @@ def assemble_cors_origins(cls, v) -> list[str]: # Fuzzy Matching THRESHOLD: int = 70 - # LLM - MODEL: str = "phi4:14b" - MODEL_CONTEXT: int = 9500 - TEMPERATURE: float = 0.0 - CONTEXT_WINDOW_LENGTH: int | None = 120 - TOKEN_LIMIT_FRAC: float = 2 / 3 - TOKENIZER_MODEL: str = "microsoft/phi-4" - DECOMPOSE_BY: int | None = None - # Label policies (JSON dict: label -> {disambiguation, anonymize}) DISAMBIGUATION_LABEL_POLICIES: dict | None = None From 0990214341968f1929d3402f6ff1070c3566eb64 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 15:47:35 -0300 Subject: [PATCH 049/104] =?UTF-8?q?=F0=9F=A6=96=20Changed=20aymurai/api/en?= =?UTF-8?q?dpoints/routers/anonymizer/anonymizer.py=20for=20release/v1.5.0?= =?UTF-8?q?=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🦖 Changed aymurai/utils/entity_disambiguation/__init__.py for release/v1.5.0 compatibility 🔥 Removed aymurai/utils/entity_disambiguation/llm.py for release/v1.5.0 compatibility --- .../routers/anonymizer/anonymizer.py | 7 +- .../utils/entity_disambiguation/__init__.py | 7 +- aymurai/utils/entity_disambiguation/llm.py | 379 ------------------ 3 files changed, 2 insertions(+), 391 deletions(-) delete mode 100644 aymurai/utils/entity_disambiguation/llm.py diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 5b3690bd..c90da84c 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -37,7 +37,6 @@ from aymurai.utils.entity_disambiguation import ( build_canonical_entities, get_canonical_dates, - load_prompts_from_yaml, map_canonical_entities_ner_preds, ) from aymurai.utils.misc import get_element @@ -396,8 +395,6 @@ async def anonymizer_disambiguate( effective_label_policies = _merge_label_policies(label_policies) logger.info("disambiguation labels: %d", len(labels)) - prompt_library = load_prompts_from_yaml() - all_detected_labels = { label.attrs.aymurai_label for label in labels @@ -407,9 +404,7 @@ async def anonymizer_disambiguate( and effective_label_policies.get(label.attrs.aymurai_label).anonymize } - default_llm_labels = ( - target_labels if target_labels else list(prompt_library.as_dict.keys()) - ) + default_llm_labels = target_labels if target_labels else [] llm_labels: list[str] = [] fuzzy_labels: set[str] = set() diff --git a/aymurai/utils/entity_disambiguation/__init__.py b/aymurai/utils/entity_disambiguation/__init__.py index 0794d1b3..1cfebd3d 100644 --- a/aymurai/utils/entity_disambiguation/__init__.py +++ b/aymurai/utils/entity_disambiguation/__init__.py @@ -5,17 +5,12 @@ from aymurai.utils.entity_disambiguation.fuzzy import ( build_canonical_entities, ) -from aymurai.utils.entity_disambiguation.llm import ( - llm_canonical_entities_inference, - load_prompts_from_yaml, -) + from aymurai.utils.entity_disambiguation.date_formatter import get_canonical_dates __all__ = [ "assign_label_instances", "build_canonical_entities", - "llm_canonical_entities_inference", "map_canonical_entities_ner_preds", - "load_prompts_from_yaml", "get_canonical_dates", ] diff --git a/aymurai/utils/entity_disambiguation/llm.py b/aymurai/utils/entity_disambiguation/llm.py deleted file mode 100644 index 6121d40c..00000000 --- a/aymurai/utils/entity_disambiguation/llm.py +++ /dev/null @@ -1,379 +0,0 @@ -import copy -import json -from functools import lru_cache -from pathlib import Path - -from more_itertools import unique_everseen -from transformers import AutoTokenizer - -from aymurai.llm_providers import OllamaLLMProvider -from aymurai.meta.api_interfaces import ( - DocLabel, - DocumentAnnotations, - PromptLibrary, - PromptSet, -) -from aymurai.meta.entities import CanonicalEntities, CanonicalEntity -from aymurai.settings import settings -from aymurai.utils.json_data import get_pretty -from aymurai.utils.yaml_data import load_yaml - - -@lru_cache(maxsize=1) -def load_prompts_from_yaml(): - """ - Loads and caches LLM prompt templates from the resources directory. - - Returns: - PromptLibrary: The loaded prompt library. - """ - path = Path(settings.RESOURCES_BASEPATH) / "llm/entity_disambiguation.yml" - data = load_yaml(file_path=str(path)) - - prompts = [] - for label, content in data.items(): - prompts.append( - PromptSet( - label=label, - system=content.get("system", ""), - user=content.get("user", ""), - ) - ) - return PromptLibrary(root=prompts) - - -def _extract_snippet(doc_text: str, label: DocLabel, window_length: int | None) -> str: - """ - Extracts and normalizes a text snippet around a label span. - - Args: - doc_text (str): Full document text. - label (DocLabel): Label containing span offsets. - window_length (int | None): Number of characters to include around - the label. If None, returns the full document text. - - Returns: - str: The extracted and normalized snippet. - """ - - if window_length is None: - return " ".join(doc_text.split()) - - start, end = label.start_char, label.end_char - window_start = max(0, start - window_length) - window_end = min(len(doc_text), end + window_length) - - # Expand to word boundaries to avoid truncating leading/trailing words. - while window_start > 0 and not doc_text[window_start - 1].isspace(): - window_start -= 1 - while window_end < len(doc_text) and not doc_text[window_end - 1].isspace(): - window_end += 1 - - snippet = doc_text[window_start:window_end] - return " ".join(snippet.split()) - - -def _iter_alias_snippets( - predictions: DocumentAnnotations, - *, - entity_label: str, - aliases_set: set[str], - window_length: int | None, -): - """ - Yields (alias, snippet) pairs for labels matching the target entity label. - - Args: - predictions (DocumentAnnotations): Document annotations to scan. - entity_label (str): Target NER label to match. - aliases_set (set[str]): Alias set to filter matches. - window_length (int | None): Window length for snippet extraction. - - Yields: - tuple[str, str]: (alias, snippet) pairs in appearance order. - """ - for pred in predictions: - if not pred.labels: - continue - doc_text = getattr(pred, "document", "") - - for label in pred.labels: - if label.attrs.aymurai_label != entity_label: - continue - - alias = label.attrs.aymurai_alt_text or label.text - if alias not in aliases_set: - continue - - snippet = _extract_snippet(doc_text, label, window_length) - yield alias, snippet - - -def _collect_entity_context( - predictions: DocumentAnnotations, - entity_label: str, - aliases: list[str], - window_length: int | None, - max_context_snippets: int | None = 5, -) -> list[str]: - """ - Collects unique context snippets for aliases, preserving appearance order. - - Args: - predictions (DocumentAnnotations): Document annotations to search within. - entity_label (str): NER label category to match (e.g., "PER"). - aliases (list[str]): Aliases to match against label text. - window_length (int | None): Characters to include around each match. - max_context_snippets (int | None): Max number of snippets to return. - If None, returns all unique snippets. Defaults to 5. - - Returns: - list[str]: Ordered, deduplicated context snippets. - """ - aliases_set = set(aliases) - - deduped_in_order = list( - unique_everseen( - _iter_alias_snippets( - predictions, - entity_label=entity_label, - aliases_set=aliases_set, - window_length=window_length, - ), - key=lambda item: item[1], - ) - ) - - # baseline in appearance order: first snippet per alias - seen_aliases: set[str] = set() - baseline = [ - snippet - for alias, snippet in deduped_in_order - if not (alias in seen_aliases or seen_aliases.add(alias)) - ] - - # remaining snippets in appearance order - baseline_set = set(baseline) - remaining = [ - snippet for _, snippet in deduped_in_order if snippet not in baseline_set - ] - - merged = baseline + remaining - - effective_limit = ( - None - if max_context_snippets is None - else max(max_context_snippets, len(baseline)) - ) - - return merged if effective_limit is None else merged[:effective_limit] - - -def _add_canonical_entities_context( - predictions: DocumentAnnotations, - entities: CanonicalEntities, - context_window_length: int | None = 120, - target_label: str | None = None, - max_snippets_per_entity: int | None = 5, -) -> CanonicalEntities: - """ - Attaches context snippets to each canonical entity based on predictions. - - Args: - predictions (DocumentAnnotations): Full document annotations. - entities (CanonicalEntities): Canonical entities to enrich with context. - context_window_length (int | None): Characters to include around each - mention. If None, uses the full document text. - target_label (str | None): Optional label filter to restrict extraction. - max_snippets_per_entity (int | None): Max snippets per entity. If None, - returns all unique snippets. - - Returns: - CanonicalEntities: Entities enriched with context snippets in attributes. - """ - - entities_with_context = copy.deepcopy(entities) - - for entity in entities_with_context: - if entity.attributes is None: - entity.attributes = {} - - current_target = target_label or entity.aymurai_label - - entity.attributes["context"] = _collect_entity_context( - predictions, - current_target, - list(entity.aliases), - context_window_length, - max_snippets_per_entity, - ) - - return entities_with_context - - -_TOKENIZER_CACHE = {} - - -def _get_model_tokens( - system_prompt: str, user_prompt: str, tokenizer_model: str -) -> int: - """ - Estimates token count for a system/user prompt using a HuggingFace tokenizer. - - Args: - system_prompt (str): System role prompt. - user_prompt (str): User role prompt. - tokenizer_model (str): HuggingFace tokenizer identifier or local path. - - Returns: - int: Approximate token count for the combined prompts. - """ - try: - if tokenizer_model not in _TOKENIZER_CACHE: - _TOKENIZER_CACHE[tokenizer_model] = AutoTokenizer.from_pretrained( - tokenizer_model - ) - - tokenizer = _TOKENIZER_CACHE[tokenizer_model] - - messages = [ - {"role": "system", "content": system_prompt}, - {"role": "user", "content": user_prompt}, - ] - - full_text = tokenizer.apply_chat_template(messages, tokenize=False) - tokens = tokenizer.encode(full_text) - - return len(tokens) - - except Exception: - # Fallback: simple word count approximation (one word ~ 1.4 tokens) - combined_text = f"{system_prompt} {user_prompt}" - word_count = len(combined_text.split()) - - approx_tokens = int(word_count * 1.4) + 20 - - return approx_tokens - - -def llm_canonical_entities_inference( - paragraphs: DocumentAnnotations, - canonical_entities_pre_cluster: CanonicalEntities, - system_prompt: str, - user_prompt_template: str, - model: str, - tokenizer_model: str, - target_label: str, - context_window_length: int | None = 120, - model_context: int = 9_500, - token_limit_frac: float = 2 / 3, - temperature: int = 0, - decompose_by: int | None = 0, -) -> CanonicalEntities: - """ - Refines pre-clustered entities into canonical forms using LLM inference. - - Args: - paragraphs (DocumentAnnotations): Annotated paragraphs containing labels. - canonical_entities_pre_cluster (CanonicalEntities): Pre-clustered entities. - system_prompt (str): System prompt for the LLM. - user_prompt_template (str): Template for user prompt formatting. - model (str): LLM model identifier. - tokenizer_model (str): Tokenizer identifier for token counting. - target_label (str): NER label to process (e.g., "PER"). - context_window_length (int | None): Context window length around mentions. - model_context (int): Max context window size for the LLM. - token_limit_frac (float): Fraction of model_context to use for batching. - temperature (int): Sampling temperature. - decompose_by (int | None): Batch size; if None, inferred. - - Returns: - CanonicalEntities: Canonical entities refined by the LLM. - """ - - canonical_entities_with_context = _add_canonical_entities_context( - predictions=paragraphs, - entities=canonical_entities_pre_cluster, - context_window_length=context_window_length, - target_label=target_label, - ) - - canonical_entities_prompt = [ - ce.model_dump(include={"canonical_text", "aliases", "attributes"}) - for ce in canonical_entities_with_context - ] - - token_limit = int(model_context * token_limit_frac) - - if decompose_by is None: - # NOTE: dynamically find the maximum batch size that fits the token limit - # by iteratively shrinking the candidate list. - current_batch_size = len(canonical_entities_prompt) - - while current_batch_size > 0: - test_batch = canonical_entities_prompt[:current_batch_size] - test_prompt = user_prompt_template.format( - canonical_entities=get_pretty(test_batch) - ) - - num_tokens = _get_model_tokens( - system_prompt=system_prompt, - user_prompt=test_prompt, - tokenizer_model=tokenizer_model, - ) - - if num_tokens <= token_limit: - decompose_by = current_batch_size - break - - current_batch_size -= 1 - - if not decompose_by: - # NOTE: returns None if even a single entity exceeds the token limit. - return None - - if decompose_by <= 0: - entity_batches = [canonical_entities_prompt] - else: - entity_batches = [ - canonical_entities_prompt[i : i + decompose_by] - for i in range(0, len(canonical_entities_prompt), decompose_by) - ] - - all_raw_outputs = [] - all_user_prompts = [] - - for batch_index, batch in enumerate(entity_batches): - user_prompt = user_prompt_template.format( - canonical_entities=get_pretty(batch), - ) - - all_user_prompts.append(user_prompt) - - len_tokens = _get_model_tokens( - system_prompt=system_prompt, - user_prompt=user_prompt, - tokenizer_model=tokenizer_model, - ) - if len_tokens > model_context: - # NOTE: skip batches that exceed physical context window to prevent LLM hallucination or crash. - continue - - provider = OllamaLLMProvider(model=model) - response = provider.generate( - messages=[ - {"role": "system", "content": system_prompt}, - {"role": "user", "content": user_prompt}, - ], - options={"temperature": temperature, "num_ctx": model_context}, - format=CanonicalEntities.model_json_schema(), - ) - - batch_entities = json.loads(response.text).get("canonical_entities", []) - all_raw_outputs.extend(batch_entities) - - canonical_entities_llm = [ - CanonicalEntity.model_validate(e) for e in all_raw_outputs - ] - - return canonical_entities_llm From b05b768a189e73ac83b389838367ae38ae0645b5 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 15:52:52 -0300 Subject: [PATCH 050/104] =?UTF-8?q?=E2=8F=AA=20Reverted=20docker-compose.y?= =?UTF-8?q?ml=20to=205b9c220?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 205 +++++---------------------------------------- 1 file changed, 19 insertions(+), 186 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index eb8d8fe0..3ce7c536 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,196 +1,29 @@ -x-api-lite: &api-lite - image: ghcr.io/aymurai/api:latest - build: - context: . - dockerfile: ./docker/api/Dockerfile - target: aymurai-api - shm_size: "2gb" - ports: - - "8899:8899" - volumes: - - ./resources/cache:/resources/cache - env_file: - - .env - - .env.common - -x-api-full: &api-full - image: ghcr.io/aymurai/api:full - build: - context: . - dockerfile: ./docker/api/Dockerfile - target: aymurai-api-full - shm_size: "2gb" - ports: - - "8899:8899" - restart: always - -x-ollama: &ollama-base - image: ollama/ollama - ports: - - "11434:11434" - volumes: - - ollama:/root/.ollama - restart: always - shm_size: "2gb" - services: - mlflow: - image: ghcr.io/mlflow/mlflow:latest - container_name: mlflow - ports: - - "5000:5000" - environment: - AWS_ACCESS_KEY_ID: ${AWS_ACCESS_KEY_ID} - AWS_SECRET_ACCESS_KEY: ${AWS_SECRET_ACCESS_KEY} - MLFLOW_S3_ENDPOINT_URL: http://minio:9000 - MLFLOW_S3_IGNORE_TLS: ${MLFLOW_S3_IGNORE_TLS} - command: - [ - "/bin/sh", - "-c", - "pip install --no-cache-dir psycopg2-binary boto3 && mlflow server --host 0.0.0.0 --port 5000 --backend-store-uri postgresql://mlflow:mlflow@postgres:5432/mlflow --default-artifact-root ${MLFLOW_ARTIFACT_ROOT}", - ] - depends_on: - postgres: - condition: service_healthy - minio: - condition: service_started - healthcheck: - test: - [ - "CMD", - "python", - "-c", - "import urllib.request; urllib.request.urlopen('http://localhost:5000')", - ] - interval: 10s - timeout: 5s - retries: 6 - - postgres: - image: postgres:16 - container_name: postgres - ports: - - "5432:5432" - environment: - POSTGRES_USER: mlflow - POSTGRES_PASSWORD: mlflow - POSTGRES_DB: mlflow - volumes: - - postgres-data:/var/lib/postgresql/data - healthcheck: - test: ["CMD-SHELL", "pg_isready -U mlflow"] - interval: 10s - timeout: 5s - retries: 6 - - minio: - image: minio/minio:latest - container_name: minio + aymurai-api: + image: ghcr.io/aymurai/api:latest ports: - - "9002:9000" - - "9001:9001" - environment: - MINIO_ROOT_USER: ${AWS_ACCESS_KEY_ID} - MINIO_ROOT_PASSWORD: ${AWS_SECRET_ACCESS_KEY} - command: ["server", "/data", "--console-address", ":9001"] + - "8899:8899" + build: + context: . + dockerfile: ./docker/api/Dockerfile + target: aymurai-api + env_file: + - .env + - .env.common volumes: - - minio-data:/data - # Healthcheck removed; minio image lacks wget and minio-mc already waits for readiness. + - ./resources/cache:/resources/cache - minio-mc: - image: minio/mc:latest - container_name: minio-mc - depends_on: - minio: - condition: service_started - entrypoint: - [ - "/bin/sh", - "-c", - "until (/usr/bin/mc alias set local http://minio:9000 ${AWS_ACCESS_KEY_ID} ${AWS_SECRET_ACCESS_KEY}) do sleep 1; done; /usr/bin/mc mb -p local/mlflow; /usr/bin/mc anonymous set none local/mlflow; exit 0;", - ] - - # CPU-friendly API - aymurai-api: - <<: *api-lite - container_name: aymurai-api - depends_on: - - ollama - environment: - OLLAMA_HOST: http://ollama:11434 - TORCH_DEVICE: cpu - - # GPU-enabled API - aymurai-api-gpu: - <<: *api-lite - container_name: aymurai-api-gpu - depends_on: - - ollama-gpu - environment: - OLLAMA_HOST: http://ollama-gpu:11434 - TORCH_DEVICE: cuda - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: all - capabilities: [ gpu ] - - # CPU-friendly Full API aymurai-api-full: - <<: *api-full - container_name: aymurai-api-full - depends_on: - - ollama - environment: - OLLAMA_HOST: http://ollama:11434 - TORCH_DEVICE: cpu - deploy: - resources: - limits: - memory: 4g - cpus: "4.0" - - # GPU-enabled Full API - aymurai-api-full-gpu: - <<: *api-full - container_name: aymurai-api-full-gpu - depends_on: - - ollama-gpu - environment: - OLLAMA_HOST: http://ollama-gpu:11434 - TORCH_DEVICE: cuda + image: ghcr.io/aymurai/api:full + ports: + - "8899:8899" + build: + context: . + dockerfile: ./docker/api/Dockerfile + target: aymurai-api-full + restart: always deploy: resources: - reservations: - devices: - - driver: nvidia - count: all - capabilities: [ gpu ] limits: memory: 4g cpus: "4.0" - - # CPU-only Ollama (default) - ollama: - <<: *ollama-base - container_name: ollama - - # GPU-enabled Ollama (run instead on GPU hosts) - ollama-gpu: - <<: *ollama-base - container_name: ollama-gpu - deploy: - resources: - reservations: - devices: - - driver: nvidia - count: all - capabilities: [ gpu ] - -volumes: - ollama: - postgres-data: - minio-data: From ebe414b5679966f60058bcffaafa2df00c3f8044 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 15:55:04 -0300 Subject: [PATCH 051/104] =?UTF-8?q?=E2=8F=AA=20Revert=20docker/api/Dockerf?= =?UTF-8?q?ile=20to=204196117?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/api/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 2462d4ec..660e5a7e 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -33,6 +33,7 @@ RUN --mount=type=bind,source=.git,target=.git \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ uv sync --frozen --no-editable + # ------------------- # Base API Stage # ------------------- @@ -74,7 +75,6 @@ COPY --from=builder --chown=app:app /app/.venv /app/.venv # Copy static resources COPY resources/api/static /resources/api/static COPY resources/pipelines /resources/pipelines -COPY resources/llm /resources/llm # Set working directory WORKDIR /app @@ -96,7 +96,6 @@ ENV TF_CPP_MIN_LOG_LEVEL=3 \ # Copy additional resources COPY ./resources/api resources/api COPY ./resources/pipelines/production resources/pipelines/production -COPY ./resources/llm resources/llm # Initialize application to download models RUN uv run python /app/.venv/lib/python3.10/site-packages/aymurai/api/main.py From d312eea5412affce89f19b625e808901eca5beed Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:13:27 -0300 Subject: [PATCH 052/104] =?UTF-8?q?=F0=9F=A6=96=20Changed=20docs/anonymiza?= =?UTF-8?q?tion/README.md=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/anonymization/README.md | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/docs/anonymization/README.md b/docs/anonymization/README.md index 9beee13d..19603da6 100644 --- a/docs/anonymization/README.md +++ b/docs/anonymization/README.md @@ -9,13 +9,11 @@ 1. `/misc/document-extract` recibe el DOCX/PDF y devuelve el payload estructurado (`document_id`, lista de párrafos) tal como hoy. 2. Se procesa cada párrafo con `/anonymizer/predict`, obteniendo los resultados de NER (`aymurai_label`, texto, offsets, contexto previo y posterior y otros atributos). -3. Se consolida la inferencia: agrupamos todas las menciones detectadas y armamos un paquete enriquecido con contexto circundante (párrafo u oraciones vecinas). -4. Módulo de fuzzy-matching cruza cada mención extraída para sugerir candidatos de `CanonicalEntities` (`canonical_text` y `aliases`). -5. El contexto del paso 3 más las sugerencias del paso 4 son insumo para el servicio de desambiguación (LLM); el modelo se encarga de validar los `CanonicalEntities` sugeridos o proponer nuevos, al tiempo que infiere atributos adicionales (rol procesal), devolviendo una lista refinada de `CanonicalEntities`. -6. Con esa lista se ejecuta el mapeo de `Entity` a `CanonicalEntity`: cada mención NER queda anotada con un `canonical_entity_id` y un `aymurai_label_instance` (índice entero por orden de aparición) y cualquier atributo inferido, generando la desambiguación de entidades. -7. El frontend consume esos outputs y muestra el texto original con dos niveles de revisión: etiquetas NER y asignación canónica. -8. Tras la validación manual, el cliente invoca `/anonymizer/anonymize-document`, que ahora utiliza políticas de render (`render_policy`) para aplicar reemplazos consistentes (etiqueta o subclase con sufijos opcionales) y generar el documento anonimizado final. -9. El documento anonimizado queda disponible para descarga y se registran en la base de datos las decisiones finales (etiquetas y canónicos). +3. Módulo de fuzzy-matching cruza cada mención extraída para sugerir candidatos de `CanonicalEntities` (`canonical_text` y `aliases`). +4. Con esa lista se ejecuta el mapeo de `Entity` a `CanonicalEntity`: cada mención NER queda anotada con un `canonical_entity_id` y un `aymurai_label_instance` (índice entero por orden de aparición) y cualquier atributo inferido, generando la desambiguación de entidades. +5. El frontend consume esos outputs y muestra el texto original con dos niveles de revisión: etiquetas NER y asignación canónica. +6. Tras la validación manual, el cliente invoca `/anonymizer/anonymize-document`, que ahora utiliza políticas de render (`render_policy`) para aplicar reemplazos consistentes (etiqueta o subclase con sufijos opcionales) y generar el documento anonimizado final. +7. El documento anonimizado queda disponible para descarga y se registran en la base de datos las decisiones finales (etiquetas y canónicos). ## Cambios principales en el modelo de datos @@ -72,9 +70,8 @@ El `render_policy` puede definirse por entorno (`RENDER_POLICY`) o por request y El objetivo general es optimizar la extracción y desambiguación de entidades. Para avanzar con criterio orientado a métricas mediremos cada capa y el sistema end-to-end. -- **NER**: aunque el modelo actual cubre el caso de uso, debemos planificar un nuevo ciclo de entrenamiento y finetuning. Será importante consolidar un dataset público anotado con las entidades a detectar, para lo cual podemos aprovechar repositorios públicos de documentos legales de Argentina (e idealmente, del resto de latinoamérica). Para el etiquetado automático, podemos combinar predicciones del NER actual con las extracciones obtenidas usando [`langextract`](/notebooks/experiments/anonymization/05-langextract.ipynb), y conservar solo las coincidencias exactas entre ambos sistemas para minimizar ruido. Luego, se deberán realizar algunas revisiones manuales para asegurar calidad. Este dataset nos permitirá definir un split de evaluación estable y automatizar el cálculo de F1 por etiqueta para comparar versiones de forma consistente. +- **NER**: aunque el modelo actual cubre el caso de uso, debemos planificar un nuevo ciclo de entrenamiento y finetuning. Será importante consolidar un dataset público anotado con las entidades a detectar, para lo cual podemos aprovechar repositorios públicos de documentos legales de Argentina (e idealmente, del resto de latinoamérica). Luego, se deberán realizar algunas revisiones manuales para asegurar calidad. Este dataset nos permitirá definir un split de evaluación estable y automatizar el cálculo de F1 por etiqueta para comparar versiones de forma consistente. - **Heurística de agrupación**: vamos a contrastar variantes como Levenshtein normalizada, token fuzzy matching o TF-IDF con coseno. Cada método se ejecutará sobre predicciones reales del NER (para medir robustez ante ruido) y sobre etiquetas existentes (para estimar el techo teórico). La métrica utilizada para evaluar será aquella definida en `/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md`, contra un conjunto de `CanonicalEntities` ya anotados. -- **LLM para desambiguación**: la calidad depende de cómo se promptea y del contexto entregado. Deberíamos experimentar con distintas ventanas de contexto variable (documento completo, párrafos que contienen entidades, oraciones vecinas, metadata, etc.), variantes de prompt (instrucciones directas versus cadenas guiadas) y configuraciones de temperatura/top-p. Cada variante se evaluará con la métrica anteriormente mencionada. Finalmente consolidaremos una evaluación integrada combinando el mejor NER disponible, la heurística con mayor cobertura y baja tasa de falsos positivos y la versión de prompt más precisa. El benchmark se ejecutará sobre un conjunto de documentos de validación con etiquetas canónicas revisadas. From dde8f0e89e1c9d56d7e39aa2cbfe577d2603ea2a Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:17:26 -0300 Subject: [PATCH 053/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20docs/experimen?= =?UTF-8?q?ts/README.md=20for=20realease/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔥 Removed docs/experiments/base.yaml for realease/v1.5.0 compatibility --- docs/experiments/README.md | 90 -------------------------------------- docs/experiments/base.yaml | 50 --------------------- 2 files changed, 140 deletions(-) delete mode 100644 docs/experiments/README.md delete mode 100644 docs/experiments/base.yaml diff --git a/docs/experiments/README.md b/docs/experiments/README.md deleted file mode 100644 index 87c1f771..00000000 --- a/docs/experiments/README.md +++ /dev/null @@ -1,90 +0,0 @@ -# Experiments Setup - -This guide walks through running the entity-disambiguation experiments with MLflow -tracking and MinIO artifacts. - -## 1) Update the devcontainer - -The devcontainer installs base dependencies via `uv`. The MLflow client lives in the -`mlops` dependency group, so install it after rebuilding the container: - -```bash -uv sync --frozen --all-extras --group mlops -``` - -If you use VS Code, run "Dev Containers: Rebuild and Reopen in Container" first. - -## 2) Configure environment - -- Set MinIO credentials in `.env`: - - `AWS_ACCESS_KEY_ID` - - `AWS_SECRET_ACCESS_KEY` -- Verify MLflow settings in `.env.common`: - - `MLFLOW_TRACKING_URI` - - `MLFLOW_S3_ENDPOINT_URL` - - `MLFLOW_ARTIFACT_ROOT` - -The experiment runner also uses: -- `API_BASE_URL` (defaults to `http://localhost:8899`) -- `REQUEST_TIMEOUT` (defaults to `300`) - -## 3) Start services - -```bash -make mlops-up -make ollama-up -make api-up -``` - -If you need the GPU services, set: -```bash -make ollama-up OLLAMA_SERVICE=ollama-gpu -make api-up API_SERVICE=aymurai-api-gpu -``` - -## 4) Pull the model - -```bash -make ollama-pull MODEL=gemma3:270m -``` - -## 5) Run the experiment - -```bash -make exp-run CONFIG=resources/experiments/entity-disambiguation/exp-gemma3-pv1.yaml -``` - -## Predictions vs. ground truth filenames - -Ground-truth files are expected to end with `-test.json`, while predictions use -the same base name without the suffix. - -Example: -- `document-1-test.json` (ground truth) -- `document-1.json` (prediction) - -Predictions are written to disk (not logged as artifacts). MLflow logs: -- Run params (model, prompt IDs, dataset hash, etc.) -- Aggregate metrics and per-document scores (as an artifact) -- Prompt text (if enabled in config) - -## 6) Access MLflow UI - -If running remotely, forward the MLflow port: -```bash -ssh -L 5000:127.0.0.1:5000 user@remote-host -``` - -Then open `http://localhost:5000`. - -## Config location - -Experiment configs live under: -- `resources/experiments/entity-disambiguation/` - -Use the template at `docs/experiments/base.yaml` when creating new experiment -configs. Copy it into `resources/experiments/entity-disambiguation/` and adjust -the model, prompts, and data paths as needed. - -The main runner is: -- `aymurai/experiments/entity_disambiguation/runner.py` diff --git a/docs/experiments/base.yaml b/docs/experiments/base.yaml deleted file mode 100644 index a3fb6adc..00000000 --- a/docs/experiments/base.yaml +++ /dev/null @@ -1,50 +0,0 @@ -experiment: - name: "entity-disambiguation" - run_name: "{model}-{system_id}-{user_id}-{timestamp}" - -model: - provider: "ollama" - name: "llama3:8b" - temperature: 0.2 - max_tokens: 512 - -prompts: - system: - id: "sys-001" - text: "" - user: - id: "user-001" - text: "" - - -data: - ground_truth_dir: "/data/gt" - input_dir: "/data/input" - dataset_id: "gt-v1" - manifest: - enabled: true - mode: "metadata_only" - -predictions: - output_base_dir: "/data/preds" - dir_name_template: "preds-{model}-{system_id}-{user_id}-{timestamp}" - -logging: - mlflow: - experiment_name: "entity-disambiguation" - privacy: - log_prompt_text: true - log_data_manifest: false - log_per_doc_scores: true - per_doc_scores: - id_strategy: "anon_filename" - -evaluation: - function: "evaluate_disambiguation" - weights: - w_ent: 0.4 - w_alias: 0.35 - w_label: 0.2 - w_role: 0.05 - per_doc_scores: true - normalize: true From d56007591325c0153133f494835cf4a0270d180e Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:20:26 -0300 Subject: [PATCH 054/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20notebooks/expe?= =?UTF-8?q?riments/anonymization/05-langextract.ipynb=20for=20release/v1.5?= =?UTF-8?q?.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../anonymization/05-langextract.ipynb | 353 ------------------ 1 file changed, 353 deletions(-) delete mode 100644 notebooks/experiments/anonymization/05-langextract.ipynb diff --git a/notebooks/experiments/anonymization/05-langextract.ipynb b/notebooks/experiments/anonymization/05-langextract.ipynb deleted file mode 100644 index df2b0646..00000000 --- a/notebooks/experiments/anonymization/05-langextract.ipynb +++ /dev/null @@ -1,353 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "7052227b", - "metadata": {}, - "outputs": [], - "source": [ - "import langextract as lx\n", - "from rich.pretty import pprint" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "01ef2998", - "metadata": {}, - "outputs": [], - "source": [ - "# 1. Define the prompt and extraction rules\n", - "prompt = \"\"\"\n", - " Sos un asistente especializado en el análisis de documentos judiciales.\n", - " Tu tarea es identificar y extraer menciones de información sensible para su posterior anonimización.\n", - " Debés detectar fragmentos textuales que correspondan a cualquiera de las siguientes entidades:\n", - "\n", - " - \"BANCO\": Nombre de una entidad bancaria, pública o privada.\n", - " - \"CBU\": Código Bancario Uniforme (22 dígitos) de una cuenta.\n", - " - \"CORREO_ELECTRONICO\": Dirección de correo electrónico.\n", - " - \"CUIJ\": Código Único de Identificación Jurídica de causas judiciales.\n", - " - \"CUIT_CUIL\": Número de CUIT o CUIL de una persona física o jurídica.\n", - " - \"DIRECCION\": Dirección postal específica (calle, número, etc.).\n", - " - \"DNI\": Número de Documento Nacional de Identidad u otro documento identificatorio.\n", - " - \"EDAD\": Edad explícita de una persona.\n", - " - \"ESTUDIOS\": Nivel o institución educativa que permita identificar a la persona (ej. \"primario incompleto\", \"secundario completo\", \"Licenciado en…\").\n", - " - \"FECHA\": Fecha completa o parcial (día, mes y/o año).\n", - " - \"LINK\": Enlace o URL a una página web.\n", - " - \"LOC\": Localización geográfica específica (ciudad, barrio, comisaría, etc.).\n", - " - \"MARCA_AUTOMOVIL\": Marca de un vehículo (ej. Toyota, Ford).\n", - " - \"NACIONALIDAD\": Nacionalidad de una persona (ej. \"argentino\", \"brasileña\").\n", - " - \"NUM_ACTUACION\": Número identificatorio de una actuación administrativa o contravencional.\n", - " - \"NUM_CAJA_AHORRO\": Número completo de una caja de ahorro o cuenta bancaria.\n", - " - \"NUM_EXPEDIENTE\": Número de expediente judicial o administrativo.\n", - " - \"NUM_MATRICULA\": Número de matrícula profesional o académica.\n", - " - \"PATENTE_DOMINIO\": Patente o dominio de un vehículo.\n", - " - \"PER\": Nombre y apellido(s) de una persona física. Los nombres inicializados y los apodos también cuentan como información sensible a anonimizar.\n", - " - \"TELEFONO\": Número telefónico (fijo o celular).\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96f85b5f", - "metadata": {}, - "outputs": [], - "source": [ - "# 2. Provide a high-quality example to guide the model\n", - "examples = [\n", - " lx.data.ExampleData(\n", - " text=\"El 5 de mayo de 2023 el señor Fiscal indicó que realizó distintas medidas de prueba y que del resultado surge que tanto la investigada como el menor Juan Pérez se domicilian en la calle Sarmiento 1234, de la localidad de Moreno, por lo que solicitó que se declare la incompetencia en razón del territorio y se envíe el caso al Juzgado de Garantías que corresponda del Departamento Judicial de Moreno, con jurisdicción en el partido de Moreno.\",\n", - " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"FECHA\", extraction_text=\"5 de mayo de 2023\"\n", - " ),\n", - " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Juan Pérez\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"DIRECCION\", extraction_text=\"Sarmiento 1234\"\n", - " ),\n", - " lx.data.Extraction(extraction_class=\"LOC\", extraction_text=\"Moreno\"),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"JUZGADO DE 1RA INSTANCIA EN LO PENAL CONTRAVENCIONAL Y DE FALTAS N°10 SECRETARIA N°19\\nCarlos Gómez sobre 84 - HOMICIDIO CULPOSO Y OTROS\\nNúmero: 52345/2022\\nCUIJ: 12-34567890-1\\nActuación Nro: 2022-009876\",\n", - " extractions=[\n", - " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Carlos Gómez\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"NUM_EXPEDIENTE\", extraction_text=\"52345/2022\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"CUIJ\", extraction_text=\"12-34567890-1\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"NUM_ACTUACION\", extraction_text=\"2022-009876\"\n", - " ),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"Acusado: Miguel Torres, DNI 30123456, nacido el 14/02/1990, de 34 años de edad, de nacionalidad paraguaya, género varón cis, con estudios secundarios completos, hizo hasta 3er año porque fue padre joven, con último domicilio en Av. Corrientes 3456, de esta ciudad, donde vive con su hermana y su cuñado Jorge Pérez. Tiene dos hijos a su cargo, de 5 y 8 años. Su hijo de 8 vive con él, su hija de 5 vive con su madre, Laura Fernández.\",\n", - " extractions=[\n", - " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Miguel Torres\"),\n", - " lx.data.Extraction(extraction_class=\"DNI\", extraction_text=\"30123456\"),\n", - " lx.data.Extraction(extraction_class=\"FECHA\", extraction_text=\"14/02/1990\"),\n", - " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"34\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"NACIONALIDAD\", extraction_text=\"paraguaya\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"ESTUDIOS\",\n", - " extraction_text=\"estudios secundarios completos\",\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"DIRECCION\",\n", - " extraction_text=\"Av. Corrientes 3456\",\n", - " ),\n", - " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Jorge Pérez\"),\n", - " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"5\"),\n", - " lx.data.Extraction(extraction_class=\"EDAD\", extraction_text=\"8\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Laura Fernández\"\n", - " ),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"El testigo Juan López dejó asentado su número de contacto: 11-2345-6789. Indicó que la médica Dra. Ana García, MN 12345, asistió al lugar donde se hallaba un vehículo Volkswagen, patente AB123CD.\",\n", - " extractions=[\n", - " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Juan López\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"TELEFONO\", extraction_text=\"11-2345-6789\"\n", - " ),\n", - " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Ana García\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"NUM_MATRICULA\", extraction_text=\"12345\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"MARCA_AUTOMOVIL\",\n", - " extraction_text=\"Volkswagen\",\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"PATENTE_DOMINIO\", extraction_text=\"AB123CD\"\n", - " ),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"Se identificó una transferencia bancaria con los siguientes datos: CUIT 20-12345678-3, CBU 2850590940090412345671, Caja de Ahorro N° 12345678, Banco Nación.\",\n", - " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"CUIT_CUIL\", extraction_text=\"20-12345678-3\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"CBU\",\n", - " extraction_text=\"2850590940090412345671\",\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"NUM_CAJA_AHORRO\", extraction_text=\"12345678\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"BANCO\", extraction_text=\"Banco Nación\"\n", - " ),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"Para mayor información, comunicarse a fiscalia.central@justicia.gob.ar o visitar el sitio https://justicia.gob.ar/actuaciones.\",\n", - " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"CORREO_ELECTRONICO\",\n", - " extraction_text=\"fiscalia.central@justicia.gob.ar\",\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"LINK\",\n", - " extraction_text=\"https://justicia.gob.ar/actuaciones\",\n", - " ),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"En la Ciudad Autónoma de Buenos Aires, el día 5 de mayo de 2023, el Sr. Fiscal hace saber que Juan Pérez se domicilia en la calle Sarmiento 1234, localidad de Moreno.\",\n", - " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"FECHA\", extraction_text=\"5 de mayo de 2023\"\n", - " ),\n", - " lx.data.Extraction(extraction_class=\"PER\", extraction_text=\"Juan Pérez\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"DIRECCION\", extraction_text=\"Sarmiento 1234\"\n", - " ),\n", - " lx.data.Extraction(extraction_class=\"LOC\", extraction_text=\"Moreno\"),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"Por otra parte, la División Investigaciones Judiciales de la Policía Federal Argentina informó que no se dio intervención a ninguna otra Fiscalía u otro Juzgado por la sustracción del vehículo Volkswagen Voyage, dominio KXY-876\",\n", - " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"PATENTE_DOMINIO\", extraction_text=\"KXY-876\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"MARCA_AUTOMOVIL\",\n", - " extraction_text=\"Volkswagen Voyage\",\n", - " ),\n", - " ],\n", - " ),\n", - " lx.data.ExampleData(\n", - " text=\"A su vez, requirió informes al Banco BBVA Francés, respecto de las cuentas bancarias de la denunciante, Carla Alejandra Garcia, D.N.I. 36.998.621 identificadas como Caja de ahorro en pesos argentinos número 117-59824/6 con CBU 0180132640000004685591 y Caja de ahorro en dólares número 119-619018/2 con CBU 0170115544000062081822.\",\n", - " extractions=[\n", - " lx.data.Extraction(\n", - " extraction_class=\"PER\", extraction_text=\"Carla Alejandra Garcia\"\n", - " ),\n", - " lx.data.Extraction(extraction_class=\"DNI\", extraction_text=\"36.998.621\"),\n", - " lx.data.Extraction(\n", - " extraction_class=\"NUM_CAJA_AHORRO\", extraction_text=\"117-59824/6\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"CBU\", extraction_text=\"0180132640000004685591\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"NUM_CAJA_AHORRO\", extraction_text=\"119-619018/2\"\n", - " ),\n", - " lx.data.Extraction(\n", - " extraction_class=\"CBU\", extraction_text=\"0170115544000062081822\"\n", - " ),\n", - " ],\n", - " ),\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb82c82d", - "metadata": {}, - "outputs": [], - "source": [ - "len(examples)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c52e56f4", - "metadata": {}, - "outputs": [], - "source": [ - "iter_examples = iter(examples)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "68945d23", - "metadata": {}, - "outputs": [], - "source": [ - "example = next(iter_examples)\n", - "pprint(example)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a34c40a8", - "metadata": {}, - "outputs": [], - "source": [ - "# Sample text to extract from\n", - "text = \"La Fiscalía determinó que el objeto de este caso es investigar el hecho que tuvo lugar el día 12 de marzo de 2023 a las 8:50 horas aproximadamente, ocasión en que Carlos Gómez y María Rodriguez estafaron a Juan Pérez por un monto total de pesos treinta y tres mil novecientos sesenta ($33.960).\"\n", - "\n", - "# Run the extraction\n", - "result = lx.extract(\n", - " text_or_documents=text,\n", - " prompt_description=prompt,\n", - " examples=examples,\n", - " model_id=\"llama3.1:8b\",\n", - " model_url=\"http://localhost:11434\",\n", - " max_char_buffer=16_384,\n", - " fence_output=False,\n", - " use_schema_constraints=False,\n", - ")\n", - "\n", - "pprint(result)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9064a3b6", - "metadata": {}, - "outputs": [], - "source": [ - "# Custom OpenAI model integration\n", - "# Support for Ollama gpt-oss:20b #116\n", - "# https://github.com/google/langextract/issues/116#issuecomment-3209618602\n", - "from langextract.providers.openai import OpenAILanguageModel\n", - "\n", - "\n", - "# Custom OpenAI model class to handle Ollama gpt-oss:20b\n", - "class CustomOpenAIModel(OpenAILanguageModel):\n", - " def _process_single_prompt(self, prompt, config):\n", - " api_params = {\n", - " \"model\": self.model_id,\n", - " \"messages\": [{\"role\": \"user\", \"content\": prompt}],\n", - " \"temperature\": 0.1,\n", - " \"max_tokens\": 2000,\n", - " }\n", - "\n", - " try:\n", - " response = self._client.chat.completions.create(**api_params)\n", - " output_text = response.choices[0].message.content\n", - " return lx.inference.ScoredOutput(score=1.0, output=output_text)\n", - "\n", - " except Exception as e:\n", - " raise lx.exceptions.InferenceRuntimeError(\n", - " f\"Custom OpenAI API error: {str(e)}\", original=e\n", - " ) from e\n", - "\n", - "\n", - "# Instantiate the custom model\n", - "custom_model = CustomOpenAIModel(\n", - " model_id=\"gpt-oss:20b\",\n", - " api_key=\"dummy\",\n", - " base_url=\"http://localhost:11434/v1\",\n", - ")\n", - "\n", - "# Run extraction with the custom model\n", - "result = lx.extract(\n", - " text_or_documents=text,\n", - " prompt_description=prompt,\n", - " examples=examples,\n", - " model=custom_model,\n", - " fence_output=False,\n", - " use_schema_constraints=False,\n", - ")\n", - "pprint(result)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e905e794", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai (3.10.19)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.19" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From d35c6cb53ccce0130e5dd35f91ca5ed2038cd17b Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:31:36 -0300 Subject: [PATCH 055/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20all=20the=20?= =?UTF-8?q?=20notebooks=20from=20folder:=20notebooks/experiments/entity-di?= =?UTF-8?q?sambiguation=20that=20had=20something=20related=20to=20LLM=20di?= =?UTF-8?q?sambiguation=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01-entity-disambiguation.ipynb | 506 ---- .../02-disambiguation-metric.ipynb | 431 --- ...ation-from-pre-clustered-validations.ipynb | 899 ------ ...tion-pre-clustered-manual-validation.ipynb | 2447 ----------------- .../07-LLM-entities-disambiguation.ipynb | 1713 ------------ .../08-disambiguation-endpoint-smoke.ipynb | 399 --- 6 files changed, 6395 deletions(-) delete mode 100644 notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb delete mode 100644 notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb delete mode 100644 notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb delete mode 100644 notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb delete mode 100644 notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb delete mode 100644 notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb diff --git a/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb deleted file mode 100644 index d8ff91eb..00000000 --- a/notebooks/experiments/entity-disambiguation/01-entity-disambiguation.ipynb +++ /dev/null @@ -1,506 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "c8fc128c", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext rich\n", - "\n", - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8eeefe8b", - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import json\n", - "import mimetypes\n", - "import os\n", - "import re\n", - "import time\n", - "from pathlib import Path\n", - "from typing import Iterable\n", - "\n", - "import requests\n", - "from tqdm import tqdm\n", - "\n", - "from aymurai.llm_providers import OllamaLLMProvider\n", - "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", - "from aymurai.utils.json_data import get_pretty, save_json" - ] - }, - { - "cell_type": "markdown", - "id": "84d11bba", - "metadata": {}, - "source": [ - "## /document-extract endpoint output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e0ec450", - "metadata": {}, - "outputs": [], - "source": [ - "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8899\")\n", - "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", - "DATA_ROOT = Path(\n", - " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/disambiguation-eval\")\n", - ")\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", - "\n", - "print(f\"Target endpoint: {ENDPOINT}\")\n", - "print(f\"Data root: {DATA_ROOT.resolve()}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef352767", - "metadata": {}, - "outputs": [], - "source": [ - "if not DATA_ROOT.exists():\n", - " raise FileNotFoundError(\n", - " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", - " )\n", - "\n", - "\n", - "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "\n", - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "print(f\"Discovered {len(documents)} documents.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "21fd6e36", - "metadata": {}, - "outputs": [], - "source": [ - "def call_extraction_api(\n", - " session: requests.Session, file_path: Path\n", - ") -> dict[str, object]:\n", - " payload: dict[str, object] = {\n", - " \"path\": str(file_path),\n", - " \"status\": \"failure\",\n", - " \"status_code\": None,\n", - " \"elapsed_s\": None,\n", - " \"detail\": None,\n", - " }\n", - "\n", - " if not file_path.exists():\n", - " payload[\"detail\"] = \"File does not exist\"\n", - " return payload\n", - "\n", - " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", - " files = {\n", - " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", - " }\n", - "\n", - " try:\n", - " start = time.perf_counter()\n", - " response = session.post(\n", - " ENDPOINT,\n", - " files=files,\n", - " timeout=REQUEST_TIMEOUT,\n", - " )\n", - " elapsed = time.perf_counter() - start\n", - " except requests.RequestException as exc:\n", - " payload[\"detail\"] = f\"Request failed: {exc}\"\n", - " return payload\n", - " finally:\n", - " files[\"file\"][1].close()\n", - "\n", - " payload[\"status_code\"] = response.status_code\n", - " payload[\"elapsed_s\"] = elapsed\n", - "\n", - " try:\n", - " response_body = response.json()\n", - " except ValueError:\n", - " response_body = {\"raw\": response.text[:500]}\n", - "\n", - " if response.ok:\n", - " payload[\"status\"] = \"success\"\n", - " payload[\"detail\"] = {\n", - " \"document_id\": response_body.get(\"document_id\"),\n", - " \"document\": response_body.get(\"document\", []),\n", - " }\n", - " else:\n", - " payload[\"detail\"] = response_body\n", - "\n", - " return payload" - ] - }, - { - "cell_type": "markdown", - "id": "9254ef68", - "metadata": {}, - "source": [ - "## Inference" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a308cf90", - "metadata": {}, - "outputs": [], - "source": [ - "# Function to make inference using the API\n", - "def get_predictions(sample: str) -> dict:\n", - " response = requests.post(\n", - " url=f\"{API_BASE_URL}/anonymizer/predict\", json={\"text\": sample}\n", - " )\n", - " response.raise_for_status()\n", - " return response.json()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7ef6a0fa", - "metadata": {}, - "outputs": [], - "source": [ - "from itertools import chain\n", - "from operator import itemgetter\n", - "from typing import Any\n", - "\n", - "from more_itertools import unique_everseen\n", - "\n", - "\n", - "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", - " \"\"\"\n", - " Parse prediction labels to extract unique aymurai_label and aymurai_alt_text pairs.\n", - "\n", - " Args:\n", - " predictions (list[dict[str, Any]]): A list of prediction dictionaries.\n", - "\n", - " Returns:\n", - " list[dict[str, str]]: A list of dictionaries containing unique aymurai_label and aymurai_alt_text pairs.\n", - " \"\"\"\n", - " attrs_stream = (\n", - " label.get(\"attrs\") or {}\n", - " for label in chain.from_iterable(pred.get(\"labels\", ()) for pred in predictions)\n", - " )\n", - "\n", - " unique_pairs = unique_everseen(\n", - " (\n", - " attrs.get(\"aymurai_label\"),\n", - " attrs.get(\"aymurai_alt_text\"),\n", - " )\n", - " for attrs in attrs_stream\n", - " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", - " )\n", - "\n", - " return sorted(\n", - " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", - " key=itemgetter(\"aymurai_label\", \"text\"),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "ccbe21f4", - "metadata": {}, - "source": [ - "## CanonicalEntity extraction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd025617", - "metadata": {}, - "outputs": [], - "source": [ - "# Available models\n", - "# model = \"gpt-oss:20b\"\n", - "# model = \"llama3\"\n", - "model = \"phi4:14b\"\n", - "# model = \"llama3.1:8b\"\n", - "# model = \"gemma3:270m\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25284997", - "metadata": {}, - "outputs": [], - "source": [ - "# Sanity check\n", - "provider = OllamaLLMProvider(model=model)\n", - "provider.generate(\"hola, ¿cómo estás?\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c7ec7c6", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt = \"\"\"\n", - "Eres un asistente especializado en anonimización de sentencias judiciales.\n", - "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", - "Una **entidad canónica** es la representación única de una entidad real.\n", - "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", - "\n", - "# Reglas\n", - "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", - "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", - "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", - "- Cada entidad canónica debe incluir:\n", - " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", - " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", - " - `aliases` (todas las menciones textuales relevantes).\n", - " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", - "\n", - "# Notas\n", - "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", - "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - "\n", - "# Ejemplo\n", - "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", - "A: ```json\n", - "[\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Laura Beatriz Gómez\",\n", - " \"aliases\": [\"Laura Beatriz Gómez\"],\n", - " \"attributes\": {\"role\": \"Denunciante\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"42987654\",\n", - " \"aliases\": [\"42.987.654\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DIRECCION\",\n", - " \"canonical_text\": \"calle Falsa 123\",\n", - " \"aliases\": [\"calle Falsa 123\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", - " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", - " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", - " \"attributes\": {\"role\": \"Denunciado\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"27654321\",\n", - " \"aliases\": [\"27.654.321\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"calle Real 789\",\n", - " \"aliases\": [\"calle Real 789\"]\n", - " }\n", - "]\n", - "```\n", - "\"\"\"\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6994e3c3", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template = \"\"\"\n", - "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", - "\n", - "# Documento\n", - "{document_text}\n", - "\n", - "# Menciones de entidades detectadas por el NER\n", - "{ner_output_json}\n", - "\n", - "# Instrucciones\n", - "1. Evalúa cada mención listada. Si representa una entidad real, inclúyela en la lista de aliases de alguna entidad canónica.\n", - "2. No omitas entidades válidas, alias con iniciales ni variantes abreviadas.\n", - "3. Solo fusiona menciones cuando exista evidencia clara de que se refieren a la misma entidad.\n", - "4. Normaliza canonical_text; mantén los alias tal como aparecen.\n", - "5. Utiliza attributes para indicar roles (p. ej. {{\"role\": \"Denunciante\"}}) o aclaraciones de desambiguación.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "349fa489", - "metadata": {}, - "outputs": [], - "source": [ - "def extract_canonical_entities(\n", - " doc_path: str, model: str = \"phi4:14b\"\n", - ") -> CanonicalEntities:\n", - " \"\"\"\n", - " Extract canonical entities from a document.\n", - "\n", - " Args:\n", - " doc_path (str): The path to the document.\n", - " model (str, optional): The model to use for extraction. Defaults to \"phi4:14b\".\n", - "\n", - " Raises:\n", - " ValueError: If the document is empty or not found.\n", - " ValueError: If the document summary is empty or not found.\n", - "\n", - " Returns:\n", - " CanonicalEntities: The extracted canonical entities.\n", - " \"\"\"\n", - " # Extract document\n", - " session = requests.Session()\n", - " document = call_extraction_api(session, Path(doc_path))\n", - " document = document.get(\"detail\", {}).get(\"document\")\n", - "\n", - " if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")\n", - "\n", - " # Get NER predictions\n", - " ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - " parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", - " ner_output_json = get_pretty(parsed_ner_labels)\n", - "\n", - " # Prepare user prompt\n", - " user_prompt = user_prompt_template.format(\n", - " document_text=\"\\n\".join(document).strip(),\n", - " ner_output_json=ner_output_json,\n", - " )\n", - "\n", - " # Get canonical entities from the model\n", - " provider = OllamaLLMProvider(model=model)\n", - " response = provider.generate(\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options={\"temperature\": 0},\n", - " format=CanonicalEntities.model_json_schema(),\n", - " )\n", - "\n", - " # Parse canonical entities from response\n", - " canonical_entities = [\n", - " output for output in json.loads(response.text)[\"canonical_entities\"]\n", - " ]\n", - "\n", - " canonical_entities = [\n", - " CanonicalEntity.model_validate(canonical_entity)\n", - " for canonical_entity in canonical_entities\n", - " ]\n", - "\n", - " return canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52c14551", - "metadata": {}, - "outputs": [], - "source": [ - "output_root = Path(DATA_ROOT) / \"preds\"\n", - "output_root.mkdir(parents=True, exist_ok=True)\n", - "\n", - "prompt_version = \"1\"\n", - "\n", - "timestamp = time.strftime(\"%y%m%d_%H%M\")\n", - "base_dir_name = f\"preds-{model}-pv{prompt_version}-{timestamp}\"\n", - "output_dir = output_root / base_dir_name\n", - "\n", - "output_dir.mkdir(parents=True, exist_ok=False)\n", - "print(f\"Saving canonical entities to {output_dir}\")\n", - "\n", - "for doc_path in documents:\n", - " print(f\"Processing document: {doc_path}\")\n", - "\n", - " try:\n", - " canonical_entities = extract_canonical_entities(doc_path, model=model)\n", - " print(f\"Extracted {len(canonical_entities)} canonical entities.\")\n", - "\n", - " target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", - " )\n", - " target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)\n", - " target_path = output_dir / f\"{target_filename}.json\"\n", - "\n", - " save_json(\n", - " [\n", - " canonical_entity.model_dump()\n", - " | {\"entity_id\": canonical_entity.entity_id.hex}\n", - " for canonical_entity in canonical_entities\n", - " ],\n", - " str(target_path),\n", - " )\n", - "\n", - " except Exception as e:\n", - " print(f\"Error processing document {doc_path}: {e}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f734b642", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai (3.10.19)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.19" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb b/notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb deleted file mode 100644 index ebe84474..00000000 --- a/notebooks/experiments/entity-disambiguation/02-disambiguation-metric.ipynb +++ /dev/null @@ -1,431 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "10301fb9", - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import json\n", - "import unicodedata\n", - "from pathlib import Path\n", - "from typing import Any, Dict, Iterable, List, Optional, Set, Tuple\n", - "\n", - "from IPython.display import Markdown\n", - "from ollama import ChatResponse\n", - "from pydantic import BaseModel\n", - "from pydantic.json_schema import JsonSchemaValue\n", - "from rich.pretty import pprint\n", - "from tqdm import tqdm\n", - "\n", - "from aymurai.meta.entities import CanonicalEntity # , EntityRelation\n", - "from aymurai.utils.json_data import get_pretty, load_json, save_json" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "93f3977b", - "metadata": {}, - "outputs": [], - "source": [ - "def normalize_text(text: str) -> str:\n", - " \"\"\"\n", - " Normaliza un alias:\n", - " - pasa a minúsculas\n", - " - elimina espacios extra\n", - " - quita tildes/acentos\n", - " \"\"\"\n", - " if text is None:\n", - " return \"\"\n", - " text = text.strip().lower()\n", - " # eliminar acentos\n", - " text = unicodedata.normalize(\"NFD\", text)\n", - " text = \"\".join(ch for ch in text if unicodedata.category(ch) != \"Mn\")\n", - " return text" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cfaeeada", - "metadata": {}, - "outputs": [], - "source": [ - "def get_alias_set(entity: Dict[str, Any]) -> Set[str]:\n", - " \"\"\"\n", - " Devuelve el conjunto de aliases normalizados para una entidad,\n", - " asegurándose de incluir el canonical_text como alias.\n", - " \"\"\"\n", - " aliases = set()\n", - " # aliases explícitos\n", - " for a in entity.get(\"aliases\", []):\n", - " norm = normalize_text(a)\n", - " if norm:\n", - " aliases.add(norm)\n", - " # incluir canonical_text\n", - " canonical = normalize_text(entity.get(\"canonical_text\", \"\"))\n", - " if canonical:\n", - " aliases.add(canonical)\n", - " return aliases" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "789f9be0", - "metadata": {}, - "outputs": [], - "source": [ - "def alias_jaccard(aliases_gold: Set[str], aliases_pred: Set[str]) -> float:\n", - " \"\"\"\n", - " Similaridad Jaccard entre conjuntos de aliases.\n", - " \"\"\"\n", - " if not aliases_gold and not aliases_pred:\n", - " return 1.0\n", - " union = aliases_gold | aliases_pred\n", - " if not union:\n", - " return 0.0\n", - " inter = aliases_gold & aliases_pred\n", - " return len(inter) / len(union)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b551edbc", - "metadata": {}, - "outputs": [], - "source": [ - "def greedy_matching(\n", - " sim_matrix: List[List[float]], sim_threshold: float\n", - ") -> List[Tuple[int, int, float]]:\n", - " \"\"\"\n", - " Emparejamiento greedy máximo por similitud:\n", - " - sim_matrix[i][j] = similitud entre entidad gold i y pred j\n", - " - sim_threshold: mínimo para considerar un match\n", - "\n", - " Devuelve una lista de tuplas (i_gold, j_pred, sim).\n", - " \"\"\"\n", - " matches: List[Tuple[int, int, float]] = []\n", - " num_gold = len(sim_matrix)\n", - " num_pred = len(sim_matrix[0]) if num_gold > 0 else 0\n", - "\n", - " # Generar la lista de candidatos (i, j, sim) por encima del umbral\n", - " candidates: List[Tuple[float, int, int]] = []\n", - " for i in range(num_gold):\n", - " for j in range(num_pred):\n", - " sim = sim_matrix[i][j]\n", - " if sim >= sim_threshold:\n", - " candidates.append((sim, i, j))\n", - "\n", - " # Ordenar descendente por similitud\n", - " candidates.sort(reverse=True, key=lambda x: x[0])\n", - "\n", - " used_gold = set()\n", - " used_pred = set()\n", - "\n", - " for sim, i, j in candidates:\n", - " if i in used_gold or j in used_pred:\n", - " continue\n", - " used_gold.add(i)\n", - " used_pred.add(j)\n", - " matches.append((i, j, sim))\n", - "\n", - " return matches\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b59d4083", - "metadata": {}, - "outputs": [], - "source": [ - "def compute_metrics_components(\n", - " gold_entities: List[Dict[str, Any]],\n", - " pred_entities: List[Dict[str, Any]],\n", - " sim_threshold: float = 0.3,\n", - ") -> Dict[str, float]:\n", - " \"\"\"\n", - " Calcula los componentes de la métrica:\n", - " - F1_ent: F1 de entidades (detección de entidades canónicas)\n", - " - AliasF1_macro: F1 macro promedio sobre aliases por entidad emparejada\n", - " - Acc_label: accuracy de labels en entidades emparejadas\n", - " - Acc_role: accuracy de roles en entidades emparejadas\n", - " \"\"\"\n", - "\n", - " # Caso trivial: sin entidades en ambos\n", - " if not gold_entities and not pred_entities:\n", - " return {\n", - " \"F1_ent\": 1.0,\n", - " \"AliasF1_macro\": 1.0,\n", - " \"Acc_label\": 1.0,\n", - " \"Acc_role\": 1.0,\n", - " }\n", - "\n", - " # Preprocesar aliases, labels y roles\n", - " gold_aliases = [get_alias_set(e) for e in gold_entities]\n", - " pred_aliases = [get_alias_set(e) for e in pred_entities]\n", - "\n", - " gold_labels = [e.get(\"aymurai_label\") for e in gold_entities]\n", - " pred_labels = [e.get(\"aymurai_label\") for e in pred_entities]\n", - "\n", - " gold_roles = [e.get(\"attributes\", {}).get(\"role\") for e in gold_entities]\n", - " pred_roles = [e.get(\"attributes\", {}).get(\"role\") for e in pred_entities]\n", - "\n", - " num_gold = len(gold_entities)\n", - " num_pred = len(pred_entities)\n", - "\n", - " # Matriz de similitud de aliases\n", - " sim_matrix: List[List[float]] = []\n", - " for i in range(num_gold):\n", - " row = []\n", - " for j in range(num_pred):\n", - " sim = alias_jaccard(gold_aliases[i], pred_aliases[j])\n", - " row.append(sim)\n", - " sim_matrix.append(row)\n", - "\n", - " # Matching greedy\n", - " matches = greedy_matching(sim_matrix, sim_threshold=sim_threshold)\n", - "\n", - " TP = len(matches)\n", - " FN = num_gold - TP\n", - " FP = num_pred - TP\n", - "\n", - " # Entidad-level precision/recall/F1\n", - " if TP + FP > 0:\n", - " P_ent = TP / (TP + FP)\n", - " else:\n", - " P_ent = 0.0\n", - "\n", - " if TP + FN > 0:\n", - " R_ent = TP / (TP + FN)\n", - " else:\n", - " R_ent = 0.0\n", - "\n", - " if P_ent + R_ent > 0:\n", - " F1_ent = 2 * P_ent * R_ent / (P_ent + R_ent)\n", - " else:\n", - " F1_ent = 0.0\n", - "\n", - " # Alias-level F1 macro\n", - " if TP > 0:\n", - " alias_f1_sum = 0.0\n", - " label_correct = 0\n", - " role_correct = 0\n", - "\n", - " for i, j, _sim in matches:\n", - " A_g = gold_aliases[i]\n", - " A_p = pred_aliases[j]\n", - "\n", - " inter = len(A_g & A_p)\n", - " P_alias = inter / len(A_p) if len(A_p) > 0 else 0.0\n", - " R_alias = inter / len(A_g) if len(A_g) > 0 else 0.0\n", - " if P_alias + R_alias > 0:\n", - " F1_alias = 2 * P_alias * R_alias / (P_alias + R_alias)\n", - " else:\n", - " F1_alias = 0.0\n", - "\n", - " alias_f1_sum += F1_alias\n", - "\n", - " # label\n", - " if gold_labels[i] == pred_labels[j]:\n", - " label_correct += 1\n", - "\n", - " # rol\n", - " if gold_roles[i] == pred_roles[j]:\n", - " role_correct += 1\n", - "\n", - " AliasF1_macro = alias_f1_sum / TP\n", - " Acc_label = label_correct / TP\n", - " Acc_role = role_correct / TP\n", - " else:\n", - " AliasF1_macro = 0.0\n", - " Acc_label = 0.0\n", - " Acc_role = 0.0\n", - "\n", - " return {\n", - " \"F1_ent\": F1_ent,\n", - " \"AliasF1_macro\": AliasF1_macro,\n", - " \"Acc_label\": Acc_label,\n", - " \"Acc_role\": Acc_role,\n", - " }\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "14cab697", - "metadata": {}, - "outputs": [], - "source": [ - "def evaluate_disambiguation(\n", - " gold_json: Any,\n", - " pred_json: Any,\n", - " w_ent: float = 0.4,\n", - " w_alias: float = 0.35,\n", - " w_label: float = 0.2,\n", - " w_role: float = 0.05,\n", - " sim_threshold: float = 0.3,\n", - ") -> Tuple[float, Dict[str, float]]:\n", - " \"\"\"\n", - " Función principal pedida:\n", - " - gold_json: JSON ground truth (lista de entidades o string JSON)\n", - " - pred_json: JSON predicho (lista de entidades o string JSON)\n", - " - w_ent, w_alias, w_label, w_role: pesos de cada componente\n", - " - sim_threshold: umbral mínimo de similitud de aliases para emparejar entidades\n", - "\n", - " Devuelve una tupla (Score_global, métricas_componentes) donde:\n", - " - Score_global es un escalar entre 0 y 1.\n", - " - métricas_componentes es un dict con los valores individuales de cada métrica.\n", - " \"\"\"\n", - "\n", - " # Si vienen como string, parsear JSON\n", - " if isinstance(gold_json, str):\n", - " gold_entities = json.loads(gold_json)\n", - " else:\n", - " gold_entities = gold_json\n", - "\n", - " if isinstance(pred_json, str):\n", - " pred_entities = json.loads(pred_json)\n", - " else:\n", - " pred_entities = pred_json\n", - "\n", - " metrics = compute_metrics_components(\n", - " gold_entities,\n", - " pred_entities,\n", - " sim_threshold=sim_threshold,\n", - " )\n", - "\n", - " score = (\n", - " w_ent * metrics[\"F1_ent\"]\n", - " + w_alias * metrics[\"AliasF1_macro\"]\n", - " + w_label * metrics[\"Acc_label\"]\n", - " + w_role * metrics[\"Acc_role\"]\n", - " )\n", - "\n", - " return score, metrics\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12f75b12", - "metadata": {}, - "outputs": [], - "source": [ - "# Ejemplo de JSON gold y pred\n", - "gold = [\n", - " {\n", - " \"entity_id\": \"GT_1\",\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"Juan Pérez\",\n", - " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\"],\n", - " \"attributes\": {\"role\": \"imputado\"},\n", - " \"relations\": [],\n", - " }\n", - "]\n", - "\n", - "pred = [\n", - " {\n", - " \"entity_id\": \"P_1\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Juan Pérez\",\n", - " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\"],\n", - " \"attributes\": {\"role\": \"imputado\"},\n", - " \"relations\": [],\n", - " }\n", - "]\n", - "\n", - "\n", - "score, metrics = evaluate_disambiguation(gold, pred)\n", - "print(\"Metrics vector:\", metrics)\n", - "print(\"Score global:\", score)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4d1a279b", - "metadata": {}, - "outputs": [], - "source": [ - "# Ejemplo de JSON gold y pred\n", - "gold = [\n", - " {\n", - " \"entity_id\": \"GT_1\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Juan Pérez\",\n", - " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\"],\n", - " \"attributes\": {\"role\": \"imputado\"},\n", - " \"relations\": [],\n", - " },\n", - " {\n", - " \"entity_id\": \"GT_2\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"María Gómez\",\n", - " \"aliases\": [\"María\", \"Sra. Gómez\"],\n", - " \"attributes\": {\"role\": \"imputado\"},\n", - " \"relations\": [],\n", - " },\n", - "]\n", - "\n", - "pred = [\n", - " {\n", - " \"entity_id\": \"P_1\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Juan Pérez\",\n", - " \"aliases\": [\"Juan Pérez\", \"Pérez, Juan\", \"Pérez Juan\"],\n", - " \"attributes\": {\"role\": \"imputado\"},\n", - " \"relations\": [],\n", - " },\n", - " {\n", - " \"entity_id\": \"GT_2\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"María Gómez\",\n", - " \"aliases\": [\"María\", \"Sra. Gómez\"],\n", - " \"attributes\": {\"role\": \"imputado\"},\n", - " \"relations\": [],\n", - " },\n", - "]\n", - "\n", - "score, metrics = evaluate_disambiguation(gold, pred)\n", - "print(\"Metrics vector:\", metrics)\n", - "print(\"Score global:\", score)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb0c3ddf", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.19" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb b/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb deleted file mode 100644 index e907c3fc..00000000 --- a/notebooks/experiments/entity-disambiguation/04-entity-disambiguation-from-pre-clustered-validations.ipynb +++ /dev/null @@ -1,899 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "c8fc128c", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext rich\n", - "\n", - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8eeefe8b", - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import mimetypes\n", - "import os\n", - "import re\n", - "import sqlite3\n", - "import time\n", - "import unicodedata\n", - "from collections import Counter\n", - "from operator import itemgetter\n", - "from pathlib import Path\n", - "from typing import Iterable\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "import requests\n", - "from more_itertools import flatten, unique_everseen\n", - "from rapidfuzz import fuzz, process\n", - "\n", - "from aymurai.llm_providers import OllamaLLMProvider\n", - "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", - "from aymurai.utils.json_data import get_pretty, load_json, save_json" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e0ec450", - "metadata": {}, - "outputs": [], - "source": [ - "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8999\")\n", - "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", - "DATA_ROOT = Path(\n", - " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/disambiguation-eval\")\n", - ")\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", - "\n", - "print(f\"Target endpoint: {ENDPOINT}\")\n", - "print(f\"Data root: {DATA_ROOT.resolve()}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4b017330", - "metadata": {}, - "outputs": [], - "source": [ - "def call_extraction_api(\n", - " session: requests.Session, file_path: Path\n", - ") -> dict[str, object]:\n", - " \"\"\"\n", - " Calls the document extraction API with the given file.\n", - "\n", - " Args:\n", - " session (requests.Session): The HTTP session to use for the request.\n", - " file_path (Path): The path to the file to be extracted.\n", - " Returns:\n", - " dict[str, object]: The response payload containing status and details.\n", - " \"\"\"\n", - " payload: dict[str, object] = {\n", - " \"path\": str(file_path),\n", - " \"status\": \"failure\",\n", - " \"status_code\": None,\n", - " \"elapsed_s\": None,\n", - " \"detail\": None,\n", - " }\n", - "\n", - " if not file_path.exists():\n", - " payload[\"detail\"] = \"File does not exist\"\n", - " return payload\n", - "\n", - " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", - " files = {\n", - " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", - " }\n", - "\n", - " try:\n", - " start = time.perf_counter()\n", - " response = session.post(\n", - " ENDPOINT,\n", - " files=files,\n", - " timeout=REQUEST_TIMEOUT,\n", - " )\n", - " elapsed = time.perf_counter() - start\n", - " except requests.RequestException as exc:\n", - " payload[\"detail\"] = f\"Request failed: {exc}\"\n", - " return payload\n", - " finally:\n", - " files[\"file\"][1].close()\n", - "\n", - " payload[\"status_code\"] = response.status_code\n", - " payload[\"elapsed_s\"] = elapsed\n", - "\n", - " try:\n", - " response_body = response.json()\n", - " except ValueError:\n", - " response_body = {\"raw\": response.text[:500]}\n", - "\n", - " if response.ok:\n", - " payload[\"status\"] = \"success\"\n", - " payload[\"detail\"] = {\n", - " \"document_id\": response_body.get(\"document_id\"),\n", - " \"document\": response_body.get(\"document\", []),\n", - " }\n", - " else:\n", - " payload[\"detail\"] = response_body\n", - "\n", - " return payload" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef352767", - "metadata": {}, - "outputs": [], - "source": [ - "if not DATA_ROOT.exists():\n", - " raise FileNotFoundError(\n", - " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", - " )\n", - "\n", - "\n", - "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "\n", - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "print(f\"Discovered {len(documents)} documents.\")\n", - "documents" - ] - }, - { - "cell_type": "markdown", - "id": "5c1e471d", - "metadata": {}, - "source": [ - "## Fetch data from database" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "281524f4", - "metadata": {}, - "outputs": [], - "source": [ - "# Anonymization document\n", - "conn = sqlite3.connect(\"/workspace/sqlite/database.db\")\n", - "anonymization_document = pd.read_sql_query(\"SELECT * FROM anonymization_document\", conn)\n", - "conn.close()\n", - "\n", - "anonymization_document" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c6db4fc5", - "metadata": {}, - "outputs": [], - "source": [ - "# Anonymization document paragraphs\n", - "conn = sqlite3.connect(\"/workspace/sqlite/database.db\")\n", - "anonymization_document_paragraph = pd.read_sql_query(\n", - " \"SELECT * FROM anonymization_document_paragraph\", conn\n", - ")\n", - "conn.close()\n", - "\n", - "anonymization_document_paragraph" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ee8bf74e", - "metadata": {}, - "outputs": [], - "source": [ - "# Anonymization paragraph\n", - "conn = sqlite3.connect(\"/workspace/sqlite/database.db\")\n", - "anonymization_paragraph = pd.read_sql_query(\n", - " \"SELECT * FROM anonymization_paragraph\", conn\n", - ")\n", - "conn.close()\n", - "\n", - "anonymization_paragraph" - ] - }, - { - "cell_type": "markdown", - "id": "ffd8f27e", - "metadata": {}, - "source": [ - "## Get particular document" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25086b1a", - "metadata": {}, - "outputs": [], - "source": [ - "doc_filename = \"\" # Replace with actual document filename\n", - "\n", - "# Get document ID\n", - "document_id = anonymization_document.loc[\n", - " anonymization_document[\"name\"].str.startswith(doc_filename), \"id\"\n", - "].values[0]\n", - "document_id" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "caa4628c", - "metadata": {}, - "outputs": [], - "source": [ - "# Get paragraph IDs for the document\n", - "paragraph_ids = anonymization_document_paragraph.loc[\n", - " anonymization_document_paragraph[\"document_id\"] == document_id, \"paragraph_id\"\n", - "].tolist()\n", - "\n", - "paragraph_ids" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18307aab", - "metadata": {}, - "outputs": [], - "source": [ - "# Get paragraphs\n", - "doc_paragraphs = anonymization_paragraph.loc[\n", - " anonymization_paragraph[\"id\"].isin(paragraph_ids)\n", - "]\n", - "doc_paragraphs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c7b4ffe", - "metadata": {}, - "outputs": [], - "source": [ - "# Get validations\n", - "validations = doc_paragraphs.loc[:, \"validation\"].map(eval).tolist()\n", - "validations = list(flatten(validations))\n", - "validations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5a262978", - "metadata": {}, - "outputs": [], - "source": [ - "# Parse validations to extract labels and alt texts\n", - "validations = [\n", - " {\n", - " \"aymurai_label\": validation[\"attrs\"][\"aymurai_label\"],\n", - " \"text\": validation[\"attrs\"].get(\"aymurai_alt_text\") or validation[\"text\"],\n", - " }\n", - " for validation in validations\n", - "]\n", - "\n", - "validations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1de8c68f", - "metadata": {}, - "outputs": [], - "source": [ - "# Remove duplicates and sort\n", - "validations = list(unique_everseen(validations))\n", - "validations = sorted(\n", - " validations,\n", - " key=itemgetter(\"aymurai_label\", \"text\"),\n", - ")\n", - "validations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3fb25d74", - "metadata": {}, - "outputs": [], - "source": [ - "# Fix 'TEL' labels\n", - "for validation in validations:\n", - " if validation[\"aymurai_label\"] == \"TEL\":\n", - " validation[\"aymurai_label\"] = \"TELEFONO\"\n", - "\n", - "validations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ea1d64c9", - "metadata": {}, - "outputs": [], - "source": [ - "# Map 'TEXTO_ANONIMIZAR' to 'NOMBRE_ARCHIVO' when applicable\n", - "for validation in validations:\n", - " extension = os.path.splitext(validation[\"text\"])[1].lower()\n", - " if validation[\"aymurai_label\"] == \"TEXTO_ANONIMIZAR\":\n", - " if extension.endswith(\n", - " (\n", - " \"jpg\",\n", - " \"jpeg\",\n", - " \"png\",\n", - " \"pdf\",\n", - " \"docx\",\n", - " \"odt\",\n", - " \"mp4\",\n", - " \"enc\",\n", - " )\n", - " ):\n", - " validation[\"aymurai_label\"] = \"NOMBRE_ARCHIVO\"\n", - "\n", - "validations" - ] - }, - { - "cell_type": "markdown", - "id": "68a55889", - "metadata": {}, - "source": [ - "## Cluster entities based on textual" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b7fa3f5b", - "metadata": {}, - "outputs": [], - "source": [ - "def normalize(s: str) -> str:\n", - " \"\"\"\n", - " Normalize string for clustering.\n", - "\n", - " Args:\n", - " s (str): input string\n", - "\n", - " Returns:\n", - " str: normalized string\n", - " \"\"\"\n", - " # strip accents, lowercase, collapse spaces\n", - " s = \"\".join(\n", - " c for c in unicodedata.normalize(\"NFD\", s) if unicodedata.category(c) != \"Mn\"\n", - " )\n", - " s = \" \".join(s.lower().split())\n", - " return s\n", - "\n", - "\n", - "def cluster_with_cdist(\n", - " entities: list[str], threshold: int = 90, scorer: callable = fuzz.token_set_ratio\n", - "):\n", - " \"\"\"\n", - " Cluster entities based on similarity using a distance matrix.\n", - "\n", - " Args:\n", - " entities (list[str]): list of entity strings\n", - " threshold (int): similarity threshold for clustering\n", - " scorer (callable): similarity scoring function\n", - "\n", - " Returns:\n", - " list[list[tuple[str, str]]]: clusters of (original, normalized) entity tuples\n", - " \"\"\"\n", - " # matrix of similarities on normalized strings\n", - " # normalize however you like; here just lower + strip\n", - " normed = [\" \".join(e.lower().split()) for e in entities]\n", - " sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold)\n", - " sim = np.array(sim)\n", - "\n", - " # union-find\n", - " parent = list(range(len(normed)))\n", - "\n", - " def find(i):\n", - " while parent[i] != i:\n", - " parent[i] = parent[parent[i]]\n", - " i = parent[i]\n", - " return i\n", - "\n", - " def union(i, j):\n", - " ri, rj = find(i), find(j)\n", - " if ri != rj:\n", - " parent[rj] = ri\n", - "\n", - " # link pairs above threshold (upper triangle only)\n", - " n = len(normed)\n", - " for i in range(n):\n", - " for j in range(i + 1, n):\n", - " if sim[i, j] >= threshold:\n", - " union(i, j)\n", - "\n", - " # collect clusters\n", - " clusters = {}\n", - " for idx in range(n):\n", - " root = find(idx)\n", - " clusters.setdefault(root, []).append((entities[idx], normed[idx]))\n", - " return list(clusters.values())\n", - "\n", - "\n", - "def pick_canonical(cluster: list[tuple[str, str]]) -> str:\n", - " \"\"\"\n", - " Pick canonical text from a cluster.\n", - "\n", - " Args:\n", - " cluster (list[tuple[str, str]]): cluster of (original, normalized) entity tuples\n", - "\n", - " Returns:\n", - " str: chosen canonical text\n", - " \"\"\"\n", - " # prefer longest original; fall back to first\n", - " return max(cluster, key=lambda x: len(x[0]))[0]\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "82d57afd", - "metadata": {}, - "outputs": [], - "source": [ - "# Cluster entities\n", - "clusters = cluster_with_cdist(\n", - " [f\"{v['aymurai_label']}:{v['text']}\" for v in validations],\n", - " threshold=95,\n", - ")\n", - "\n", - "for cluster in clusters:\n", - " canonical = pick_canonical(cluster)\n", - " originals = [c[0] for c in cluster]\n", - " print(f\"Canonical: {canonical} -> {originals}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9d542a89", - "metadata": {}, - "outputs": [], - "source": [ - "def parse_item(item: tuple[str, ...]) -> tuple[str, str, str]:\n", - " \"\"\"\n", - " Parse an item into (label, orig, norm).\n", - "\n", - " Accepts:\n", - " - (orig, norm, label)\n", - " - (labelled_orig, labelled_norm) with prefix 'LABEL:'\n", - " Args:\n", - " item (tuple[str, ...]): input item\n", - "\n", - " Returns:\n", - " tuple[str, str, str]: (label, orig, norm)\n", - " \"\"\"\n", - " if len(item) == 3:\n", - " orig, norm, label = item\n", - " return label, orig, norm\n", - "\n", - " # len == 2: assume \"LABEL:text\"\n", - " labelled_orig, labelled_norm = item\n", - " label, orig = labelled_orig.split(\":\", 1)\n", - " _, norm = labelled_norm.split(\":\", 1)\n", - " return label, orig, norm\n", - "\n", - "\n", - "def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str:\n", - " \"\"\"\n", - " Pick the most common label from parsed items.\n", - "\n", - " Args:\n", - " parsed_items (list[tuple[str, str, str]]): parsed items\n", - "\n", - " Returns:\n", - " str: chosen label\n", - " \"\"\"\n", - " labels = [lbl for lbl, _, _ in parsed_items]\n", - " # majority vote; fallback to first\n", - " return Counter(labels).most_common(1)[0][0]\n", - "\n", - "\n", - "def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str:\n", - " \"\"\"\n", - " Choose the longest original surface form; tweak as needed.\n", - "\n", - " Args:\n", - " parsed_items (list[tuple[str, str, str]]): parsed items\n", - "\n", - " Returns:\n", - " str: chosen canonical text\n", - " \"\"\"\n", - " return max(parsed_items, key=lambda x: len(x[1]))[1]\n", - "\n", - "\n", - "def clusters_to_canonical_entities(\n", - " clusters: list[list[tuple[str, str]]],\n", - ") -> list[CanonicalEntity]:\n", - " \"\"\"\n", - " Convert clusters to CanonicalEntity objects.\n", - "\n", - " Args:\n", - " clusters (list[list[tuple[str, str]]]): clusters of (original, normalized) entity tuples\n", - "\n", - " Returns:\n", - " list[CanonicalEntity]: list of CanonicalEntity objects\n", - " \"\"\"\n", - " canonical_entities = []\n", - "\n", - " for cluster in clusters:\n", - " parsed = [parse_item(item) for item in cluster] # [(label, orig, norm), ...]\n", - " label = pick_cluster_label(parsed)\n", - " canonical_text = pick_canonical_text(parsed)\n", - " aliases = sorted({orig for _, orig, _ in parsed})\n", - " ce = CanonicalEntity(\n", - " aymurai_label=label,\n", - " canonical_text=canonical_text,\n", - " aliases=aliases,\n", - " attributes={},\n", - " relations=[],\n", - " )\n", - " canonical_entities.append(ce)\n", - "\n", - " return canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "646a5e41", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = clusters_to_canonical_entities(clusters)\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "edbf9486", - "metadata": {}, - "outputs": [], - "source": [ - "# Sort by label and canonical text\n", - "canonical_entities = sorted(\n", - " canonical_entities,\n", - " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", - ")\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e063eb07", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare target filename\n", - "target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_filename))[0]\n", - ")\n", - "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)\n", - "\n", - "# Save canonical entities to JSON for reviewing\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"/resources/data/restricted/disambiguation-eval/canonical-entities/REVIEWING/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81be5a59", - "metadata": {}, - "outputs": [], - "source": [ - "# Execute this cell to load reviewed canonical entities\n", - "reviewed_canonical_entities = load_json(\n", - " \"/resources/data/restricted/disambiguation-eval/canonical-entities/REVIEWING/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", - "]\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "893a6e06", - "metadata": {}, - "outputs": [], - "source": [ - "# Persist reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"/resources/data/restricted/disambiguation-eval/canonical-entities/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "37eb822d", - "metadata": {}, - "source": [ - "## CanonicalEntity extraction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5eed876e", - "metadata": {}, - "outputs": [], - "source": [ - "# Available models\n", - "model = \"phi4:14b\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "73400ead", - "metadata": {}, - "outputs": [], - "source": [ - "# Sanity check\n", - "provider = OllamaLLMProvider(model=model)\n", - "provider.generate(\"hola, ¿cómo estás?\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4b8ac734", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt = \"\"\"\n", - "Eres un asistente especializado en anonimización de sentencias judiciales.\n", - "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", - "Una **entidad canónica** es la representación única de una entidad real.\n", - "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", - "\n", - "# Reglas\n", - "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", - "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", - "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", - "- Cada entidad canónica debe incluir:\n", - " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", - " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", - " - `aliases` (todas las menciones textuales relevantes).\n", - " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", - "\n", - "# Notas\n", - "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", - "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - "\n", - "# Ejemplo\n", - "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", - "A: ```json\n", - "[\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Laura Beatriz Gómez\",\n", - " \"aliases\": [\"Laura Beatriz Gómez\"],\n", - " \"attributes\": {\"role\": \"Denunciante\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"42987654\",\n", - " \"aliases\": [\"42.987.654\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DIRECCION\",\n", - " \"canonical_text\": \"calle Falsa 123\",\n", - " \"aliases\": [\"calle Falsa 123\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", - " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", - " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", - " \"attributes\": {\"role\": \"Denunciado\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"27654321\",\n", - " \"aliases\": [\"27.654.321\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"calle Real 789\",\n", - " \"aliases\": [\"calle Real 789\"]\n", - " }\n", - "]\n", - "```\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "50d9cd2d", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template = \"\"\"\n", - "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", - "\n", - "# Documento\n", - "{document_text}\n", - "\n", - "# Menciones de entidades canónicas agrupadas\n", - "{canonical_entities}\n", - "\n", - "# Instrucciones\n", - "1. Evalúa cada entidad canónica listada, poniendo especial atención en las aliases.\n", - "2. Si alguna alias no corresponde a esa entidad, elimínala de la lista de aliases y créala como una nueva entidad canónica.\n", - "3. Las diferencias textuales correctas en los aliases pueden ser variantes ortográficas, abreviaciones, iniciales o errores tipográficos.\n", - "4. Diferencias sutiles que permiten desambiguar entidades distintas (por ejemplo, nombres similares de personas diferentes, fechas próximas pero distintas, números de documentos, códigos de identificación o nombres de archivos con pequeñas variaciones, etc.).\n", - "5. Normaliza canonical_text; mantén los aliases tal como aparecen.\n", - "6. Identifica roles u otros atributos relevantes en el campo attributes (por ejemplo, {{\"role\": \"Denunciante\"}}).\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81f47270", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "session = requests.Session()\n", - "doc_path = next((doc for doc in documents if doc.name == doc_filename), None)\n", - "document = call_extraction_api(session, Path(doc_path))\n", - "document = document.get(\"detail\", {}).get(\"document\")\n", - "\n", - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6143dc5", - "metadata": {}, - "outputs": [], - "source": [ - "# Remove empty 'entity_id', 'relations' and 'attributes' fields\n", - "canonical_entities = [\n", - " {\n", - " k: v\n", - " for k, v in ce.items()\n", - " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", - " }\n", - " for ce in canonical_entities\n", - "]\n", - "\n", - "# Prepare user prompt\n", - "user_prompt = user_prompt_template.format(\n", - " document_text=\"\\n\".join(document).strip(),\n", - " canonical_entities=get_pretty(canonical_entities),\n", - ")\n", - "\n", - "print(user_prompt)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bd772da7", - "metadata": {}, - "outputs": [], - "source": [ - "# Get canonical entities from the model\n", - "provider = OllamaLLMProvider(model=model)\n", - "response = provider.generate(\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options={\"temperature\": 0, \"num_ctx\": 16_384},\n", - " format=CanonicalEntities.model_json_schema(),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "adb137aa", - "metadata": {}, - "outputs": [], - "source": [ - "response" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "687c02b5", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai (3.10.19)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.19" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb b/notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb deleted file mode 100644 index f34b64d0..00000000 --- a/notebooks/experiments/entity-disambiguation/05-entity-disambiguation-pre-clustered-manual-validation.ipynb +++ /dev/null @@ -1,2447 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "c8fc128c", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext rich\n", - "\n", - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8eeefe8b", - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import json\n", - "import mimetypes\n", - "import os\n", - "import re\n", - "import time\n", - "import unicodedata\n", - "from collections import Counter\n", - "from operator import itemgetter\n", - "from pathlib import Path\n", - "from typing import Iterable\n", - "\n", - "import requests\n", - "from tqdm import tqdm\n", - "\n", - "import numpy as np\n", - "import pandas as pd\n", - "import requests\n", - "from more_itertools import flatten, unique_everseen\n", - "from rapidfuzz import fuzz, process\n", - "\n", - "from aymurai.llm_providers import OllamaLLMProvider\n", - "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", - "from aymurai.utils.json_data import get_pretty, save_json, load_json" - ] - }, - { - "cell_type": "markdown", - "id": "84d11bba", - "metadata": {}, - "source": [ - "## /document-extract endpoint output" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e0ec450", - "metadata": {}, - "outputs": [], - "source": [ - "API_URL = os.getenv(\"DOCUMENT_API_BASE_URL\", \"http://127.0.0.1:8000\")\n", - "ENDPOINT = f\"{API_URL}/misc/document-extract\"\n", - "DATA_ROOT = Path(\n", - " os.getenv(\"DOCUMENT_DATA_ROOT\", \"../../../resources/data/restricted/disambiguation-eval/files\")\n", - ")\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", - "\n", - "print(f\"Target endpoint: {ENDPOINT}\")\n", - "print(f\"Data root: {DATA_ROOT.resolve()}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef352767", - "metadata": {}, - "outputs": [], - "source": [ - "if not DATA_ROOT.exists():\n", - " raise FileNotFoundError(\n", - " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", - " )\n", - "\n", - "\n", - "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "\n", - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "print(f\"Discovered {len(documents)} documents.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "21fd6e36", - "metadata": {}, - "outputs": [], - "source": [ - "def call_extraction_api(\n", - " session: requests.Session, file_path: Path\n", - ") -> dict[str, object]:\n", - " payload: dict[str, object] = {\n", - " \"path\": str(file_path),\n", - " \"status\": \"failure\",\n", - " \"status_code\": None,\n", - " \"elapsed_s\": None,\n", - " \"detail\": None,\n", - " }\n", - "\n", - " if not file_path.exists():\n", - " payload[\"detail\"] = \"File does not exist\"\n", - " return payload\n", - "\n", - " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", - " files = {\n", - " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", - " }\n", - "\n", - " try:\n", - " start = time.perf_counter()\n", - " response = session.post(\n", - " ENDPOINT,\n", - " files=files,\n", - " timeout=REQUEST_TIMEOUT_S,\n", - " )\n", - " elapsed = time.perf_counter() - start\n", - " except requests.RequestException as exc:\n", - " payload[\"detail\"] = f\"Request failed: {exc}\"\n", - " return payload\n", - " finally:\n", - " files[\"file\"][1].close()\n", - "\n", - " payload[\"status_code\"] = response.status_code\n", - " payload[\"elapsed_s\"] = elapsed\n", - "\n", - " try:\n", - " response_body = response.json()\n", - " except ValueError:\n", - " response_body = {\"raw\": response.text[:500]}\n", - "\n", - " if response.ok:\n", - " payload[\"status\"] = \"success\"\n", - " payload[\"detail\"] = {\n", - " \"document_id\": response_body.get(\"document_id\"),\n", - " \"document\": response_body.get(\"document\", []),\n", - " }\n", - " else:\n", - " payload[\"detail\"] = response_body\n", - "\n", - " return payload" - ] - }, - { - "cell_type": "markdown", - "id": "9254ef68", - "metadata": {}, - "source": [ - "## Inference" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a308cf90", - "metadata": {}, - "outputs": [], - "source": [ - "# Function to make inference using the API\n", - "def get_predictions(sample: str) -> dict:\n", - " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample})\n", - " response.raise_for_status()\n", - " return response.json()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7ef6a0fa", - "metadata": {}, - "outputs": [], - "source": [ - "from itertools import chain\n", - "from operator import itemgetter\n", - "from typing import Any\n", - "\n", - "from more_itertools import unique_everseen\n", - "\n", - "\n", - "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", - " \"\"\"\n", - " Parse prediction labels to extract unique aymurai_label and aymurai_alt_text pairs.\n", - "\n", - " Args:\n", - " predictions (list[dict[str, Any]]): A list of prediction dictionaries.\n", - "\n", - " Returns:\n", - " list[dict[str, str]]: A list of dictionaries containing unique aymurai_label and aymurai_alt_text pairs.\n", - " \"\"\"\n", - " attrs_stream = (\n", - " label.get(\"attrs\") or {}\n", - " for label in chain.from_iterable(pred.get(\"labels\", ()) for pred in predictions)\n", - " )\n", - "\n", - " unique_pairs = unique_everseen(\n", - " (\n", - " attrs.get(\"aymurai_label\"),\n", - " attrs.get(\"aymurai_alt_text\"),\n", - " )\n", - " for attrs in attrs_stream\n", - " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", - " )\n", - "\n", - " return sorted(\n", - " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", - " key=itemgetter(\"aymurai_label\", \"text\"),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "52d6b14d", - "metadata": {}, - "source": [ - "# 8241_90_17_10_2025_128 CAUSA 14663_2020-2" - ] - }, - { - "cell_type": "markdown", - "id": "7e113ea4", - "metadata": {}, - "source": [ - "In this case, I took the .json file that Juli passed me and made a first manual correction of the clustering he did in the [notebook 04 pipeline](04-entity-disambiguation-from-pre-clustered-validations.ipynb).\n", - "\n", - "For this .json, a function needs to be created to ensure that, instead of grouping the files into a single canonical entity, it divides each one into a different canonical entity of the type ***NOMBRE_ARCHIVO***." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fa6bbadf", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare target filename\n", - "target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(documents[1]))[0]\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "934be599", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare json to review\n", - "json_path = \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - "target_path = json_path + target_filename + \"-canonical-entities.json\"\n", - "canonical_entities_to_review = load_json(target_path)\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities_to_review = [\n", - " CanonicalEntity.model_validate(entity) for entity in canonical_entities_to_review\n", - "]\n", - "canonical_entities_to_review = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities_to_review\n", - "]\n", - "\n", - "canonical_entities_to_review" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b94f9ec8", - "metadata": {}, - "outputs": [], - "source": [ - "from copy import deepcopy\n", - "\n", - "def split_aliases_by_label(items: list[CanonicalEntity], target_label: str) -> list[CanonicalEntity]:\n", - " \"\"\"\n", - " Splits aliases into new CanonicalEntities if the item matches target_label.\n", - " Removes non-matching aliases from the original entity.\n", - " \"\"\"\n", - " processed_items = []\n", - "\n", - " for item in items:\n", - " # pass through items that don't match the target label\n", - " if item['aymurai_label'] != target_label:\n", - " processed_items.append(item)\n", - " continue\n", - "\n", - " # if it matches, we process the aliases\n", - " kept_aliases = []\n", - " new_entities = []\n", - "\n", - " for alias in item['aliases']:\n", - " if alias == item['canonical_text']:\n", - " # Keep this alias in the original item\n", - " kept_aliases.append(alias)\n", - " else:\n", - " # Create a NEW entity for this alias\n", - " new_ce = CanonicalEntity(\n", - " aymurai_label=target_label,\n", - " canonical_text=alias, # The alias becomes the new canonical text\n", - " aliases=[alias], # New entity starts with no aliases\n", - " attributes=deepcopy(item['attributes']),\n", - " relations=deepcopy(item['relations'])\n", - " )\n", - " new_entities.append(new_ce)\n", - "\n", - " # update the original item's aliases\n", - " item['aliases'] = kept_aliases\n", - " \n", - " # add the original item to the result\n", - " processed_items.append(item)\n", - " \n", - " # add the newly created entities to the result\n", - " processed_items.extend(new_entities)\n", - "\n", - " return processed_items" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d86ee5bb", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities_to_review = split_aliases_by_label(canonical_entities_to_review, target_label='NOMBRE_ARCHIVO')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b21bc5f4", - "metadata": {}, - "outputs": [], - "source": [ - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in canonical_entities_to_review\n", - "]\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6b9218a8", - "metadata": {}, - "outputs": [], - "source": [ - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b7e362c6", - "metadata": {}, - "outputs": [], - "source": [ - "# Execute this cell to load reviewed canonical entities\n", - "reviewed_canonical_entities = load_json(\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", - "]\n", - "\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d138d674", - "metadata": {}, - "outputs": [], - "source": [ - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "973600c7", - "metadata": {}, - "source": [ - "## CanonicalEntity extraction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "16a8520a", - "metadata": {}, - "outputs": [], - "source": [ - "# Available models\n", - "model = \"phi4:14b\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "63c6d798", - "metadata": {}, - "outputs": [], - "source": [ - "# Sanity check\n", - "provider = OllamaLLMProvider(model=model)\n", - "provider.generate(\"hola, ¿cómo estás?\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e665c5a5", - "metadata": {}, - "outputs": [], - "source": [ - "try:\n", - " stream_prompt = \"hola, ¿cómo estás?\"\n", - " pieces = []\n", - " for event in provider.stream(stream_prompt):\n", - " print(event.text, end=\"\", flush=True)\n", - " pieces.append(event.text)\n", - " print()\n", - " full_text = \"\".join(pieces)\n", - "\n", - "except Exception as exc:\n", - " print(\"La transmisión no está disponible:\", exc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "80706810", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt = \"\"\"\n", - "Eres un asistente especializado en anonimización de sentencias judiciales.\n", - "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", - "Una **entidad canónica** es la representación única de una entidad real.\n", - "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", - "\n", - "# Reglas\n", - "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", - "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", - "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", - "- Cada entidad canónica debe incluir:\n", - " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", - " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", - " - `aliases` (todas las menciones textuales relevantes).\n", - " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", - "\n", - "# Notas\n", - "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", - "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - "\n", - "# Ejemplo\n", - "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", - "A: ```json\n", - "[\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Laura Beatriz Gómez\",\n", - " \"aliases\": [\"Laura Beatriz Gómez\"],\n", - " \"attributes\": {\"role\": \"Denunciante\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"42987654\",\n", - " \"aliases\": [\"42.987.654\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DIRECCION\",\n", - " \"canonical_text\": \"calle Falsa 123\",\n", - " \"aliases\": [\"calle Falsa 123\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", - " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", - " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", - " \"attributes\": {\"role\": \"Denunciado\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"27654321\",\n", - " \"aliases\": [\"27.654.321\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"calle Real 789\",\n", - " \"aliases\": [\"calle Real 789\"]\n", - " }\n", - "]\n", - "```\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "055fa7a6", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template = \"\"\"\n", - "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", - "\n", - "# Documento\n", - "{document_text}\n", - "\n", - "# Menciones de entidades canónicas agrupadas\n", - "{canonical_entities}\n", - "\n", - "# Instrucciones\n", - "1. Evalúa cada entidad canónica listada, poniendo especial atención en las aliases.\n", - "2. Si alguna alias no corresponde a esa entidad, elimínala de la lista de aliases y créala como una nueva entidad canónica.\n", - "3. Las diferencias textuales correctas en los aliases pueden ser variantes ortográficas, abreviaciones, iniciales o errores tipográficos.\n", - "4. Diferencias sutiles que permiten desambiguar entidades distintas (por ejemplo, nombres similares de personas diferentes, fechas próximas pero distintas, números de documentos, códigos de identificación o nombres de archivos con pequeñas variaciones, etc.).\n", - "5. Normaliza canonical_text; mantén los aliases tal como aparecen.\n", - "6. Identifica roles u otros atributos relevantes en el campo attributes (por ejemplo, {{\"role\": \"Denunciante\"}}).\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9bc94b25", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "session = requests.Session()\n", - "document = call_extraction_api(session, Path(documents[1]))\n", - "document = document.get(\"detail\", {}).get(\"document\")\n", - "\n", - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d53eae0", - "metadata": {}, - "outputs": [], - "source": [ - "# Get paragraphs with at least one NER predicted label\n", - "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - "pred_paragraphs = [paragraph['document'] for paragraph in ner_predictions if paragraph['labels']]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d2b8a84d", - "metadata": {}, - "outputs": [], - "source": [ - "# Remove empty 'entity_id', 'relations' and 'attributes' fields\n", - "canonical_entities = [\n", - " {\n", - " k: v\n", - " for k, v in ce.items()\n", - " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", - " }\n", - " for ce in canonical_entities\n", - "]\n", - "\n", - "# Prepare user prompt\n", - "user_prompt = user_prompt_template.format(\n", - " document_text=\"\\n\".join(pred_paragraphs).strip(),\n", - " canonical_entities=get_pretty(canonical_entities),\n", - ")\n", - "\n", - "print(user_prompt)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "04e638df", - "metadata": {}, - "outputs": [], - "source": [ - "try:\n", - " stream_prompt = messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ]\n", - " pieces = []\n", - " for event in provider.stream(\n", - " messages=stream_prompt,\n", - " options={\"temperature\": 0, \"num_ctx\": 9_500},\n", - " format=CanonicalEntities.model_json_schema(),\n", - " ):\n", - " print(event.text, end=\"\", flush=True)\n", - " pieces.append(event.text)\n", - " print()\n", - " full_text = \"\".join(pieces)\n", - "\n", - "except Exception as exc:\n", - " print(\"La transmisión no está disponible:\", exc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1377bcfa", - "metadata": {}, - "outputs": [], - "source": [ - "# Get canonical entities from the model\n", - "\n", - "provider = OllamaLLMProvider(model=model)\n", - "response = provider.generate(\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options={\"temperature\": 0, \"num_ctx\": 16_384},\n", - " format=CanonicalEntities.model_json_schema(),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2868141f", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = [\n", - " output for output in json.loads(response.text)[\"canonical_entities\"]\n", - " ]\n", - "\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(canonical_entity)\n", - " for canonical_entity in canonical_entities\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0337fe0c", - "metadata": {}, - "outputs": [], - "source": [ - "# Save LLM-predicted canonical entities\n", - "os.makedirs(\"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\", exist_ok=True) \n", - "\n", - "target_path = Path(\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "save_json(\n", - " [\n", - " canonical_entity.model_dump()\n", - " | {\"entity_id\": canonical_entity.entity_id.hex}\n", - " for canonical_entity in canonical_entities\n", - " ],\n", - " str(target_path),\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "1ff322aa", - "metadata": {}, - "source": [ - "# 01 - NN x 5C" - ] - }, - { - "cell_type": "markdown", - "id": "924a5fc2", - "metadata": {}, - "source": [ - "# Pipeline NER - Clusterization - Validation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2197430d", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "session = requests.Session()\n", - "document = call_extraction_api(session, Path(documents[0]))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0e8b1e99", - "metadata": {}, - "outputs": [], - "source": [ - "document = document.get(\"detail\", {}).get(\"document\")\n", - "\n", - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")\n", - "\n", - "# Get NER predictions\n", - "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", - "ner_output_json = get_pretty(parsed_ner_labels)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "74407f30", - "metadata": {}, - "outputs": [], - "source": [ - "def normalize(s: str) -> str:\n", - " \"\"\"\n", - " Normalize string for clustering.\n", - "\n", - " Args:\n", - " s (str): input string\n", - "\n", - " Returns:\n", - " str: normalized string\n", - " \"\"\"\n", - " # strip accents, lowercase, collapse spaces\n", - " s = \"\".join(\n", - " c for c in unicodedata.normalize(\"NFD\", s) if unicodedata.category(c) != \"Mn\"\n", - " )\n", - " s = \" \".join(s.lower().split())\n", - " return s\n", - "\n", - "\n", - "def cluster_with_cdist(\n", - " entities: list[str], threshold: int = 90, scorer: callable = fuzz.token_set_ratio\n", - "):\n", - " \"\"\"\n", - " Cluster entities based on similarity using a distance matrix.\n", - "\n", - " Args:\n", - " entities (list[str]): list of entity strings\n", - " threshold (int): similarity threshold for clustering\n", - " scorer (callable): similarity scoring function\n", - "\n", - " Returns:\n", - " list[list[tuple[str, str]]]: clusters of (original, normalized) entity tuples\n", - " \"\"\"\n", - " # matrix of similarities on normalized strings\n", - " # normalize however you like; here just lower + strip\n", - " normed = [\" \".join(e.lower().split()) for e in entities]\n", - " sim = process.cdist(normed, normed, scorer=scorer, score_cutoff=threshold)\n", - " sim = np.array(sim)\n", - "\n", - " # union-find\n", - " parent = list(range(len(normed)))\n", - "\n", - " def find(i):\n", - " while parent[i] != i:\n", - " parent[i] = parent[parent[i]]\n", - " i = parent[i]\n", - " return i\n", - "\n", - " def union(i, j):\n", - " ri, rj = find(i), find(j)\n", - " if ri != rj:\n", - " parent[rj] = ri\n", - "\n", - " # link pairs above threshold (upper triangle only)\n", - " n = len(normed)\n", - " for i in range(n):\n", - " for j in range(i + 1, n):\n", - " if sim[i, j] >= threshold:\n", - " union(i, j)\n", - "\n", - " # collect clusters\n", - " clusters = {}\n", - " for idx in range(n):\n", - " root = find(idx)\n", - " clusters.setdefault(root, []).append((entities[idx], normed[idx]))\n", - " return list(clusters.values())\n", - "\n", - "\n", - "def pick_canonical(cluster: list[tuple[str, str]]) -> str:\n", - " \"\"\"\n", - " Pick canonical text from a cluster.\n", - "\n", - " Args:\n", - " cluster (list[tuple[str, str]]): cluster of (original, normalized) entity tuples\n", - "\n", - " Returns:\n", - " str: chosen canonical text\n", - " \"\"\"\n", - " # prefer longest original; fall back to first\n", - " return max(cluster, key=lambda x: len(x[0]))[0]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6a355dc9", - "metadata": {}, - "outputs": [], - "source": [ - "# Cluster entities\n", - "clusters = cluster_with_cdist(\n", - " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", - " threshold=95,\n", - ")\n", - "\n", - "for cluster in clusters:\n", - " canonical = pick_canonical(cluster)\n", - " originals = [c[0] for c in cluster]\n", - " print(f\"Canonical: {canonical} -> {originals}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a1f5b54c", - "metadata": {}, - "outputs": [], - "source": [ - "def parse_item(item: tuple[str, ...]) -> tuple[str, str, str]:\n", - " \"\"\"\n", - " Parse an item into (label, orig, norm).\n", - "\n", - " Accepts:\n", - " - (orig, norm, label)\n", - " - (labelled_orig, labelled_norm) with prefix 'LABEL:'\n", - " Args:\n", - " item (tuple[str, ...]): input item\n", - "\n", - " Returns:\n", - " tuple[str, str, str]: (label, orig, norm)\n", - " \"\"\"\n", - " if len(item) == 3:\n", - " orig, norm, label = item\n", - " return label, orig, norm\n", - "\n", - " # len == 2: assume \"LABEL:text\"\n", - " labelled_orig, labelled_norm = item\n", - " label, orig = labelled_orig.split(\":\", 1)\n", - " _, norm = labelled_norm.split(\":\", 1)\n", - " return label, orig, norm\n", - "\n", - "\n", - "def pick_cluster_label(parsed_items: list[tuple[str, str, str]]) -> str:\n", - " \"\"\"\n", - " Pick the most common label from parsed items.\n", - "\n", - " Args:\n", - " parsed_items (list[tuple[str, str, str]]): parsed items\n", - "\n", - " Returns:\n", - " str: chosen label\n", - " \"\"\"\n", - " labels = [lbl for lbl, _, _ in parsed_items]\n", - " # majority vote; fallback to first\n", - " return Counter(labels).most_common(1)[0][0]\n", - "\n", - "\n", - "def pick_canonical_text(parsed_items: list[tuple[str, str, str]]) -> str:\n", - " \"\"\"\n", - " Choose the longest original surface form; tweak as needed.\n", - "\n", - " Args:\n", - " parsed_items (list[tuple[str, str, str]]): parsed items\n", - "\n", - " Returns:\n", - " str: chosen canonical text\n", - " \"\"\"\n", - " return max(parsed_items, key=lambda x: len(x[1]))[1]\n", - "\n", - "\n", - "def clusters_to_canonical_entities(\n", - " clusters: list[list[tuple[str, str]]],\n", - ") -> list[CanonicalEntity]:\n", - " \"\"\"\n", - " Convert clusters to CanonicalEntity objects.\n", - "\n", - " Args:\n", - " clusters (list[list[tuple[str, str]]]): clusters of (original, normalized) entity tuples\n", - "\n", - " Returns:\n", - " list[CanonicalEntity]: list of CanonicalEntity objects\n", - " \"\"\"\n", - " canonical_entities = []\n", - "\n", - " for cluster in clusters:\n", - " parsed = [parse_item(item) for item in cluster] # [(label, orig, norm), ...]\n", - " label = pick_cluster_label(parsed)\n", - " canonical_text = pick_canonical_text(parsed)\n", - " aliases = sorted({orig for _, orig, _ in parsed})\n", - " ce = CanonicalEntity(\n", - " aymurai_label=label,\n", - " canonical_text=canonical_text,\n", - " aliases=aliases,\n", - " attributes={},\n", - " relations=[],\n", - " )\n", - " canonical_entities.append(ce)\n", - "\n", - " return canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "758cf776", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = clusters_to_canonical_entities(clusters)\n", - "\n", - "# Sort by label and canonical text\n", - "canonical_entities = sorted(\n", - " canonical_entities,\n", - " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", - ")\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6ba35eb5", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare target filename\n", - "target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(documents[0]))[0]\n", - ")\n", - "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "19f0af6f", - "metadata": {}, - "outputs": [], - "source": [ - "target_filename" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bab1a112", - "metadata": {}, - "outputs": [], - "source": [ - "\n", - "# Save canonical entities to JSON in to-review folder to save the raw output\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save canonical entities to JSON in reviewing folder to make te review manually\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "8cc94d9c", - "metadata": {}, - "source": [ - "Make a pause and review the json manually for those wrong outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "17c09855", - "metadata": {}, - "outputs": [], - "source": [ - "# Execute this cell to load reviewed canonical entities\n", - "reviewed_canonical_entities = load_json(\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", - "]\n", - "\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "64ac9530", - "metadata": {}, - "outputs": [], - "source": [ - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "40a2dced", - "metadata": {}, - "source": [ - "## CanonicalEntity extraction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e1e15dce", - "metadata": {}, - "outputs": [], - "source": [ - "# Available models\n", - "model = \"phi4:14b\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "edba631d", - "metadata": {}, - "outputs": [], - "source": [ - "# Sanity check\n", - "provider = OllamaLLMProvider(model=model)\n", - "provider.generate(\"hola, ¿cómo estás?\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cdb2d734", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt = \"\"\"\n", - "Eres un asistente especializado en anonimización de sentencias judiciales.\n", - "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", - "Una **entidad canónica** es la representación única de una entidad real.\n", - "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", - "\n", - "# Reglas\n", - "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", - "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", - "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", - "- Cada entidad canónica debe incluir:\n", - " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", - " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", - " - `aliases` (todas las menciones textuales relevantes).\n", - " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", - "\n", - "# Notas\n", - "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", - "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - "\n", - "# Ejemplo\n", - "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", - "A: ```json\n", - "[\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Laura Beatriz Gómez\",\n", - " \"aliases\": [\"Laura Beatriz Gómez\"],\n", - " \"attributes\": {\"role\": \"Denunciante\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"42987654\",\n", - " \"aliases\": [\"42.987.654\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DIRECCION\",\n", - " \"canonical_text\": \"calle Falsa 123\",\n", - " \"aliases\": [\"calle Falsa 123\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", - " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", - " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", - " \"attributes\": {\"role\": \"Denunciado\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"27654321\",\n", - " \"aliases\": [\"27.654.321\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"calle Real 789\",\n", - " \"aliases\": [\"calle Real 789\"]\n", - " }\n", - "]\n", - "```\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bedf1a83", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template = \"\"\"\n", - "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", - "\n", - "# Documento\n", - "{document_text}\n", - "\n", - "# Menciones de entidades canónicas agrupadas\n", - "{canonical_entities}\n", - "\n", - "# Instrucciones\n", - "1. Evalúa cada entidad canónica listada, poniendo especial atención en las aliases.\n", - "2. Si alguna alias no corresponde a esa entidad, elimínala de la lista de aliases y créala como una nueva entidad canónica.\n", - "3. Las diferencias textuales correctas en los aliases pueden ser variantes ortográficas, abreviaciones, iniciales o errores tipográficos.\n", - "4. Diferencias sutiles que permiten desambiguar entidades distintas (por ejemplo, nombres similares de personas diferentes, fechas próximas pero distintas, números de documentos, códigos de identificación o nombres de archivos con pequeñas variaciones, etc.).\n", - "5. Normaliza canonical_text; mantén los aliases tal como aparecen.\n", - "6. Identifica roles u otros atributos relevantes en el campo attributes (por ejemplo, {{\"role\": \"Denunciante\"}}).\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "be7ced82", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "session = requests.Session()\n", - "document = call_extraction_api(session, Path(documents[0]))\n", - "document = document.get(\"detail\", {}).get(\"document\")\n", - "\n", - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dc9607a8", - "metadata": {}, - "outputs": [], - "source": [ - "# Get paragraphs with at least one NER predicted label\n", - "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - "pred_paragraphs = [paragraph['document'] for paragraph in ner_predictions if paragraph['labels']]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "42a89610", - "metadata": {}, - "outputs": [], - "source": [ - "# Remove empty 'entity_id', 'relations' and 'attributes' fields\n", - "canonical_entities = [\n", - " {\n", - " k: v\n", - " for k, v in ce.items()\n", - " if k not in (\"entity_id\", \"relations\", \"attributes\") or v\n", - " }\n", - " for ce in canonical_entities\n", - "]\n", - "\n", - "# Prepare user prompt\n", - "user_prompt = user_prompt_template.format(\n", - " document_text=\"\\n\".join(document).strip(),\n", - " canonical_entities=get_pretty(canonical_entities),\n", - ")\n", - "\n", - "print(user_prompt)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6d3e2bc9", - "metadata": {}, - "outputs": [], - "source": [ - "# Get canonical entities from the model\n", - "provider = OllamaLLMProvider(model=model)\n", - "response = provider.generate(\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options={\"temperature\": 0, \"num_ctx\": 9_500},\n", - " format=CanonicalEntities.model_json_schema(),\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "172ed8d4", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = [\n", - " output for output in json.loads(response.text)[\"canonical_entities\"]\n", - " ]\n", - "\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(canonical_entity)\n", - " for canonical_entity in canonical_entities\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "87be578d", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "24833143", - "metadata": {}, - "outputs": [], - "source": [ - "# Save LLM-predicted canonical entities\n", - "os.makedirs(\"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\", exist_ok=True) \n", - "\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "9e0a7186", - "metadata": {}, - "source": [ - "# 1- FLORES (pdf)" - ] - }, - { - "cell_type": "markdown", - "id": "f758c28c", - "metadata": {}, - "source": [ - "# Pipeline NER - Clusterization - Validation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7f59197b", - "metadata": {}, - "outputs": [], - "source": [ - "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/1- FLORES ABARCA, Francisco Alexander s 149 bis J-01-00369422-0-2022-1 Sala Feria (II) nnya vict do apela pp_response_1765835782205.json\"\n", - "\n", - "json_path = Path(json_path)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0d1e5f7b", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "document = load_json(json_path)[\"document\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fb8086f8", - "metadata": {}, - "outputs": [], - "source": [ - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")\n", - "\n", - "# Get NER predictions\n", - "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", - "ner_output_json = get_pretty(parsed_ner_labels)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "afde9c03", - "metadata": {}, - "outputs": [], - "source": [ - "parsed_ner_labels" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bc66c703", - "metadata": {}, - "outputs": [], - "source": [ - "# Cluster entities\n", - "clusters = cluster_with_cdist(\n", - " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", - " threshold=95,\n", - ")\n", - "\n", - "for cluster in clusters:\n", - " canonical = pick_canonical(cluster)\n", - " originals = [c[0] for c in cluster]\n", - " print(f\"Canonical: {canonical} -> {originals}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a6d06d5b", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = clusters_to_canonical_entities(clusters)\n", - "\n", - "# Sort by label and canonical text\n", - "canonical_entities = sorted(\n", - " canonical_entities,\n", - " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", - ")\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5c62763a", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare target filename\n", - "target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", - ")\n", - "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3317ee7f", - "metadata": {}, - "outputs": [], - "source": [ - "# Save canonical entities to JSON in to-review folder to save the raw output\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save canonical entities to JSON in reviewing folder to make te review manually\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "4add5e66", - "metadata": {}, - "source": [ - "Make a pause and review the json manually for those wrong outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5b56adf8", - "metadata": {}, - "outputs": [], - "source": [ - "# Execute this cell to load reviewed canonical entities\n", - "reviewed_canonical_entities = load_json(\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", - "]\n", - "\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b30019e1", - "metadata": {}, - "outputs": [], - "source": [ - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "e5f587ef", - "metadata": {}, - "source": [ - "# 2 - FISSCHER (pdf)" - ] - }, - { - "cell_type": "markdown", - "id": "9d446c92", - "metadata": {}, - "source": [ - "# Pipeline NER - Clusterization - Validation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a45a578b", - "metadata": {}, - "outputs": [], - "source": [ - "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/2 - FISSCHER Alejandro Claudio s - 92_response_1765908855010.json\"\n", - "\n", - "json_path = Path(json_path)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "37fea663", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "document = load_json(json_path)[\"document\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ca4de17f", - "metadata": {}, - "outputs": [], - "source": [ - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")\n", - "\n", - "# Get NER predictions\n", - "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", - "ner_output_json = get_pretty(parsed_ner_labels)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8d8b9c0f", - "metadata": {}, - "outputs": [], - "source": [ - "parsed_ner_labels" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fa189443", - "metadata": {}, - "outputs": [], - "source": [ - "# Cluster entities\n", - "clusters = cluster_with_cdist(\n", - " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", - " threshold=95,\n", - ")\n", - "\n", - "for cluster in clusters:\n", - " canonical = pick_canonical(cluster)\n", - " originals = [c[0] for c in cluster]\n", - " print(f\"Canonical: {canonical} -> {originals}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d76f9a89", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = clusters_to_canonical_entities(clusters)\n", - "\n", - "# Sort by label and canonical text\n", - "canonical_entities = sorted(\n", - " canonical_entities,\n", - " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", - ")\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9e65d30f", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare target filename\n", - "target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", - ")\n", - "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f42c8398", - "metadata": {}, - "outputs": [], - "source": [ - "# Save canonical entities to JSON in to-review folder to save the raw output\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save canonical entities to JSON in reviewing folder to make te review manually\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "2daee78a", - "metadata": {}, - "source": [ - "Make a pause and review the json manually for those wrong outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f5a1c1c9", - "metadata": {}, - "outputs": [], - "source": [ - "# Execute this cell to load reviewed canonical entities\n", - "reviewed_canonical_entities = load_json(\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", - "]\n", - "\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "28359165", - "metadata": {}, - "outputs": [], - "source": [ - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "dfc64748", - "metadata": {}, - "source": [ - "# 2 - Feb. 2 (pdf)" - ] - }, - { - "cell_type": "markdown", - "id": "edf32104", - "metadata": {}, - "source": [ - "# Pipeline NER - Clusterization - Validation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bbafb4e9", - "metadata": {}, - "outputs": [], - "source": [ - "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/2 - Feb. 2 - DE ON, Kwan x 13944_response_1765836659235.json\"\n", - "\n", - "json_path = Path(json_path)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "679a5817", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "document = load_json(json_path)[\"document\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f640f548", - "metadata": {}, - "outputs": [], - "source": [ - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")\n", - "\n", - "# Get NER predictions\n", - "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", - "ner_output_json = get_pretty(parsed_ner_labels)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ce9cc2c1", - "metadata": {}, - "outputs": [], - "source": [ - "parsed_ner_labels" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a007f3c", - "metadata": {}, - "outputs": [], - "source": [ - "# Cluster entities\n", - "clusters = cluster_with_cdist(\n", - " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", - " threshold=95,\n", - ")\n", - "\n", - "for cluster in clusters:\n", - " canonical = pick_canonical(cluster)\n", - " originals = [c[0] for c in cluster]\n", - " print(f\"Canonical: {canonical} -> {originals}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c5ef7c49", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = clusters_to_canonical_entities(clusters)\n", - "\n", - "# Sort by label and canonical text\n", - "canonical_entities = sorted(\n", - " canonical_entities,\n", - " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", - ")\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b461fdab", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare target filename\n", - "target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", - ")\n", - "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "564fc2a4", - "metadata": {}, - "outputs": [], - "source": [ - "# Save canonical entities to JSON in to-review folder to save the raw output\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save canonical entities to JSON in reviewing folder to make te review manually\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "f8329a42", - "metadata": {}, - "source": [ - "Make a pause and review the json manually for those wrong outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5ac09ef3", - "metadata": {}, - "outputs": [], - "source": [ - "# Execute this cell to load reviewed canonical entities\n", - "reviewed_canonical_entities = load_json(\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", - "]\n", - "\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9006d7ec", - "metadata": {}, - "outputs": [], - "source": [ - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "2f7a2ba5", - "metadata": {}, - "source": [ - "# Jul. 18 (pdf)" - ] - }, - { - "cell_type": "markdown", - "id": "83b4b16e", - "metadata": {}, - "source": [ - "# Pipeline NER - Clusterization - Validation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "431ecd13", - "metadata": {}, - "outputs": [], - "source": [ - "json_path = \"../../../resources/data/restricted/disambiguation-eval/files/Jul. 18- SALA IV- IPANAQUE VILLAR Carlos Hector s 5c nnapes_response_1765835513742.json\"\n", - "\n", - "json_path = Path(json_path)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "692fc5d5", - "metadata": {}, - "outputs": [], - "source": [ - "# Extract document\n", - "document = load_json(json_path)[\"document\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4176067e", - "metadata": {}, - "outputs": [], - "source": [ - "if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")\n", - "\n", - "# Get NER predictions\n", - "ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - "parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", - "ner_output_json = get_pretty(parsed_ner_labels)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dbf3644d", - "metadata": {}, - "outputs": [], - "source": [ - "parsed_ner_labels" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8cfda586", - "metadata": {}, - "outputs": [], - "source": [ - "# Cluster entities\n", - "clusters = cluster_with_cdist(\n", - " [f\"{v['aymurai_label']}:{v['text']}\" for v in parsed_ner_labels],\n", - " threshold=95,\n", - ")\n", - "\n", - "for cluster in clusters:\n", - " canonical = pick_canonical(cluster)\n", - " originals = [c[0] for c in cluster]\n", - " print(f\"Canonical: {canonical} -> {originals}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b0c6b557", - "metadata": {}, - "outputs": [], - "source": [ - "canonical_entities = clusters_to_canonical_entities(clusters)\n", - "\n", - "# Sort by label and canonical text\n", - "canonical_entities = sorted(\n", - " canonical_entities,\n", - " key=lambda ce: (ce.aymurai_label.lower(), ce.canonical_text.lower()),\n", - ")\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4443d7c9", - "metadata": {}, - "outputs": [], - "source": [ - "# Prepare target filename\n", - "target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(json_path))[0]\n", - ")\n", - "target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9de334ef", - "metadata": {}, - "outputs": [], - "source": [ - "# Save canonical entities to JSON in to-review folder to save the raw output\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/to-review/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save canonical entities to JSON in reviewing folder to make te review manually\n", - "save_json(\n", - " [ce.model_dump() | {\"entity_id\": None} for ce in canonical_entities],\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "c0bb69fb", - "metadata": {}, - "source": [ - "Make a pause and review the json manually for those wrong outputs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "76b7ddc8", - "metadata": {}, - "outputs": [], - "source": [ - "# Execute this cell to load reviewed canonical entities\n", - "reviewed_canonical_entities = load_json(\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewing/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\"\n", - ")\n", - "\n", - "# Convert reviewed entities back to CanonicalEntity objects\n", - "canonical_entities = [\n", - " CanonicalEntity.model_validate(entity) for entity in reviewed_canonical_entities\n", - "]\n", - "\n", - "canonical_entities = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in canonical_entities\n", - "]\n", - "\n", - "canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6f5e15c9", - "metadata": {}, - "outputs": [], - "source": [ - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/reviewed/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")\n", - "\n", - "# Save reviewed canonical entities\n", - "save_json(\n", - " canonical_entities,\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted/\"\n", - " + target_filename\n", - " + \"-canonical-entities.json\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "555c7c5f", - "metadata": {}, - "source": [ - "# Start point of the old version of the pipeline" - ] - }, - { - "cell_type": "markdown", - "id": "ccbe21f4", - "metadata": {}, - "source": [ - "## CanonicalEntity extraction" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd025617", - "metadata": {}, - "outputs": [], - "source": [ - "# Available models\n", - "# model = \"gpt-oss:20b\"\n", - "# model = \"llama3\"\n", - "model = \"phi4:14b\"\n", - "# model = \"llama3.1:8b\"\n", - "# model = \"gemma3:270m\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "25284997", - "metadata": {}, - "outputs": [], - "source": [ - "# Sanity check\n", - "provider = OllamaLLMProvider(model=model)\n", - "provider.generate(\"hola, ¿cómo estás?\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "33ca3dd3", - "metadata": {}, - "outputs": [], - "source": [ - "try:\n", - " stream_prompt = \"hola, ¿cómo estás?\"\n", - " pieces = []\n", - " for event in provider.stream(stream_prompt):\n", - " print(event.text, end=\"\", flush=True)\n", - " pieces.append(event.text)\n", - " print()\n", - " full_text = \"\".join(pieces)\n", - "\n", - "except Exception as exc:\n", - " print(\"La transmisión no está disponible:\", exc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c7ec7c6", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt = \"\"\"\n", - "Eres un asistente especializado en anonimización de sentencias judiciales.\n", - "Tu tarea es agrupar las menciones de entidades nombradas detectadas por un modelo de NER en **entidades canónicas** sin omitir ninguna mención válida.\n", - "Una **entidad canónica** es la representación única de una entidad real.\n", - "Agrupa todas las menciones textuales (aliases) que se refieren a una misma persona, documento, lugar, número, fecha, etc., aunque aparezcan con variantes ortográficas o abreviadas.\n", - "\n", - "# Reglas\n", - "- Usa solo información presente en el documento y en las menciones del NER; no inventes datos ni concluyas hechos no expresos.\n", - "- Toda mención listada por el NER debe evaluarse. Si representa una entidad real, inclúyela en alguna entidad canónica.\n", - "- Puede haber falsos positivos y/o negativos, menciones ambiguas o incompletas, por lo que debes evaluar cada mención cuidadosamente.\n", - "- Cada entidad canónica debe incluir:\n", - " - `aymurai_label` (etiqueta del NER, p. ej. \"PER\", \"DNI\", etc.).\n", - " - `canonical_text` (forma normalizada: nombres completos, fechas normalizadas, etc.).\n", - " - `aliases` (todas las menciones textuales relevantes).\n", - " - `attributes` (diccionario opcional con roles u otras notas, p. ej. {\"role\": \"Juez/a\"}).\n", - "\n", - "# Notas\n", - "- `aliases` debe conservar las menciones textuales tal como aparecen en el documento.\n", - "- `attributes` es especialmente útil para distinguir roles procesales. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - "\n", - "# Ejemplo\n", - "Q: Con fecha 3 de marzo de 2023, la Sra. Laura Beatriz Gómez, DNI 42.987.654, con domicilio en calle Falsa 123, Barrio Los Pinos, Villa Azul, denunció a su expareja, el Sr. Martín Alberto Rodríguez, DNI 27.654.321, con domicilio en calle Real 789, por hechos de violencia física, psicológica y amenazas con armas blancas.\n", - "A: ```json\n", - "[\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Laura Beatriz Gómez\",\n", - " \"aliases\": [\"Laura Beatriz Gómez\"],\n", - " \"attributes\": {\"role\": \"Denunciante\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"42987654\",\n", - " \"aliases\": [\"42.987.654\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DIRECCION\",\n", - " \"canonical_text\": \"calle Falsa 123\",\n", - " \"aliases\": [\"calle Falsa 123\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"Barrio Los Pinos, Villa Azul\",\n", - " \"aliases\": [\"Barrio Los Pinos, Villa Azul\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Martín Alberto Rodríguez\",\n", - " \"aliases\": [\"Martín Alberto Rodríguez\"],\n", - " \"attributes\": {\"role\": \"Denunciado\"}\n", - " },\n", - " {\n", - " \"aymurai_label\": \"DNI\",\n", - " \"canonical_text\": \"27654321\",\n", - " \"aliases\": [\"27.654.321\"]\n", - " },\n", - " {\n", - " \"aymurai_label\": \"LOC\",\n", - " \"canonical_text\": \"calle Real 789\",\n", - " \"aliases\": [\"calle Real 789\"]\n", - " }\n", - "]\n", - "```\n", - "\"\"\"\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6994e3c3", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template = \"\"\"\n", - "A continuación se proporciona un documento judicial y las menciones de entidades nombradas detectadas por un modelo de NER.\n", - "\n", - "# Documento\n", - "{document_text}\n", - "\n", - "# Menciones de entidades detectadas por el NER\n", - "{ner_output_json}\n", - "\n", - "# Instrucciones\n", - "1. Evalúa cada mención listada. Si representa una entidad real, inclúyela en la lista de aliases de alguna entidad canónica.\n", - "2. No omitas entidades válidas, alias con iniciales ni variantes abreviadas.\n", - "3. Solo fusiona menciones cuando exista evidencia clara de que se refieren a la misma entidad.\n", - "4. Normaliza canonical_text; mantén los alias tal como aparecen.\n", - "5. Utiliza attributes para indicar roles (p. ej. {{\"role\": \"Denunciante\"}}) o aclaraciones de desambiguación.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "349fa489", - "metadata": {}, - "outputs": [], - "source": [ - "def extract_canonical_entities(\n", - " doc_path: str, model: str = \"phi4:14b\"\n", - ") -> CanonicalEntities:\n", - " \"\"\"\n", - " Extract canonical entities from a document.\n", - "\n", - " Args:\n", - " doc_path (str): The path to the document.\n", - " model (str, optional): The model to use for extraction. Defaults to \"phi4:14b\".\n", - "\n", - " Raises:\n", - " ValueError: If the document is empty or not found.\n", - " ValueError: If the document summary is empty or not found.\n", - "\n", - " Returns:\n", - " CanonicalEntities: The extracted canonical entities.\n", - " \"\"\"\n", - " # Extract document\n", - " session = requests.Session()\n", - " document = call_extraction_api(session, Path(doc_path))\n", - " document = document.get(\"detail\", {}).get(\"document\")\n", - "\n", - " if not document:\n", - " raise ValueError(\"Document text is empty or not found.\")\n", - "\n", - " # Get NER predictions\n", - " ner_predictions = [get_predictions(paragraph) for paragraph in tqdm(document)]\n", - " parsed_ner_labels = parse_prediction_labels(ner_predictions)\n", - " ner_output_json = get_pretty(parsed_ner_labels)\n", - "\n", - " # Prepare user prompt\n", - " user_prompt = user_prompt_template.format(\n", - " document_text=\"\\n\".join(document).strip(),\n", - " ner_output_json=ner_output_json,\n", - " )\n", - "\n", - " # Get canonical entities from the model\n", - " provider = OllamaLLMProvider(model=model)\n", - " response = provider.generate(\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options={\"temperature\": 0, \"num_ctx\": 12_000},\n", - " format=CanonicalEntities.model_json_schema(),\n", - " )\n", - "\n", - " # Parse canonical entities from response\n", - " canonical_entities = [\n", - " output for output in json.loads(response.text)[\"canonical_entities\"]\n", - " ]\n", - "\n", - " canonical_entities = [\n", - " CanonicalEntity.model_validate(canonical_entity)\n", - " for canonical_entity in canonical_entities\n", - " ]\n", - "\n", - " return canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52c14551", - "metadata": {}, - "outputs": [], - "source": [ - "output_root = Path(DATA_ROOT) / \"preds\"\n", - "output_root.mkdir(parents=True, exist_ok=True)\n", - "\n", - "prompt_version = \"1\"\n", - "\n", - "timestamp = time.strftime(\"%y%m%d_%H%M\")\n", - "base_dir_name = f\"preds-{model}-pv{prompt_version}-{timestamp}\"\n", - "output_dir = output_root / base_dir_name\n", - "\n", - "output_dir.mkdir(parents=True, exist_ok=False)\n", - "print(f\"Saving canonical entities to {output_dir}\")\n", - "\n", - "for doc_path in documents:\n", - " print(f\"Processing document: {doc_path}\")\n", - "\n", - " try:\n", - " canonical_entities = extract_canonical_entities(doc_path, model=model)\n", - " print(f\"Extracted {len(canonical_entities)} canonical entities.\")\n", - "\n", - " target_filename = re.sub(\n", - " r\"\\s+|_\", \"-\", os.path.splitext(os.path.basename(doc_path))[0]\n", - " )\n", - " target_filename = re.sub(r\"-{2,}\", \"-\", target_filename)\n", - " target_path = output_dir / f\"{target_filename}.json\"\n", - "\n", - " save_json(\n", - " [\n", - " canonical_entity.model_dump()\n", - " | {\"entity_id\": canonical_entity.entity_id.hex}\n", - " for canonical_entity in canonical_entities\n", - " ],\n", - " str(target_path),\n", - " )\n", - "\n", - " except Exception as e:\n", - " print(f\"Error processing document {doc_path}: {e}\")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb b/notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb deleted file mode 100644 index 5cc52d55..00000000 --- a/notebooks/experiments/entity-disambiguation/07-LLM-entities-disambiguation.ipynb +++ /dev/null @@ -1,1713 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "64957296", - "metadata": {}, - "source": [ - "from previous notebook `06-pre-disambiguation-optimization` we found that the best hyperparameters combinations are:\n", - "- scorer: `token_set_ratio`\n", - "- score_cutoff: `70`\n", - "- processor: `light_normalizer`\n", - "\n", - "we now proceed to make the canonical entities disambiguation checked by an LLM and we give the task to the LLM to give a role to each canonical entity when it is related to a person." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fb2b1f59", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext rich\n", - "\n", - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "607ea227", - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import json\n", - "import os\n", - "import re\n", - "from more_itertools import unique_everseen\n", - "\n", - "from pathlib import Path\n", - "from typing import Iterable\n", - "import uuid\n", - "\n", - "import requests\n", - "\n", - "import numpy as np\n", - "\n", - "from aymurai.llm_providers import OllamaLLMProvider\n", - "from aymurai.meta.entities import CanonicalEntities, CanonicalEntity\n", - "from aymurai.utils.json_data import get_pretty, save_json, load_json\n", - "\n", - "import aymurai.evaluation.metrics as aymurai_metrics\n", - "from aymurai.utils.entity_disambiguation import build_canonical_entities\n", - "from aymurai.meta.api_interfaces import DocumentAnnotations" - ] - }, - { - "cell_type": "markdown", - "id": "7ec52f24", - "metadata": {}, - "source": [ - "## /document-extract endpoint output and new endpoint anonymizer/disambiguate" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c7c3b672", - "metadata": {}, - "outputs": [], - "source": [ - "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8000\")\n", - "ENDPOINT_DOCUMENT_EXTRACT = f\"{API_BASE_URL}/misc/document-extract\"\n", - "\n", - "DATA_ROOT = Path(\n", - " os.getenv(\n", - " \"DOCUMENT_DATA_ROOT\", \"../../../resources/data/restricted/disambiguation-eval/files\"\n", - " )\n", - ")\n", - "GOLD_JSON_ROOT = Path(\n", - " os.getenv(\n", - " \"GOLD_JSON_ROOT\",\n", - " \"../../../resources/data/restricted/disambiguation-eval/canonical-entities/manual-predicted\",\n", - " )\n", - ")\n", - "\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "JSON_EXTENSION = {\".json\"}\n", - "\n", - "REQUEST_TIMEOUT_S = float(os.getenv(\"DOCUMENT_REQUEST_TIMEOUT\", \"30\"))\n", - "\n", - "print(f\"Target endpoint: {ENDPOINT_DOCUMENT_EXTRACT}\")\n", - "print(f\"Data root: {DATA_ROOT.resolve()}\")\n", - "\n", - "LIMIT = int(os.getenv(\"DISAMBIGUATION_DOC_LIMIT\", \"0\")) # 0 = no limit\n", - "TARGET_LABELS = os.getenv(\"DISAMBIGUATION_TARGET_LABELS\", \"PER,DIRECCION\")\n", - "TARGET_LABELS = [label.strip() for label in TARGET_LABELS.split(\",\") if label.strip()]\n", - "\n", - "FUZZY_THRESHOLD = int(os.getenv(\"DISAMBIGUATION_THRESHOLD\", \"70\"))\n", - "FUZZY_SCORER = os.getenv(\"DISAMBIGUATION_SCORER\", \"token_set_ratio\")\n", - "FUZZY_PROCESSOR = os.getenv(\"DISAMBIGUATION_PROCESSOR\", \"light_normalizer\")\n", - "\n", - "print(f\"API: {API_BASE_URL}\")\n", - "print(f\"Data root: {DATA_ROOT}\")\n", - "print(f\"Target labels: {TARGET_LABELS or 'ALL'}\")\n", - "print(\n", - " f\"Fuzzy params: scorer={FUZZY_SCORER}, threshold={FUZZY_THRESHOLD}, processor={FUZZY_PROCESSOR}\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "18a31502", - "metadata": {}, - "outputs": [], - "source": [ - "if not DATA_ROOT.exists():\n", - " raise FileNotFoundError(\n", - " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", - " )\n", - "\n", - "\n", - "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "\n", - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "if LIMIT > 0:\n", - " documents = documents[:LIMIT]\n", - "print(f\"Discovered {len(documents)} documents.\")\n", - "\n", - "gold_jsons = discover_documents(GOLD_JSON_ROOT, JSON_EXTENSION)\n", - "if LIMIT > 0:\n", - " gold_jsons = gold_jsons[:LIMIT]\n", - "print(f\"Discovered {len(gold_jsons)} gold JSON files.\")" - ] - }, - { - "cell_type": "markdown", - "id": "dcaed02f", - "metadata": {}, - "source": [ - "## Functions for API endpoints usage" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "464e9132", - "metadata": {}, - "outputs": [], - "source": [ - "from aymurai.experiments.entity_disambiguation.runner import (\n", - " call_extraction_api as extract_document,\n", - ")\n", - "\n", - "def predict_paragraphs(paragraphs: list[str]) -> list[dict]:\n", - " endpoint = f\"{API_BASE_URL}/anonymizer/predict\"\n", - " predictions = []\n", - " for paragraph in paragraphs:\n", - " response = requests.post(endpoint, json={\"text\": paragraph}, timeout=60)\n", - " response.raise_for_status()\n", - " predictions.append(response.json())\n", - " return predictions" - ] - }, - { - "cell_type": "markdown", - "id": "f2aa5d15", - "metadata": {}, - "source": [ - "## Canonical Entity extraction with ***LLM inference***" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8220314e", - "metadata": {}, - "outputs": [], - "source": [ - "# Available models\n", - "models = [\n", - " \"phi4:14b\",\n", - " \"gpt-oss:20b\",\n", - " \"llama3\",\n", - " \"llama3.1:8b\",\n", - " \"gemma3:270m\",\n", - "]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "82f8d1a2", - "metadata": {}, - "outputs": [], - "source": [ - "# # Sanity check\n", - "# provider = OllamaLLMProvider(model=models[0])\n", - "# provider.generate(\"hola, ¿cómo estás?\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f40ef8ed", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_1 = \"\"\"\n", - "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", - "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", - "\n", - "# Material de Trabajo\n", - "Para tu análisis, recibirás:\n", - "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", - "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", - "\n", - "# Tus Tareas\n", - "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", - "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", - "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", - "\n", - "# Reglas de Salida\n", - "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", - "- `canonical_text`: El nombre más completo y formal encontrado.\n", - "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Defensor/a de Cámara\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", - "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", - "\n", - "# Estructura de Respuesta (JSON)\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Alias Principal\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\n", - "# Ejemplo de Input\n", - "Contexto: \"...la declaración del Sr. Juan Carlos Ruiz ante este Juzgado. El imputado Ruiz negó los cargos. Por su parte, la Dra. Elena Sosa, fiscal de la causa, solicitó...\"\n", - "Entidades Candidatas:\n", - "[{\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Juan Carlos Ruiz\",\n", - " \"aliases\": [\n", - " \"Juan Carlos Ruiz\",\n", - " \"Ruiz\"\n", - " ]\n", - "},\n", - "{\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Elena Sosa\",\n", - " \"aliases\": [\n", - " \"Elena Sosa\"\n", - " ]\n", - "}]\n", - "\n", - "# Ejemplo de Output\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Juan Carlos Ruiz\",\n", - " \"aliases\": [\n", - " \"Juan Carlos Ruiz\",\n", - " \"Ruiz\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Imputado\"\n", - " }\n", - " },\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Elena Sosa\",\n", - " \"aliases\": [\n", - " \"Elena Sosa\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Fiscal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "40c5f5ae", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_2 = \"\"\"\n", - "Eres un asistente experto en análisis legal y anonimización de documentos judiciales.\n", - "Tu función es auditar y enriquecer una lista de **Entidades Canónicas (Personas)** pre-agrupadas.\n", - "\n", - "# Material de Trabajo\n", - "Para tu análisis, recibirás:\n", - "1. **Contexto de la Causa:** Una selección de párrafos del documento original donde se detectaron las menciones.\n", - "2. **Entidades Canónicas:** Una lista de grupos de aliases donde cada grupo representa a una única persona física, en teoría.\n", - "\n", - "# Tus Tareas\n", - "1. **Validación Semántica:** Usa el contexto para confirmar que los aliases de un grupo realmente refieren a la misma persona física. Si detectas que un grupo contiene personas distintas (ej. homónimos o familiares), sepáralos.\n", - "2. **Consolidación:** Si una persona aparece en dos grupos diferentes (ej. \"Juan Pérez\" en uno y \"Juan Alberto Pérez\" en otro), únelos en una única entidad canónica.\n", - "3. **Asignación de Rol:** Identifica el rol procesal (Juez/a, Denunciante, Imputado/a, Víctima, Abogado/a, etc.) analizando cómo interactúa la persona en los párrafos provistos.\n", - "\n", - "# Reglas de Salida\n", - "- Devuelve **únicamente** un objeto JSON que contenga el array de entidades procesadas.\n", - "- `canonical_text`: El nombre más completo y formal encontrado.\n", - "- `attributes`: Diccionario con el campo `\"role\"`. Si no se detecta rol, que el diccionario attributes quede vacío. Entre ellos pueden incluirse:\n", - " * \"Denunciante\"\n", - " * \"Denunciado/a\"\n", - " * \"Víctima\"\n", - " * \"Juez/a\"\n", - " * \"Defensor/a de Cámara\"\n", - " * \"Fiscal\"\n", - " * \"Abogado/a\"\n", - " * \"Perito/a\"\n", - " * \"Testigo\"\n", - " Debes asignar un rol tal cual se escribe en esa lista, no inventes nuevos roles.\n", - "- Mantén los `aliases` originales tal cual aparecen en el texto.\n", - "\n", - "# Estructura de Respuesta (JSON)\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Alias Principal\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d3f2848b", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template_1 = \"\"\"\n", - "A continuación se proporcionan fragmentos relevantes de un documento judicial y una lista de entidades (personas) pre-clusterizadas por similitud de texto.\n", - "\n", - "# Contexto de la causa, párrafos con alguna mención a las personas:\n", - "{document_text}\n", - "\n", - "# Entidades Pre-clusterizadas a validar:\n", - "{canonical_entities}\n", - "\n", - "# Instrucciones:\n", - "1. **Validación de Aliases:** Analiza si los aliases dentro de cada entidad canónica pertenecen realmente a la misma persona según los párrafos de contexto. \n", - " - Si un alias pertenece a una persona distinta (ej. un familiar con nombre similar), sepáralo en una nueva entidad.\n", - " - Si dos grupos de entidades canónicas refieren a la misma persona, fusiónalos.\n", - "2. **Identificación de Roles:** Extrae el rol procesal de cada persona basándote en el contexto (ej: Juez/a, Fiscal, Denunciante, Imputado/a, Víctima, Abogado/a, Perito/a, Testigo).\n", - "3. **Normalización:** Define el `canonical_text` como el nombre más completo y formal que aparezca en los aliases, si este trabajo ya está bien hecho no lo modifiques.\n", - "4. **Formato:** Devuelve la lista final de entidades en el formato JSON solicitado en el system prompt, asegurándote de no omitir a nadie que sea relevante.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7d9365ca", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_3 = \"\"\"\n", - "Eres un asistente experto en desambiguación de entidades judiciales.\n", - "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", - "\n", - "### Tu Tarea:\n", - "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", - "2. **Limpiar Aliases:** Elimina prefijos (Dr., Sra., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", - "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", - "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - " - **Nota:** No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica rol, usa `null`.\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve exclusivamente un array de objetos:\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Alias Principal\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0f7bf0f7", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_4 = \"\"\"\n", - "Eres un asistente experto en desambiguación de entidades judiciales.\n", - "Recibirás fragmentos de una causa y un JSON de entidades canónicas pre-agrupadas.\n", - "\n", - "### Tu Tarea:\n", - "1. **Validar y Fusionar:** Verifica que cada entidad represente a una única persona real. Si dos grupos de entidades refieren a la misma persona, fusiónalos.\n", - "2. **Limpiar Aliases:** Elimina prefijos (Dr., Dra., Dres., Sra., Sr., Lic., etc.) o sufijos de los nombres (Asesor, Administrativo, etc.). Los aliases deben ser solo nombres propios.\n", - "3. **Filtrar:** Elimina cualquier entidad que no sea una persona física.\n", - "4. **Asignar Rol:** Clasifica cada entidad según el contexto usando **únicamente** esta lista estandarizada:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - " \n", - " **Instrucciones críticas de rol:**\n", - " - Si una persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y el contexto no indica que es Juez, Fiscal o Defensor oficial, asígnale el rol de **\"Abogado/a\"**.\n", - " - No añadas información extra (ej. \"Juez de Cámara\" debe ser solo \"Juez/a\"). Si no se identifica un rol de la lista, usa `null`.\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve exclusivamente un array de objetos:\n", - "[\n", - " {\n", - " \"canonical_text\": \"Nombre Completo Normalizado\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f9bed0ca", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_5 = \"\"\"\n", - "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", - "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", - "4. **Limpiar:** En `canonical_text` y `aliases`, elimina otras palabras que no sean nombres propios.\n", - "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5ac77829", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_6 = \"\"\"\n", - "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", - "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", - "4. **Fusionar:** Si dos entidades candidatas refieren a la misma persona, devuélvelas como una sola.\n", - "5. No modifiques los `canonical_text` ni los `aliases` originales.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "26f1b81b", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_7 = \"\"\"\n", - "Eres un extractor de roles legales. Tu única función es auditar una lista de entidades pre-agrupadas basándote en fragmentos de texto judicial.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Filtrar:** Elimina cualquier entidad que no sea una persona física (ej: calles, instituciones, leyes, fechas).\n", - "2. **Asignar Rol:** Identifica el rol procesal usando EXCLUSIVAMENTE esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "3. **Regla \"Dr/a\":** Si la persona es mencionada como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito (como Juez o Fiscal), asígnale \"Abogado/a\".\n", - "4. **Manejo de Siglas e Iniciales:** Ten en cuenta que las personas pueden ser mencionadas por sus iniciales (ej: \"M.L.\" para \"Martín López\"). Si el contexto permite confirmar que unas iniciales refieren a una persona ya identificada, trátalas como un alias de esa misma entidad.\n", - "5. **Fusionar:** Si dos entidades candidatas refieren a la misma persona (ya sea por nombre completo, apellido solo o iniciales), devuélvelas como una sola entidad unificada.\n", - "6. **Integridad:** No modifiques los `canonical_text` ni los `aliases` originales; mantén la literalidad de lo extraído por el NER.\n", - "\n", - "Devuelve exclusivamente un array de objetos:\n", - "[\n", - " {\n", - " \"canonical_text\": \"Nombre Completo Normalizado\",\n", - " \"aliases\": [\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol Procesal\"\n", - " }\n", - " }\n", - "]\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "55aff26f", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_8 = \"\"\"\n", - "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", - " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", - " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", - "2. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", - "3. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", - "4. **Asignación de Rol:** Identifica el rol procesal basándote EXCLUSIVAMENTE en esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "5. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve un array de objetos con esta estructura:\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Nombre de la entidad,\n", - " \"aliases\": [\n", - " \"Nombre de la entidad\",\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol de la lista o null\"\n", - " }\n", - " }\n", - "]\n", - "No incluyas el campo 'context' en tu respuesta final.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "822e348e", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_9 = \"\"\"\n", - "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Asignación de Rol:** Identifica el rol procesal basándote en las ventanas de contexto dentro de cada entidad canónica en la parte de `attributes`['context']\n", - " Elija un rol EXCLUSIVAMENTE en esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "2. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", - "3. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", - " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", - " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", - "4. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", - "5. **Limpieza:** Limpiá los `aliases` y el `canonical_text` si los mismos tienen otras palabras, pero respeta que estén escritos de igual manera a que sus ventanas de contexto.\n", - " Te dejo un ejemplo de esta instrucción.\n", - " Vos recibís:\n", - " {\n", - " \"canonical_text\": \"por DREXLER, JORGE\",\n", - " \"aliases\": [\n", - " \"por DREXLER, JORGE\",\n", - " \"Jorge Drexler\"\n", - " ],\n", - " \"attributes\": {\n", - " \"context\": [\n", - " \"Fdo. por DREXLER, JORGE - JUEZ DE CÁMARA el mismo cita en el documento 56 que Juan es culpable\",\n", - " \"es acaso Jorge Drexler el juez designado para esta causa\"\n", - " ]\n", - " }\n", - " \n", - " Debés entregar:\n", - " {\n", - " \"canonical_text\": \"DREXLER, JORGE\",\n", - " \"aliases\": [\n", - " \"DREXLER, JORGE\",\n", - " \"Jorge Drexler\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Juez/a\"\n", - " }\n", - " \n", - "6. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve un array de objetos con esta estructura:\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Nombre de la entidad,\n", - " \"aliases\": [\n", - " \"Nombre de la entidad\",\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol de la lista o null\"\n", - " }\n", - " }\n", - "]\n", - "\n", - "No incluyas el campo 'context' en tu respuesta final.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fc51a3ea", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_10 = \"\"\"\n", - "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", - " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", - " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", - "2. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", - "3. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", - "4. **Asignación de Rol:** Identifica el rol procesal basándote EXCLUSIVAMENTE en esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "5. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", - "6. **Limpieza:** No modifiques la literalidad de los `aliases` ni del `canonical_text`.\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve un array de objetos con esta estructura:\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Nombre de la entidad,\n", - " \"aliases\": [\n", - " \"Nombre de la entidad\",\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol de la lista o null\"\n", - " }\n", - " }\n", - "]\n", - "No incluyas el campo 'context' en tu respuesta final.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cb600013", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_11 = \"\"\"\n", - "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y corregir una lista de personas pre-agrupadas basándote en su contexto.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Validación de Límites (Boundaries):** El modelo NER a veces incluye palabras adyacentes que no son parte del nombre (ej: \"por\", \"Fdo.\", \"Dres\", \"dijo\", \"con\"). Tu tarea es corregir los `aliases` y el `canonical_text` para que contengan ÚNICAMENTE el nombre de la persona, pero manteniendo la literalidad exacta (mayúsculas, tildes, comas) de cómo está escrito en el fragmento de `context`.\n", - "2. **Fusión y Desambiguación:** - Si dos grupos de entidades refieren a la misma persona física, fusiónalos.\n", - " - Si una persona aparece por sus iniciales (ej: \"M.L.\"), asóciala como alias del nombre completo si el contexto lo confirma.\n", - "3. **Filtrado:** Elimina entidades que no sean personas físicas.\n", - "4. **Asignación de Rol:** Usa exclusivamente: \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "5. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, el rol es \"Abogado/a\".\n", - "6. **Limpieza:** No modifiques la literalidad de los `aliases` ni del `canonical_text`.\n", - "\n", - "### Formato de Salida (JSON):\n", - "[\n", - " {\n", - " \"entity_id\": \"ID original\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Nombre exacto extraído del texto\",\n", - " \"aliases\": [\n", - " \"Nombre exacto extraído del texto (Igual al canonical)\",\n", - " \"Otros aliases exactos del texto...\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol de la lista o null\"\n", - " }\n", - " }\n", - "]\n", - "**IMPORTANTE:** El primer elemento de `aliases` debe ser idéntico al `canonical_text`. No incluyas el campo 'context' en la respuesta.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ca7b8755", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_DIR = \"\"\"\n", - "Eres un auditor experto en desambiguación de domicilios y direcciones en documentos judiciales. Tu tarea es validar y consolidar una lista de direcciones pre-agrupadas basándote en su contexto.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Consolidación Geográfica:** - Si dos entidades refieren a la misma ubicación física, fusiónalas en una sola entidad. \n", - " - Considera que una dirección puede estar escrita de forma completa en un alias (ej: \"Av. Rivadavia 123, CABA\") y de forma abreviada en otro (ej: \"Rivadavia 123\"). \n", - " - Trata las variantes ortográficas o abreviaturas (Av. vs Avenida, Piso vs P., Dpto vs Departamento) como aliases de la misma ubicación.\n", - "2. **Filtrado:** Elimina entidades que no sean direcciones postales o domicilios físicos (ej: correos electrónicos, URLs, nombres de juzgados o menciones abstractas como \"el domicilio constituido\").\n", - "\n", - "### Formato de Salida (JSON):\n", - "[\n", - " {\n", - " \"entity_id\": \"ID original\",\n", - " \"aymurai_label\": \"DIRECCION\",\n", - " \"canonical_text\": \"Dirección más completa extraída del texto\",\n", - " \"aliases\": [\n", - " \"Dirección más completa (Igual al canonical)\",\n", - " \"Variante 1\",\n", - " \"Variante 2\"\n", - " ],\n", - " \"attributes\": []\n", - " }\n", - "]\n", - "**IMPORTANTE:** No incluyas el campo 'context' en la respuesta.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3d9feb9f", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template_DIR= \"\"\"\n", - "Se proporciona la lista de entidades (direcciones) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su validez y si hay otras entidades de direcciones que corresponden a esa.\n", - "\n", - "# Entidades Pre-clusterizadas a validar:\n", - "{canonical_entities}\n", - "\n", - "Procesa la lista siguiendo las instrucciones de filtrado y fusión.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b0d4ad36", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template_PER = \"\"\"\n", - "Se proporciona la lista de entidades (personas) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su rol y validez.\n", - "\n", - "# Entidades Pre-clusterizadas a validar:\n", - "{canonical_entities}\n", - "\n", - "Procesa la lista siguiendo las instrucciones de filtrado, fusión y asignación de roles.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "efc48244", - "metadata": {}, - "outputs": [], - "source": [ - "def pre_cluster(\n", - " paragraphs: list[dict],\n", - " target_labels: list[str] = None,\n", - " threshold: int = 70,\n", - ") -> CanonicalEntities:\n", - "\n", - " predictions = DocumentAnnotations(data=paragraphs)\n", - "\n", - " labels = [\n", - " label for paragraph in predictions.data for label in (paragraph.labels or [])\n", - " ]\n", - "\n", - " target_set = {label.strip() for label in target_labels} if target_labels else None\n", - "\n", - " canonical_entities = build_canonical_entities(\n", - " labels,\n", - " target_labels=target_set,\n", - " threshold=threshold,\n", - " )\n", - "\n", - " return canonical_entities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1431d116", - "metadata": {}, - "outputs": [], - "source": [ - "import copy\n", - "\n", - "def add_canonical_entities_context(\n", - " predictions: list[dict], \n", - " entities: list[dict],\n", - " context_window_length: int | None = 120,\n", - " max_context_snippets: int | None = 5,\n", - ") -> list[dict]:\n", - " \"\"\"\n", - " Creates a deep copy of entities and adds context. \n", - " \n", - " Args:\n", - " predictions: List of prediction dictionaries from the API.\n", - " entities: List of canonical entities.\n", - " context_window_length: Length of the window around the label. If None, full paragraph is used.\n", - " target_label: The specific label to filter. If None, all labels are considered.\n", - " \"\"\"\n", - " # 1. Deep copy to protect original variable\n", - " entities_with_context = copy.deepcopy(entities)\n", - "\n", - " # 2. Process each entity\n", - " for entity in entities_with_context:\n", - " if 'attributes' not in entity or entity['attributes'] is None:\n", - " entity['attributes'] = {}\n", - " if 'context' not in entity['attributes']:\n", - " entity['attributes']['context'] = []\n", - " \n", - " aliases = [a for a in entity.get('aliases', [])]\n", - "\n", - " alias_to_snippets = {alias: [] for alias in aliases}\n", - " all_snippets_ordered = []\n", - "\n", - " # 3. Iterate through predictions\n", - " for pred in predictions:\n", - " if not pred.get('labels'):\n", - " continue\n", - "\n", - " doc_text = pred.get('document', '')\n", - " \n", - " for label in pred.get('labels', []):\n", - " if entity.get('aymurai_label') and label['attrs']['aymurai_label'] != entity.get('aymurai_label'):\n", - " continue\n", - "\n", - " alias_name = label['attrs']['aymurai_alt_text']\n", - " if alias_name not in aliases:\n", - " continue\n", - " \n", - " # Handle Window vs Full Paragraph\n", - " if context_window_length is None:\n", - " snippet = doc_text\n", - " else:\n", - " start = label['start_char']\n", - " end = label['end_char']\n", - "\n", - " window_start = max(0, start - context_window_length)\n", - " window_end = min(len(doc_text), end + context_window_length)\n", - "\n", - " # Expand to word boundaries to avoid truncating leading/trailing words.\n", - " while window_start > 0 and not doc_text[window_start - 1].isspace():\n", - " window_start -= 1\n", - " while window_end < len(doc_text) and not doc_text[window_end - 1].isspace():\n", - " window_end += 1\n", - "\n", - " snippet = doc_text[window_start:window_end]\n", - "\n", - " clean_snippet = \" \".join(snippet.split())\n", - "\n", - " if clean_snippet not in alias_to_snippets[alias_name]:\n", - " alias_to_snippets[alias_name].append(clean_snippet)\n", - " if clean_snippet not in all_snippets_ordered:\n", - " all_snippets_ordered.append(clean_snippet)\n", - "\n", - " baseline = []\n", - " for alias in aliases:\n", - " snips = alias_to_snippets.get(alias, [])\n", - " if snips:\n", - " baseline.append(snips[0])\n", - " \n", - " baseline = list(unique_everseen(baseline))\n", - " \n", - " remaining = [s for s in all_snippets_ordered if s not in baseline]\n", - " merged = baseline + remaining\n", - "\n", - " effective_limit = max(max_context_snippets, len(baseline))\n", - " entity['attributes']['context'] = merged[:effective_limit]\n", - "\n", - " return entities_with_context\n", - "\n", - "def validate_canonical_entities(\n", - " canonical_entities_raw: list[CanonicalEntity], target_label: str | None = None\n", - ") -> list[CanonicalEntity]:\n", - "\n", - " if target_label:\n", - " canonical_entities_val = [\n", - " e for e in canonical_entities_raw if e.aymurai_label == target_label\n", - " ]\n", - " else:\n", - " canonical_entities_val = canonical_entities_raw\n", - "\n", - " canonical_entities_val = [\n", - " CanonicalEntity.model_validate(canonical_entity)\n", - " for canonical_entity in canonical_entities_val\n", - " ]\n", - "\n", - " canonical_entities_val = [\n", - " entity.model_dump() | {\"entity_id\": uuid.uuid4()}\n", - " for entity in canonical_entities_val\n", - " ]\n", - "\n", - " return canonical_entities_val" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fded1133", - "metadata": {}, - "outputs": [], - "source": [ - "tokenizers = {\n", - " \"phi4:14b\": \"microsoft/phi-4\",\n", - " \"gpt-oss:20b\": \"EleutherAI/gpt-neox-20b\",\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f93c8263", - "metadata": {}, - "outputs": [], - "source": [ - "from transformers import AutoTokenizer\n", - "\n", - "def get_phi4_tokens(system_prompt, user_prompt, model):\n", - " \n", - " try:\n", - " tokenizer = AutoTokenizer.from_pretrained(tokenizers[model])\n", - " \n", - " messages = [\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ]\n", - " try:\n", - " full_text = tokenizer.apply_chat_template(\n", - " messages, \n", - " tokenize=False, \n", - " add_generation_prompt=True\n", - " )\n", - " except Exception:\n", - " full_text = f\"{system_prompt}\\n{user_prompt}\"\n", - " \n", - " tokens = tokenizer.encode(full_text)\n", - " return len(tokens)\n", - " \n", - " except Exception as e:\n", - " print(f\"Error loading tokenizer {tokenizers[model]}: {e}\")\n", - " return int(len((system_prompt + user_prompt).split()) * 1.4)\n", - "\n", - "\n", - "\n", - "def llm_infer_canonical_entities(\n", - " system_prompt: str,\n", - " user_prompt_template: str,\n", - " model: str,\n", - " document_path: Path,\n", - " gold_path: Path,\n", - " context_window_length: int | None = 120,\n", - " model_context: int = 9_500,\n", - " token_limit_frac: float = 2/3,\n", - " target_label: str = \"PER\",\n", - " temperature: int = 0,\n", - " decompose_by: int | None = 0,\n", - ") -> dict:\n", - " \n", - " \"\"\"\n", - " Infers canonical entities using an LLM by providing context windows \n", - " around detected entities and pre-clusterization results.\n", - " \"\"\"\n", - "\n", - " # 1. Filename cleaning\n", - " clean_base_name = document_path.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", - " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", - "\n", - " print(f\"----- Processing document: {target_filename} -----\")\n", - "\n", - " # 2. Extract document text via API\n", - " session = requests.Session()\n", - " api_response = extract_document(\n", - " session,\n", - " file_path = Path(document_path),\n", - " endpoint=f\"{API_BASE_URL}/misc/document-extract\",\n", - " timeout_s=300,\n", - " )\n", - " \n", - " document_paragraphs = api_response.get(\"detail\", {}).get(\"document\")\n", - "\n", - " if not document_paragraphs:\n", - " raise ValueError(\"Document text is empty or not found for {target_filename}.\")\n", - "\n", - " # 3. Get the pre-clustered entities with context from API calls\n", - " predictions = predict_paragraphs(document_paragraphs)\n", - " \n", - " canonical_entities_pre_cluster = pre_cluster(\n", - " paragraphs=predictions,\n", - " target_labels=[target_label],\n", - " threshold=70,\n", - " )\n", - "\n", - " canonical_entities_pre_cluster = validate_canonical_entities(\n", - " canonical_entities_raw=canonical_entities_pre_cluster,\n", - " target_label=target_label\n", - " )\n", - "\n", - " canonical_entities_with_context = add_canonical_entities_context(\n", - " predictions=predictions,\n", - " entities=canonical_entities_pre_cluster,\n", - " context_window_length=context_window_length,\n", - " )\n", - "\n", - " # 4. Clean entities to save tokens\n", - " canonical_entities_prompt = [\n", - " {\n", - " k: v\n", - " for k, v in ce.items()\n", - " if k in (\"canonical_text\",\"aliases\",\"attributes\")\n", - " }\n", - " for ce in canonical_entities_with_context\n", - " ]\n", - "\n", - " token_limit = int(model_context*token_limit_frac)\n", - "\n", - " # 5. Find Optimal Batch Size if decompose_by is None\n", - " if decompose_by is None:\n", - " current_batch_size = len(canonical_entities_prompt)\n", - " print(f\"{'-' * 60}\")\n", - " print(\"Searching for optimal batch size...\")\n", - " print(f\"Starting with {current_batch_size} entities.\")\n", - " \n", - " while current_batch_size > 0:\n", - " # Test with the first N entities\n", - " test_batch = canonical_entities_prompt[:current_batch_size]\n", - " test_prompt = user_prompt_template.format(\n", - " canonical_entities=get_pretty(test_batch)\n", - " )\n", - " \n", - " num_tokens = get_phi4_tokens(system_prompt=system_prompt, user_prompt=test_prompt, model=model)\n", - " \n", - " if num_tokens <= token_limit:\n", - " decompose_by = current_batch_size\n", - " print(f\"{'-' * 60}\")\n", - " print(f\"Optimal batch size found: {decompose_by} entities ({num_tokens} tokens).\")\n", - " break\n", - " \n", - " current_batch_size -= 1\n", - " \n", - " if not decompose_by: # Safety check if even 1 entity is too large\n", - " print(\"\\nEven a single entity exceeds the token limit.\")\n", - " return None\n", - "\n", - " # 6. Prepare batches. If decompose_by is 0 or less, we put all entities in one single list (one batch)\n", - " if decompose_by <= 0:\n", - " entity_batches = [canonical_entities_prompt]\n", - " else:\n", - " entity_batches = [\n", - " canonical_entities_prompt[i : i + decompose_by]\n", - " for i in range(0, len(canonical_entities_prompt), decompose_by)\n", - " ]\n", - "\n", - " all_raw_outputs = []\n", - " all_user_prompts = []\n", - "\n", - " # 7. Iterate through batches\n", - " for batch_index, batch in enumerate(entity_batches):\n", - " print(f\"{'-' * 60}\")\n", - " print(f\"Processing batch {batch_index + 1}/{len(entity_batches)}.\")\n", - " \n", - " user_prompt = user_prompt_template.format(\n", - " canonical_entities=get_pretty(batch),\n", - " )\n", - " \n", - " all_user_prompts.append(user_prompt)\n", - "\n", - " # 7.A Token Validation\n", - " len_tokens = get_phi4_tokens(system_prompt=system_prompt, user_prompt=user_prompt, model=model)\n", - " if len_tokens > model_context:\n", - " print(f\"Batch {batch_index} too large ({len_tokens} tokens).\")\n", - " print(\"Skipping batch.\")\n", - " continue\n", - " else:\n", - " print(f\"Total batch tokens: {len_tokens} within model context ({model_context}).\")\n", - "\n", - " # 7.B LLM Inference\n", - " provider = OllamaLLMProvider(model=model)\n", - " response = provider.generate(\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options={\"temperature\": temperature, \"num_ctx\": model_context},\n", - " format=CanonicalEntities.model_json_schema(),\n", - " )\n", - "\n", - " # 7.C Parse and collect results\n", - " batch_entities = json.loads(response.text).get(\"canonical_entities\", [])\n", - " all_raw_outputs.extend(batch_entities)\n", - "\n", - "\n", - " canonical_entities_llm = validate_canonical_entities(\n", - " canonical_entities_raw=all_raw_outputs\n", - " )\n", - "\n", - " # 8. Load Gold Standard for reference\n", - " canonical_entities_gold = load_json(json_file_path=gold_path)\n", - "\n", - " print(f\"{'-' * 60}\")\n", - " print(f\"Summary for {target_filename}:\")\n", - " print(f\"- Pre-cluster entities: {len(canonical_entities_pre_cluster)}\")\n", - " print(f\"- LLM generated entities: {len(canonical_entities_llm)}\")\n", - " print(f\"- Gold standard entities: {len(canonical_entities_gold)}\")\n", - "\n", - " # 9. Map the canonical entities in the predictions documents te return the right format for the front-end\n", - "\n", - " predictions_llm = copy.deepcopy(predictions)\n", - " \n", - " new_ids_map = {}\n", - "\n", - " for document in predictions_llm:\n", - " if not document.get('labels'):\n", - " continue\n", - "\n", - " for label in document.get('labels'):\n", - " label_text = label['attrs']['aymurai_alt_text']\n", - " if (\n", - " label['attrs']['canonical_entity_id'] is None\n", - " and len(label['attrs']['aymurai_label_subclass']) == 0\n", - " ):\n", - " pred_label = label['attrs']['aymurai_label']\n", - " for ce in canonical_entities_llm:\n", - " ce_label = ce.get(\"aymurai_label\")\n", - " if pred_label == ce_label:\n", - " entity_id = ce.get(\"entity_id\")\n", - " attributes = ce.get(\"attributes\") or {}\n", - " role = attributes.get(\"role\")\n", - " aliases = ce.get(\"aliases\") or []\n", - "\n", - " if any(\n", - " str(alias).strip() == str(label_text).strip()\n", - " for alias in aliases\n", - " ):\n", - " label['attrs']['canonical_entity_id'] = entity_id\n", - " if ce_label == \"PER\" and role is not None:\n", - " label['attrs']['aymurai_label_subclass'].append(role)\n", - " break\n", - "\n", - " if label['attrs']['canonical_entity_id'] is None:\n", - " key = (label['attrs']['aymurai_label'], str(label_text).strip())\n", - " if key not in new_ids_map:\n", - " new_ids_map[key] = uuid.uuid4()\n", - "\n", - " label['attrs']['canonical_entity_id'] = new_ids_map[key]\n", - "\n", - " # 10. Return structured results\n", - " return {\n", - " \"target_filename\": target_filename,\n", - " \"pre_cluster_json\": canonical_entities_pre_cluster,\n", - " \"canonical_entities_with_context\": canonical_entities_with_context,\n", - " \"llm_output_json\": canonical_entities_llm,\n", - " \"gold_standard_json\": canonical_entities_gold,\n", - " \"system_prompt\": system_prompt,\n", - " \"user_prompts\": all_user_prompts,\n", - " \"len_tokens\": len_tokens,\n", - " \"predictions\": predictions_llm\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "586b1ddd", - "metadata": {}, - "outputs": [], - "source": [ - "def get_document_paths(document_check: Path, pre_clusterization_root: Path) -> dict:\n", - " \"\"\"\n", - " Generates the pre-cluster and gold JSON paths for a given document.\n", - " \n", - " Args:\n", - " document_check (Path): The original document Path object.\n", - " pre_clusterization_root (Path): The root directory for pre-clusterization data.\n", - " \n", - " Returns:\n", - " dict: A dictionary containing the 'pre_cluster_path' and 'gold_path'.\n", - " \"\"\"\n", - " # 1. Prepare target filename\n", - " clean_base_name = document_check.stem.replace(\"_\", \"-\").replace(\" \", \"-\")\n", - " target_filename = re.sub(r\"-{2,}\", \"-\", clean_base_name).strip(\"-\")\n", - "\n", - " # 2. Define subdirectories\n", - " pre_cluster_dir = pre_clusterization_root / 'best-pre-clusterization-per'\n", - " gold_dir = pre_clusterization_root / 'gold-jsons'\n", - "\n", - " # 3. Build final paths\n", - " pre_cluster_json_path = pre_cluster_dir / f\"{target_filename}-ner-preds-pre-cluster.json\"\n", - " gold_json_path = gold_dir / f\"{target_filename}-canonical-entities-gold.json\"\n", - "\n", - " return {\n", - " \"target_filename\": target_filename,\n", - " \"pre_cluster_path\": pre_cluster_json_path,\n", - " \"gold_path\": gold_json_path\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3f419ede", - "metadata": {}, - "outputs": [], - "source": [ - "PRE_CLUSTERIZATION_ROOT = GOLD_JSON_ROOT.parent / \"pre-clusterization\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "90229978", - "metadata": {}, - "outputs": [], - "source": [ - "import shutil\n", - "\n", - "def run_llm_grid_search(\n", - " models: list,\n", - " system_prompts: dict,\n", - " user_prompt_templates: dict,\n", - " context_window_lengths: list,\n", - " model_context_lengths: list,\n", - " temperatures: list,\n", - " token_limit_frac: float,\n", - " documents: list[Path],\n", - " target_label: str,\n", - " base_output_path: Path,\n", - " decompose_by: int | None = 0\n", - "):\n", - " \"\"\"\n", - " Runs a grid search over hyperparameters using nested loops.\n", - " \"\"\"\n", - "\n", - " # To keep track of all results and find the best\n", - " all_combinations_results = []\n", - "\n", - " for model in models:\n", - " for system_prompt_name, system_prompt in system_prompts.items():\n", - " for user_prompt_template_name, user_prompt_template in user_prompt_templates.items():\n", - " for context_window_length in context_window_lengths:\n", - " for model_context in model_context_lengths:\n", - " for temperature in temperatures:\n", - " \n", - " print(\n", - " f\"\\nRunning grid search with model: {model}, \"\n", - " f\"context_window_length: {context_window_length}, \"\n", - " f\"model_context: {model_context}, \"\n", - " f\"temperature: {temperature}\"\n", - " )\n", - "\n", - " # 1. Create a descriptive folder name with the cleaned names\n", - " combo_name = (\n", - " f\"model-{model}-{system_prompt_name}-\"\n", - " f\"{user_prompt_template_name}-context_window-{context_window_length}-\"\n", - " f\"model_context-{model_context}-temperature-{temperature}\"\n", - " )\n", - "\n", - " combo_dir = base_output_path / combo_name\n", - " combo_dir.mkdir(parents=True, exist_ok=True)\n", - "\n", - " metrics_results = {}\n", - " metrics_file_path = (\n", - " combo_dir / f\"evaluation_metrics_{target_label}.json\"\n", - " )\n", - "\n", - " # List to collect scores for this specific combination\n", - " current_combo_scores = []\n", - "\n", - " for document in documents:\n", - " \n", - " # Get document paths\n", - " paths = get_document_paths(document, PRE_CLUSTERIZATION_ROOT) # We use this because the gold_json is in an specific folder\n", - "\n", - " # Run LLM inference\n", - " llm_response_dict = llm_infer_canonical_entities(\n", - " system_prompt=system_prompt,\n", - " user_prompt_template=user_prompt_template,\n", - " model=model,\n", - " document_path=document,\n", - " gold_path=paths['gold_path'], # When adding this to the experiment runner, make sure to pass the correct gold path\n", - " context_window_length=context_window_length,\n", - " model_context=model_context,\n", - " target_label=target_label,\n", - " temperature=temperature,\n", - " decompose_by=decompose_by,\n", - " token_limit_frac=token_limit_frac\n", - " )\n", - " # Extract predictions\n", - " ce_llm = llm_response_dict['llm_output_json']\n", - " \n", - " # Validate and prepare for saving\n", - " ce_llm = [\n", - " CanonicalEntity.model_validate(entity)\n", - " for entity in ce_llm\n", - " ]\n", - "\n", - " ce_llm = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in ce_llm\n", - " ]\n", - "\n", - " # Save the result as the llm-pred.json\n", - " target_filename = llm_response_dict['target_filename']\n", - " llm_filename = f\"{target_filename}-llm-pred.json\"\n", - " llm_output_path = combo_dir / llm_filename\n", - "\n", - " save_json(\n", - " file_path=llm_output_path, json_data=ce_llm\n", - " )\n", - "\n", - " # Extract gold standard\n", - " ce_gold = llm_response_dict['gold_standard_json']\n", - " \n", - " # Validate and prepare for saving\n", - " ce_gold = [\n", - " CanonicalEntity.model_validate(entity)\n", - " for entity in ce_gold\n", - " ]\n", - "\n", - " ce_gold = [\n", - " entity.model_dump() | {\"entity_id\": entity.entity_id.hex}\n", - " for entity in ce_gold\n", - " ]\n", - "\n", - " len_llm = len(ce_llm)\n", - " len_gold = len(ce_gold)\n", - "\n", - " # Evaluate metrics\n", - " score, metrics = aymurai_metrics.evaluate_disambiguation(\n", - " gold_json=ce_gold,\n", - " pred_json=ce_llm,\n", - " target_label=target_label,\n", - " )\n", - " current_combo_scores.append(score)\n", - " doc_id = target_filename\n", - " metrics_results[doc_id] = {\n", - " \"label\": target_label,\n", - " \"metric_value\": score,\n", - " \"detailed_metrics\": metrics,\n", - " \"len_llm_predictions\": len_llm,\n", - " \"len_gold_standard\": len_gold\n", - " }\n", - "\n", - " # --- Calculate Average for this combination ---\n", - " avg_score = (\n", - " np.mean(current_combo_scores) if current_combo_scores else 0.0\n", - " )\n", - "\n", - " # Add average to the results file for this folder\n", - " final_output = {\n", - " \"average_combination_score\": avg_score,\n", - " \"document_details\": metrics_results,\n", - " }\n", - "\n", - " with open(metrics_file_path, \"w\") as f:\n", - " json.dump(final_output, f, indent=4)\n", - "\n", - " # Store combination info for final ranking\n", - " all_combinations_results.append(\n", - " {\n", - " \"name\": combo_name,\n", - " \"score\": avg_score,\n", - " \"params\": {\n", - " \"model\": model,\n", - " \"system_prompt\": system_prompt_name,\n", - " \"user_prompt_template\": user_prompt_template_name,\n", - " \"context_window_length\": context_window_length,\n", - " \"model_context\": model_context\n", - " },\n", - " }\n", - " )\n", - "\n", - " # Save all combinations results in a summary file\n", - " summary_file_path = (\n", - " base_output_path / f\"results_summary_{target_label}.json\"\n", - " )\n", - " with open(summary_file_path, \"w\") as f:\n", - " json.dump(all_combinations_results, f, indent=4)\n", - "\n", - " # --- Find the best combination ---\n", - " best_combo = max(all_combinations_results, key=lambda x: x[\"score\"])\n", - "\n", - " print(f\"\\nGrid Search for {target_label} completed.\")\n", - "\n", - " # We now copy the best combination folder to a new location with a standardized name\n", - " src = Path(base_output_path) / best_combo[\"name\"]\n", - " # Combine the parent destination path with the new folder name\n", - " new_name = f\"best-llm-pred-{target_label.lower()}\"\n", - " dest = Path(base_output_path.parent) / new_name\n", - " \n", - " try:\n", - " # copytree creates the destination directory with the 'new_name'\n", - " shutil.copytree(src, dest)\n", - " print(f\"Successfully copied '{src.name}' to '{dest}'\")\n", - " except FileExistsError:\n", - " print(f\"Error: A folder named '{new_name}' already exists in '{base_output_path.parent}'\")\n", - " except Exception as e:\n", - " print(f\"An error occurred: {e}\") \n", - "\n", - " return best_combo" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5110dc60", - "metadata": {}, - "outputs": [], - "source": [ - "models = [\n", - " \"phi4:14b\",\n", - " \"gpt-oss:20b\",\n", - " \"llama3\",\n", - " \"llama3.1:8b\",\n", - " \"gemma3:270m\",\n", - "]\n", - "\n", - "system_prompts = {\n", - " \"system_prompt_1\": system_prompt_1,\n", - " \"system_prompt_2\": system_prompt_2,\n", - " \"system_prompt_3\": system_prompt_3,\n", - " \"system_prompt_4\": system_prompt_4,\n", - " \"system_prompt_5\": system_prompt_5,\n", - " \"system_prompt_6\": system_prompt_6,\n", - " \"system_prompt_7\": system_prompt_7,\n", - " \"system_prompt_8\": system_prompt_8,\n", - " \"system_prompt_9\": system_prompt_9,\n", - " \"system_prompt_10\": system_prompt_10,\n", - " \"system_prompt_11\": system_prompt_11\n", - "}\n", - "\n", - "\n", - "user_prompt_templates = {\n", - " \"user_prompt_template_PER\": user_prompt_template_PER,\n", - "}\n", - "\n", - "context_window_lengths = list(range(80, 200, 10))\n", - "\n", - "model_context_lengths = [7_500, 8_000, 8_500, 9_000, 9_500]\n", - "\n", - "temperatures = list(np.arange(0,0.3,0.1))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7949d277", - "metadata": {}, - "outputs": [], - "source": [ - "document_check = documents[1]\n", - "paths = get_document_paths(document_check, PRE_CLUSTERIZATION_ROOT)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d6ff4f5a", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict = llm_infer_canonical_entities(\n", - " system_prompt=system_prompts['system_prompt_9'],\n", - " user_prompt_template=user_prompt_templates['user_prompt_template_PER'],\n", - " model=models[0],\n", - " document_path=document_check,\n", - " gold_path=paths[\"gold_path\"],\n", - " context_window_length=120,\n", - " model_context=9_500,\n", - " token_limit_frac=2/3,\n", - " temperature=0,\n", - " target_label=\"PER\",\n", - " decompose_by=None\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "60a2356a", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict = llm_infer_canonical_entities(\n", - " system_prompt=system_prompt_DIR,\n", - " user_prompt_template=user_prompt_template_DIR,\n", - " model=models[0],\n", - " document_path=document_check,\n", - " gold_path=paths[\"gold_path\"],\n", - " context_window_length=None,\n", - " model_context=9_500,\n", - " token_limit_frac=2/3,\n", - " temperature=0,\n", - " target_label=\"DIRECCION\",\n", - " decompose_by=None\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "690c940d", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict['predictions']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8e8bcb07", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict['llm_output_json']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "135c1f36", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict['canonical_entities_with_context']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59f003a9", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict[\"pre_cluster_json\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "22e29b34", - "metadata": {}, - "outputs": [], - "source": [ - "llm_response_dict[\"gold_standard_json\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2845f2f5", - "metadata": {}, - "outputs": [], - "source": [ - "print(llm_response_dict[\"user_prompts\"][0])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "38e587f3", - "metadata": {}, - "outputs": [], - "source": [ - "print(llm_response_dict['system_prompt'])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4fe27195", - "metadata": {}, - "outputs": [], - "source": [ - "models = [\n", - " \"phi4:14b\",\n", - "]\n", - "\n", - "system_prompts = {\n", - " \"system_prompt_9\": system_prompt_9\n", - "}\n", - "\n", - "\n", - "user_prompt_templates = {\n", - " \"user_prompt_template_PER\": user_prompt_template_PER,\n", - "}\n", - "\n", - "context_window_lengths = [120]\n", - "\n", - "model_context_lengths = [9_500]\n", - "\n", - "temperatures = [0]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a32b4244", - "metadata": {}, - "outputs": [], - "source": [ - "top_result = run_llm_grid_search(\n", - " models=models,\n", - " system_prompts=system_prompts,\n", - " user_prompt_templates=user_prompt_templates,\n", - " context_window_lengths=context_window_lengths,\n", - " model_context_lengths=model_context_lengths,\n", - " temperatures=temperatures,\n", - " documents=documents,\n", - " target_label=\"PER\",\n", - " base_output_path=GOLD_JSON_ROOT.parent / \"llm-grid-search-results\",\n", - " token_limit_frac=2/3,\n", - " decompose_by=None\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "86da6a45", - "metadata": {}, - "outputs": [], - "source": [ - "print(\n", - " f\"The best hyperparameter combination is '{top_result['name']}' \"\n", - " f\"with an average score of {top_result['score']:.4f}.\"\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb b/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb deleted file mode 100644 index 6eed83f1..00000000 --- a/notebooks/experiments/entity-disambiguation/08-disambiguation-endpoint-smoke.ipynb +++ /dev/null @@ -1,399 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "b3a62938", - "metadata": {}, - "source": [ - "# Disambiguation endpoint smoke test\n", - "\n", - "This notebook runs the full flow using the API endpoints:\n", - "1) document extraction\n", - "2) NER prediction per paragraph\n", - "3) disambiguation\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2edb7397", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7e468613", - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import json\n", - "import os\n", - "from pathlib import Path\n", - "\n", - "import requests" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "80f525f3", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template_PER = \"\"\"\n", - "Se proporciona la lista de entidades (personas) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su rol y validez.\n", - "\n", - "# Entidades Pre-clusterizadas a validar:\n", - "{canonical_entities}\n", - "\n", - "Procesa la lista siguiendo las instrucciones de filtrado, fusión y asignación de roles.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6c8f2ce2", - "metadata": {}, - "outputs": [], - "source": [ - "user_prompt_template_DIR = \"\"\"\n", - "Se proporciona la lista de entidades (direcciones) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su validez y si hay otras entidades de direcciones que corresponden a esa.\n", - "\n", - "# Entidades Pre-clusterizadas a validar:\n", - "{canonical_entities}\n", - "\n", - "Procesa la lista siguiendo las instrucciones de filtrado y fusión.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1aa9140e", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_PER = \"\"\"\n", - "Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Asignación de Rol:** Identifica el rol procesal basándote en las ventanas de contexto dentro de cada entidad canónica en la parte de `attributes`['context']\n", - " Elija un rol EXCLUSIVAMENTE en esta lista:\n", - " - \"Denunciante\", \"Denunciado/a\", \"Víctima\", \"Juez/a\", \"Defensor/a de Cámara\", \"Asesor/a Tutelar\", \"Fiscal\", \"Abogado/a\", \"Perito/a\", \"Testigo\".\n", - "2. **Regla \"Dr/a\":** Si se menciona como \"Dr.\", \"Dra.\" o \"Dres.\" y no hay otro cargo explícito, asígnale el rol \"Abogado/a\".\n", - "3. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona.\n", - " - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos.\n", - " - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo.\n", - "4. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes).\n", - "5. **Limpieza:** Limpiá los `aliases` y el `canonical_text` si los mismos tienen otras palabras, pero respeta que estén escritos de igual manera a que sus ventanas de contexto.\n", - " Te dejo un ejemplo de esta instrucción.\n", - " Vos recibís:\n", - " {\n", - " \"canonical_text\": \"por DREXLER, JORGE\",\n", - " \"aliases\": [\n", - " \"por DREXLER, JORGE\",\n", - " \"Jorge Drexler\"\n", - " ],\n", - " \"attributes\": {\n", - " \"context\": [\n", - " \"Fdo. por DREXLER, JORGE - JUEZ DE CÁMARA el mismo cita en el documento 56 que Juan es culpable\",\n", - " \"es acaso Jorge Drexler el juez designado para esta causa\"\n", - " ]\n", - " }\n", - "\n", - " Debés entregar:\n", - " {\n", - " \"canonical_text\": \"DREXLER, JORGE\",\n", - " \"aliases\": [\n", - " \"DREXLER, JORGE\",\n", - " \"Jorge Drexler\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Juez/a\"\n", - " }\n", - "\n", - "6. **Manejo de Iniciales:** Identifica si las siglas (ej: \"M.L.\") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma.\n", - "\n", - "### Formato de Salida (JSON):\n", - "Devuelve un array de objetos con esta estructura:\n", - "[\n", - " {\n", - " \"entity_id\": \"optional-unique-id\",\n", - " \"aymurai_label\": \"PER\",\n", - " \"canonical_text\": \"Nombre de la entidad\",\n", - " \"aliases\": [\n", - " \"Nombre de la entidad\",\n", - " \"Alias 1\",\n", - " \"Alias 2\"\n", - " ],\n", - " \"attributes\": {\n", - " \"role\": \"Rol de la lista o null\"\n", - " }\n", - " }\n", - "]\n", - "\n", - "No incluyas el campo 'context' en tu respuesta final.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d67ad4f2", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompt_DIR = \"\"\"\n", - "Eres un auditor experto en desambiguación de domicilios y direcciones en documentos judiciales. Tu tarea es validar y consolidar una lista de direcciones pre-agrupadas basándote en su contexto.\n", - "\n", - "### Instrucciones Estrictas:\n", - "1. **Consolidación Geográfica:** - Si dos entidades refieren a la misma ubicación física, fusiónalas en una sola entidad.\n", - " - Considera que una dirección puede estar escrita de forma completa en un alias (ej: \"Av. Rivadavia 123, CABA\") y de forma abreviada en otro (ej: \"Rivadavia 123\").\n", - " - Trata las variantes ortográficas o abreviaturas (Av. vs Avenida, Piso vs P., Dpto vs Departamento) como aliases de la misma ubicación.\n", - "2. **Filtrado:** Elimina entidades que no sean direcciones postales o domicilios físicos (ej: correos electrónicos, URLs, nombres de juzgados o menciones abstractas como \"el domicilio constituido\").\n", - "\n", - "### Formato de Salida (JSON):\n", - "[\n", - " {\n", - " \"entity_id\": \"ID original\",\n", - " \"aymurai_label\": \"DIRECCION\",\n", - " \"canonical_text\": \"Dirección más completa extraída del texto\",\n", - " \"aliases\": [\n", - " \"Dirección más completa (Igual al canonical)\",\n", - " \"Variante 1\",\n", - " \"Variante 2\"\n", - " ],\n", - " \"attributes\": []\n", - " }\n", - "]\n", - "**IMPORTANTE:** No incluyas el campo 'context' en la respuesta.\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "43dcd972", - "metadata": {}, - "outputs": [], - "source": [ - "SYSTEM_PROMPTS = {\n", - " \"PER\": system_prompt_PER,\n", - " \"DIRECCION\": system_prompt_DIR,\n", - "}\n", - "\n", - "USER_PROMPT_TEMPLATES = {\n", - " \"PER\": user_prompt_template_PER,\n", - " \"DIRECCION\": user_prompt_template_DIR,\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a54d0295", - "metadata": {}, - "outputs": [], - "source": [ - "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8000\")\n", - "DATA_ROOT = Path(\n", - " os.getenv(\n", - " \"DISAMBIGUATION_DATA_ROOT\",\n", - " \"../../../resources/data/restricted/disambiguation-eval/files\",\n", - " )\n", - ")\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "\n", - "LIMIT = int(os.getenv(\"DISAMBIGUATION_DOC_LIMIT\", \"0\")) # 0 = no limit\n", - "TARGET_LABELS = os.getenv(\"DISAMBIGUATION_TARGET_LABELS\")\n", - "\n", - "print(f\"API: {API_BASE_URL}\")\n", - "print(f\"Data root: {DATA_ROOT}\")\n", - "print(f\"Target labels: {TARGET_LABELS or 'All the targets that have the prompt set'}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "58e9d69e", - "metadata": {}, - "outputs": [], - "source": [ - "from aymurai.experiments.entity_disambiguation.runner import (\n", - " call_extraction_api as extract_document,\n", - ")\n", - "\n", - "def discover_documents(root: Path, extensions: set[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "def predict_paragraphs(paragraphs: list[str]) -> list[dict]:\n", - " endpoint = f\"{API_BASE_URL}/anonymizer/predict\"\n", - " predictions = []\n", - " for paragraph in paragraphs:\n", - " response = requests.post(\n", - " endpoint, json={\"text\": paragraph}, params={\"use_cache\": False}, timeout=60\n", - " )\n", - " response.raise_for_status()\n", - " predictions.append(response.json())\n", - " return predictions\n", - "\n", - "\n", - "def disambiguate(\n", - " predictions: list[dict], use_custom_prompts: bool = True\n", - ") -> list[dict]:\n", - " endpoint = f\"{API_BASE_URL}/anonymizer/disambiguate\"\n", - "\n", - " payload = {\"paragraphs\": predictions}\n", - "\n", - " if use_custom_prompts:\n", - " custom_prompts_list = []\n", - "\n", - " for label in SYSTEM_PROMPTS.keys():\n", - " custom_prompts_list.append(\n", - " {\n", - " \"label\": label,\n", - " \"system\": SYSTEM_PROMPTS.get(label, \"\"),\n", - " \"user\": USER_PROMPT_TEMPLATES.get(label, \"\"),\n", - " }\n", - " )\n", - "\n", - " payload[\"custom_prompts\"] = custom_prompts_list\n", - "\n", - " else:\n", - " payload[\"custom_prompts\"] = []\n", - "\n", - " params = {\"use_cache\": False}\n", - "\n", - " if TARGET_LABELS:\n", - " params[\"target_labels\"] = TARGET_LABELS\n", - "\n", - " else:\n", - " params[\"target_labels\"] = []\n", - "\n", - " response = requests.post(\n", - " endpoint,\n", - " params=params,\n", - " json=payload,\n", - " timeout=600,\n", - " )\n", - "\n", - " response.raise_for_status()\n", - " return response.json()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "72f3d427", - "metadata": {}, - "outputs": [], - "source": [ - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "if LIMIT > 0:\n", - " documents = documents[:LIMIT]\n", - "\n", - "print(f\"Found {len(documents)} documents\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d844f2c8", - "metadata": {}, - "outputs": [], - "source": [ - "for doc_path in documents[1:2]:\n", - " print(f\"\\n=== {doc_path.name} ===\")\n", - " session = requests.Session()\n", - " document = extract_document(\n", - " session,\n", - " endpoint=f\"{API_BASE_URL}/misc/document-extract\",\n", - " file_path=doc_path,\n", - " timeout_s=300,\n", - " )\n", - " paragraphs = document[\"detail\"][\"document\"]\n", - " print(f\"Paragraphs: {len(paragraphs)}\")\n", - "\n", - " predictions = predict_paragraphs(paragraphs)\n", - " print(f\"Predictions: {len(predictions)}\")\n", - "\n", - " disambiguated = disambiguate(predictions=predictions, use_custom_prompts=False)\n", - " print(f\"NER prdictions: {len(disambiguated.get('data', []))}\")\n", - " print(json.dumps(disambiguated, indent=2, ensure_ascii=False))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f65c14ab", - "metadata": {}, - "outputs": [], - "source": [ - "predictions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0eb0561f", - "metadata": {}, - "outputs": [], - "source": [ - "disambiguated" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e7296e8a", - "metadata": {}, - "outputs": [], - "source": [ - "for pred in disambiguated.get(\"data\", []):\n", - " labels = pred.get(\"labels\", [])\n", - " if labels:\n", - " for label in labels:\n", - " attrs = label.get(\"attrs\", {})\n", - " if attrs.get(\"aymurai_label\") == \"FECHA\":\n", - " print(\n", - " label.get(\"text\"),\n", - " attrs.get(\"aymurai_label_subclass\"),\n", - " attrs.get(\"canonical_entity_id\"),\n", - " )" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 69e90d7d63df072307fc1a4d2f5820fe15cc7f2f Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:33:51 -0300 Subject: [PATCH 056/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20notebooks/expe?= =?UTF-8?q?riments/llm-providers=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../llm-providers/01-ollama-provider.ipynb | 200 ------------------ 1 file changed, 200 deletions(-) delete mode 100644 notebooks/experiments/llm-providers/01-ollama-provider.ipynb diff --git a/notebooks/experiments/llm-providers/01-ollama-provider.ipynb b/notebooks/experiments/llm-providers/01-ollama-provider.ipynb deleted file mode 100644 index 216292c4..00000000 --- a/notebooks/experiments/llm-providers/01-ollama-provider.ipynb +++ /dev/null @@ -1,200 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "dcfd3a57", - "metadata": {}, - "source": [ - "# `OllamaLLMProvider`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9890c8fb", - "metadata": {}, - "outputs": [], - "source": [ - "import asyncio\n", - "\n", - "from rich.pretty import pprint\n", - "\n", - "from aymurai.llm_providers import OllamaLLMProvider" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "85317574", - "metadata": {}, - "outputs": [], - "source": [ - "MODEL_NAME = \"llama3.2:3b\"\n", - "SYSTEM_PROMPT = \"Eres un asistente legal especializado en anonimización y desambiguación de entidades.\"\n", - "\n", - "provider = OllamaLLMProvider(model=MODEL_NAME, system_prompt=SYSTEM_PROMPT)\n", - "provider" - ] - }, - { - "cell_type": "markdown", - "id": "94e43f16", - "metadata": {}, - "source": [ - "## Chunking" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "53afac4f", - "metadata": {}, - "outputs": [], - "source": [ - "sample_text = (\n", - " \"La jueza fijó audiencia para la próxima semana y solicitó a las partes presentar \"\n", - " \"documentación adicional relacionada con la causa. El objetivo es determinar si existieron \"\n", - " \"violaciones al protocolo vigente y establecer medidas de protección para las víctimas.\"\n", - ")\n", - "\n", - "chunks = provider.chunk_text(sample_text, max_tokens=10, overlap=0)\n", - "for chunk in chunks:\n", - " print(f\"Chunk {chunk.index}: {chunk.token_count} tokens\")\n", - " pprint(chunk)" - ] - }, - { - "cell_type": "markdown", - "id": "1aa4d182", - "metadata": {}, - "source": [ - "## Generation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f1ce3b9b", - "metadata": {}, - "outputs": [], - "source": [ - "prompt = (\n", - " \"Resume en español el siguiente extracto de un expediente judicial y menciona los actores involucrados:\"\n", - " + sample_text\n", - ")\n", - "\n", - "try:\n", - " summary_response = provider.generate(prompt)\n", - " print(summary_response.text)\n", - " pprint(summary_response.metadata)\n", - "\n", - "except Exception as exc:\n", - " print(\"No se pudo contactar a Ollama:\", exc)" - ] - }, - { - "cell_type": "markdown", - "id": "da8f9c60", - "metadata": {}, - "source": [ - "## Streaming" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4ac718bd", - "metadata": {}, - "outputs": [], - "source": [ - "try:\n", - " stream_prompt = \"Explica en detalle el procedimiento legal descrito.\"\n", - " pieces = []\n", - " for event in provider.stream(stream_prompt):\n", - " print(event.text, end=\"\", flush=True)\n", - " pieces.append(event.text)\n", - " print()\n", - " full_text = \"\".join(pieces)\n", - "\n", - "except Exception as exc:\n", - " print(\"La transmisión no está disponible:\", exc)" - ] - }, - { - "cell_type": "markdown", - "id": "async-section", - "metadata": {}, - "source": [ - "## Async calls" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "async-demo", - "metadata": {}, - "outputs": [], - "source": [ - "async def demo_async_generate():\n", - " try:\n", - " result = await provider.async_generate(\"Di un resumen breve del texto\")\n", - " print(result.text)\n", - " except Exception as exc:\n", - " print(\"No se pudo contactar a Ollama (async):\", exc)\n", - "\n", - "\n", - "await demo_async_generate()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "72c5c551", - "metadata": {}, - "outputs": [], - "source": [ - "async def demo_async_stream():\n", - " try:\n", - " parts = []\n", - " async for event in provider.async_stream(\"Explica el caso con más detalle\"):\n", - " print(event.text, end=\"\", flush=True)\n", - " parts.append(event.text)\n", - " print()\n", - " except Exception as exc:\n", - " print(\"La transmisión async no está disponible:\", exc)\n", - "\n", - "\n", - "await demo_async_stream()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "67ede506", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai (3.10.19)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.19" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From aa888667d2cfe749558078f5b701af3b4b265bb3 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:36:44 -0300 Subject: [PATCH 057/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20notebooks/expe?= =?UTF-8?q?riments/summarization=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../01-summarization-benchmark.ipynb | 735 -------- .../02-statistical-analysis.ipynb | 1651 ----------------- .../03-summarization-endpoint.ipynb | 170 -- .../04-dspy-prompt-optimization.ipynb | 955 ---------- 4 files changed, 3511 deletions(-) delete mode 100644 notebooks/experiments/summarization/01-summarization-benchmark.ipynb delete mode 100644 notebooks/experiments/summarization/02-statistical-analysis.ipynb delete mode 100644 notebooks/experiments/summarization/03-summarization-endpoint.ipynb delete mode 100644 notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb diff --git a/notebooks/experiments/summarization/01-summarization-benchmark.ipynb b/notebooks/experiments/summarization/01-summarization-benchmark.ipynb deleted file mode 100644 index e2a6558a..00000000 --- a/notebooks/experiments/summarization/01-summarization-benchmark.ipynb +++ /dev/null @@ -1,735 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "f900ed31", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext autoreload\n", - "%autoreload 2\n", - "\n", - "%load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "03359440", - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import mimetypes\n", - "import os\n", - "import time\n", - "from pathlib import Path\n", - "from typing import Iterable\n", - "\n", - "import ollama\n", - "import requests\n", - "from IPython.display import Markdown\n", - "from ollama import ChatResponse\n", - "from tqdm import tqdm\n", - "\n", - "from aymurai.utils.json_data import load_json, save_json\n", - "from aymurai.utils.yaml_data import load_yaml" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6297e02c", - "metadata": {}, - "outputs": [], - "source": [ - "os.environ[\"OLLAMA_KEEP_ALIVE\"] = \"0\"\n", - "print(\"OLLAMA_KEEP_ALIVE set to 0. Models will unload immediately after use.\")" - ] - }, - { - "cell_type": "markdown", - "id": "1d59c9c9", - "metadata": {}, - "source": [ - "## Documents" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "28110bf0", - "metadata": {}, - "outputs": [], - "source": [ - "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8899\")\n", - "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", - "DATA_ROOT = Path(\n", - " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", - ")\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", - "\n", - "print(f\"Target endpoint: {ENDPOINT}\")\n", - "print(f\"Data root: {DATA_ROOT.resolve()}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d3fb80b7", - "metadata": {}, - "outputs": [], - "source": [ - "if not DATA_ROOT.exists():\n", - " raise FileNotFoundError(\n", - " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", - " )\n", - "\n", - "\n", - "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "\n", - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "print(f\"Discovered {len(documents)} documents.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "aebe1738", - "metadata": {}, - "outputs": [], - "source": [ - "def call_extraction_api(\n", - " session: requests.Session, file_path: Path\n", - ") -> dict[str, object]:\n", - " payload: dict[str, object] = {\n", - " \"path\": str(file_path),\n", - " \"status\": \"failure\",\n", - " \"status_code\": None,\n", - " \"elapsed_s\": None,\n", - " \"detail\": None,\n", - " }\n", - "\n", - " if not file_path.exists():\n", - " payload[\"detail\"] = \"File does not exist\"\n", - " return payload\n", - "\n", - " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", - " files = {\n", - " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", - " }\n", - "\n", - " try:\n", - " start = time.perf_counter()\n", - " response = session.post(\n", - " ENDPOINT,\n", - " files=files,\n", - " timeout=REQUEST_TIMEOUT,\n", - " )\n", - " elapsed = time.perf_counter() - start\n", - " except requests.RequestException as exc:\n", - " payload[\"detail\"] = f\"Request failed: {exc}\"\n", - " return payload\n", - " finally:\n", - " files[\"file\"][1].close()\n", - "\n", - " payload[\"status_code\"] = response.status_code\n", - " payload[\"elapsed_s\"] = elapsed\n", - "\n", - " try:\n", - " response_body = response.json()\n", - " except ValueError:\n", - " response_body = {\"raw\": response.text[:500]}\n", - "\n", - " if response.ok:\n", - " payload[\"status\"] = \"success\"\n", - " payload[\"detail\"] = {\n", - " \"document_id\": response_body.get(\"document_id\"),\n", - " \"document\": response_body.get(\"document\", []),\n", - " }\n", - " else:\n", - " payload[\"detail\"] = response_body\n", - "\n", - " return payload" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9f04a9d2", - "metadata": {}, - "outputs": [], - "source": [ - "doc_path = documents[0]\n", - "extracted_document = call_extraction_api(requests.Session(), doc_path)[\"detail\"]\n", - "document = \"\\n\".join(extracted_document[\"document\"])\n", - "print(document)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb930b69", - "metadata": {}, - "outputs": [], - "source": [ - "extracted_documents = []\n", - "\n", - "for doc_path in tqdm(documents):\n", - " session = requests.Session()\n", - " extracted_document = call_extraction_api(session, doc_path)\n", - " extracted_documents.append(\n", - " {\n", - " \"doc_path\": os.path.basename(doc_path),\n", - " **extracted_document,\n", - " }\n", - " )\n", - " session.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ce7ea84c", - "metadata": {}, - "outputs": [], - "source": [ - "len(extracted_documents)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7a4fee57", - "metadata": {}, - "outputs": [], - "source": [ - "extracted_documents[-1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a11c0245", - "metadata": {}, - "outputs": [], - "source": [ - "# Filter out empty extracted documents\n", - "extracted_documents = [\n", - " doc for doc in extracted_documents if len(doc[\"detail\"][\"document\"])\n", - "]\n", - "len(extracted_documents)" - ] - }, - { - "cell_type": "markdown", - "id": "e509e467", - "metadata": {}, - "source": [ - "## LLMs" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "00604dcd", - "metadata": {}, - "outputs": [], - "source": [ - "MODELS = [\n", - " # Llama\n", - " \"llama3.1:8b\",\n", - " \"llama3.2:3b\",\n", - " # Gemma\n", - " \"gemma3:4b\",\n", - " \"gemma3n:e4b\",\n", - " \"gemma3:12b\",\n", - " # Qwen\n", - " \"qwen3:8b\",\n", - " \"qwen3:14b\",\n", - " # Phi\n", - " \"phi3:3.8b\",\n", - " \"phi4:14b\",\n", - " # DeepSeek\n", - " \"deepseek-r1:8b\",\n", - " \"deepseek-r1:14b\",\n", - " # GPT\n", - " \"gpt-oss:20b\",\n", - "]" - ] - }, - { - "cell_type": "markdown", - "id": "7669a65c", - "metadata": {}, - "source": [ - "### System Prompts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f1adce13", - "metadata": {}, - "outputs": [], - "source": [ - "system_prompts = load_yaml(\"/resources/llm/summarization.yml\")[\"system-prompts\"]\n", - "system_prompts" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4dfe7899", - "metadata": {}, - "outputs": [], - "source": [ - "# Function to get chat response from the model\n", - "def get_chat_response(\n", - " system_prompt: str,\n", - " user_prompt: str,\n", - " model: str = \"llama3.2:3b\",\n", - " options: dict = {\"num_ctx\": 16_384, \"num_predict\": 4096},\n", - ") -> ChatResponse:\n", - " \"\"\"\n", - " Get chat response from the model.\n", - "\n", - " Args:\n", - " system_prompt (str): The system prompt.\n", - " user_prompt (str): The prompt from the user.\n", - " model (str, optional): The model to use. Defaults to \"llama3.2:3b\".\n", - " options (dict, optional): The options for the chat.\n", - " Defaults to {\"num_ctx\": 16_384, \"num_predict\": 4096}.\n", - "\n", - " Returns:\n", - " ChatResponse: The response from the chat.\n", - " \"\"\"\n", - " response = ollama.chat(\n", - " model=model,\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": system_prompt},\n", - " {\"role\": \"user\", \"content\": user_prompt},\n", - " ],\n", - " options=options,\n", - " )\n", - "\n", - " return response" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c8016bd", - "metadata": {}, - "outputs": [], - "source": [ - "iter_documents = iter(extracted_documents)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e8677785", - "metadata": {}, - "outputs": [], - "source": [ - "document = next(iter_documents)\n", - "document = \"\\n\".join(document[\"detail\"][\"document\"])\n", - "print(document)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "034bd672", - "metadata": {}, - "outputs": [], - "source": [ - "# Define system prompt and get chat response\n", - "system_prompt = system_prompts[\"baseline\"]\n", - "\n", - "# Get chat response\n", - "chat_response = get_chat_response(system_prompt, document)\n", - "print(chat_response.message.content)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "918dc835", - "metadata": {}, - "outputs": [], - "source": [ - "# Define system prompt and get chat response\n", - "system_prompt = system_prompts[\"task-specific\"]\n", - "\n", - "# Get chat response\n", - "chat_response = get_chat_response(system_prompt, document)\n", - "print(chat_response.message.content)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4f4b55f3", - "metadata": {}, - "outputs": [], - "source": [ - "# Define prompt parameters\n", - "INFORMATION = \"\"\"\n", - " - Hechos relevantes (qué ocurrió).\n", - " - Actores clave (quiénes están involucrados).\n", - " * Denunciante(s).\n", - " * Denunciado(s).\n", - " * Testigo(s).\n", - " * Juez(es).\n", - " * Abogado(s).\n", - " * Fiscal(es).\n", - " * Perito(s).\n", - " * Otros (especificar).\n", - " - Cronología (cuándo ocurrieron los hechos y eventos procesales importantes).\n", - " - Lugar(es) (dónde ocurrieron los hechos y eventos procesales importantes).\n", - " - Fundamentos (normas legales, precedentes judiciales, doctrinas aplicadas).\n", - " - Decisión (resultado/medida adoptada).\n", - "\"\"\"\n", - "\n", - "ENTITIES = \"\"\"\n", - " - \"BANCO\": Nombre de una entidad bancaria, pública o privada.\n", - " - \"CBU\": Código Bancario Uniforme (22 dígitos) de una cuenta.\n", - " - \"CORREO_ELECTRONICO\": Dirección de correo electrónico.\n", - " - \"CUIJ\": Código Único de Identificación Jurídica de causas judiciales.\n", - " - \"CUIT_CUIL\": Número de CUIT o CUIL de una persona física o jurídica.\n", - " - \"DIRECCION\": Dirección específica (calle, número, intersección de calles y/o avenidas, código postal, etc.).\n", - " - \"DNI\": Número de Documento Nacional de Identidad u otro documento identificatorio.\n", - " - \"EDAD\": Edad explícita de una persona.\n", - " - \"ESTUDIOS\": Nivel o institución educativa que permita identificar a la persona (ej. \"primario incompleto\", \"secundario completo\", \"Licenciado en…\").\n", - " - \"FECHA\": Fecha completa o parcial (día, mes y/o año).\n", - " - \"LINK\": Enlace o URL a una página web.\n", - " - \"LOC\": Localización geográfica específica (país, provincia, estado, ciudad, localidad, barrio, etc.).\n", - " - \"MARCA_AUTOMOVIL\": Marca de un vehículo (ej. Toyota, Ford, Suzuki, etc.).\n", - " - \"NACIONALIDAD\": Nacionalidad de una persona (ej. \"argentino\", \"brasileña\").\n", - " - \"NUM_ACTUACION\": Número identificatorio de una actuación administrativa o contravencional.\n", - " - \"NUM_CAJA_AHORRO\": Número completo de una caja de ahorro o cuenta bancaria.\n", - " - \"NUM_EXPEDIENTE\": Número de expediente judicial o administrativo.\n", - " - \"NUM_MATRICULA\": Número de matrícula profesional o académica.\n", - " - \"PATENTE_DOMINIO\": Patente o dominio de un vehículo.\n", - " - \"PER\": Nombre y apellido(s) de una persona física. Los nombres inicializados (ej., \"M.T.G\") y los apodos (ej., \"el Gato\") también cuentan como información sensible a anonimizar.\n", - " - \"TELEFONO\": Número telefónico (fijo o celular).\n", - "\"\"\"\n", - "\n", - "\n", - "# Define system prompt\n", - "system_prompt = system_prompts[\"template\"].format(\n", - " information_to_extract=INFORMATION,\n", - " entities_to_identify=ENTITIES,\n", - ")\n", - "\n", - "print(system_prompt)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3efcf14f", - "metadata": {}, - "outputs": [], - "source": [ - "# Get chat response\n", - "chat_response = get_chat_response(system_prompt, document)\n", - "Markdown(chat_response.message.content)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "92f8d337", - "metadata": {}, - "outputs": [], - "source": [ - "def evaluate_chat_response(\n", - " system_prompt: str,\n", - " user_prompt: str,\n", - " model: str = \"llama3.2:3b\",\n", - " options: dict = {\"num_ctx\": 16_384, \"num_predict\": 4096},\n", - ") -> dict:\n", - " \"\"\"\n", - " Get chat response from the model and evaluate tokens and runtime metrics.\n", - "\n", - " Args:\n", - " system_prompt (str): The system prompt.\n", - " user_prompt (str): The prompt from the user.\n", - " model (str, optional): The model to use. Defaults to \"llama3.2:3b\".\n", - " options (dict, optional): The options for the chat.\n", - " Defaults to {\"num_ctx\": 16_384, \"num_predict\": 4096}.\n", - "\n", - " Returns:\n", - " dict: A dictionary containing:\n", - " - response: The content of the response\n", - " - model: The model name\n", - " - input_tokens: Number of tokens in the prompt (prompt_eval_count)\n", - " - input_duration_ms: Time taken to process input tokens in milliseconds\n", - " - output_tokens: Number of tokens in the output (eval_count)\n", - " - output_duration_ms: Time taken to generate output tokens in milliseconds\n", - " - total_tokens: Total number of tokens processed\n", - " - total_duration_ms: Total duration of the request in milliseconds\n", - " - tokens_per_second: Rate of token generation (output tokens / output duration)\n", - " \"\"\"\n", - " start = time.time()\n", - "\n", - " # Get the chat response\n", - " response = get_chat_response(\n", - " user_prompt=user_prompt,\n", - " model=model,\n", - " system_prompt=system_prompt,\n", - " options=options,\n", - " )\n", - "\n", - " end = time.time()\n", - "\n", - " # Extract metrics\n", - " input_tokens = (\n", - " response.prompt_eval_count if hasattr(response, \"prompt_eval_count\") else None\n", - " )\n", - " output_tokens = response.eval_count if hasattr(response, \"eval_count\") else None\n", - " total_tokens = None\n", - "\n", - " # If total_tokens is still None but we have input and output tokens\n", - " if total_tokens is None and input_tokens is not None and output_tokens is not None:\n", - " total_tokens = input_tokens + output_tokens\n", - "\n", - " # Extract durations and convert nanoseconds to milliseconds\n", - " input_duration_ms = None\n", - " if hasattr(response, \"prompt_eval_duration\"):\n", - " input_duration_ms = response.prompt_eval_duration / 1_000_000 # ns to ms\n", - "\n", - " output_duration_ms = None\n", - " if hasattr(response, \"eval_duration\"):\n", - " output_duration_ms = response.eval_duration / 1_000_000 # ns to ms\n", - "\n", - " model_total_duration_ms = None\n", - " if hasattr(response, \"total_duration\"):\n", - " model_total_duration_ms = response.total_duration / 1_000_000 # ns to ms\n", - "\n", - " # Calculate the total duration from our timer (this will include network latency)\n", - " measured_duration_ms = (end - start) * 1000\n", - "\n", - " # Calculate tokens per second for generation\n", - " tokens_per_second = None\n", - " if (\n", - " output_tokens is not None\n", - " and output_duration_ms is not None\n", - " and output_duration_ms > 0\n", - " ):\n", - " tokens_per_second = output_tokens / (output_duration_ms / 1000)\n", - "\n", - " return {\n", - " \"model\": model,\n", - " \"options\": options,\n", - " \"system_prompt\": system_prompt,\n", - " \"user_prompt\": user_prompt,\n", - " \"chat_response\": response.message.content,\n", - " \"input_tokens\": input_tokens,\n", - " \"input_duration_ms\": input_duration_ms,\n", - " \"output_tokens\": output_tokens,\n", - " \"output_duration_ms\": output_duration_ms,\n", - " \"total_tokens\": total_tokens,\n", - " \"model_duration_ms\": model_total_duration_ms,\n", - " \"measured_duration_ms\": measured_duration_ms,\n", - " \"tokens_per_second\": tokens_per_second,\n", - " \"raw_response\": response.model_dump(), # Include the full response object for reference\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5fce8d0f", - "metadata": {}, - "outputs": [], - "source": [ - "# Test our new evaluation function\n", - "test_result = evaluate_chat_response(\n", - " system_prompt=system_prompts[\"task-specific\"],\n", - " user_prompt=document,\n", - ")\n", - "\n", - "# Display the metrics\n", - "print(f\"Response from {test_result['model']}:\")\n", - "print(\"-\" * 50)\n", - "print(test_result[\"raw_response\"])\n", - "print(\"-\" * 50)\n", - "print(f\"Input tokens: {test_result['input_tokens']}\")\n", - "print(f\"Input processing time: {test_result['input_duration_ms']:.2f} ms\")\n", - "print(f\"Output tokens: {test_result['output_tokens']}\")\n", - "print(f\"Output generation time: {test_result['output_duration_ms']:.2f} ms\")\n", - "print(f\"Total tokens: {test_result['total_tokens']}\")\n", - "print(f\"Model reported duration: {test_result['model_duration_ms']:.2f} ms\")\n", - "print(f\"Measured duration: {test_result['measured_duration_ms']:.2f} ms\")\n", - "print(f\"Generation speed: {test_result['tokens_per_second']:.2f} tokens/second\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "68a55804", - "metadata": {}, - "outputs": [], - "source": [ - "errors = []\n", - "results = []" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "868fbd4c", - "metadata": {}, - "outputs": [], - "source": [ - "DEVICE = \"cuda\"\n", - "\n", - "results = load_json(f\"./summarization-benchmark-results-{DEVICE}.json\")\n", - "results[-1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5ca81c50", - "metadata": {}, - "outputs": [], - "source": [ - "len(results)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "72c190b3", - "metadata": {}, - "outputs": [], - "source": [ - "for extracted_document in tqdm(\n", - " extracted_documents, total=len(extracted_documents), desc=\"Evaluating documents\"\n", - "):\n", - " doc_path = os.path.basename(extracted_document[\"doc_path\"])\n", - " document = \"\\n\".join(extracted_document[\"detail\"][\"document\"])\n", - "\n", - " if not document.strip():\n", - " print(f\"Skipping empty document: {doc_path}\")\n", - " continue\n", - "\n", - " for model in MODELS:\n", - " for system_prompt_type in system_prompts:\n", - " print(\n", - " f\"Evaluating {doc_path} with model {model} and prompt {system_prompt_type}\"\n", - " )\n", - " if any(\n", - " r\n", - " for r in results\n", - " if r[\"doc_path\"] == doc_path\n", - " and r[\"model\"] == model\n", - " and r[\"system_prompt_type\"] == system_prompt_type\n", - " and r[\"device\"] == DEVICE\n", - " ):\n", - " print(\n", - " f\"Skipping {doc_path} with model {model} and prompt {system_prompt_type} on {DEVICE} (already evaluated)\"\n", - " )\n", - " continue\n", - "\n", - " system_prompt = system_prompts[system_prompt_type]\n", - " if system_prompt_type == \"template\":\n", - " system_prompt = system_prompts[\"template\"].format(\n", - " information_to_extract=INFORMATION,\n", - " entities_to_identify=ENTITIES,\n", - " )\n", - "\n", - " try:\n", - " result = evaluate_chat_response(\n", - " system_prompt=system_prompt,\n", - " user_prompt=document,\n", - " model=model,\n", - " )\n", - " result[\"doc_path\"] = doc_path\n", - " result[\"system_prompt_type\"] = system_prompt_type\n", - " result[\"device\"] = DEVICE\n", - " results.append(result)\n", - "\n", - " save_json(\n", - " results,\n", - " f\"./summarization-benchmark-results-{DEVICE}.json\",\n", - " )\n", - "\n", - " except Exception as e:\n", - " print(f\"Error evaluating {doc_path} with model {model}: {e}\")\n", - " errors.append(\n", - " {\n", - " \"doc_path\": doc_path,\n", - " \"model\": model,\n", - " \"system_prompt\": system_prompt,\n", - " \"device\": DEVICE,\n", - " \"error\": str(e),\n", - " }\n", - " )\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1359dec5", - "metadata": {}, - "outputs": [], - "source": [ - "len(errors)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "849850e9", - "metadata": {}, - "outputs": [], - "source": [ - "errors" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cc9c3cab", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.18" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/summarization/02-statistical-analysis.ipynb b/notebooks/experiments/summarization/02-statistical-analysis.ipynb deleted file mode 100644 index aef5a7d9..00000000 --- a/notebooks/experiments/summarization/02-statistical-analysis.ipynb +++ /dev/null @@ -1,1651 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "f5458e0a", - "metadata": {}, - "source": [ - "# Summaries Analysis\n", - "\n", - "This notebook performs both **quantitative** and **qualitative** analyses of the summaries generated by the API, to build a complete picture of model summary performance.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "id": "481c1d32", - "metadata": {}, - "source": [ - "\n", - "\n", - "**1. Quantitative Analysis**\n", - "- Conduct a **statistical and exploratory data analysis** of the API results using Pandas and descriptive statistics. \n", - "- Explore and refine the **visualizations** to better highlight differences and distributions. \n", - "- Compare **model runtimes** (CPU vs GPU) for the same document to assess performance efficiency. \n", - "\n", - "\n", - "\n", - "**1. Qualitative Analysis**\n", - "- **Garbage Detection:** Identify low-quality or nonsensical summaries (e.g., hallucinations or “garbage” outputs). \n", - " These can often be detected as **outliers** in the quantitative performance metrics. \n", - " DeepSeek has shown clear examples of this behavior. \n", - "- **Summary Comparison:** Evaluate the **relative quality and performance** of summaries across different models, linking the findings with the quantitative metrics.\n" - ] - }, - { - "cell_type": "markdown", - "id": "69039406", - "metadata": {}, - "source": [ - "## Quantitative Analysis" - ] - }, - { - "cell_type": "markdown", - "id": "d98633a6", - "metadata": {}, - "source": [ - "#### Load data and function definitions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5be98b6f", - "metadata": {}, - "outputs": [], - "source": [ - "# Libraries imports\n", - "\n", - "import os\n", - "import json\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "import seaborn as sns" - ] - }, - { - "cell_type": "markdown", - "id": "b4b981af", - "metadata": {}, - "source": [ - "Function definitions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d58de8bc", - "metadata": {}, - "outputs": [], - "source": [ - "# Attempt to identify parameter scale (in billions) from model names\n", - "def get_model_parameter_scale(model_name):\n", - " import re\n", - "\n", - " if not model_name:\n", - " return None\n", - "\n", - " known_params = {\n", - " \"gemma3:12b\": 12,\n", - " \"gemma3:40b\": 40,\n", - " \"gemma3:20b\": 20,\n", - " \"gemma3:22b\": 22,\n", - " \"gemma3:38b\": 38,\n", - " \"llama3.1:8b\": 8,\n", - " \"llama3.2:3b\": 3,\n", - " \"llama3.2:11b\": 11,\n", - " \"deepseek-r1:1.1b\": 1.1,\n", - " \"deepseek-r1:1b\": 1,\n", - " \"phi-3:3.8b\": 3.8,\n", - " \"phi-4:14b\": 14,\n", - " \"qwen3:3.8b\": 3.8,\n", - " \"qwen3:14b\": 14,\n", - " \"qwen3:72b\": 72,\n", - " }\n", - "\n", - " model_name_lower = model_name.lower()\n", - " if model_name_lower in known_params:\n", - " return known_params[model_name_lower]\n", - "\n", - " match = re.search(r\"(\\d+(?:\\.\\d+)?)\\s*b\", model_name_lower)\n", - " if match:\n", - " try:\n", - " return float(match.group(1))\n", - " except ValueError:\n", - " return None\n", - " return None\n", - "\n", - "\n", - "def unique_vals(df, col):\n", - " print(col)\n", - " return print(f\"Total {col}: {(df[col].nunique())} \\n {(df[col].unique())} \\n\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "03ae93cc", - "metadata": {}, - "outputs": [], - "source": [ - "DATA_PATH = \"/resources/data/restricted/summarization\" # Change this to your data path\n", - "cuda_summaries_file = os.path.join(\n", - " DATA_PATH, \"summarization-benchmark-results-cuda.json\"\n", - ")\n", - "cpu_summaries_file = os.path.join(DATA_PATH, \"summarization-benchmark-results-cpu.json\")\n", - "\n", - "with open(cuda_summaries_file, \"r\") as f:\n", - " cuda_summaries = json.load(f)\n", - "with open(cpu_summaries_file, \"r\") as f:\n", - " cpu_summaries = json.load(f)\n", - "\n", - "summaries = cuda_summaries + cpu_summaries\n", - "df = pd.DataFrame(summaries)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "64887e36", - "metadata": {}, - "outputs": [], - "source": [ - "df.doc_path.nunique()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9eff2b81", - "metadata": {}, - "outputs": [], - "source": [ - "df.doc_path = df.doc_path.apply(lambda x: os.path.basename(x))\n", - "df.doc_path.nunique()" - ] - }, - { - "cell_type": "markdown", - "id": "9000571b", - "metadata": {}, - "source": [ - "### Descriptive analysis" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4081f62e", - "metadata": {}, - "outputs": [], - "source": [ - "df.head(4)" - ] - }, - { - "cell_type": "markdown", - "id": "bdaddf02", - "metadata": {}, - "source": [ - "#### Prompts visualization/print" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3dd1c488", - "metadata": {}, - "outputs": [], - "source": [ - "import pprint\n", - "\n", - "unique = (\n", - " df[[\"system_prompt\", \"system_prompt_type\"]].drop_duplicates().reset_index(drop=True)\n", - ")\n", - "\n", - "for _, row in unique.iterrows():\n", - " print(\"Type:\", row[\"system_prompt_type\"])\n", - " print(\"Prompt:\")\n", - " pprint.pprint(row[\"system_prompt\"])\n", - " print(\"---\\n\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f7a99302", - "metadata": {}, - "outputs": [], - "source": [ - "df.info()" - ] - }, - { - "cell_type": "markdown", - "id": "9b7300d5", - "metadata": {}, - "source": [ - "#### Data engineer (ms -> mins)" - ] - }, - { - "cell_type": "markdown", - "id": "f628dc9e", - "metadata": {}, - "source": [ - "Create new columns to mins unit" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ed9c4c4", - "metadata": {}, - "outputs": [], - "source": [ - "ms_cols = [c for c in df.columns if c.endswith(\"ms\")]\n", - "ms_min_cols = [[c.replace(\"ms\", \"min\"), c] for c in ms_cols]\n", - "time_cols = [c[0] for c in ms_min_cols]\n", - "\n", - "for cols in ms_min_cols:\n", - " c, ms_col = cols\n", - " df[c] = df[ms_col] / 1000 / 60\n", - "\n", - "df.head(2)\n", - "\n", - "time_cols" - ] - }, - { - "cell_type": "markdown", - "id": "4d25024d", - "metadata": {}, - "source": [ - "#### Describe columns" - ] - }, - { - "cell_type": "markdown", - "id": "33014b1c", - "metadata": {}, - "source": [ - "We describe the float type columns:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "61cc141c", - "metadata": {}, - "outputs": [], - "source": [ - "desc = (\n", - " df[\n", - " [\n", - " \"input_tokens\",\n", - " \"output_tokens\",\n", - " \"total_tokens\",\n", - " \"input_duration_min\",\n", - " \"output_duration_min\",\n", - " \"model_duration_min\",\n", - " \"tokens_per_second\",\n", - " ]\n", - " ]\n", - " .describe()\n", - " .T\n", - ")\n", - "print(desc)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6dbb2ba5", - "metadata": {}, - "outputs": [], - "source": [ - "840 / 60" - ] - }, - { - "cell_type": "markdown", - "id": "116603ca", - "metadata": {}, - "source": [ - "We observed that the 75% of the results have model_duration_min <= 7.7 minutes, and the is at list one outlier with model_duration_min = 840 minutes (14 hours)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bcd5ccbd", - "metadata": {}, - "outputs": [], - "source": [ - "df[df[\"model_duration_min\"] > 840]" - ] - }, - { - "cell_type": "markdown", - "id": "7945a14f", - "metadata": {}, - "source": [ - "This is an outlier due the garbage of its output:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f02adf9b", - "metadata": {}, - "outputs": [], - "source": [ - "import pprint\n", - "\n", - "df[df[\"model_duration_min\"] > 840].chat_response.iloc[0][-200:]" - ] - }, - { - "cell_type": "markdown", - "id": "1ddcf0b0", - "metadata": {}, - "source": [ - "Visualization of unique values per main columns:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e0ec9e75", - "metadata": {}, - "outputs": [], - "source": [ - "for col in [\n", - " \"model\",\n", - " \"system_prompt\",\n", - " \"device\",\n", - " \"system_prompt_type\",\n", - " \"user_prompt\",\n", - " \"doc_path\",\n", - "]:\n", - " unique_vals(df, col)" - ] - }, - { - "cell_type": "markdown", - "id": "2e1f550d", - "metadata": {}, - "source": [ - "### Model comparison" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d3d684ef", - "metadata": {}, - "outputs": [], - "source": [ - "df.groupby(\"model\")[\n", - " [\"tokens_per_second\", \"model_duration_min\", \"total_tokens\"]\n", - "].mean().sort_values(\"tokens_per_second\", ascending=False)\n", - "df.groupby([\"model\", \"device\"])[[\"model_duration_min\", \"tokens_per_second\"]].mean()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4f749026", - "metadata": {}, - "outputs": [], - "source": [ - "# Runtime distribution\n", - "plt.figure(figsize=(8, 5), dpi=50)\n", - "sns.boxplot(data=df, x=\"model\", y=\"model_duration_min\", hue=\"device\")\n", - "plt.xticks(rotation=45)\n", - "plt.title(\"Model Duration by Device\")\n", - "plt.grid(True)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "86d0a9a8", - "metadata": {}, - "source": [ - "Since deepseek-r1:8b has a duration one or two orders of magnitude longer compared to other models, we removed it from the visualization to avoid scaling issues:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "646c45d5", - "metadata": {}, - "outputs": [], - "source": [ - "df_to_plot = df[df[\"model\"] != \"deepseek-r1:8b\"]\n", - "# Runtime distribution\n", - "plt.figure(figsize=(8, 5), dpi=100)\n", - "sns.boxplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"device\")\n", - "plt.xticks(rotation=45)\n", - "plt.title(\"Tokens per second by device\")\n", - "plt.grid(True)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2ceada36", - "metadata": {}, - "outputs": [], - "source": [ - "df_to_plot = df[df[\"model\"] != \"deepseek-r1:8b\"]\n", - "# Runtime distribution\n", - "plt.figure(figsize=(8, 5), dpi=100)\n", - "sns.boxplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"system_prompt_type\")\n", - "plt.xticks(rotation=45)\n", - "plt.title(\"Model Duration by device\")\n", - "plt.grid(True)\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "30d74a25", - "metadata": {}, - "outputs": [], - "source": [ - "df_to_plot = df[df[\"model\"] != \"deepseek-r1:8b\"]\n", - "# Runtime distribution\n", - "plt.figure(figsize=(8, 5), dpi=100)\n", - "sns.boxplot(\n", - " data=df_to_plot, x=\"model\", y=\"model_duration_min\", hue=\"system_prompt_type\"\n", - ")\n", - "plt.xticks(rotation=45)\n", - "plt.title(\"Model Duration by device\")\n", - "plt.grid(True)\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "3b6df54f", - "metadata": {}, - "source": [ - "It can be seen how much better cuda performs over cpu" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8fd45e41", - "metadata": {}, - "outputs": [], - "source": [ - "# Throughput\n", - "plt.figure(figsize=(8, 5), dpi=100)\n", - "sns.barplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"system_prompt_type\")\n", - "plt.xticks(rotation=45)\n", - "plt.grid(True)\n", - "plt.title(\"Throughput (tokens/sec) by Model and Prompt Type\")\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "60c2cbb3", - "metadata": {}, - "outputs": [], - "source": [ - "# Throughput\n", - "plt.figure(figsize=(8, 5), dpi=100)\n", - "sns.barplot(\n", - " data=df_to_plot, x=\"model\", y=\"model_duration_min\", hue=\"system_prompt_type\"\n", - ")\n", - "plt.xticks(rotation=45)\n", - "plt.grid(True)\n", - "plt.ylabel(\"Model duration (min)\")\n", - "plt.title(\"Tokens per second by Model and Prompt Type\")\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a8c681b9", - "metadata": {}, - "outputs": [], - "source": [ - "# Token ratios\n", - "plt.figure(figsize=(8, 5), dpi=100)\n", - "df_to_plot[\"compression_ratio\"] = df_to_plot[\"output_tokens\"] / df[\"input_tokens\"]\n", - "sns.violinplot(data=df_to_plot, x=\"model\", y=\"compression_ratio\")\n", - "plt.xticks(rotation=45)\n", - "plt.grid(True)\n", - "plt.title(\"Output/Input Token Ratio (Compression Quality Proxy)\")\n", - "plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "id": "8bc2cfc2", - "metadata": {}, - "source": [ - "A nivel " - ] - }, - { - "cell_type": "markdown", - "id": "36a2746e", - "metadata": {}, - "source": [ - "The mean imput tokens by model are:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb3d4078", - "metadata": {}, - "outputs": [], - "source": [ - "for filter, df_filtered in [\n", - " (\"all\", df),\n", - " (\"cuda\", df[df[\"device\"] == \"cuda\"]),\n", - " (\"cpu\", df[df[\"device\"] == \"cpu\"]),\n", - "]:\n", - " fig, axes = plt.subplots(ncols=2, figsize=(10, 5))\n", - " label = filter if filter != \"all\" else filter + \" devices\"\n", - "\n", - " sns.barplot(\n", - " data=df_filtered,\n", - " x=\"model\",\n", - " y=\"tokens_per_second\",\n", - " ax=axes[0],\n", - " order=vc.index if \"vc\" in globals() else None,\n", - " label=label,\n", - " )\n", - " axes[0].set_title(\"Generation Speed by Model\")\n", - " axes[0].set_ylabel(\"Tokens per Second\")\n", - " axes[0].tick_params(axis=\"x\", rotation=45)\n", - " axes[0].grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", - "\n", - " sns.barplot(\n", - " data=df_filtered,\n", - " x=\"model\",\n", - " y=\"measured_duration_min\",\n", - " ax=axes[1],\n", - " order=vc.index if \"vc\" in globals() else None,\n", - " label=label,\n", - " )\n", - " axes[1].set_title(\"Total Processing Time by Model\")\n", - " axes[1].set_ylabel(\"Duration (min)\")\n", - " axes[1].tick_params(axis=\"x\", rotation=45)\n", - " axes[1].grid(axis=\"y\", linestyle=\"--\", alpha=0.7)\n", - "\n", - " plt.tight_layout()\n", - " plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "id": "a7afc1f2", - "metadata": {}, - "source": [ - "### Gap Analysis (CPU - CUDA)" - ] - }, - { - "cell_type": "markdown", - "id": "ea239bb0", - "metadata": {}, - "source": [ - "#### Time Gap" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7218eea4", - "metadata": {}, - "outputs": [], - "source": [ - "# time gap between CPU and CUDA (cpu_ms - cuda_ms)\n", - "pivot = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", - "pivot.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "50c879eb", - "metadata": {}, - "outputs": [], - "source": [ - "# time gap between CPU and CUDA (cpu_ms - cuda_ms)\n", - "pivot = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", - "if {\"cpu\", \"cuda\"}.issubset(pivot.columns):\n", - " # ensure no missing values and work on a copy\n", - " pivot = pivot.reindex(pivot.index).fillna(0).copy()\n", - "\n", - " # reset index so 'model' becomes a column\n", - " pivot = pivot.reset_index().rename(columns={\"index\": \"model\"})\n", - "\n", - " # ensure numeric types and compute difference (values are already in minutes)\n", - " pivot[\"cpu\"] = pd.to_numeric(pivot[\"cpu\"], errors=\"coerce\").fillna(0)\n", - " pivot[\"cuda\"] = pd.to_numeric(pivot[\"cuda\"], errors=\"coerce\").fillna(0)\n", - " pivot[\"cpu_minus_cuda_min\"] = pivot[\"cpu\"] - pivot[\"cuda\"]\n", - "\n", - " # build a 1-D list of model names ordered by the gap\n", - " order = list(pivot.sort_values(\"cpu_minus_cuda_min\", ascending=False)[\"model\"])\n", - "\n", - " plt.figure(figsize=(12, 5))\n", - " sns.barplot(data=pivot, x=\"model\", y=\"cpu_minus_cuda_min\", order=order)\n", - " plt.axhline(0, color=\"k\", linestyle=\"--\", linewidth=0.8)\n", - " plt.xticks(rotation=45)\n", - " plt.ylabel(\"CPU - CUDA duration (min)\")\n", - " plt.title(\"Time gap between CPU and CUDA by model (CPU - CUDA)\")\n", - " plt.tight_layout()\n", - " plt.show()\n", - "else:\n", - " print(\n", - " \"Not enough data to compute CPU vs CUDA gap (missing 'cpu' or 'cuda' device rows).\"\n", - " )" - ] - }, - { - "cell_type": "markdown", - "id": "583b4638", - "metadata": {}, - "source": [ - "#### Token per second gap" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0ea8df17", - "metadata": {}, - "outputs": [], - "source": [ - "# time gap between CPU and CUDA (cpu_ms - cuda_ms)\n", - "pivot = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", - "if {\"cpu\", \"cuda\"}.issubset(pivot.columns):\n", - " # ensure no missing values and work on a copy\n", - " pivot = pivot.reindex(pivot.index).fillna(0).copy()\n", - "\n", - " # reset index so 'model' becomes a column\n", - " pivot = pivot.reset_index().rename(columns={\"index\": \"model\"})\n", - "\n", - " # ensure numeric types and compute difference (values are already in minutes)\n", - " pivot[\"cpu\"] = pd.to_numeric(pivot[\"cpu\"], errors=\"coerce\").fillna(0)\n", - " pivot[\"cuda\"] = pd.to_numeric(pivot[\"cuda\"], errors=\"coerce\").fillna(0)\n", - " pivot[\"cpu_minus_cuda_min\"] = pivot[\"cpu\"] - pivot[\"cuda\"]\n", - "\n", - " # build a 1-D list of model names ordered by the gap\n", - " order = list(pivot.sort_values(\"cpu_minus_cuda_min\", ascending=False)[\"model\"])\n", - "\n", - " plt.figure(figsize=(12, 5))\n", - " sns.barplot(data=pivot, x=\"model\", y=\"cpu_minus_cuda_min\", order=order)\n", - " plt.axhline(0, color=\"k\", linestyle=\"--\", linewidth=0.8)\n", - " plt.xticks(rotation=45)\n", - " plt.ylabel(\"CPU - CUDA tokens per second gap\")\n", - " plt.title(\"Token per second gap between CPU and CUDA by model (CPU - CUDA)\")\n", - " plt.tight_layout()\n", - " plt.show()\n", - "else:\n", - " print(\n", - " \"Not enough data to compute CPU vs CUDA gap (missing 'cpu' or 'cuda' device rows).\"\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bebfb4d2", - "metadata": {}, - "outputs": [], - "source": [ - "df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "797cfad4", - "metadata": {}, - "outputs": [], - "source": [ - "pivot_token = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", - "pivot_dur = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", - "\n", - "# prepare a list of models to keep consistent ordering (try to reuse vc order if present)\n", - "models = list(vc.index) if \"vc\" in globals() else sorted(df[\"model\"].unique())\n", - "\n", - "\n", - "# build a safe summary even if one device is missing\n", - "def safe_gap(pivot, models):\n", - " # ensure index contains all models and missing values filled with 0\n", - " p = (\n", - " pivot.reindex(models)\n", - " .fillna(0)\n", - " .copy()\n", - " .reset_index()\n", - " .rename(columns={\"index\": \"model\"})\n", - " )\n", - " # coerce numeric and add cpu/cuda columns if missing\n", - " p[\"cpu\"] = pd.to_numeric(p.get(\"cpu\", 0), errors=\"coerce\").fillna(0)\n", - " p[\"cuda\"] = pd.to_numeric(p.get(\"cuda\", 0), errors=\"coerce\").fillna(0)\n", - " return p\n", - "\n", - "\n", - "p_token = safe_gap(pivot_token, models)\n", - "p_dur = safe_gap(pivot_dur, models)\n", - "\n", - "model_summary = pd.DataFrame(\n", - " {\n", - " \"model\": p_token[\"model\"],\n", - " \"gap_input_tokens\": p_token[\"cpu\"] - p_token[\"cuda\"],\n", - " # convert minutes gap to seconds\n", - " \"gap_total_duration_min\": (p_dur[\"cpu\"] - p_dur[\"cuda\"]),\n", - " }\n", - ")\n", - "\n", - "# bubble size: proportional to number of samples per model (scaled for plotting)\n", - "counts = df.groupby(\"model\").size().reindex(model_summary[\"model\"]).fillna(1)\n", - "model_summary[\"bubble_size\"] = (counts / counts.max()) * 400 + 50\n", - "\n", - "# ensure columns have expected dtypes\n", - "model_summary[\"gap_input_tokens\"] = pd.to_numeric(\n", - " model_summary[\"gap_input_tokens\"], errors=\"coerce\"\n", - ").fillna(0)\n", - "model_summary[\"gap_total_duration_min\"] = pd.to_numeric(\n", - " model_summary[\"gap_total_duration_min\"], errors=\"coerce\"\n", - ").fillna(0)\n", - "\n", - "model_summary.head()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c00d6e92", - "metadata": {}, - "outputs": [], - "source": [ - "pivot_token = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", - "pivot_dur = df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", - "\n", - "# prepare a list of models to keep consistent ordering (try to reuse vc order if present)\n", - "models = list(vc.index) if \"vc\" in globals() else sorted(df[\"model\"].unique())\n", - "\n", - "\n", - "# build a safe summary even if one device is missing\n", - "def safe_gap(pivot, models):\n", - " # ensure index contains all models and missing values filled with 0\n", - " p = (\n", - " pivot.reindex(models)\n", - " .fillna(0)\n", - " .copy()\n", - " .reset_index()\n", - " .rename(columns={\"index\": \"model\"})\n", - " )\n", - " # coerce numeric and add cpu/cuda columns if missing\n", - " p[\"cpu\"] = pd.to_numeric(p.get(\"cpu\", 0), errors=\"coerce\").fillna(0)\n", - " p[\"cuda\"] = pd.to_numeric(p.get(\"cuda\", 0), errors=\"coerce\").fillna(0)\n", - " return p\n", - "\n", - "\n", - "p_token = safe_gap(pivot_token, models)\n", - "p_dur = safe_gap(pivot_dur, models)\n", - "\n", - "model_summary = pd.DataFrame(\n", - " {\n", - " \"model\": p_token[\"model\"],\n", - " \"gap_tokens\": p_token[\"cpu\"] - p_token[\"cuda\"],\n", - " # convert minutes gap to seconds\n", - " \"gap_total_duration_min\": (p_dur[\"cpu\"] - p_dur[\"cuda\"]),\n", - " }\n", - ")\n", - "\n", - "# bubble size: proportional to number of samples per model (scaled for plotting)\n", - "counts = df.groupby(\"model\").size().reindex(model_summary[\"model\"]).fillna(1)\n", - "model_summary[\"bubble_size\"] = (counts / counts.max()) * 400 + 50\n", - "\n", - "# ensure columns have expected dtypes\n", - "model_summary[\"gap_tokens\"] = pd.to_numeric(\n", - " model_summary[\"gap_tokens\"], errors=\"coerce\"\n", - ").fillna(0)\n", - "model_summary[\"gap_total_duration_min\"] = pd.to_numeric(\n", - " model_summary[\"gap_total_duration_min\"], errors=\"coerce\"\n", - ").fillna(0)\n", - "\n", - "model_summary.head()\n", - "\n", - "\n", - "fig, ax = plt.subplots(figsize=(12, 6))\n", - "ax.scatter(\n", - " model_summary[\"gap_tokens\"],\n", - " model_summary[\"gap_total_duration_min\"],\n", - " # s=model_summary[\"bubble_size\"],\n", - " alpha=0.7,\n", - " color=\"#1f77b4\",\n", - " edgecolors=\"black\",\n", - ")\n", - "for _, row in model_summary.iterrows():\n", - " ax.text(\n", - " row[\"gap_tokens\"],\n", - " row[\"gap_total_duration_min\"],\n", - " row[\"model\"],\n", - " fontsize=9,\n", - " ha=\"left\",\n", - " va=\"bottom\",\n", - " alpha=0.9,\n", - " )\n", - "ax.set_ylabel(\"Average Total Duration Gap (min)\")\n", - "ax.set_xlabel(\"Average Tokens per second\")\n", - "# ax.set_ylabel(\"Average Total Duration (s)\")\n", - "ax.grid(True, linestyle=\"--\", alpha=0.6)\n", - "ax.set_title(\"CPU vs CUDA Performance Gap by Model\")\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8542204f", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7c42e753", - "metadata": {}, - "outputs": [], - "source": [ - "def make_summary(df):\n", - " pivot_token = df.groupby([\"model\", \"device\"])[\"tokens_per_second\"].mean().unstack()\n", - " pivot_dur = (\n", - " df.groupby([\"model\", \"device\"])[\"measured_duration_min\"].mean().unstack()\n", - " )\n", - "\n", - " # prepare a list of models to keep consistent ordering\n", - " models = sorted(df[\"model\"].unique())\n", - "\n", - " # build a safe summary even if one device is missing\n", - " def safe_gap(pivot, models):\n", - " p = (\n", - " pivot.reindex(models)\n", - " .fillna(0)\n", - " .copy()\n", - " .reset_index()\n", - " .rename(columns={\"index\": \"model\"})\n", - " )\n", - " p[\"cpu\"] = pd.to_numeric(p.get(\"cpu\", 0), errors=\"coerce\").fillna(0)\n", - " p[\"cuda\"] = pd.to_numeric(p.get(\"cuda\", 0), errors=\"coerce\").fillna(0)\n", - " return p\n", - "\n", - " p_token = safe_gap(pivot_token, models)\n", - " p_dur = safe_gap(pivot_dur, models)\n", - "\n", - " model_summary = pd.DataFrame(\n", - " {\n", - " \"model\": p_token[\"model\"],\n", - " # CUDA - CPU gap for tokens per second\n", - " \"gap_tokens\": p_token[\"cuda\"] - p_token[\"cpu\"],\n", - " # CUDA - CPU gap for total duration (minutes)\n", - " \"gap_total_duration_min\": p_dur[\"cuda\"] - p_dur[\"cpu\"],\n", - " }\n", - " )\n", - "\n", - " # add parameter scale and bubble size\n", - " model_summary[\"param_scale\"] = model_summary[\"model\"].apply(\n", - " get_model_parameter_scale\n", - " )\n", - " model_summary[\"param_scale\"] = pd.to_numeric(\n", - " model_summary[\"param_scale\"], errors=\"coerce\"\n", - " ).fillna(0)\n", - "\n", - " # counts = df.groupby('model').size().reindex(model_summary['model']).fillna(1)\n", - " # model_summary['bubble_size'] = (counts / counts.max()) * 400 + 50\n", - "\n", - " # ensure numeric types and no NaNs\n", - " model_summary[\"gap_tokens\"] = pd.to_numeric(\n", - " model_summary[\"gap_tokens\"], errors=\"coerce\"\n", - " ).fillna(0)\n", - " model_summary[\"gap_total_duration_min\"] = pd.to_numeric(\n", - " model_summary[\"gap_total_duration_min\"], errors=\"coerce\"\n", - " ).fillna(0)\n", - "\n", - " return model_summary\n", - "\n", - "\n", - "model_summary = make_summary(df)\n", - "model_summary.head()\n", - "\n", - "model_summary.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9fef1bba", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "\n", - "# generate a unique color per model\n", - "palette = sns.color_palette(n_colors=len(model_summary))\n", - "model_summary.sort_values(\"param_scale\", inplace=True)\n", - "model_colors = dict(zip(model_summary[\"model\"], palette))\n", - "\n", - "fig, ax = plt.subplots(figsize=(12, 6))\n", - "i = 1\n", - "# plot bubbles with model-specific colors\n", - "for _, row in model_summary.iterrows():\n", - " color = model_colors[row[\"model\"]]\n", - " ax.scatter(\n", - " row[\"param_scale\"], # row[\"gap_total_duration_min\"],\n", - " row[\"gap_tokens\"],\n", - " s=row[\"param_scale\"] * 100,\n", - " alpha=0.7,\n", - " color=color,\n", - " edgecolors=\"black\",\n", - " linewidth=0.7,\n", - " )\n", - " ax.text(\n", - " row[\"param_scale\"] + (0.5 * (-1) ** i), # row[\"gap_total_duration_min\"]\n", - " row[\"gap_tokens\"],\n", - " row[\"model\"],\n", - " fontsize=9,\n", - " ha=\"left\",\n", - " va=\"bottom\",\n", - " alpha=1,\n", - " fontweight=\"bold\",\n", - " color=color,\n", - " )\n", - " i += 1\n", - "\n", - " # add a label for the bubble size\n", - "\n", - "ax.set_ylabel(\"Average Tokens per Second\")\n", - "ax.set_xlabel(\"Parameter Scale (Billion Parameters)\")\n", - "ax.grid(True, linestyle=\"--\", alpha=0.6)\n", - "ax.set_title(\"CUDA - CPU Gap Token per Second by Model Parameter Scale per Model\")\n", - "\n", - "# optional legend showing color per model\n", - "handles = [\n", - " plt.Line2D(\n", - " [0],\n", - " [0],\n", - " marker=\"o\",\n", - " color=\"w\",\n", - " label=model,\n", - " markerfacecolor=color,\n", - " markersize=8,\n", - " markeredgecolor=\"black\",\n", - " )\n", - " for model, color in model_colors.items()\n", - "]\n", - "ax.legend(handles=handles, title=\"Model\", loc=\"best\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cdfdde71", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import seaborn as sns\n", - "\n", - "# generate a unique color per model\n", - "palette = sns.color_palette(n_colors=len(model_summary))\n", - "model_summary.sort_values(\"param_scale\", inplace=True)\n", - "model_colors = dict(zip(model_summary[\"model\"], palette))\n", - "\n", - "fig, ax = plt.subplots(figsize=(12, 6), dpi=100)\n", - "i = 1\n", - "# plot bubbles with model-specific colors\n", - "for _, row in model_summary.iterrows():\n", - " color = model_colors[row[\"model\"]]\n", - " ax.scatter(\n", - " row[\"param_scale\"], # row[\"gap_total_duration_min\"],\n", - " row[\"gap_total_duration_min\"],\n", - " s=row[\"param_scale\"] * 100,\n", - " alpha=0.7,\n", - " color=color,\n", - " edgecolors=\"black\",\n", - " linewidth=0.7,\n", - " )\n", - " ax.text(\n", - " row[\"param_scale\"] + (0.5 * (-1) ** i), # row[\"gap_total_duration_min\"]\n", - " row[\"gap_total_duration_min\"],\n", - " row[\"model\"],\n", - " fontsize=9,\n", - " ha=\"left\",\n", - " va=\"bottom\",\n", - " alpha=1,\n", - " fontweight=\"bold\",\n", - " color=color,\n", - " )\n", - " i += 1\n", - "\n", - " # add a label for the bubble size\n", - "\n", - "ax.set_ylabel(\"Average Total Duration Gap (min)\")\n", - "ax.set_xlabel(\"Parameter Scale (Billion Parameters)\")\n", - "ax.grid(True, linestyle=\"--\", alpha=0.6)\n", - "ax.set_title(\"CUDA - CPU Gap Token per Second by Model Parameter Scale per Model\")\n", - "\n", - "# optional legend showing color per model\n", - "handles = [\n", - " plt.Line2D(\n", - " [0],\n", - " [0],\n", - " marker=\"o\",\n", - " color=\"w\",\n", - " label=model,\n", - " markerfacecolor=color,\n", - " markersize=8,\n", - " markeredgecolor=\"black\",\n", - " )\n", - " for model, color in model_colors.items()\n", - "]\n", - "ax.legend(handles=handles, title=\"Model\", loc=\"best\")\n", - "\n", - "plt.tight_layout()\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "36d4c49b", - "metadata": {}, - "outputs": [], - "source": [ - "(\n", - " df.iloc[0].output_tokens / df.iloc[0].output_duration_ms\n", - ") * 1000 # it is tokens_per_second" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8666d95d", - "metadata": {}, - "outputs": [], - "source": [ - "from aymurai.utils.json_data import load_json, save_json\n", - "\n", - "save_json(\n", - " summaries,\n", - " DATA_PATH + \"summaries.json\",\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eae7c0e6", - "metadata": {}, - "outputs": [], - "source": [ - "df.iloc[0].input_duration_ms + df.iloc[0].output_duration_ms # total duration in ms" - ] - }, - { - "cell_type": "markdown", - "id": "8d4847a7", - "metadata": {}, - "source": [ - "## Qualitative Analysis" - ] - }, - { - "cell_type": "markdown", - "id": "4c19dacc", - "metadata": {}, - "source": [ - "### Garbage Detection - Outliers " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0bba4ac3", - "metadata": {}, - "outputs": [], - "source": [ - "df.describe()" - ] - }, - { - "cell_type": "markdown", - "id": "600d3507", - "metadata": {}, - "source": [ - "max output_tokens is 163840, same value as max input token, so, it is truncated. We will see examples" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8cfce3c0", - "metadata": {}, - "outputs": [], - "source": [ - "df_truncated = df[df[\"output_tokens\"] > 16000]\n", - "print(\"Truncated summary analysis: \\ndoc paths: \\n\", df_truncated.doc_path.unique())\n", - "print(\"Models: \\n\", df_truncated.model.unique())\n", - "df_truncated.head()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "77a9fe88", - "metadata": {}, - "outputs": [], - "source": [ - "df_truncated.groupby([\"model\", \"doc_path\", \"system_prompt_type\"]).count()" - ] - }, - { - "cell_type": "markdown", - "id": "fc67ba29", - "metadata": {}, - "source": [ - "11 of 12 outputs truncated correspond to deepseek-r1:8b model, and the other one to phi3:3.8b. We will see the hallucinations bellow" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "687db5cd", - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure(figsize=(12, 6))\n", - "sns.boxplot(data=df, x=\"model\", y=\"model_duration_ms\")\n", - "plt.xticks(rotation=45)\n", - "plt.title(\"Runtime Variability Across Documents\")\n", - "plt.ylabel(\"Model Duration (ms)\")\n", - "plt.grid(True, alpha=0.4)\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fba9021e", - "metadata": {}, - "outputs": [], - "source": [ - "corr = df_to_plot[\n", - " [\n", - " \"input_tokens\",\n", - " \"output_tokens\",\n", - " \"model_duration_ms\",\n", - " \"tokens_per_second\",\n", - " \"compression_ratio\",\n", - " ]\n", - "].corr()\n", - "sns.heatmap(corr, annot=True, cmap=\"coolwarm\", center=0)\n", - "plt.title(\"Correlation Between Metrics\")\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "95666d38", - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure(figsize=(12, 6))\n", - "sns.boxplot(data=df_to_plot, x=\"model\", y=\"tokens_per_second\", hue=\"device\")\n", - "plt.xticks(rotation=45)\n", - "plt.title(\"Tokens per Second Variability Across Documents\")\n", - "plt.ylabel(\"Tokens per Second\")\n", - "plt.grid(True, alpha=0.4)\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dce57b6a", - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure(figsize=(12, 6))\n", - "sns.boxplot(data=df_to_plot, x=\"model\", y=\"model_duration_min\")\n", - "plt.xticks(rotation=45)\n", - "plt.title(\"Runtime Variability Across Documents\")\n", - "plt.ylabel(\"Model Duration (min)\")\n", - "plt.grid(True, alpha=0.4)\n", - "plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "id": "19b0ed7e", - "metadata": {}, - "source": [ - "### Analysis by document" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1a4f0af7", - "metadata": {}, - "outputs": [], - "source": [ - "df_cuda = df[df[\"device\"] == \"cuda\"]\n", - "plt.figure(figsize=(10, 6))\n", - "sns.boxplot(data=df_cuda, x=\"doc_path\", y=\"tokens_per_second\", hue=\"model\")\n", - "plt.xticks(rotation=90)\n", - "plt.title(\"Tokens per second by Document and Model - CUDA\")\n", - "plt.grid(True)\n", - "plt.tight_layout()\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8c4f88ac", - "metadata": {}, - "outputs": [], - "source": [ - "plt.figure(figsize=(10, 6))\n", - "sns.boxplot(data=df, x=\"doc_path\", y=\"tokens_per_second\", hue=\"model\")\n", - "plt.xticks(rotation=90)\n", - "plt.title(\"Throughput by Document and Model\")\n", - "plt.tight_layout()\n", - "plt.show()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fc30cd3b", - "metadata": {}, - "outputs": [], - "source": [ - "order = sorted(df[\"model\"].unique())\n", - "order" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c9ef6921", - "metadata": {}, - "outputs": [], - "source": [ - "i = 1\n", - "for doc in df[\"doc_path\"].unique():\n", - " df_doc = df[df[\"doc_path\"] == doc]\n", - " doc_name = doc.split(\"/\")[-1]\n", - " plt.figure(figsize=(10, 6))\n", - " sns.boxplot(\n", - " data=df_doc, x=\"model\", y=\"tokens_per_second\", hue=\"device\", order=order\n", - " )\n", - " plt.xticks(rotation=90)\n", - " plt.grid(True)\n", - " plt.title(f\"Fig. {i}: {doc_name}\")\n", - " plt.tight_layout()\n", - " i += 1\n", - " plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "8977b125", - "metadata": {}, - "source": [ - "#### Summary comparison (same document)" - ] - }, - { - "cell_type": "markdown", - "id": "31ba2818", - "metadata": {}, - "source": [ - "##### cuda vs llama (same model)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2c76d769", - "metadata": {}, - "outputs": [], - "source": [ - "last_N = 1000\n", - "document = \"1- FLORES ABARCA, Francisco Alexander s 149 bis J-01-00369422-0-2022-1 Sala Feria (II) nnya vict do apela pp.pdf\"\n", - "model = \"llama3.2:3b\"\n", - "devices = [\"cuda\", \"cpu\"]\n", - "df_doc = df[df[\"doc_path\"] == document]\n", - "for d in devices:\n", - " df_filtered = df_doc[\n", - " (df[\"model\"] == model)\n", - " & (df[\"device\"] == d)\n", - " & (df[\"system_prompt_type\"] == \"template\")\n", - " ]\n", - " print(\n", - " f\"--------------------- Document: {document}, device= {d}, model= {model}---------------------\"\n", - " )\n", - " text = df_filtered[\"chat_response\"].astype(str).fillna(\"\")[-last_N:].values[0]\n", - " print(text)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "d1afcf25", - "metadata": {}, - "source": [ - " **Interpretation**\n", - "- Running the same model (Llama 3.2:3b) and same prompt/document in cuda is 5–6× faster than in cpu\n", - "- Despite the speedup, output content remains consistent, with both versions extracting similar entities and structure.\n", - "- The CUDA output finishes much faster but tends to include slightly more redundant or verbose entities (e.g., repeated names), suggesting minor decoding variability due to parallelization.\n", - "- The CPU output is slower but more stable and concise, with slightly better formatting consistency.\n", - "\n", - "This comparison confirms that CUDA significantly improves throughput without major semantic drift, though some token-level differences may appear." - ] - }, - { - "cell_type": "markdown", - "id": "699a16de", - "metadata": {}, - "source": [ - "##### gemma vs llama (cuda)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4ad69da3", - "metadata": {}, - "outputs": [], - "source": [ - "last_N = 1000\n", - "document = \"aymurai - ejemplo 02.docx\"\n", - "models = [\"phi3:3.8b\", \"gemma3:12b\"]\n", - "df_doc = df[df[\"doc_path\"] == document]\n", - "for m in models:\n", - " df_filtered = df_doc[\n", - " (df[\"model\"] == m)\n", - " & (df[\"device\"] == \"cuda\")\n", - " & (df[\"system_prompt_type\"] == \"template\")\n", - " ]\n", - " print(\n", - " f\"--------------------- Document: {document}, model= {m}---------------------\"\n", - " )\n", - " text = df_filtered[\"chat_response\"].astype(str).fillna(\"\")[-last_N:].values[0]\n", - " print(text)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "5d7a976c", - "metadata": {}, - "source": [ - "- Both models now generate coherent, well-structured summaries capturing key actors, context, and applied laws.\n", - "Phi 3:3.8b stands out for its richer narrative detail , like “Ana Carolina Rodríguez (DNI 34.112.456) y su hija menor M.F.R”\n", - "\n", - "- Gemma 3:12b produces a clearer and more factual summary, focusing on explicit information and structured entities.\n", - "- Phi offers greater completeness and contextual depth, while Gemma achieves higher precision and speed.\n", - "Overall, they show complementary strengths: Phi excels in descriptive depth, Gemma in concise factual extraction." - ] - }, - { - "cell_type": "markdown", - "id": "182387a0", - "metadata": {}, - "source": [ - "##### Same document, phi3 vs. phi4" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8ea9f690", - "metadata": {}, - "outputs": [], - "source": [ - "df.columns" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "31fb2d90", - "metadata": {}, - "outputs": [], - "source": [ - "set(df.model)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cfece56c", - "metadata": {}, - "outputs": [], - "source": [ - "set(df.doc_path)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e1296370", - "metadata": {}, - "outputs": [], - "source": [ - "df.columns" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "63a4ef9d", - "metadata": {}, - "outputs": [], - "source": [ - "last_N = 1000\n", - "document = \"aymurai - ejemplo 02.docx\"\n", - "models = [\"phi3:3.8b\", \"phi4:14b\"]\n", - "df_doc = df[df[\"doc_path\"] == document]\n", - "for m in models:\n", - " df_filtered = df_doc[\n", - " (df[\"model\"] == m)\n", - " & (df[\"device\"] == \"cuda\")\n", - " & (df[\"system_prompt_type\"] == \"template\")\n", - " ]\n", - " print(\n", - " f\"--------------------- Document: {document}, model= {m}---------------------\"\n", - " )\n", - " text = df_filtered[\"chat_response\"].astype(str).fillna(\"\")[-last_N:].values[0]\n", - " print(text)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "markdown", - "id": "e078eef3", - "metadata": {}, - "source": [ - "When comparing phi3:3.8b and phi4:14b on the same document, the improvement in phi4 is evident both in structure and content quality. \n", - "\n", - "While phi3 tends to generate verbose outputs and include unnecessary placeholders (e.g., “not mentioned in the document provided”), phi4 produces concise, relevant, and well-organized information. \n", - "\n", - "Its summaries remain focused on the extracted entities without overgenerating text, which improves readability and coherence. The token usage, shown in Fig. 4, also confirm this efficiency: phi4 requires fewer output tokens while maintaining higher generation speed and precision in content extraction." - ] - }, - { - "cell_type": "markdown", - "id": "aebe3666", - "metadata": {}, - "source": [ - "#### Tokens/sec by document: cuda and cpu" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2023483d", - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import pandas as pd\n", - "\n", - "# Compute mean and std per document/model/device\n", - "df_summary = (\n", - " df.groupby([\"doc_path\", \"model\", \"device\"])[\"tokens_per_second\"]\n", - " .agg([\"mean\", \"std\", \"count\"])\n", - " .reset_index()\n", - ")\n", - "df_summary[\"sem\"] = df_summary[\"std\"] / df_summary[\"count\"] ** 0.5 # standard error\n", - "\n", - "# Sort models for consistent order\n", - "# order = sorted(df_summary['model'].unique())\n", - "\n", - "# --- Plot for each device type ---\n", - "for device in [\"cuda\", \"cpu\"]:\n", - " df_device = df_summary[df_summary[\"device\"] == device]\n", - "\n", - " plt.figure(figsize=(10, 6))\n", - "\n", - " # Plot one line per document\n", - " for doc, df_doc in df_device.groupby(\"doc_path\"):\n", - " doc_name = doc.split(\"/\")[-1][:20]\n", - " plt.errorbar(\n", - " df_doc[\"model\"],\n", - " df_doc[\"mean\"],\n", - " yerr=df_doc[\"sem\"],\n", - " fmt=\"-o\",\n", - " capsize=3,\n", - " alpha=0.7,\n", - " label=doc_name,\n", - " )\n", - "\n", - " plt.xticks(rotation=90)\n", - " plt.xlabel(\"Model\")\n", - " plt.ylabel(\"Tokens per second (mean ± SEM)\")\n", - " plt.title(f\"Performance across documents ({device.upper()})\")\n", - " plt.grid(True, linestyle=\"--\", alpha=0.6)\n", - " plt.legend(\n", - " title=\"Document\", fontsize=\"small\", loc=\"best\"\n", - " ) # bbox_to_anchor=(1.05, 1), loc='upper left')\n", - " plt.tight_layout()\n", - " plt.show()\n" - ] - }, - { - "cell_type": "markdown", - "id": "2fbe4fdc", - "metadata": {}, - "source": [ - "**Overall speed:**\n", - "- On CUDA, generation speed ranges from ~10 to 90 tokens/sec — up to 10× faster than CPU.\n", - "- On CPU, all models stay below 13 tokens/sec, showing clear hardware dependency.\n", - " \n", - "**Model comparison:**\n", - "- Llama 3.2:3b consistently achieves the highest speed across both devices, though its summary quality is limited.\n", - "- Phi 3/4 and DeepSeek 1.1b are among the slowest, likely due to heavier contextual reasoning or token complexity — however, DeepSeek often fails to summarize properly, repeating or looping.\n", - "- Gemma 3:12b and Gemma 3:4b show balanced performance, maintaining moderate speed and stable behavior across documents.\n", - "\n", - "**Document variability:**\n", - "- Speed variation across documents is low, indicating that model performance is robust to input differences.\n", - "- Slight dips appear for longer or denser texts, especially in CPU runs.\n", - " \n", - "**Key insight:**\n", - "- CUDA acceleration drastically improves throughput without affecting consistency across documents.\n", - "- Llama remains the best trade-off between speed and reliability, while Phi and Gemma prioritize content quality over raw speed." - ] - }, - { - "cell_type": "markdown", - "id": "0b721074", - "metadata": {}, - "source": [ - "### Output outliers/hallucinations visualizations" - ] - }, - { - "cell_type": "markdown", - "id": "c3a3c149", - "metadata": {}, - "source": [ - "We see the last 100 characters of each output that was truncated (df['output_tokens']>16000)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ca18869a", - "metadata": {}, - "outputs": [], - "source": [ - "N = 100\n", - "for idx, txt in enumerate(df_truncated[\"chat_response\"].astype(str).fillna(\"\")):\n", - " print(\n", - " f\"+++++++++++++ Truncated summary {idx} (model={df_truncated.iloc[idx].get('model', '')}, system_prompt_type={df_truncated.iloc[idx].get('system_prompt_type', '')}, doc_path={df_truncated.iloc[idx].get('doc_path', '')}) +++++++++++++\"\n", - " )\n", - " text = txt[-N:]\n", - " print(text)\n", - " print(\"\\n\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "aed870a3", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.15" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/summarization/03-summarization-endpoint.ipynb b/notebooks/experiments/summarization/03-summarization-endpoint.ipynb deleted file mode 100644 index 059248c0..00000000 --- a/notebooks/experiments/summarization/03-summarization-endpoint.ipynb +++ /dev/null @@ -1,170 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d636dee3", - "metadata": {}, - "source": [ - "# Summarization API endpoint" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "53cbedeb", - "metadata": {}, - "outputs": [], - "source": [ - "import json\n", - "import os\n", - "\n", - "import requests\n", - "from rich.pretty import pprint" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "24dfb1f2", - "metadata": {}, - "outputs": [], - "source": [ - "API_BASE_URL = os.getenv(\"AYMURAI_API_BASE_URL\", \"http://localhost:8999\")\n", - "SUMMARIZE_URL = f\"{API_BASE_URL}/llm/summarize\"\n", - "print(f\"POST {SUMMARIZE_URL}\")" - ] - }, - { - "cell_type": "markdown", - "id": "2be189f4", - "metadata": {}, - "source": [ - "## Build request payload" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4b547916", - "metadata": {}, - "outputs": [], - "source": [ - "sample_text = \"\"\"\n", - "La inteligencia artificial (IA) ha revolucionado numerosos campos, desde la medicina hasta la industria del entretenimiento,\n", - "y el ámbito de la justicia no es una excepción. La IA tiene el potencial de transformar la forma en que se administran los\n", - "sistemas legales, mejorando la eficiencia y la precisión en la toma de decisiones judiciales. Sin embargo, también plantea\n", - "desafíos éticos y legales significativos que deben ser abordados cuidadosamente.\n", - "\"\"\".strip()\n", - "\n", - "payload = {\n", - " \"text\": sample_text,\n", - " \"model\": \"llama3.2:3b\",\n", - " \"system_prompt\": \"Eres un asistente que resume textos de manera concisa y clara sin inventar información.\",\n", - " \"tokenizer\": None,\n", - " \"options\": {\"num_ctx\": 1024, \"num_predict\": 512, \"stream\": True},\n", - "}\n", - "\n", - "pprint(payload)\n" - ] - }, - { - "cell_type": "markdown", - "id": "aa2adc0d", - "metadata": {}, - "source": [ - "## Call the endpoint" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81d6d33f", - "metadata": {}, - "outputs": [], - "source": [ - "def call_summarize(text_payload: dict) -> dict:\n", - " response = requests.post(SUMMARIZE_URL, json=text_payload)\n", - " response.raise_for_status()\n", - " return response.json()\n", - "\n", - "\n", - "result = call_summarize(payload)\n", - "pprint({\"model\": result.get(\"model\"), \"chunks_used\": result.get(\"chunks_used\")})\n", - "print(\"Summary:\")\n", - "print(result.get(\"summary\", \"\"))\n", - "\n", - "print(\"Steps:\")\n", - "pprint(result.get(\"steps\", []))" - ] - }, - { - "cell_type": "markdown", - "id": "d3402133", - "metadata": {}, - "source": [ - "## Streamed call" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "aaa18c09", - "metadata": {}, - "outputs": [], - "source": [ - "STREAM_URL = f\"{API_BASE_URL}/llm/summarize/stream\"\n", - "\n", - "\n", - "def stream_summarize(text_payload: dict) -> None:\n", - " with requests.post(STREAM_URL, json=text_payload, stream=True, timeout=120) as resp:\n", - " resp.raise_for_status()\n", - " for raw_line in resp.iter_lines():\n", - " if not raw_line:\n", - " continue\n", - " if not raw_line.startswith(b\"data: \"):\n", - " continue\n", - " event = json.loads(raw_line.split(b\"data: \", 1)[1])\n", - " if event.get(\"type\") == \"token\":\n", - " print(event.get(\"text\", \"\"), end=\"\", flush=True)\n", - " elif event.get(\"type\") == \"summary\":\n", - " print(\"\\n\\n---\\nFinal summary:\\n\")\n", - " print(event.get(\"summary\", \"\"))\n", - " print(\"\\nSteps:\", event.get(\"steps\", []))\n", - " else:\n", - " print(f\"\\n[{event.get('type')}] {event}\")\n", - "\n", - "\n", - "stream_summarize(payload)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d14bc8be", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai (3.10.19)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.19" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb b/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb deleted file mode 100644 index f54a1005..00000000 --- a/notebooks/experiments/summarization/04-dspy-prompt-optimization.ipynb +++ /dev/null @@ -1,955 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "0bf2c8f0", - "metadata": {}, - "outputs": [], - "source": [ - "# !uv add dspy" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fab6180c", - "metadata": {}, - "outputs": [], - "source": [ - "%load_ext rich" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c1734177", - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "import dspy\n", - "\n", - "from aymurai.utils.json_data import load_json" - ] - }, - { - "cell_type": "markdown", - "id": "011093f3", - "metadata": {}, - "source": [ - "## Fetch data" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2d546951", - "metadata": {}, - "outputs": [], - "source": [ - "labels_dir = \"/workspace/notebooks/experiments/entity-disambiguation/entities-reviewed\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4dd3dbc2", - "metadata": {}, - "outputs": [], - "source": [ - "filenames = os.listdir(labels_dir)\n", - "filenames[:1]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "60e2e77a", - "metadata": {}, - "outputs": [], - "source": [ - "filename = filenames[0]\n", - "label_data = load_json(os.path.join(labels_dir, filename))\n", - "label_data" - ] - }, - { - "cell_type": "markdown", - "id": "43684f12", - "metadata": {}, - "source": [ - "## Documents" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c2c389b4", - "metadata": {}, - "outputs": [], - "source": [ - "import mimetypes\n", - "import time\n", - "from pathlib import Path\n", - "from typing import Iterable\n", - "\n", - "import requests" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ebc22f54", - "metadata": {}, - "outputs": [], - "source": [ - "API_BASE_URL = os.getenv(\"API_BASE_URL\", \"http://localhost:8899\")\n", - "ENDPOINT = f\"{API_BASE_URL}/misc/document-extract\"\n", - "DATA_ROOT = Path(\n", - " os.getenv(\"DOCUMENT_DATA_ROOT\", \"/resources/data/restricted/summarization\")\n", - ")\n", - "DOC_EXTENSIONS = {\".pdf\", \".docx\"}\n", - "REQUEST_TIMEOUT = float(os.getenv(\"REQUEST_TIMEOUT\", \"30\"))\n", - "\n", - "print(f\"Target endpoint: {ENDPOINT}\")\n", - "print(f\"Data root: {DATA_ROOT.resolve()}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "78f2d559", - "metadata": {}, - "outputs": [], - "source": [ - "if not DATA_ROOT.exists():\n", - " raise FileNotFoundError(\n", - " f\"Directory '{DATA_ROOT}' not found. Update DATA_ROOT before continuing.\"\n", - " )\n", - "\n", - "\n", - "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", - " extensions = {ext.lower() for ext in extensions}\n", - " return sorted(\n", - " path\n", - " for path in root.rglob(\"*\")\n", - " if path.is_file() and path.suffix.lower() in extensions\n", - " )\n", - "\n", - "\n", - "documents = discover_documents(DATA_ROOT, DOC_EXTENSIONS)\n", - "print(f\"Discovered {len(documents)} documents.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "04c89e3b", - "metadata": {}, - "outputs": [], - "source": [ - "def call_extraction_api(\n", - " session: requests.Session, file_path: Path\n", - ") -> dict[str, object]:\n", - " payload: dict[str, object] = {\n", - " \"path\": str(file_path),\n", - " \"status\": \"failure\",\n", - " \"status_code\": None,\n", - " \"elapsed_s\": None,\n", - " \"detail\": None,\n", - " }\n", - "\n", - " if not file_path.exists():\n", - " payload[\"detail\"] = \"File does not exist\"\n", - " return payload\n", - "\n", - " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", - " files = {\n", - " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", - " }\n", - "\n", - " try:\n", - " start = time.perf_counter()\n", - " response = session.post(\n", - " ENDPOINT,\n", - " files=files,\n", - " timeout=REQUEST_TIMEOUT,\n", - " )\n", - " elapsed = time.perf_counter() - start\n", - " except requests.RequestException as exc:\n", - " payload[\"detail\"] = f\"Request failed: {exc}\"\n", - " return payload\n", - " finally:\n", - " files[\"file\"][1].close()\n", - "\n", - " payload[\"status_code\"] = response.status_code\n", - " payload[\"elapsed_s\"] = elapsed\n", - "\n", - " try:\n", - " response_body = response.json()\n", - " except ValueError:\n", - " response_body = {\"raw\": response.text[:500]}\n", - "\n", - " if response.ok:\n", - " payload[\"status\"] = \"success\"\n", - " payload[\"detail\"] = {\n", - " \"document_id\": response_body.get(\"document_id\"),\n", - " \"document\": response_body.get(\"document\", []),\n", - " }\n", - " else:\n", - " payload[\"detail\"] = response_body\n", - "\n", - " return payload" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08b9ebb8", - "metadata": {}, - "outputs": [], - "source": [ - "doc_path = Path(os.path.join(DATA_ROOT, \"aymurai - ejemplo 01.docx\"))\n", - "extracted_document = call_extraction_api(requests.Session(), doc_path)\n", - "document = \"\\n\".join(extracted_document[\"detail\"][\"document\"])\n", - "print(document)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6f722d5", - "metadata": {}, - "outputs": [], - "source": [ - "references = load_json(os.path.join(labels_dir, filename))\n", - "references" - ] - }, - { - "cell_type": "markdown", - "id": "137a89c6", - "metadata": {}, - "source": [ - "## Evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5e9b03a8", - "metadata": {}, - "outputs": [], - "source": [ - "# lm = dspy.LM(\"ollama_chat/gpt-oss:20b\", api_base=\"http://localhost:11434\")\n", - "lm = dspy.LM(\"ollama_chat/qwen3:8b\", api_base=\"http://localhost:11434\")\n", - "dspy.configure(lm=lm)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "81c419f3", - "metadata": {}, - "outputs": [], - "source": [ - "print(document)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9825ac86", - "metadata": {}, - "outputs": [], - "source": [ - "# qwen3:14b\n", - "summarize = dspy.ChainOfThought(\"document -> summary\")\n", - "response = summarize(document=document)\n", - "print(response.summary)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e8b91d03", - "metadata": {}, - "outputs": [], - "source": [ - "summarize = dspy.ChainOfThought(\"document -> summary\")\n", - "response = summarize(document=document)\n", - "print(response.summary)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a17443d0", - "metadata": {}, - "outputs": [], - "source": [ - "print(response.reasoning)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "15d30a8d", - "metadata": {}, - "outputs": [], - "source": [ - "from dataclasses import dataclass\n", - "\n", - "from rapidfuzz import fuzz\n", - "\n", - "\n", - "class AssessSummary(dspy.Signature):\n", - " \"\"\"High-precision assessment of legal summaries with strict grounding requirements.\"\"\"\n", - "\n", - " # Inputs\n", - " document = dspy.InputField(\n", - " desc=\"Verbatim source document. Treat it as the only ground truth; cite exact passages when justifying decisions.\"\n", - " )\n", - " summary = dspy.InputField(\n", - " desc=\"Candidate legal summary whose clarity, factual grounding, and entity coverage will be judged.\"\n", - " )\n", - " references = dspy.InputField(\n", - " desc=\"Ordered list of salient legal entities, citations, or parties expected to appear verbatim in the summary.\"\n", - " )\n", - "\n", - " # Outputs\n", - " language_ok: bool = dspy.OutputField(\n", - " desc=\"Return True only if the input summary is completely written in the same language as the document.\"\n", - " )\n", - " language_reason = dspy.OutputField(\n", - " desc=\"Identify any language mismatches or confirm consistent language use.\"\n", - " )\n", - " clarity_ok: bool = dspy.OutputField(\n", - " desc=\"Return True only if the summary is concise, logically ordered, and understandable without assuming missing context.\"\n", - " )\n", - " clarity_reason = dspy.OutputField(\n", - " desc=\"Briefly highlight phrasing strengths or point out specific sentences that harmed clarity.\"\n", - " )\n", - " factfulness_ok: bool = dspy.OutputField(\n", - " desc=\"Return True only if every claim is explicitly supported by the document. Any unsupported or extrapolated statement must flip this to False.\"\n", - " )\n", - " factfulness_reason = dspy.OutputField(\n", - " desc=\"Quote the exact evidence backing supported claims. Explicitly list each unsupported or hallucinated statement.\"\n", - " )\n", - " coverage_ok: bool = dspy.OutputField(\n", - " desc=\"Return True only if the summary mentions the expected references with correct attributes and relationships.\"\n", - " )\n", - " coverage_reason = dspy.OutputField(\n", - " desc=\"Explain which references were correctly included or omitted, explicitly citing the relevant summary spans.\"\n", - " )\n", - "\n", - "\n", - "@dataclass\n", - "class SummaryScore:\n", - " score: float\n", - " coverage_score: float\n", - " judgement: dspy.Prediction\n", - "\n", - "\n", - "class SummaryMetric(dspy.Module):\n", - " COVERAGE_THRESHOLD = 0.9\n", - "\n", - " def __call__(self, document, references, summary, trace=None):\n", - " coverage_score = self._coverage_score(summary, references)\n", - "\n", - " # with dspy.context(\n", - " # lm=dspy.LM(\"ollama_chat/gpt-oss:20b\", api_base=\"http://localhost:11434\")\n", - " # ):\n", - " # Run assessment model\n", - " judgement = self.predict(\n", - " document=document,\n", - " summary=summary,\n", - " references=references,\n", - " )\n", - "\n", - " if not judgement.language_ok:\n", - " return SummaryScore(\n", - " score=0.0,\n", - " coverage_score=coverage_score,\n", - " judgement=judgement,\n", - " )\n", - "\n", - " score = sum(\n", - " [\n", - " 0.2 * (judgement.clarity_ok or 0),\n", - " 0.2 * (judgement.factfulness_ok or 0),\n", - " 0.6 * (coverage_score * (judgement.coverage_ok or 0)),\n", - " ]\n", - " )\n", - "\n", - " return SummaryScore(\n", - " score=score,\n", - " coverage_score=coverage_score,\n", - " judgement=judgement,\n", - " )\n", - "\n", - " def predict(self, document, summary, references):\n", - " return dspy.Predict(AssessSummary)(\n", - " document=document,\n", - " summary=summary,\n", - " references=references,\n", - " )\n", - "\n", - " def _coverage_score(\n", - " self, summary: str, references, threshold: float | None = None\n", - " ) -> float:\n", - " \"\"\"\n", - " Calculate the coverage score of the summary against the reference entities.\n", - "\n", - " Args:\n", - " summary (str): The summary text to be evaluated for coverage.\n", - " references (list): The list of reference entities expected to be covered in the summary.\n", - " threshold (float | None): The minimum similarity threshold to consider an entity as covered.\n", - " Defaults to COVERAGE_THRESHOLD.\n", - "\n", - " Returns:\n", - " float: The coverage score representing how well the summary covers the reference entities.\n", - " \"\"\"\n", - " if not references:\n", - " return 1.0\n", - "\n", - " threshold = threshold or self.COVERAGE_THRESHOLD\n", - " summary_lower = summary.lower()\n", - " total_score, counted = 0.0, 0\n", - "\n", - " for ref in references:\n", - " aliases = list(ref.get(\"aliases\") or [])\n", - " canonical = ref.get(\"canonical_text\")\n", - " if canonical:\n", - " aliases = [canonical, *aliases]\n", - "\n", - " aliases = set(alias.strip().lower() for alias in aliases if alias)\n", - "\n", - " best = max(\n", - " fuzz.partial_ratio(alias.lower(), summary_lower) / 100.0\n", - " for alias in aliases\n", - " )\n", - " if best < threshold:\n", - " best = 0.0\n", - "\n", - " total_score += best\n", - " counted += 1\n", - "\n", - " return total_score / counted if counted else 0.0\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e6607ae5", - "metadata": {}, - "outputs": [], - "source": [ - "metric = SummaryMetric()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f43d5278", - "metadata": {}, - "outputs": [], - "source": [ - "# phi3:14b\n", - "score = metric(document, references, response.summary)\n", - "score" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "636d3124", - "metadata": {}, - "outputs": [], - "source": [ - "score = metric(document, references, response.summary)\n", - "score" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a2e23a09", - "metadata": {}, - "outputs": [], - "source": [ - "summarization_results = load_json(\n", - " DATA_ROOT / \"summarization-benchmark-results-cuda.json\"\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52a0ef90", - "metadata": {}, - "outputs": [], - "source": [ - "len(summarization_results)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "88820925", - "metadata": {}, - "outputs": [], - "source": [ - "summaries = [\n", - " doc\n", - " for doc in summarization_results\n", - " if doc[\"doc_path\"] == os.path.basename(doc_path)\n", - "]\n", - "\n", - "len(summaries)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cb08ce45", - "metadata": {}, - "outputs": [], - "source": [ - "from tqdm import tqdm\n", - "\n", - "evaluation_results = []\n", - "\n", - "for summary_entry in tqdm(summaries):\n", - " summary = summary_entry[\"chat_response\"]\n", - " score = metric(document, references, summary)\n", - " evaluation_results.append(\n", - " {\n", - " \"doc_path\": summary_entry[\"doc_path\"],\n", - " \"summary\": summary,\n", - " \"score\": score,\n", - " \"metadata\": {\n", - " \"model\": summary_entry.get(\"model\"),\n", - " \"system_prompt_type\": summary_entry.get(\"system_prompt_type\"),\n", - " \"options\": summary_entry.get(\"options\"),\n", - " },\n", - " }\n", - " )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "986029ec", - "metadata": {}, - "outputs": [], - "source": [ - "evaluation_results = sorted(\n", - " evaluation_results, key=lambda x: x[\"score\"].score, reverse=True\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7637aa56", - "metadata": {}, - "outputs": [], - "source": [ - "evaluation_results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a2be4980", - "metadata": {}, - "outputs": [], - "source": [ - "# Update the score recomputation\n", - "\n", - "evaluation_results_bkp = evaluation_results.copy()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "55177b67", - "metadata": {}, - "outputs": [], - "source": [ - "evaluation_results[-1][\"score\"].score = 0" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4a33d896", - "metadata": {}, - "outputs": [], - "source": [ - "evaluation_results[-1][\"score\"]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bac3165b", - "metadata": {}, - "outputs": [], - "source": [ - "for eval_result in evaluation_results:\n", - " summary_score = eval_result[\"score\"]\n", - " judgement = summary_score.judgement\n", - "\n", - " score = sum(\n", - " [\n", - " 0.2 * (judgement.clarity_ok or 0),\n", - " 0.2 * (judgement.factfulness_ok or 0),\n", - " 0.6 * (summary_score.coverage_score or 0),\n", - " ]\n", - " )\n", - "\n", - " summary_score.score = score" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "78790a1b", - "metadata": {}, - "outputs": [], - "source": [ - "evaluation_resultsv = sorted(\n", - " evaluation_results, key=lambda x: x[\"score\"].score, reverse=True\n", - ")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ea3d7601", - "metadata": {}, - "outputs": [], - "source": [ - "evaluation_results" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "91f48ef6", - "metadata": {}, - "outputs": [], - "source": [ - "lm.history[0]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ff02fd1c", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "markdown", - "id": "71898f8f", - "metadata": {}, - "source": [ - "---\n", - "## Optimization" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "831a7eee", - "metadata": {}, - "outputs": [], - "source": [ - "labels_docs_map = {} # Fill in with appropriate mapping of labels to documents" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "69fa5ec5", - "metadata": {}, - "outputs": [], - "source": [ - "examples = []\n", - "\n", - "for filename, doc_path in labels_docs_map.items():\n", - " references = load_json(os.path.join(labels_dir, filename))\n", - " extracted_document = call_extraction_api(requests.Session(), Path(doc_path))\n", - " document = \"\\n\".join(extracted_document[\"detail\"][\"document\"])\n", - "\n", - " example = dspy.Example(\n", - " document=document,\n", - " references=references,\n", - " ).with_inputs(\"document\")\n", - " examples.append(example)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "307668d0", - "metadata": {}, - "outputs": [], - "source": [ - "examples[:2]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d2403a1c", - "metadata": {}, - "outputs": [], - "source": [ - "# Split examples into simple train/dev partitions\n", - "train_examples = examples[:8]\n", - "dev_examples = examples[8:]\n", - "\n", - "print(f\"Train examples: {len(train_examples)}\")\n", - "print(f\"Dev examples: {len(dev_examples)}\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fe1d3d92", - "metadata": {}, - "outputs": [], - "source": [ - "class CoTSummarizer(dspy.Module):\n", - " def __init__(self):\n", - " super().__init__()\n", - " self.cot = dspy.ChainOfThought(\"document -> summary\")\n", - "\n", - " def forward(self, document):\n", - " # references flows through so optimizers can use it in demos/prompts\n", - " return self.cot(document=document)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8ce4e7b5", - "metadata": {}, - "outputs": [], - "source": [ - "metric_module = SummaryMetric()\n", - "\n", - "\n", - "def summary_metric(example, prediction, trace=None):\n", - " package = metric_module(\n", - " document=example.document,\n", - " references=example.references,\n", - " summary=prediction.summary,\n", - " trace=trace,\n", - " )\n", - "\n", - " if trace is not None:\n", - " return package.score >= 0.75\n", - "\n", - " return package.score" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a194d49a", - "metadata": {}, - "outputs": [], - "source": [ - "evaluate = dspy.Evaluate(\n", - " devset=examples,\n", - " metric=summary_metric,\n", - " num_threads=8,\n", - " display_progress=True,\n", - " display_table=True,\n", - ")\n", - "\n", - "evaluation = evaluate(\n", - " program=CoTSummarizer(),\n", - ")\n", - "\n", - "evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "305f5d0f", - "metadata": {}, - "outputs": [], - "source": [ - "from dspy.teleprompt import COPRO\n", - "\n", - "model_to_generate_prompts = dspy.LM(\n", - " \"ollama_chat/gpt-oss:20b\",\n", - " api_base=\"http://localhost:11434\",\n", - " drop_params=True,\n", - ")\n", - "\n", - "copro = COPRO(\n", - " prompt_model=model_to_generate_prompts,\n", - " metric=summary_metric,\n", - ")\n", - "eval_kwargs = {\"num_threads\": 16, \"display_progress\": True, \"display_table\": 0}\n", - "\n", - "copro_program = copro.compile(\n", - " student=CoTSummarizer(),\n", - " trainset=examples,\n", - " eval_kwargs=eval_kwargs,\n", - ")\n", - "\n", - "copro_program" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "126401a0", - "metadata": {}, - "outputs": [], - "source": [ - "copro_program" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e4b7b2f1", - "metadata": {}, - "outputs": [], - "source": [ - "from dspy.teleprompt import COPRO\n", - "\n", - "model_to_generate_prompts = dspy.LM(\n", - " \"ollama_chat/gpt-oss:20b\",\n", - " api_base=\"http://localhost:11434\",\n", - " drop_params=True,\n", - ")\n", - "\n", - "copro = COPRO(\n", - " prompt_model=model_to_generate_prompts,\n", - " metric=summary_metric,\n", - ")\n", - "eval_kwargs = {\"num_threads\": 16, \"display_progress\": True, \"display_table\": 0}\n", - "\n", - "copro_program = copro.compile(\n", - " student=CoTSummarizer(),\n", - " trainset=examples,\n", - " eval_kwargs=eval_kwargs,\n", - ")\n", - "\n", - "copro_program" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "56912cdf", - "metadata": {}, - "outputs": [], - "source": [ - "copro_program" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9d604c0e", - "metadata": {}, - "outputs": [], - "source": [ - "evaluate = dspy.Evaluate(\n", - " devset=examples,\n", - " metric=summary_metric,\n", - " num_threads=8,\n", - " display_progress=True,\n", - " display_table=True,\n", - ")\n", - "\n", - "\n", - "evaluation = evaluate(program=copro_program)\n", - "evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6224fc48", - "metadata": {}, - "outputs": [], - "source": [ - "from dspy.teleprompt import MIPROv2\n", - "\n", - "program = CoTSummarizer()\n", - "\n", - "optimizer = MIPROv2(\n", - " prompt_model=model_to_generate_prompts,\n", - " metric=summary_metric,\n", - " auto=\"medium\",\n", - ")\n", - "\n", - "# Optimize program\n", - "print(\"Optimizing program with MIPRO...\")\n", - "optimized_program = optimizer.compile(\n", - " program.deepcopy(),\n", - " trainset=train_examples,\n", - " valset=dev_examples,\n", - " max_bootstrapped_demos=4,\n", - " max_labeled_demos=0,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2a262672", - "metadata": {}, - "outputs": [], - "source": [ - "bootstrapped_eval = evaluate(program=optimized_program)\n", - "bootstrapped_eval" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1a9e63a6", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "aymurai", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.18" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From e333f4cac345b119bdc74f36fa9251d4478f41c6 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:44:31 -0300 Subject: [PATCH 058/104] =?UTF-8?q?=F0=9F=A6=96=20Changed=20pyproject.toml?= =?UTF-8?q?=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 51e6aa24..f858567c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -84,10 +84,6 @@ dependencies = [ "pymupdf4llm>=0.0.17", "pypandoc>=1.15", "python-docx>=1.2.0", - "langextract[openai]==1.1.0", - "ollama==0.6.1", - "tiktoken==0.12.0", - "marker-pdf==1.10.1", "docx2txt>=0.9", ] @@ -96,11 +92,6 @@ Homepage = "https://www.aymurai.info/" Repository = "https://github.com/aymurAI/backend" Issues = "https://github.com/AymurAI/backend/issues" -[dependency-groups] -mlops = [ - "mlflow>=2.12.1", - "boto3>=1.34.0", -] dev = [ "matplotlib>=3.10.0", "seaborn>=0.13.2", From f735c1b5daa437532eb86e103914828f89c57fe4 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:45:29 -0300 Subject: [PATCH 059/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20resources/llm?= =?UTF-8?q?=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/llm/entity_disambiguation.yml | 69 ------------------------ resources/llm/summarization.yml | 71 ------------------------- 2 files changed, 140 deletions(-) delete mode 100644 resources/llm/entity_disambiguation.yml delete mode 100755 resources/llm/summarization.yml diff --git a/resources/llm/entity_disambiguation.yml b/resources/llm/entity_disambiguation.yml deleted file mode 100644 index 14615b37..00000000 --- a/resources/llm/entity_disambiguation.yml +++ /dev/null @@ -1,69 +0,0 @@ -PER: - system: | - Eres un auditor experto en desambiguación de entidades legales. Tu tarea es validar y enriquecer una lista de personas pre-agrupadas. - - ### Instrucciones Estrictas: - 1. **Asignación de Rol:** Identifica el rol procesal basándote en las ventanas de contexto dentro de cada entidad canónica en la parte de `attributes`['context'] - Elija un rol EXCLUSIVAMENTE en esta lista: - - "Denunciante", "Denunciado/a", "Víctima", "Juez/a", "Defensor/a de Cámara", "Asesor/a Tutelar", "Fiscal", "Abogado/a", "Perito/a", "Testigo". - 2. **Regla "Dr/a":** Si se menciona como "Dr.", "Dra." o "Dres." y no hay otro cargo explícito, asígnale el rol "Abogado/a". - 3. **Validación y Fusión:** - Usa los fragmentos de contexto para confirmar que todos los aliases de un grupo pertenecen a la misma persona. - - Si detectas que dos entidades distintas son en realidad la misma persona (ej: un grupo con el nombre completo y otro con iniciales o cargo), fusiónalos. - - Si un alias dentro de un grupo pertenece a una persona diferente, sepáralo. - 4. **Filtrado:** Elimina cualquier entidad que no sea una persona física (ej: instituciones, direcciones, leyes). - 5. **Limpieza:** Limpiá los `aliases` y el `canonical_text` si los mismos tienen otras palabras, pero respeta que estén escritos de igual manera a que sus ventanas de contexto. - Te dejo un ejemplo de esta instrucción. - Vos recibís: - { - "canonical_text": "por DREXLER, JORGE", - "aliases": [ - "por DREXLER, JORGE", - "Jorge Drexler" - ], - "attributes": { - "context": [ - "Fdo. por DREXLER, JORGE - JUEZ DE CÁMARA el mismo cita en el documento 56 que Juan es culpable", - "es acaso Jorge Drexler el juez designado para esta causa" - ] - } - - Debés entregar: - { - "canonical_text": "DREXLER, JORGE", - "aliases": [ - "DREXLER, JORGE", - "Jorge Drexler" - ], - "attributes": { - "role": "Juez/a" - } - - 6. **Manejo de Iniciales:** Identifica si las siglas (ej: "M.L.") corresponden a una persona con nombre completo en el listado y únelas si el contexto lo confirma. - - ### Formato de Salida (JSON): - Devuelve un array de objetos con esta estructura: - [ - { - "entity_id": "optional-unique-id", - "aymurai_label": "PER", - "canonical_text": "Nombre de la entidad", - "aliases": [ - "Nombre de la entidad", - "Alias 1", - "Alias 2" - ], - "attributes": { - "role": "Rol de la lista o null" - } - } - ] - - No incluyas el campo 'context' en tu respuesta final. - - user: | - Se proporciona la lista de entidades (personas) pre-clusterizadas. Cada una incluye en `attributes['context']` las ventanas de texto de ±120 caracteres donde fue mencionada en la causa judicial para que puedas determinar su rol y validez. - - # Entidades Pre-clusterizadas a validar: - {canonical_entities} - - Procesa la lista siguiendo las instrucciones de filtrado, fusión y asignación de roles. diff --git a/resources/llm/summarization.yml b/resources/llm/summarization.yml deleted file mode 100755 index 78a502fc..00000000 --- a/resources/llm/summarization.yml +++ /dev/null @@ -1,71 +0,0 @@ -system-prompts: - baseline: | - Eres un asistente especializado en resumir documentos. - Tu único objetivo es producir un resumen fiel, claro y conciso del texto que recibirás. - No añadas interpretaciones ni conclusiones no presentes en el documento. - - task-specific: | - Eres un analista legal especializado en elaborar resúmenes de resoluciones y documentos jurídicos. - Tu tarea es condensar la información esencial: hechos, cuestiones jurídicas, fundamentos y decisión. - Mantén precisión terminológica y evita inferencias no textuales. Si algún elemento no aparece en el texto, no lo inventes. - - template: | - Eres un asistente especializado en el análisis de documentos judiciales. - Debes elaborar un resumen conciso del texto recibido, priorizando la información más relevante e identificando: - - {information_to_extract} - - Además, cuando el texto lo permita, debes reconocer y listar las siguientes entidades: - - {entities_to_identify} - - # Formato de salida (Markdown) - - ## Resumen del documento - [Descripción narrativa: hechos principales, cuestiones jurídicas, fundamentos legales y decisión.] - - ## Entidades relevantes - [Listado de entidades identificadas, agrupadas por tipo y, cuando sea posible, indicando relaciones o correspondencias.] - -defaults: - information-to-extract: | - - Hechos relevantes (qué ocurrió). - - Actores clave (quiénes están involucrados). - * Denunciante(s). - * Acusado/a(s). - * Testigo/a(s). - * Juez/a(s). - * Abogado/a(s). - * Fiscal(es). - * Perito(s). - * Otros (especificar). - - Cronología (cuándo ocurrieron los hechos y eventos procesales importantes). - - Lugar(es) (dónde ocurrieron los hechos y eventos procesales importantes). - - Fundamentos (normas legales, precedentes judiciales, doctrinas aplicadas). - - Decisión (resultado/medida adoptada). - - entities-to-identify: | - - "BANCO": Nombre de una entidad bancaria, pública o privada. - - "CBU": Código Bancario Uniforme (22 dígitos) de una cuenta. - - "CORREO_ELECTRONICO": Dirección de correo electrónico. - - "CUIJ": Código Único de Identificación Jurídica de causas judiciales. - - "CUIT_CUIL": Número de CUIT o CUIL de una persona física o jurídica. - - "DIRECCION": Dirección específica (calle, número, intersección de calles y/o avenidas, código postal, etc.). - - "DNI": Número de Documento Nacional de Identidad u otro documento identificatorio. - - "EDAD": Edad explícita de una persona. - - "ESTUDIOS": Nivel o institución educativa que permita identificar a la persona (ej. "primario incompleto", "secundario completo", "Licenciado en…"). - - "FECHA": Fecha completa o parcial (día, mes y/o año). - - "IP": Dirección IP (IPv4 o IPv6). - - "LINK": Enlace o URL a una página web. - - "LOC": Localización geográfica específica (país, provincia, estado, ciudad, localidad, barrio, etc.). - - "MARCA_AUTOMOVIL": Marca de un vehículo (ej. Toyota, Ford, Suzuki, etc.). - - "NACIONALIDAD": Nacionalidad de una persona (ej. "argentino", "brasileña"). - - "NOMBRE_ARCHIVO": Nombre completo de un archivo digital (incluyendo extensión). - - "NUM_ACTUACION": Número identificatorio de una actuación administrativa o contravencional. - - "NUM_CAJA_AHORRO": Número completo de una caja de ahorro o cuenta bancaria. - - "NUM_EXPEDIENTE": Número de expediente judicial o administrativo. - - "NUM_MATRICULA": Número de matrícula profesional o académica. - - "PATENTE_DOMINIO": Patente o dominio de un vehículo. - - "PER": Nombre(s) y apellido(s) de una persona física. Los nombres inicializados (ej., "M.T.G") y los apodos (ej., "el Gato") también cuentan como información sensible a anonimizar. - - "TELEFONO": Número telefónico (fijo o celular). - - "USUARIX": Nombre de usuario o "handle" en redes sociales o plataformas digitales. From 568496e01ec68d2bd305aeb702141533cbc6008a Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:48:24 -0300 Subject: [PATCH 060/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20summarization?= =?UTF-8?q?=5Fapp=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- summarization_app/app.py | 759 ------------------------- summarization_app/run_streamlit_app.sh | 10 - 2 files changed, 769 deletions(-) delete mode 100755 summarization_app/app.py delete mode 100755 summarization_app/run_streamlit_app.sh diff --git a/summarization_app/app.py b/summarization_app/app.py deleted file mode 100755 index e5404bc8..00000000 --- a/summarization_app/app.py +++ /dev/null @@ -1,759 +0,0 @@ -import json -import re -import textwrap -from pathlib import Path - -import matplotlib.pyplot as plt -import pandas as pd -import seaborn as sns -import streamlit as st - -# Set page configuration -st.set_page_config( - page_title="Document Summarization Experiments", - page_icon="📄", - layout="wide", -) - - -# Function to load the results -@st.cache_data -def load_data(file_path: str): - try: - with open(file_path, "r") as f: - data = json.load(f) - return data - except Exception as e: - st.error(f"Error loading data: {e}") - return [] - - -# Function to extract unique values from the dataset -def get_unique_values(data, field): - values = set() - for item in data: - if field in item: - values.add(item[field]) - return sorted(list(values)) - - -# Create a helper function to handle None values -def get_sort_key(item, field, sort_order): - value = item.get(field) - # Handle None values by putting them at the end - if value is None: - return float("inf") if sort_order == "Ascending" else float("-inf") - return value - - -# Mapping from UI names to data fields for sorting and plotting -SORT_FIELD_MAP = { - "Model": "model", - "Prompt Type": "system_prompt_type", - "Tokens per Second": "tokens_per_second", - "Duration": "measured_duration_ms", - "Input Tokens": "input_tokens", - "Output Tokens": "output_tokens", - "Device": "device", -} - - -# Attempt to identify parameter scale (in billions) from model names -def get_model_parameter_scale(model_name): - if not model_name: - return None - - known_params = { - "gemma3:12b": 12, - "gemma3:40b": 40, - "gemma3:20b": 20, - "gemma3:22b": 22, - "gemma3:38b": 38, - "llama3.1:8b": 8, - "llama3.2:3b": 3, - "llama3.2:11b": 11, - "deepseek-r1:1.1b": 1.1, - "deepseek-r1:1b": 1, - "phi-3:3.8b": 3.8, - "phi-4:14b": 14, - "qwen3:3.8b": 3.8, - "qwen3:14b": 14, - "qwen3:72b": 72, - } - - model_name_lower = model_name.lower() - if model_name_lower in known_params: - return known_params[model_name_lower] - - match = re.search(r"(\d+(?:\.\d+)?)\s*b", model_name_lower) - if match: - try: - return float(match.group(1)) - except ValueError: - return None - return None - - -# Main function -def main(): - st.title("📄 Document Summarization Experiments") - - # File selector - results_file = st.sidebar.file_uploader("Upload JSON results file", type=["json"]) - - if results_file is not None: - # Load data from uploaded file - content = results_file.getvalue().decode("utf-8") - data = json.loads(content) - else: - # Try to load from the default path - default_path = "./summarization-benchmark-results.json" - if Path(default_path).exists(): - data = load_data(default_path) - st.sidebar.success(f"Loaded data from {default_path}") - else: - st.sidebar.warning("Please upload a JSON results file") - st.stop() - - # Extract unique values for filters - models = get_unique_values(data, "model") - prompt_types = get_unique_values(data, "system_prompt_type") - doc_paths = get_unique_values(data, "doc_path") - doc_filenames = {doc_path: Path(doc_path).name for doc_path in doc_paths} - devices = get_unique_values(data, "device") - - # Create filters in the sidebar - st.sidebar.header("Filters") - - model_options = ["All"] + models - default_models = ["All"] if models else [] - selected_models = st.sidebar.multiselect( - "Select Models", options=model_options, default=default_models - ) - selected_prompt_type = st.sidebar.selectbox( - "Select Prompt Type", ["All"] + prompt_types - ) - selected_doc = st.sidebar.selectbox( - "Select Document", ["All"] + list(doc_filenames.values()) - ) - selected_device = st.sidebar.selectbox("Select Device", ["All"] + devices) - - # Add metrics display option - st.sidebar.header("Display Options") - show_metrics = st.sidebar.checkbox("Show Metrics", value=True) - show_system_prompt = st.sidebar.checkbox("Show System Prompt", value=False) - show_raw_response = st.sidebar.checkbox("Show Raw Response", value=False) - - # Sorting options - st.sidebar.header("Sorting") - sort_by = st.sidebar.selectbox( - "Sort by", - [ - "Default", - "Model", - "Prompt Type", - "Tokens per Second", - "Duration", - "Input Tokens", - "Output Tokens", - "Device", - ], - ) - sort_order = st.sidebar.radio("Sort order", ["Ascending", "Descending"]) - - # Filter data based on selections - filtered_data = data - - if "All" in selected_models: - if len(selected_models) == 1: - selected_models_filter = None - else: - selected_models_filter = { - model for model in selected_models if model != "All" - } - else: - selected_models_filter = set(selected_models) - - if selected_models_filter: - filtered_data = [ - item - for item in filtered_data - if item.get("model") in selected_models_filter - ] - - if selected_prompt_type != "All": - filtered_data = [ - item - for item in filtered_data - if item.get("system_prompt_type") == selected_prompt_type - ] - - if selected_doc != "All": - filtered_data = [ - item - for item in filtered_data - if doc_filenames.get(item.get("doc_path")) == selected_doc - ] - - if selected_device != "All": - filtered_data = [ - item for item in filtered_data if item.get("device") == selected_device - ] - - # Apply sorting - if sort_by != "Default": - field = SORT_FIELD_MAP.get(sort_by) - if field: - # Sort the filtered data - filtered_data = sorted( - filtered_data, - key=lambda item: get_sort_key(item, field, sort_order), - reverse=(sort_order == "Descending"), - ) - - # Display results count - st.write(f"Found {len(filtered_data)} result(s) out of {len(data)} total.") - - # Pagination controls - st.sidebar.header("Pagination") - items_per_page_options = [5, 10, 20, 50, 100, "All"] - - # Create session state for items per page if it doesn't exist - if "items_per_page" not in st.session_state: - st.session_state.items_per_page = 10 - - # Handle the items per page selection - selected_items = st.sidebar.selectbox( - "Results per page", - options=items_per_page_options, - index=items_per_page_options.index( - 10 if 10 in items_per_page_options else items_per_page_options[1] - ), - key="items_per_page_selector", - ) - - # Handle the "All" option - if selected_items == "All": - items_per_page = len(filtered_data) - else: - items_per_page = selected_items - - # Update session state - if st.session_state.items_per_page != items_per_page: - st.session_state.items_per_page = items_per_page - st.session_state.current_page = ( - 1 # Reset to first page when changing items per page - ) - - total_pages = max(1, (len(filtered_data) + items_per_page - 1) // items_per_page) - - # Create session state for pagination if it doesn't exist - if "current_page" not in st.session_state: - st.session_state.current_page = 1 - - # Ensure current page is valid after filtering - if st.session_state.current_page > total_pages: - st.session_state.current_page = 1 - - # Only show pagination controls if there are multiple pages - if total_pages > 1: - col_label, col_input, _ = st.columns([1, 1, 6]) - - with col_label: - st.markdown("**Page**") - st.caption(f"1 - {total_pages}") - - with col_input: - current_page = st.number_input( - "Page selector", - min_value=1, - max_value=total_pages, - value=st.session_state.current_page, - step=1, - label_visibility="collapsed", - ) - st.session_state.current_page = current_page - else: - st.session_state.current_page = 1 - - current_page = st.session_state.current_page - - # Calculate start and end indices for the current page - start_idx = (current_page - 1) * items_per_page - end_idx = min(start_idx + items_per_page, len(filtered_data)) - - # Get the subset of data for the current page - page_data = filtered_data[start_idx:end_idx] - - # Show page information - col1, col2 = st.columns([3, 1]) - with col1: - st.write( - f"Displaying results {start_idx + 1}-{end_idx} of {len(filtered_data)}" - ) - - with col2: - # If we have multiple pages, show a page indicator - if total_pages > 1: - st.write(f"Page {current_page} of {total_pages}") - - # Display the filtered results - if page_data: - for idx, result in enumerate(page_data): - device_tag = ( - f" ({result.get('device', 'N/A')})" if result.get("device") else "" - ) - title = f"{result.get('model', 'N/A')}{device_tag} - [{result.get('system_prompt_type', 'Unknown')}] - {Path(result.get('doc_path', 'N/A')).name}" - - with st.expander(title): - # Display metrics as a table in a clean format - if show_metrics: - col1, col2 = st.columns(2) - - with col1: - st.subheader("Summarization Context") - context_info = { - "Model": result.get("model", "N/A"), - "Device": result.get("device", "N/A"), - "Prompt Type": result.get("system_prompt_type", "Unknown"), - "Document": Path(result.get("doc_path", "N/A")).name, - } - st.table(pd.DataFrame([context_info])) - - with col2: - st.subheader("Performance Metrics") - metrics = { - "Input Tokens": result.get("input_tokens", "N/A"), - "Output Tokens": result.get("output_tokens", "N/A"), - "Total Tokens": result.get("total_tokens", "N/A"), - "Tokens/Second": f"{result.get('tokens_per_second', 0):.2f}", - "Duration (sec)": f"{result.get('measured_duration_ms', 0) / 1000:.2f}", - "Device": result.get("device", "N/A"), - } - st.table(pd.DataFrame([metrics])) - - if show_system_prompt: - st.subheader("System Prompt") - st.caption( - f"Prompt type: **{result.get('system_prompt_type', 'Unknown')}**" - ) - st.code( - result.get("system_prompt", "N/A"), - language="markdown", - ) - - # Display chat response as markdown - st.subheader("Response") - st.markdown(result.get("chat_response", "No response available")) - - # Optional: Display raw response as a JSON - if show_raw_response and "raw_response" in result: - st.subheader("Raw Response") - st.json(result["raw_response"]) - - # Show a summary visualization if more than one result is selected - if len(filtered_data) > 1: - st.header("Summary Visualizations") - - # Create a DataFrame for easier analysis - df = pd.DataFrame(filtered_data) - df = df.loc[:, ~pd.Index(df.columns).duplicated()] - if "model" in df.columns: - df["model"] = df["model"].apply( - lambda value: ( - value - if isinstance(value, str) - else str(value) - if value is not None - else "Unknown" - ) - ) - if "doc_path" in df.columns: - df["document_name"] = df["doc_path"].apply( - lambda p: Path(p).name if isinstance(p, str) else "Unknown" - ) - else: - df["document_name"] = "Unknown" - df["model_params_b"] = df["model"].apply(get_model_parameter_scale) - df["total_duration_sec"] = df["measured_duration_ms"] / 1000 - - # Determine ordering for models in visualizations based on sorting - if "model" in df.columns: - model_values = df["model"].dropna().unique().tolist() - else: - model_values = [] - model_order = model_values.copy() - sort_field = SORT_FIELD_MAP.get(sort_by) - ascending = sort_order == "Ascending" - - if sort_by == "Model": - model_order = sorted(model_values, reverse=not ascending) - elif ( - sort_field - and sort_field in df.columns - and pd.api.types.is_numeric_dtype(df[sort_field]) - ): - model_metric = ( - df.groupby("model")[sort_field] - .mean() - .dropna() - .sort_values(ascending=ascending) - ) - if not model_metric.empty: - model_order = model_metric.index.tolist() - # Append any models missing from the metric (e.g., all NaNs) - remaining_models = [ - model for model in model_values if model not in model_order - ] - model_order.extend(remaining_models) - - if "model" in df.columns and not df.empty: - model_summary = ( - df.groupby("model") - .agg( - avg_input_tokens=("input_tokens", "mean"), - avg_total_duration_ms=("measured_duration_ms", "mean"), - avg_tokens_per_second=("tokens_per_second", "mean"), - runs=("model", "count"), - params_b=("model_params_b", "mean"), - ) - .reset_index() - ) - model_summary["avg_total_duration_sec"] = ( - model_summary["avg_total_duration_ms"] / 1000 - ) - default_param_scale = ( - model_summary["params_b"].median() - if not model_summary["params_b"].dropna().empty - else 1.0 - ) - model_summary["params_b"].fillna(default_param_scale, inplace=True) - model_summary["bubble_size"] = model_summary["params_b"] * 60 - else: - model_summary = pd.DataFrame() - - # Set up tabs for different visualizations - tab1, tab2, tab3, tab4 = st.tabs( - [ - "Performance Metrics", - "Token Usage", - "Prompt Analysis", - "Device Performance", - ] - ) - - with tab1: - col1, col2 = st.columns(2) - - with col1: - # Generation speed by model - fig, ax = plt.subplots(figsize=(10, 6)) - sns.barplot( - data=df, - x="model", - y="tokens_per_second", - order=model_order or None, - ax=ax, - ) - plt.title("Generation Speed by Model") - plt.xticks(rotation=45, ha="right") - plt.ylabel("Tokens per Second") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - with col2: - # Total duration by model - fig, ax = plt.subplots(figsize=(10, 6)) - sns.barplot( - data=df, - x="model", - y="measured_duration_ms", - order=model_order or None, - ax=ax, - ) - plt.title("Total Processing Time by Model") - plt.xticks(rotation=45, ha="right") - plt.ylabel("Duration (ms)") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - st.subheader("Input Tokens vs Total Duration (Average)") - if not model_summary.empty: - fig, ax = plt.subplots(figsize=(12, 6)) - ax.scatter( - model_summary["avg_input_tokens"], - model_summary["avg_total_duration_sec"], - s=model_summary["bubble_size"], - alpha=0.7, - color="#1f77b4", - edgecolors="black", - ) - for _, row in model_summary.iterrows(): - ax.text( - row["avg_input_tokens"], - row["avg_total_duration_sec"], - row["model"], - fontsize=9, - ha="left", - va="bottom", - alpha=0.9, - ) - ax.set_xlabel("Average Input Tokens") - ax.set_ylabel("Average Total Duration (s)") - ax.grid(True, linestyle="--", alpha=0.6) - st.pyplot(fig) - else: - st.info("Not enough data to render the bubble chart.") - - st.subheader("Performance Distributions") - dist_col1, dist_col2 = st.columns(2) - - with dist_col1: - fig, ax = plt.subplots(figsize=(10, 6)) - sns.violinplot( - data=df, - x="model", - y="tokens_per_second", - order=model_order or None, - inner="quartile", - ax=ax, - ) - plt.xticks(rotation=45, ha="right") - plt.ylabel("Tokens per Second") - plt.title("Tokens per Second Distribution by Model") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - with dist_col2: - fig, ax = plt.subplots(figsize=(10, 6)) - sns.violinplot( - data=df, - x="model", - y="total_duration_sec", - order=model_order or None, - inner="quartile", - ax=ax, - ) - plt.xticks(rotation=45, ha="right") - plt.ylabel("Total Duration (s)") - plt.title("Total Duration Distribution by Model") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - with tab2: - col1, col2 = st.columns(2) - - with col1: - # Input vs Output tokens - df_melted = pd.melt( - df, - id_vars=["model"], - value_vars=["input_tokens", "output_tokens"], - var_name="Token Type", - value_name="Token Count", - ) - fig, ax = plt.subplots(figsize=(10, 6)) - sns.barplot( - data=df_melted, - x="model", - y="Token Count", - order=model_order or None, - hue="Token Type", - ax=ax, - ) - plt.title("Input vs Output Tokens by Model") - plt.xticks(rotation=45, ha="right") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - with col2: - # Input processing time vs Output generation time - df_melted = pd.melt( - df, - id_vars=["model"], - value_vars=["input_duration_ms", "output_duration_ms"], - var_name="Processing Stage", - value_name="Duration (ms)", - ) - fig, ax = plt.subplots(figsize=(10, 6)) - sns.barplot( - data=df_melted, - x="model", - y="Duration (ms)", - order=model_order or None, - hue="Processing Stage", - ax=ax, - ) - plt.title("Processing Time Breakdown by Model") - plt.xticks(rotation=45, ha="right") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - with tab3: - col1, col2 = st.columns(2) - - with col1: - # Prompt type distribution - fig, ax = plt.subplots(figsize=(10, 6)) - prompt_counts = ( - df["system_prompt_type"].value_counts().reset_index() - ) - prompt_counts.columns = ["prompt_type", "count"] - sns.barplot(data=prompt_counts, x="prompt_type", y="count", ax=ax) - plt.title("Prompt Type Distribution") - plt.xticks(rotation=45, ha="right") - plt.ylabel("Count") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - with col2: - # Performance by prompt type - fig, ax = plt.subplots(figsize=(10, 6)) - sns.boxplot( - data=df, - x="system_prompt_type", - y="tokens_per_second", - ax=ax, - ) - plt.title("Performance by Prompt Type") - plt.xticks(rotation=45, ha="right") - plt.ylabel("Tokens per Second") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - st.subheader("Document Coverage by Model") - doc_counts = df.assign( - document_label=df["document_name"].apply( - lambda name: ( - textwrap.shorten(name, width=55, placeholder="…") - if isinstance(name, str) - else name - ) - ), - _count=1, - ).pivot_table( - index="document_label", - columns="model", - values="_count", - aggfunc="sum", - fill_value=0, - ) - if not doc_counts.empty: - if model_order: - ordered_cols = [ - col for col in model_order if col in doc_counts.columns - ] - remaining_cols = [ - col for col in doc_counts.columns if col not in ordered_cols - ] - doc_counts = doc_counts[ordered_cols + remaining_cols] - doc_totals = doc_counts.sum(axis=1).sort_values(ascending=False) - max_docs = 25 - if len(doc_totals) > max_docs: - doc_counts = doc_counts.loc[doc_totals.index[:max_docs]] - st.caption( - f"Showing top {max_docs} documents by experiment count." - ) - fig, ax = plt.subplots(figsize=(12, max(6, 0.4 * len(doc_counts)))) - sns.heatmap( - doc_counts, - annot=True, - fmt="d", - cmap="YlGnBu", - linewidths=0.3, - linecolor="white", - cbar=True, - ax=ax, - ) - plt.xlabel("Model") - plt.ylabel("Document") - plt.xticks(rotation=45, ha="right") - plt.yticks(rotation=0) - plt.title("Experiment Coverage per Document and Model") - st.pyplot(fig) - else: - st.info( - "Document coverage heatmap is unavailable with the current selection." - ) - - with tab4: - # Device performance analysis - st.subheader("Performance by Device") - if "device" in df.columns and not df.empty: - # Performance by device (all models combined) - col1, col2 = st.columns(2) - - with col1: - fig, ax = plt.subplots(figsize=(10, 6)) - sns.boxplot(data=df, x="device", y="tokens_per_second", ax=ax) - plt.title("Tokens per Second by Device") - plt.ylabel("Tokens per Second") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - with col2: - fig, ax = plt.subplots(figsize=(10, 6)) - sns.boxplot(data=df, x="device", y="total_duration_sec", ax=ax) - plt.title("Total Duration by Device") - plt.ylabel("Duration (seconds)") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - - # Model performance by device - st.subheader("Model Performance by Device") - fig, ax = plt.subplots(figsize=(12, 8)) - sns.barplot( - data=df, - x="model", - y="tokens_per_second", - hue="device", - order=model_order or None, - ax=ax, - ) - plt.title("Tokens per Second by Model and Device") - plt.xticks(rotation=45, ha="right") - plt.ylabel("Tokens per Second") - plt.grid(axis="y", linestyle="--", alpha=0.7) - plt.legend(title="Device") - st.pyplot(fig) - - # Device usage count - st.subheader("Device Usage Distribution") - device_counts = df["device"].value_counts().reset_index() - device_counts.columns = ["device", "count"] - fig, ax = plt.subplots(figsize=(8, 5)) - sns.barplot(data=device_counts, x="device", y="count", ax=ax) - plt.title("Number of Experiments by Device") - plt.ylabel("Count") - plt.grid(axis="y", linestyle="--", alpha=0.7) - st.pyplot(fig) - else: - st.info( - "Device performance data is unavailable with the current selection." - ) - - else: - st.info("No results match the selected filters.") - - # Add footer with instructions - st.sidebar.markdown("---") - st.sidebar.markdown("### Instructions") - st.sidebar.markdown( - """ - 1. Use the filters above to narrow down results: - - Filter by model, prompt type, document, or device (CPU/CUDA) - - Use multiple selections in the Models filter - 2. Expand result items to view details - 3. Toggle display options to show/hide metrics and raw responses - 4. Explore visualization tabs: - - Performance Metrics: Compare speed and duration between models - - Token Usage: Analyze input and output token distributions - - Prompt Analysis: Review prompt type performance - - Device Performance: Compare CPU vs CUDA performance - 5. Sort results by any metric including device type - """ - ) - - -if __name__ == "__main__": - main() diff --git a/summarization_app/run_streamlit_app.sh b/summarization_app/run_streamlit_app.sh deleted file mode 100755 index 0e419441..00000000 --- a/summarization_app/run_streamlit_app.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -# Set environment variables to reduce Streamlit watching -export STREAMLIT_SERVER_WATCH_DIRS="false" -export STREAMLIT_SERVER_HEADLESS="true" -export STREAMLIT_SERVER_FILE_WATCHER_TYPE="none" - -# Run Streamlit app -echo "Starting Streamlit app..." -python -m streamlit run app.py From 0d4e78edf6c6e5df592e0c8509ec396eab9bfcc0 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Thu, 19 Feb 2026 16:49:34 -0300 Subject: [PATCH 061/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20test/llm=5Fpro?= =?UTF-8?q?viders=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/llm_providers/__init__.py | 0 test/llm_providers/test_providers.py | 148 --------------------------- 2 files changed, 148 deletions(-) delete mode 100644 test/llm_providers/__init__.py delete mode 100644 test/llm_providers/test_providers.py diff --git a/test/llm_providers/__init__.py b/test/llm_providers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/test/llm_providers/test_providers.py b/test/llm_providers/test_providers.py deleted file mode 100644 index 9fbc64ae..00000000 --- a/test/llm_providers/test_providers.py +++ /dev/null @@ -1,148 +0,0 @@ -import unittest -from unittest.mock import AsyncMock, MagicMock, patch - -from aymurai.llm_providers import LLMProvider, LLMResponse, OllamaLLMProvider - - -class DummyProvider(LLMProvider): - def __init__(self, **kwargs): - super().__init__(model="dummy", **kwargs) - self.last_prompt = None - - def generate(self, prompt: str, **kwargs) -> LLMResponse: - self.last_prompt = prompt - return LLMResponse(text=f"echo::{prompt}") - - def stream(self, prompt, **kwargs): - return super().stream(prompt, **kwargs) - - -class FakeTokenizer: - def encode(self, text, add_special_tokens: bool = False): - return text.split() - - -class BaseProviderTests(unittest.TestCase): - def test_chunk_text_respects_token_limit(self): - provider = DummyProvider(max_context_tokens=4, chunk_overlap=1) - text = "uno dos tres cuatro cinco seis" - chunks = provider.chunk_text(text) - self.assertGreater(len(chunks), 1) - for i, chunk in enumerate(chunks): - self.assertEqual(chunk.index, i) - self.assertLessEqual(chunk.token_count, 4) - - def test_chunk_text_overlap_applied(self): - provider = DummyProvider(max_context_tokens=3, chunk_overlap=1) - text = "one two three four" - chunks = provider.chunk_text(text) - self.assertEqual([c.index for c in chunks], [0, 1]) - self.assertTrue(chunks[0].text.split()[-1] in chunks[1].text.split()) - - def test_chunk_text_fallback_count(self): - provider = DummyProvider(max_context_tokens=1) - provider._tokenizer = type("EmptyTok", (), {"encode": lambda self, t: []})() - chunks = provider.chunk_text("hello") - self.assertEqual(len(chunks), 1) - self.assertEqual(chunks[0].token_count, 0) - - -class OllamaProviderTests(unittest.TestCase): - def test_generate_builds_messages(self): - provider = OllamaLLMProvider(model="llama3", system_prompt="Sistema") - fake_response = {"message": {"content": "respuesta"}, "eval_count": 10} - with patch("aymurai.llm_providers.ollama_provider.ollama.chat") as mock_chat: - mock_chat.return_value = fake_response - response = provider.generate("Hola") - - self.assertEqual(response.text, "respuesta") - args, kwargs = mock_chat.call_args - self.assertEqual(kwargs["model"], "llama3") - self.assertEqual(kwargs["messages"][0]["role"], "system") - self.assertEqual(response.metadata.get("model"), "llama3") - self.assertEqual(response.metadata.get("provider"), "ollama") - self.assertIn("eval_count", response.metadata) - self.assertIn("eval_duration", response.metadata) - - def test_generate_forwards_keep_alive(self): - provider = OllamaLLMProvider(model="llama3", keep_alive=30) - fake_response = {"message": {"content": "ok"}} - with patch("aymurai.llm_providers.ollama_provider.ollama.chat") as mock_chat: - mock_chat.return_value = fake_response - _ = provider.generate("Hola") - _, kwargs = mock_chat.call_args - self.assertEqual(kwargs["keep_alive"], 30) - - def test_stream_yields_chunks(self): - provider = OllamaLLMProvider(model="llama3") - fake_chunks = iter( - [ - {"message": {"content": "Hola"}, "done": False}, - {"message": {"content": " Mundo"}, "done": True}, - ] - ) - with patch("aymurai.llm_providers.ollama_provider.ollama.chat") as mock_chat: - mock_chat.return_value = fake_chunks - pieces = list(provider.stream("Hola")) - - self.assertEqual([piece.text for piece in pieces], ["Hola", " Mundo"]) - _, kwargs = mock_chat.call_args - self.assertTrue(kwargs["stream"]) - self.assertEqual(pieces[-1].text, " Mundo") - self.assertTrue(pieces[-1].metadata.get("done")) - - def test_generate_raises_without_prompt_or_messages(self): - provider = OllamaLLMProvider(model="llama3") - with self.assertRaises(ValueError): - provider.generate(prompt=None, messages=None) - - -class AsyncOllamaProviderTests(unittest.IsolatedAsyncioTestCase): - async def test_async_generate_builds_messages(self): - provider = OllamaLLMProvider(model="llama3", system_prompt="Sistema") - fake_response = {"message": {"content": "respuesta"}, "eval_count": 10} - mock_client = MagicMock() - mock_client.chat = AsyncMock(return_value=fake_response) - - with patch( - "aymurai.llm_providers.ollama_provider.AsyncClient", - return_value=mock_client, - ): - response = await provider.async_generate("Hola") - - self.assertEqual(response.text, "respuesta") - mock_client.chat.assert_awaited_once() - _, kwargs = mock_client.chat.call_args - self.assertEqual(kwargs["model"], "llama3") - self.assertEqual(kwargs["messages"][0]["role"], "system") - self.assertEqual(response.metadata.get("model"), "llama3") - self.assertEqual(response.metadata.get("provider"), "ollama") - self.assertIn("eval_count", response.metadata) - - async def test_async_stream_yields_chunks(self): - provider = OllamaLLMProvider(model="llama3") - - async def fake_gen(): - yield {"message": {"content": "Hola"}, "done": False} - yield {"message": {"content": " Mundo"}, "done": True} - - mock_client = MagicMock() - mock_client.chat = AsyncMock(return_value=fake_gen()) - - with patch( - "aymurai.llm_providers.ollama_provider.AsyncClient", - return_value=mock_client, - ): - pieces = [] - last_chunk = None - async for chunk in provider.async_stream("Hola"): - pieces.append(chunk.text) - last_chunk = chunk - - self.assertEqual(pieces, ["Hola", " Mundo"]) - mock_client.chat.assert_awaited() - self.assertTrue(last_chunk.metadata.get("done")) - - -if __name__ == "__main__": - unittest.main() From 6fd575a2b2b5ed5d0ba5044f760f3874a2c15b40 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Fri, 20 Feb 2026 11:02:20 -0300 Subject: [PATCH 062/104] =?UTF-8?q?=F0=9F=90=9B=20Bug=20fixed=20in=20pypro?= =?UTF-8?q?ject.toml=20line=20106=20for=20.venv=20build=20up?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + uv.lock | 754 ------------------------------------------------- 2 files changed, 1 insertion(+), 754 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f858567c..8a94a2b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -92,6 +92,7 @@ Homepage = "https://www.aymurai.info/" Repository = "https://github.com/aymurAI/backend" Issues = "https://github.com/AymurAI/backend/issues" +[dependency-groups] dev = [ "matplotlib>=3.10.0", "seaborn>=0.13.2", diff --git a/uv.lock b/uv.lock index 2adadb0f..dbcc39c0 100644 --- a/uv.lock +++ b/uv.lock @@ -8,15 +8,6 @@ resolution-markers = [ "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')", ] -[[package]] -name = "absl-py" -version = "2.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/10/2a/c93173ffa1b39c1d0395b7e842bbdc62e556ca9d8d3b5572926f3e4ca752/absl_py-2.3.1.tar.gz", hash = "sha256:a97820526f7fbfd2ec1bce83f3f25e3a14840dac0d8e02a0b71cd75db3f77fc9", size = 116588, upload-time = "2025-07-03T09:31:44.05Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/aa/ba0014cc4659328dc818a28827be78e6d97312ab0cb98105a770924dc11e/absl_py-2.3.1-py3-none-any.whl", hash = "sha256:eeecf07f0c2a93ace0772c92e596ace6d3d3996c042b2128459aaae2a76de11d", size = 135811, upload-time = "2025-07-03T09:31:42.253Z" }, -] - [[package]] name = "accelerate" version = "1.12.0" @@ -141,24 +132,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] -[[package]] -name = "anthropic" -version = "0.46.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "httpx" }, - { name = "jiter" }, - { name = "pydantic" }, - { name = "sniffio" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d4/68/3b4c045edf6dc6933895e8f279cc77c7684874c8aba46a4e6241c8b147cf/anthropic-0.46.0.tar.gz", hash = "sha256:eac3d43271d02321a57c3ca68aca84c3d58873e8e72d1433288adee2d46b745b", size = 202191, upload-time = "2025-02-18T20:35:33.314Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/6f/346beae0375df5f6907230bc63d557ef5d7659be49250ac5931a758322ae/anthropic-0.46.0-py3-none-any.whl", hash = "sha256:1445ec9be78d2de7ea51b4d5acd3574e414aea97ef903d0ecbb57bec806aaa49", size = 223228, upload-time = "2025-02-18T20:35:28.659Z" }, -] - [[package]] name = "anyio" version = "4.12.1" @@ -299,12 +272,9 @@ dependencies = [ { name = "flair" }, { name = "jiwer" }, { name = "joblib" }, - { name = "langextract", extra = ["openai"] }, - { name = "marker-pdf" }, { name = "more-itertools" }, { name = "numpy" }, { name = "odfpy" }, - { name = "ollama" }, { name = "psutil" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -321,7 +291,6 @@ dependencies = [ { name = "sentencepiece" }, { name = "sqlmodel" }, { name = "tenacity" }, - { name = "tiktoken" }, { name = "torch" }, { name = "unidecode" }, { name = "uvicorn" }, @@ -342,10 +311,6 @@ dev = [ { name = "seaborn" }, { name = "streamlit" }, ] -mlops = [ - { name = "boto3" }, - { name = "mlflow" }, -] [package.metadata] requires-dist = [ @@ -360,12 +325,9 @@ requires-dist = [ { name = "flair", specifier = "==0.15.1" }, { name = "jiwer", specifier = "==3.0.5" }, { name = "joblib", specifier = ">=1.4.2" }, - { name = "langextract", extras = ["openai"], specifier = "==1.1.0" }, - { name = "marker-pdf", specifier = "==1.10.1" }, { name = "more-itertools", specifier = ">=10.5.0" }, { name = "numpy", specifier = "<2.0.0" }, { name = "odfpy", specifier = ">=1.4.1" }, - { name = "ollama", specifier = "==0.6.1" }, { name = "psutil", specifier = "==6.1.0" }, { name = "pydantic", specifier = ">=2.10.4" }, { name = "pydantic-settings", specifier = ">=2.7.0" }, @@ -382,7 +344,6 @@ requires-dist = [ { name = "sentencepiece", specifier = "==0.2.0" }, { name = "sqlmodel", specifier = "==0.0.22" }, { name = "tenacity", specifier = ">=9.0.0" }, - { name = "tiktoken", specifier = "==0.12.0" }, { name = "torch", specifier = ">=1.13.1" }, { name = "unidecode", specifier = "==1.3.8" }, { name = "uvicorn", specifier = ">=0.34.0" }, @@ -403,10 +364,6 @@ dev = [ { name = "seaborn", specifier = ">=0.13.2" }, { name = "streamlit", specifier = ">=1.21.0" }, ] -mlops = [ - { name = "boto3", specifier = ">=1.34.0" }, - { name = "mlflow", specifier = ">=2.12.1" }, -] [[package]] name = "babel" @@ -659,50 +616,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, ] -[[package]] -name = "cryptography" -version = "46.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, - { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, - { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, - { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, - { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, - { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, - { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, - { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, - { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, - { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, - { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, - { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, - { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, - { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, - { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, - { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, - { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, - { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, - { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, - { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, - { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, - { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, - { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, - { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, - { url = "https://files.pythonhosted.org/packages/d9/cd/1a8633802d766a0fa46f382a77e096d7e209e0817892929655fe0586ae32/cryptography-46.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a23582810fedb8c0bc47524558fb6c56aac3fc252cb306072fd2815da2a47c32", size = 3689163, upload-time = "2025-10-15T23:18:13.821Z" }, - { url = "https://files.pythonhosted.org/packages/4c/59/6b26512964ace6480c3e54681a9859c974172fb141c38df11eadd8416947/cryptography-46.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:e7aec276d68421f9574040c26e2a7c3771060bc0cff408bae1dcb19d3ab1e63c", size = 3429474, upload-time = "2025-10-15T23:18:15.477Z" }, -] - [[package]] name = "cycler" version = "0.12.1" @@ -712,20 +625,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] -[[package]] -name = "databricks-sdk" -version = "0.77.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-auth" }, - { name = "protobuf" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1e/54/f2393af72974d8e70bfd44b52f17b917190b4934bab66508f4afec9e9285/databricks_sdk-0.77.0.tar.gz", hash = "sha256:56b6017ae17dc31ee821e49746d2ff627a029127166c702088428527813422bd", size = 827462, upload-time = "2026-01-06T13:19:09.432Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/aa/d9186684dbcd338cf51e93621bcf53efa843fe647c0f29f549ebddbf2870/databricks_sdk-0.77.0-py3-none-any.whl", hash = "sha256:42e3211b7dbd53b81a795981149ee08d5b025442a73e464264569edc8c46ee0a", size = 779180, upload-time = "2026-01-06T13:19:07.757Z" }, -] - [[package]] name = "datasets" version = "4.4.2" @@ -844,20 +743,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, ] -[[package]] -name = "docker" -version = "7.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/9b/4a2ea29aeba62471211598dac5d96825bb49348fa07e906ea930394a83ce/docker-7.1.0.tar.gz", hash = "sha256:ad8c70e6e3f8926cb8a92619b832b4ea5299e2831c14284663184e200546fa6c", size = 117834, upload-time = "2024-05-23T11:13:57.216Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e3/26/57c6fb270950d476074c087527a558ccb6f4436657314bfb6cdf484114c4/docker-7.1.0-py3-none-any.whl", hash = "sha256:c96b93b7f0a746f9e77d325bcfb87422a3d8bd4f03136ae8a85b37f1898d5fc0", size = 147774, upload-time = "2024-05-23T11:13:55.01Z" }, -] - [[package]] name = "docopt" version = "0.6.2" @@ -902,15 +787,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ca/34/64e900657cad3c4df8a417fccbc4370ca851864edbd0f468210f1b57d084/dspy-3.1.0-py3-none-any.whl", hash = "sha256:b9f4d42cad9ac32b13fdf085dd3246c8ee8339c759cb291c5e7b7f9f5fb5dd72", size = 291317, upload-time = "2026-01-06T18:50:17.559Z" }, ] -[[package]] -name = "einops" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/81/df4fbe24dff8ba3934af99044188e20a98ed441ad17a274539b74e82e126/einops-0.8.1.tar.gz", hash = "sha256:de5d960a7a761225532e0f1959e5315ebeafc0cd43394732f103ca44b9837e84", size = 54805, upload-time = "2025-02-09T03:17:00.434Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/87/62/9773de14fe6c45c23649e98b83231fffd7b9892b6cf863251dc2afa73643/einops-0.8.1-py3-none-any.whl", hash = "sha256:919387eb55330f5757c6bea9165c5ff5cfe63a642682ea788a6d472576d81737", size = 64359, upload-time = "2025-02-09T03:17:01.998Z" }, -] - [[package]] name = "email-validator" version = "2.3.0" @@ -1095,15 +971,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697, upload-time = "2026-01-02T15:33:31.133Z" }, ] -[[package]] -name = "filetype" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020, upload-time = "2022-11-02T17:34:04.141Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, -] - [[package]] name = "fire" version = "0.7.1" @@ -1152,36 +1019,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604, upload-time = "2025-02-05T14:45:41.788Z" }, ] -[[package]] -name = "flask" -version = "3.1.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/dc/6d/cfe3c0fcc5e477df242b98bfe186a4c34357b4847e87ecaef04507332dab/flask-3.1.2.tar.gz", hash = "sha256:bf656c15c80190ed628ad08cdfd3aaa35beb087855e2f494910aa3774cc4fd87", size = 720160, upload-time = "2025-08-19T21:03:21.205Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/f9/7f9263c5695f4bd0023734af91bedb2ff8209e8de6ead162f35d8dc762fd/flask-3.1.2-py3-none-any.whl", hash = "sha256:ca1d8112ec8a6158cc29ea4858963350011b5c846a414cdb7a954aa9e967d03c", size = 103308, upload-time = "2025-08-19T21:03:19.499Z" }, -] - -[[package]] -name = "flask-cors" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "flask" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/74/0fc0fa68d62f21daef41017dafab19ef4b36551521260987eb3a5394c7ba/flask_cors-6.0.2.tar.gz", hash = "sha256:6e118f3698249ae33e429760db98ce032a8bf9913638d085ca0f4c5534ad2423", size = 13472, upload-time = "2025-12-12T20:31:42.861Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/af/72ad54402e599152de6d067324c46fe6a4f531c7c65baf7e96c63db55eaf/flask_cors-6.0.2-py3-none-any.whl", hash = "sha256:e57544d415dfd7da89a9564e1e3a9e515042df76e12130641ca6f3f2f03b699a", size = 13257, upload-time = "2025-12-12T20:31:41.3Z" }, -] - [[package]] name = "fonttools" version = "4.61.1" @@ -1307,164 +1144,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" }, ] -[[package]] -name = "google-api-core" -version = "2.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-auth" }, - { name = "googleapis-common-protos" }, - { name = "proto-plus" }, - { name = "protobuf" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/61/da/83d7043169ac2c8c7469f0e375610d78ae2160134bf1b80634c482fa079c/google_api_core-2.28.1.tar.gz", hash = "sha256:2b405df02d68e68ce0fbc138559e6036559e685159d148ae5861013dc201baf8", size = 176759, upload-time = "2025-10-28T21:34:51.529Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/d4/90197b416cb61cefd316964fd9e7bd8324bcbafabf40eef14a9f20b81974/google_api_core-2.28.1-py3-none-any.whl", hash = "sha256:4021b0f8ceb77a6fb4de6fde4502cecab45062e66ff4f2895169e0b35bc9466c", size = 173706, upload-time = "2025-10-28T21:34:50.151Z" }, -] - -[[package]] -name = "google-auth" -version = "2.47.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1-modules" }, - { name = "rsa" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/3c/ec64b9a275ca22fa1cd3b6e77fefcf837b0732c890aa32d2bd21313d9b33/google_auth-2.47.0.tar.gz", hash = "sha256:833229070a9dfee1a353ae9877dcd2dec069a8281a4e72e72f77d4a70ff945da", size = 323719, upload-time = "2026-01-06T21:55:31.045Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/18/79e9008530b79527e0d5f79e7eef08d3b179b7f851cfd3a2f27822fbdfa9/google_auth-2.47.0-py3-none-any.whl", hash = "sha256:c516d68336bfde7cf0da26aab674a36fedcf04b37ac4edd59c597178760c3498", size = 234867, upload-time = "2026-01-06T21:55:28.6Z" }, -] - -[package.optional-dependencies] -requests = [ - { name = "requests" }, -] - -[[package]] -name = "google-cloud-core" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a6/03/ef0bc99d0e0faf4fdbe67ac445e18cdaa74824fd93cd069e7bb6548cb52d/google_cloud_core-2.5.0.tar.gz", hash = "sha256:7c1b7ef5c92311717bd05301aa1a91ffbc565673d3b0b4163a52d8413a186963", size = 36027, upload-time = "2025-10-29T23:17:39.513Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/20/bfa472e327c8edee00f04beecc80baeddd2ab33ee0e86fd7654da49d45e9/google_cloud_core-2.5.0-py3-none-any.whl", hash = "sha256:67d977b41ae6c7211ee830c7912e41003ea8194bff15ae7d72fd6f51e57acabc", size = 29469, upload-time = "2025-10-29T23:17:38.548Z" }, -] - -[[package]] -name = "google-cloud-storage" -version = "3.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-api-core" }, - { name = "google-auth" }, - { name = "google-cloud-core" }, - { name = "google-crc32c" }, - { name = "google-resumable-media" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d2/8e/fab2de1a0ab7fdbd452eaae5a9a5c933d0911c26b04efa0c76ddfd921259/google_cloud_storage-3.7.0.tar.gz", hash = "sha256:9ce59c65f4d6e372effcecc0456680a8d73cef4f2dc9212a0704799cb3d69237", size = 17258914, upload-time = "2025-12-09T18:24:48.97Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/80/6e5c7c83cea15ed4dfc4843b9df9db0716bc551ac938f7b5dd18a72bd5e4/google_cloud_storage-3.7.0-py3-none-any.whl", hash = "sha256:469bc9540936e02f8a4bfd1619e9dca1e42dec48f95e4204d783b36476a15093", size = 303364, upload-time = "2025-12-09T18:24:47.343Z" }, -] - -[[package]] -name = "google-crc32c" -version = "1.8.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/03/41/4b9c02f99e4c5fb477122cd5437403b552873f014616ac1d19ac8221a58d/google_crc32c-1.8.0.tar.gz", hash = "sha256:a428e25fb7691024de47fecfbff7ff957214da51eddded0da0ae0e0f03a2cf79", size = 14192, upload-time = "2025-12-16T00:35:25.142Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/ac/6f7bc93886a823ab545948c2dd48143027b2355ad1944c7cf852b338dc91/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:0470b8c3d73b5f4e3300165498e4cf25221c7eb37f1159e221d1825b6df8a7ff", size = 31296, upload-time = "2025-12-16T00:19:07.261Z" }, - { url = "https://files.pythonhosted.org/packages/f7/97/a5accde175dee985311d949cfcb1249dcbb290f5ec83c994ea733311948f/google_crc32c-1.8.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:119fcd90c57c89f30040b47c211acee231b25a45d225e3225294386f5d258288", size = 30870, upload-time = "2025-12-16T00:29:17.669Z" }, - { url = "https://files.pythonhosted.org/packages/3d/63/bec827e70b7a0d4094e7476f863c0dbd6b5f0f1f91d9c9b32b76dcdfeb4e/google_crc32c-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6f35aaffc8ccd81ba3162443fabb920e65b1f20ab1952a31b13173a67811467d", size = 33214, upload-time = "2025-12-16T00:40:19.618Z" }, - { url = "https://files.pythonhosted.org/packages/63/bc/11b70614df04c289128d782efc084b9035ef8466b3d0a8757c1b6f5cf7ac/google_crc32c-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:864abafe7d6e2c4c66395c1eb0fe12dc891879769b52a3d56499612ca93b6092", size = 33589, upload-time = "2025-12-16T00:40:20.7Z" }, - { url = "https://files.pythonhosted.org/packages/3e/00/a08a4bc24f1261cc5b0f47312d8aebfbe4b53c2e6307f1b595605eed246b/google_crc32c-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:db3fe8eaf0612fc8b20fa21a5f25bd785bc3cd5be69f8f3412b0ac2ffd49e733", size = 34437, upload-time = "2025-12-16T00:35:19.437Z" }, -] - -[[package]] -name = "google-genai" -version = "1.56.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "google-auth", extra = ["requests"] }, - { name = "httpx" }, - { name = "pydantic" }, - { name = "requests" }, - { name = "sniffio" }, - { name = "tenacity" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/ad/d3ac5a102135bd3f1e4b1475ca65d2bd4bcc22eb2e9348ac40fe3fadb1d6/google_genai-1.56.0.tar.gz", hash = "sha256:0491af33c375f099777ae207d9621f044e27091fafad4c50e617eba32165e82f", size = 340451, upload-time = "2025-12-17T12:35:05.412Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/93/94bc7a89ef4e7ed3666add55cd859d1483a22737251df659bf1aa46e9405/google_genai-1.56.0-py3-none-any.whl", hash = "sha256:9e6b11e0c105ead229368cb5849a480e4d0185519f8d9f538d61ecfcf193b052", size = 426563, upload-time = "2025-12-17T12:35:03.717Z" }, -] - -[[package]] -name = "google-resumable-media" -version = "2.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "google-crc32c" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/64/d7/520b62a35b23038ff005e334dba3ffc75fcf583bee26723f1fd8fd4b6919/google_resumable_media-2.8.0.tar.gz", hash = "sha256:f1157ed8b46994d60a1bc432544db62352043113684d4e030ee02e77ebe9a1ae", size = 2163265, upload-time = "2025-11-17T15:38:06.659Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/0b/93afde9cfe012260e9fe1522f35c9b72d6ee222f316586b1f23ecf44d518/google_resumable_media-2.8.0-py3-none-any.whl", hash = "sha256:dd14a116af303845a8d932ddae161a26e86cc229645bc98b39f026f9b1717582", size = 81340, upload-time = "2025-11-17T15:38:05.594Z" }, -] - -[[package]] -name = "googleapis-common-protos" -version = "1.72.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e5/7b/adfd75544c415c487b33061fe7ae526165241c1ea133f9a9125a56b39fd8/googleapis_common_protos-1.72.0.tar.gz", hash = "sha256:e55a601c1b32b52d7a3e65f43563e2aa61bcd737998ee672ac9b951cd49319f5", size = 147433, upload-time = "2025-11-06T18:29:24.087Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/ab/09169d5a4612a5f92490806649ac8d41e3ec9129c636754575b3553f4ea4/googleapis_common_protos-1.72.0-py3-none-any.whl", hash = "sha256:4299c5a82d5ae1a9702ada957347726b167f9f8d1fc352477702a1e851ff4038", size = 297515, upload-time = "2025-11-06T18:29:13.14Z" }, -] - -[[package]] -name = "graphene" -version = "3.4.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "graphql-core" }, - { name = "graphql-relay" }, - { name = "python-dateutil" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cc/f6/bf62ff950c317ed03e77f3f6ddd7e34aaa98fe89d79ebd660c55343d8054/graphene-3.4.3.tar.gz", hash = "sha256:2a3786948ce75fe7e078443d37f609cbe5bb36ad8d6b828740ad3b95ed1a0aaa", size = 44739, upload-time = "2024-11-09T20:44:25.757Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/66/e0/61d8e98007182e6b2aca7cf65904721fb2e4bce0192272ab9cb6f69d8812/graphene-3.4.3-py2.py3-none-any.whl", hash = "sha256:820db6289754c181007a150db1f7fff544b94142b556d12e3ebc777a7bf36c71", size = 114894, upload-time = "2024-11-09T20:44:23.851Z" }, -] - -[[package]] -name = "graphql-core" -version = "3.2.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/9b/037a640a2983b09aed4a823f9cf1729e6d780b0671f854efa4727a7affbe/graphql_core-3.2.7.tar.gz", hash = "sha256:27b6904bdd3b43f2a0556dad5d579bdfdeab1f38e8e8788e555bdcb586a6f62c", size = 513484, upload-time = "2025-11-01T22:30:40.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/14/933037032608787fb92e365883ad6a741c235e0ff992865ec5d904a38f1e/graphql_core-3.2.7-py3-none-any.whl", hash = "sha256:17fc8f3ca4a42913d8e24d9ac9f08deddf0a0b2483076575757f6c412ead2ec0", size = 207262, upload-time = "2025-11-01T22:30:38.912Z" }, -] - -[[package]] -name = "graphql-relay" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "graphql-core" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d1/13/98fbf8d67552f102488ffc16c6f559ce71ea15f6294728d33928ab5ff14d/graphql-relay-3.2.0.tar.gz", hash = "sha256:1ff1c51298356e481a0be009ccdff249832ce53f30559c1338f22a0e0d17250c", size = 50027, upload-time = "2022-04-16T11:03:45.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/74/16/a4cf06adbc711bd364a73ce043b0b08d8fa5aae3df11b6ee4248bcdad2e0/graphql_relay-3.2.0-py3-none-any.whl", hash = "sha256:c9b22bd28b170ba1fe674c74384a8ff30a76c8e26f88ac3aa1584dd3179953e5", size = 16940, upload-time = "2022-04-16T11:03:43.895Z" }, -] - [[package]] name = "greenlet" version = "3.3.0" @@ -1481,18 +1160,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740, upload-time = "2025-12-04T14:47:52.773Z" }, ] -[[package]] -name = "gunicorn" -version = "23.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031, upload-time = "2024-08-10T20:25:27.378Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" }, -] - [[package]] name = "h11" version = "0.16.0" @@ -1560,15 +1227,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] -[[package]] -name = "huey" -version = "2.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/29/3428d52eb8e85025e264a291641a9f9d6407cc1e51d1b630f6ac5815999a/huey-2.6.0.tar.gz", hash = "sha256:8d11f8688999d65266af1425b831f6e3773e99415027177b8734b0ffd5e251f6", size = 221068, upload-time = "2026-01-06T03:01:02.055Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/34/fae9ac8f1c3a552fd3f7ff652b94c78d219dedc5fce0c0a4232457760a00/huey-2.6.0-py3-none-any.whl", hash = "sha256:1b9df9d370b49c6d5721ba8a01ac9a787cf86b3bdc584e4679de27b920395c3f", size = 76951, upload-time = "2026-01-06T03:01:00.808Z" }, -] - [[package]] name = "huggingface-hub" version = "0.36.0" @@ -1704,15 +1362,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, ] -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - [[package]] name = "jedi" version = "0.19.2" @@ -2102,38 +1751,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } -[[package]] -name = "langextract" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "aiohttp" }, - { name = "async-timeout" }, - { name = "exceptiongroup" }, - { name = "google-cloud-storage" }, - { name = "google-genai" }, - { name = "ml-collections" }, - { name = "more-itertools" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/75/e8/1a403e454301b92ccdb8a0c2f3a7b5c13e378c35acea00fdf78654539b9f/langextract-1.1.0.tar.gz", hash = "sha256:856672a8d8b0184d7154263e8d046045c822c777ebc23cb1922d580814e2b21f", size = 112029, upload-time = "2025-11-14T22:21:30.511Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/55/21/4b9eafeb9046514ea36901139137f53fe40e8c5dfc29e1183f4c6b85b890/langextract-1.1.0-py3-none-any.whl", hash = "sha256:e4fae2d9c9134cd0b50602f4714a5dce4c97da5b417fa62f5e602fc066fc1bff", size = 121592, upload-time = "2025-11-14T22:21:29.044Z" }, -] - -[package.optional-dependencies] -openai = [ - { name = "openai" }, -] - [[package]] name = "lark" version = "1.3.1" @@ -2232,60 +1849,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] -[[package]] -name = "markdown2" -version = "2.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/42/f8/b2ae8bf5f28f9b510ae097415e6e4cb63226bb28d7ee01aec03a755ba03b/markdown2-2.5.4.tar.gz", hash = "sha256:a09873f0b3c23dbfae589b0080587df52ad75bb09a5fa6559147554736676889", size = 145652, upload-time = "2025-07-27T16:16:24.307Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/06/2697b5043c3ecb720ce0d243fc7cf5024c0b5b1e450506e9b21939019963/markdown2-2.5.4-py3-none-any.whl", hash = "sha256:3c4b2934e677be7fec0e6f2de4410e116681f4ad50ec8e5ba7557be506d3f439", size = 49954, upload-time = "2025-07-27T16:16:23.026Z" }, -] - -[[package]] -name = "markdownify" -version = "1.2.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "beautifulsoup4" }, - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3f/bc/c8c8eea5335341306b0fa7e1cb33c5e1c8d24ef70ddd684da65f41c49c92/markdownify-1.2.2.tar.gz", hash = "sha256:b274f1b5943180b031b699b199cbaeb1e2ac938b75851849a31fd0c3d6603d09", size = 18816, upload-time = "2025-11-16T19:21:18.565Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/43/ce/f1e3e9d959db134cedf06825fae8d5b294bd368aacdd0831a3975b7c4d55/markdownify-1.2.2-py3-none-any.whl", hash = "sha256:3f02d3cc52714084d6e589f70397b6fc9f2f3a8531481bf35e8cc39f975e186a", size = 15724, upload-time = "2025-11-16T19:21:17.622Z" }, -] - -[[package]] -name = "marker-pdf" -version = "1.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anthropic" }, - { name = "click" }, - { name = "filetype" }, - { name = "ftfy" }, - { name = "google-genai" }, - { name = "markdown2" }, - { name = "markdownify" }, - { name = "openai" }, - { name = "pdftext" }, - { name = "pillow" }, - { name = "pre-commit" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "rapidfuzz" }, - { name = "regex" }, - { name = "scikit-learn" }, - { name = "surya-ocr" }, - { name = "torch" }, - { name = "tqdm" }, - { name = "transformers" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/71/03/708eda637267b6e559ee8c62ff00585ecc78b2700ced4c849bde364409b7/marker_pdf-1.10.1.tar.gz", hash = "sha256:8164bcc04a3b58d6be512cc43571802a00dafc3f799b29207ec9f1edf6092cf9", size = 133302, upload-time = "2025-09-30T15:44:59.591Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/ca/d025e1b10b028e75c22ab2ea5b638ac25b3e121561896000683affbda505/marker_pdf-1.10.1-py3-none-any.whl", hash = "sha256:d7b3beee48216c1e7d5cee888735af1798758049e8f46fc531e899e03f3a1b67", size = 188914, upload-time = "2025-09-30T15:44:58.441Z" }, -] - [[package]] name = "markupsafe" version = "3.0.3" @@ -2366,97 +1929,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, ] -[[package]] -name = "ml-collections" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "absl-py" }, - { name = "pyyaml" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b8/f8/1a9ae6696dbb6bc9c44ddf5c5e84710d77fe9a35a57e8a06722e1836a4a6/ml_collections-1.1.0.tar.gz", hash = "sha256:0ac1ac6511b9f1566863e0bb0afad0c64e906ea278ad3f4d2144a55322671f6f", size = 61356, upload-time = "2025-04-17T08:25:02.247Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/8a/18d4ff2c7bd83f30d6924bd4ad97abf418488c3f908dea228d6f0961ad68/ml_collections-1.1.0-py3-none-any.whl", hash = "sha256:23b6fa4772aac1ae745a96044b925a5746145a70734f087eaca6626e92c05cbc", size = 76707, upload-time = "2025-04-17T08:24:59.038Z" }, -] - -[[package]] -name = "mlflow" -version = "3.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alembic" }, - { name = "cryptography" }, - { name = "docker" }, - { name = "flask" }, - { name = "flask-cors" }, - { name = "graphene" }, - { name = "gunicorn", marker = "sys_platform != 'win32'" }, - { name = "huey" }, - { name = "matplotlib" }, - { name = "mlflow-skinny" }, - { name = "mlflow-tracing" }, - { name = "numpy" }, - { name = "pandas" }, - { name = "pyarrow" }, - { name = "scikit-learn" }, - { name = "scipy" }, - { name = "sqlalchemy" }, - { name = "waitress", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/f8/10ccb111ed53732dfceae0369073023f96acd6b00f92fb3c24473938702d/mlflow-3.8.1.tar.gz", hash = "sha256:0823377bedff4d530b0d560bf394daf9f7e9fbba53453add04eadad34de962cc", size = 8550037, upload-time = "2025-12-26T16:46:49.199Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/d5/a20b87c6cd99395fee04d6034686512305530c71ceaabe3a151eeaa25ed7/mlflow-3.8.1-py3-none-any.whl", hash = "sha256:42f26b52438fdb615588e150407c6516d0f64d417436dfc75599c525a464f210", size = 9062281, upload-time = "2025-12-26T16:46:46.528Z" }, -] - -[[package]] -name = "mlflow-skinny" -version = "3.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachetools" }, - { name = "click" }, - { name = "cloudpickle" }, - { name = "databricks-sdk" }, - { name = "fastapi" }, - { name = "gitpython" }, - { name = "importlib-metadata" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-proto" }, - { name = "opentelemetry-sdk" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "requests" }, - { name = "sqlparse" }, - { name = "typing-extensions" }, - { name = "uvicorn" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7e/00/18486d9072739e63471c1e441e78cdb6a10c641312d98f6699715406451e/mlflow_skinny-3.8.1.tar.gz", hash = "sha256:0c0aade08187030a4653e267bcd63de2f12cbfebf4c6737832cba45d6fb3594d", size = 2082226, upload-time = "2025-12-26T16:30:11.171Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/24/42e52320636fcbabeaf50704f9269a328acc995e1b8a44df6fea33130a0a/mlflow_skinny-3.8.1-py3-none-any.whl", hash = "sha256:3a6ee27f5ac1e67c1d565fa0e12c070b27129b03e669dcaf88ff841176429142", size = 2506002, upload-time = "2025-12-26T16:30:09.357Z" }, -] - -[[package]] -name = "mlflow-tracing" -version = "3.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cachetools" }, - { name = "databricks-sdk" }, - { name = "opentelemetry-api" }, - { name = "opentelemetry-proto" }, - { name = "opentelemetry-sdk" }, - { name = "packaging" }, - { name = "protobuf" }, - { name = "pydantic" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/52/e5/9cdca5a91afd71e15943f3dbe00e788bd36479637e9b2e0625224027ff01/mlflow_tracing-3.8.1.tar.gz", hash = "sha256:c032ba715994a4580323f3045fa2700a6323033d87e564bbcbda37e6ab993071", size = 1130700, upload-time = "2025-12-26T16:31:39.314Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/e3/ddbe3e2d1219fa9235559ab88ebf98e1e4f48c62672f0dfb8f1eb07276dc/mlflow_tracing-3.8.1-py3-none-any.whl", hash = "sha256:12d9b5b7177b4152979d003e0d967b280c4252758639aebdfd672734283b17bf", size = 1359007, upload-time = "2025-12-26T16:31:37.514Z" }, -] - [[package]] name = "more-itertools" version = "10.8.0" @@ -2825,19 +2297,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045, upload-time = "2020-01-18T16:55:48.852Z" } -[[package]] -name = "ollama" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "httpx" }, - { name = "pydantic" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/5a/652dac4b7affc2b37b95386f8ae78f22808af09d720689e3d7a86b6ed98e/ollama-0.6.1.tar.gz", hash = "sha256:478c67546836430034b415ed64fa890fd3d1ff91781a9d548b3325274e69d7c6", size = 51620, upload-time = "2025-11-13T23:02:17.416Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354, upload-time = "2025-11-13T23:02:16.292Z" }, -] - [[package]] name = "openai" version = "1.109.1" @@ -2857,75 +2316,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627, upload-time = "2025-09-24T13:00:50.754Z" }, ] -[[package]] -name = "opencv-python-headless" -version = "4.11.0.86" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929, upload-time = "2025-01-16T13:53:40.22Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/53/2c50afa0b1e05ecdb4603818e85f7d174e683d874ef63a6abe3ac92220c8/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca", size = 37326460, upload-time = "2025-01-16T13:52:57.015Z" }, - { url = "https://files.pythonhosted.org/packages/3b/43/68555327df94bb9b59a1fd645f63fafb0762515344d2046698762fc19d58/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81", size = 56723330, upload-time = "2025-01-16T13:55:45.731Z" }, - { url = "https://files.pythonhosted.org/packages/45/be/1438ce43ebe65317344a87e4b150865c5585f4c0db880a34cdae5ac46881/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efabcaa9df731f29e5ea9051776715b1bdd1845d7c9530065c7951d2a2899eb", size = 29487060, upload-time = "2025-01-16T13:51:59.625Z" }, - { url = "https://files.pythonhosted.org/packages/dd/5c/c139a7876099916879609372bfa513b7f1257f7f1a908b0bdc1c2328241b/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0a27c19dd1f40ddff94976cfe43066fbbe9dfbb2ec1907d66c19caef42a57b", size = 49969856, upload-time = "2025-01-16T13:53:29.654Z" }, - { url = "https://files.pythonhosted.org/packages/95/dd/ed1191c9dc91abcc9f752b499b7928aacabf10567bb2c2535944d848af18/opencv_python_headless-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:f447d8acbb0b6f2808da71fddd29c1cdd448d2bc98f72d9bb78a7a898fc9621b", size = 29324425, upload-time = "2025-01-16T13:52:49.048Z" }, - { url = "https://files.pythonhosted.org/packages/86/8a/69176a64335aed183529207ba8bc3d329c2999d852b4f3818027203f50e6/opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca", size = 39402386, upload-time = "2025-01-16T13:52:56.418Z" }, -] - -[[package]] -name = "opentelemetry-api" -version = "1.39.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "importlib-metadata" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/97/b9/3161be15bb8e3ad01be8be5a968a9237c3027c5be504362ff800fca3e442/opentelemetry_api-1.39.1.tar.gz", hash = "sha256:fbde8c80e1b937a2c61f20347e91c0c18a1940cecf012d62e65a7caf08967c9c", size = 65767, upload-time = "2025-12-11T13:32:39.182Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/df/d3f1ddf4bb4cb50ed9b1139cc7b1c54c34a1e7ce8fd1b9a37c0d1551a6bd/opentelemetry_api-1.39.1-py3-none-any.whl", hash = "sha256:2edd8463432a7f8443edce90972169b195e7d6a05500cd29e6d13898187c9950", size = 66356, upload-time = "2025-12-11T13:32:17.304Z" }, -] - -[[package]] -name = "opentelemetry-proto" -version = "1.39.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/49/1d/f25d76d8260c156c40c97c9ed4511ec0f9ce353f8108ca6e7561f82a06b2/opentelemetry_proto-1.39.1.tar.gz", hash = "sha256:6c8e05144fc0d3ed4d22c2289c6b126e03bcd0e6a7da0f16cedd2e1c2772e2c8", size = 46152, upload-time = "2025-12-11T13:32:48.681Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/51/95/b40c96a7b5203005a0b03d8ce8cd212ff23f1793d5ba289c87a097571b18/opentelemetry_proto-1.39.1-py3-none-any.whl", hash = "sha256:22cdc78efd3b3765d09e68bfbd010d4fc254c9818afd0b6b423387d9dee46007", size = 72535, upload-time = "2025-12-11T13:32:33.866Z" }, -] - -[[package]] -name = "opentelemetry-sdk" -version = "1.39.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "opentelemetry-semantic-conventions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/eb/fb/c76080c9ba07e1e8235d24cdcc4d125ef7aa3edf23eb4e497c2e50889adc/opentelemetry_sdk-1.39.1.tar.gz", hash = "sha256:cf4d4563caf7bff906c9f7967e2be22d0d6b349b908be0d90fb21c8e9c995cc6", size = 171460, upload-time = "2025-12-11T13:32:49.369Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/98/e91cf858f203d86f4eccdf763dcf01cf03f1dae80c3750f7e635bfa206b6/opentelemetry_sdk-1.39.1-py3-none-any.whl", hash = "sha256:4d5482c478513ecb0a5d938dcc61394e647066e0cc2676bee9f3af3f3f45f01c", size = 132565, upload-time = "2025-12-11T13:32:35.069Z" }, -] - -[[package]] -name = "opentelemetry-semantic-conventions" -version = "0.60b1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "opentelemetry-api" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/df/553f93ed38bf22f4b999d9be9c185adb558982214f33eae539d3b5cd0858/opentelemetry_semantic_conventions-0.60b1.tar.gz", hash = "sha256:87c228b5a0669b748c76d76df6c364c369c28f1c465e50f661e39737e84bc953", size = 137935, upload-time = "2025-12-11T13:32:50.487Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/5e/5958555e09635d09b75de3c4f8b9cae7335ca545d77392ffe7331534c402/opentelemetry_semantic_conventions-0.60b1-py3-none-any.whl", hash = "sha256:9fa8c8b0c110da289809292b0591220d3a7b53c1526a23021e977d68597893fb", size = 219982, upload-time = "2025-12-11T13:32:36.955Z" }, -] - [[package]] name = "optuna" version = "4.6.0" @@ -3022,21 +2412,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, ] -[[package]] -name = "pdftext" -version = "0.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "pypdfium2" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/7b/fe3205d44d6058932bbc785f0b9da2ed35b62e17479a8a7d2baca9df1cc6/pdftext-0.6.3.tar.gz", hash = "sha256:ab5c5dfe0f1fb78de1db837ccadac1ea41b07ce1890fead973c9a84cdaf54dec", size = 21968, upload-time = "2025-06-11T14:42:09.492Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/b9/4437bb89f04e57f48c96492a50d6168da5e201940de6620730d390449991/pdftext-0.6.3-py3-none-any.whl", hash = "sha256:528431ed8bdce39d74372cd3d27e8544af812f1f1adc81db229cf9fb48dacacb", size = 23693, upload-time = "2025-06-11T14:42:08.157Z" }, -] - [[package]] name = "pexpect" version = "4.9.0" @@ -3192,18 +2567,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] -[[package]] -name = "proto-plus" -version = "1.27.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/01/89/9cbe2f4bba860e149108b683bc2efec21f14d5f7ed6e25562ad86acbc373/proto_plus-1.27.0.tar.gz", hash = "sha256:873af56dd0d7e91836aee871e5799e1c6f1bda86ac9a983e0bb9f0c266a568c4", size = 56158, upload-time = "2025-12-16T13:46:25.729Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/24/3b7a0818484df9c28172857af32c2397b6d8fcd99d9468bd4684f98ebf0a/proto_plus-1.27.0-py3-none-any.whl", hash = "sha256:1baa7f81cf0f8acb8bc1f6d085008ba4171eaf669629d1b6d1673b21ed1c0a82", size = 50205, upload-time = "2025-12-16T13:46:24.76Z" }, -] - [[package]] name = "protobuf" version = "6.33.2" @@ -3267,27 +2630,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641, upload-time = "2025-10-24T10:04:22.57Z" }, ] -[[package]] -name = "pyasn1" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, -] - -[[package]] -name = "pyasn1-modules" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, -] - [[package]] name = "pycparser" version = "2.23" @@ -3456,26 +2798,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793, upload-time = "2025-12-23T03:14:02.103Z" }, ] -[[package]] -name = "pypdfium2" -version = "4.30.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/14/838b3ba247a0ba92e4df5d23f2bea9478edcfd72b78a39d6ca36ccd84ad2/pypdfium2-4.30.0.tar.gz", hash = "sha256:48b5b7e5566665bc1015b9d69c1ebabe21f6aee468b509531c3c8318eeee2e16", size = 140239, upload-time = "2024-05-09T18:33:17.552Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/9a/c8ff5cc352c1b60b0b97642ae734f51edbab6e28b45b4fcdfe5306ee3c83/pypdfium2-4.30.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33ceded0b6ff5b2b93bc1fe0ad4b71aa6b7e7bd5875f1ca0cdfb6ba6ac01aab", size = 2837254, upload-time = "2024-05-09T18:32:48.653Z" }, - { url = "https://files.pythonhosted.org/packages/21/8b/27d4d5409f3c76b985f4ee4afe147b606594411e15ac4dc1c3363c9a9810/pypdfium2-4.30.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:4e55689f4b06e2d2406203e771f78789bd4f190731b5d57383d05cf611d829de", size = 2707624, upload-time = "2024-05-09T18:32:51.458Z" }, - { url = "https://files.pythonhosted.org/packages/11/63/28a73ca17c24b41a205d658e177d68e198d7dde65a8c99c821d231b6ee3d/pypdfium2-4.30.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e6e50f5ce7f65a40a33d7c9edc39f23140c57e37144c2d6d9e9262a2a854854", size = 2793126, upload-time = "2024-05-09T18:32:53.581Z" }, - { url = "https://files.pythonhosted.org/packages/d1/96/53b3ebf0955edbd02ac6da16a818ecc65c939e98fdeb4e0958362bd385c8/pypdfium2-4.30.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3d0dd3ecaffd0b6dbda3da663220e705cb563918249bda26058c6036752ba3a2", size = 2591077, upload-time = "2024-05-09T18:32:55.99Z" }, - { url = "https://files.pythonhosted.org/packages/ec/ee/0394e56e7cab8b5b21f744d988400948ef71a9a892cbeb0b200d324ab2c7/pypdfium2-4.30.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc3bf29b0db8c76cdfaac1ec1cde8edf211a7de7390fbf8934ad2aa9b4d6dfad", size = 2864431, upload-time = "2024-05-09T18:32:57.911Z" }, - { url = "https://files.pythonhosted.org/packages/65/cd/3f1edf20a0ef4a212a5e20a5900e64942c5a374473671ac0780eaa08ea80/pypdfium2-4.30.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1f78d2189e0ddf9ac2b7a9b9bd4f0c66f54d1389ff6c17e9fd9dc034d06eb3f", size = 2812008, upload-time = "2024-05-09T18:32:59.886Z" }, - { url = "https://files.pythonhosted.org/packages/c8/91/2d517db61845698f41a2a974de90762e50faeb529201c6b3574935969045/pypdfium2-4.30.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:5eda3641a2da7a7a0b2f4dbd71d706401a656fea521b6b6faa0675b15d31a163", size = 6181543, upload-time = "2024-05-09T18:33:02.597Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c4/ed1315143a7a84b2c7616569dfb472473968d628f17c231c39e29ae9d780/pypdfium2-4.30.0-py3-none-musllinux_1_1_i686.whl", hash = "sha256:0dfa61421b5eb68e1188b0b2231e7ba35735aef2d867d86e48ee6cab6975195e", size = 6175911, upload-time = "2024-05-09T18:33:05.376Z" }, - { url = "https://files.pythonhosted.org/packages/7a/c4/9e62d03f414e0e3051c56d5943c3bf42aa9608ede4e19dc96438364e9e03/pypdfium2-4.30.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:f33bd79e7a09d5f7acca3b0b69ff6c8a488869a7fab48fdf400fec6e20b9c8be", size = 6267430, upload-time = "2024-05-09T18:33:08.067Z" }, - { url = "https://files.pythonhosted.org/packages/90/47/eda4904f715fb98561e34012826e883816945934a851745570521ec89520/pypdfium2-4.30.0-py3-none-win32.whl", hash = "sha256:ee2410f15d576d976c2ab2558c93d392a25fb9f6635e8dd0a8a3a5241b275e0e", size = 2775951, upload-time = "2024-05-09T18:33:10.567Z" }, - { url = "https://files.pythonhosted.org/packages/25/bd/56d9ec6b9f0fc4e0d95288759f3179f0fcd34b1a1526b75673d2f6d5196f/pypdfium2-4.30.0-py3-none-win_amd64.whl", hash = "sha256:90dbb2ac07be53219f56be09961eb95cf2473f834d01a42d901d13ccfad64b4c", size = 2892098, upload-time = "2024-05-09T18:33:13.107Z" }, - { url = "https://files.pythonhosted.org/packages/be/7a/097801205b991bc3115e8af1edb850d30aeaf0118520b016354cf5ccd3f6/pypdfium2-4.30.0-py3-none-win_arm64.whl", hash = "sha256:119b2969a6d6b1e8d55e99caaf05290294f2d0fe49c12a3f17102d01c441bd29", size = 2752118, upload-time = "2024-05-09T18:33:15.489Z" }, -] - [[package]] name = "pysocks" version = "1.7.1" @@ -3580,16 +2902,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, ] -[[package]] -name = "pywin32" -version = "311" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, - { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, - { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, -] - [[package]] name = "pywinpty" version = "3.0.2" @@ -3845,18 +3157,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, ] -[[package]] -name = "rsa" -version = "4.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pyasn1" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, -] - [[package]] name = "s3transfer" version = "0.16.0" @@ -4117,15 +3417,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276, upload-time = "2024-08-31T09:43:22.358Z" }, ] -[[package]] -name = "sqlparse" -version = "0.5.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, -] - [[package]] name = "stack-data" version = "0.6.3" @@ -4182,30 +3473,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c0/95/6b7873f0267973ebd55ba9cd33a690b35a116f2779901ef6185a0e21864d/streamlit-1.52.2-py3-none-any.whl", hash = "sha256:a16bb4fbc9781e173ce9dfbd8ffb189c174f148f9ca4fb8fa56423e84e193fc8", size = 9025937, upload-time = "2025-12-17T17:07:57.67Z" }, ] -[[package]] -name = "surya-ocr" -version = "0.17.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "einops" }, - { name = "filetype" }, - { name = "opencv-python-headless" }, - { name = "pillow" }, - { name = "platformdirs" }, - { name = "pre-commit" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "pypdfium2" }, - { name = "python-dotenv" }, - { name = "torch" }, - { name = "transformers" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/97/f868c1034da3d5788eb0d59f4b314f71bafe491e2524d3de3aa42fac2fd4/surya_ocr-0.17.0.tar.gz", hash = "sha256:3110ec9a2be0d4296968ced02ee4d33941f34c145a2d6ac508f75122014ed170", size = 155481, upload-time = "2025-09-23T21:41:37.027Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/91/7df8763a2d38ce628c3244520e338619b84aedc83ca760e0a0d42c5cf25e/surya_ocr-0.17.0-py3-none-any.whl", hash = "sha256:a728adb1aadd26493f1b937ec411f4b041fa93c8e3524c42b4c627c2e4744d5c", size = 183395, upload-time = "2025-09-23T21:41:35.369Z" }, -] - [[package]] name = "sympy" version = "1.14.0" @@ -4628,15 +3895,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, ] -[[package]] -name = "waitress" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bf/cb/04ddb054f45faa306a230769e868c28b8065ea196891f09004ebace5b184/waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", size = 179901, upload-time = "2024-11-16T20:02:35.195Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/57/a27182528c90ef38d82b636a11f606b0cbb0e17588ed205435f8affe3368/waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", size = 56232, upload-time = "2024-11-16T20:02:33.858Z" }, -] - [[package]] name = "watchdog" version = "6.0.0" @@ -4744,18 +4002,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] -[[package]] -name = "werkzeug" -version = "3.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/45/ea/b0f8eeb287f8df9066e56e831c7824ac6bab645dd6c7a8f4b2d767944f9b/werkzeug-3.1.4.tar.gz", hash = "sha256:cd3cd98b1b92dc3b7b3995038826c68097dcb16f9baa63abe35f20eafeb9fe5e", size = 864687, upload-time = "2025-11-29T02:15:22.841Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960, upload-time = "2025-11-29T02:15:21.13Z" }, -] - [[package]] name = "widgetsnbextension" version = "4.0.15" From ef1b7f53e564a74cc1dde5863dce222747879956 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Fri, 20 Feb 2026 11:07:31 -0300 Subject: [PATCH 063/104] =?UTF-8?q?=F0=9F=90=9B=20Bug=20fixed=20in=20funct?= =?UTF-8?q?ion=20'=5Fnormalize=5Ftext'=20from=20'aymurai.text.extractors.u?= =?UTF-8?q?tils'=20that=20was=20changed=20to=20'normalize=5Ftext'=20becaus?= =?UTF-8?q?e=20it's=20used=20in=20aymurai/text/extractors/docx.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/text/extractors/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aymurai/text/extractors/utils.py b/aymurai/text/extractors/utils.py index 9c449fe0..881b0633 100644 --- a/aymurai/text/extractors/utils.py +++ b/aymurai/text/extractors/utils.py @@ -24,7 +24,7 @@ ODT_NS = {"text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0"} -def _normalize_text(text: str) -> str: +def normalize_text(text: str) -> str: """ Normalize Unicode output consistently across extractors. @@ -140,7 +140,7 @@ def pdf_to_text( paragraphs = _extract_and_merge_paragraphs(file_path, np.ceil(y_tolerance)) docu = "\n\n".join(paragraphs) - return _normalize_text(docu) + return normalize_text(docu) def load_xml_from_docx(path: Path, xmlfile: str = "word/footnotes.xml") -> Any | None: From 90db8918dae1cd7826c970c950d535d6fbf7907d Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Fri, 20 Feb 2026 11:18:49 -0300 Subject: [PATCH 064/104] =?UTF-8?q?=E2=8F=AA=20Revert=20elimination=20of?= =?UTF-8?q?=20folder=20aymurai/experiments/entity=5Fdisambiguation=20for?= =?UTF-8?q?=20experimental=20purposes.=20There=20was=20an=20error=20in=20d?= =?UTF-8?q?eleting=20everything,=20files=20will=20be=20changed=20in=20next?= =?UTF-8?q?=20commit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity_disambiguation/__init__.py | 1 + .../entity_disambiguation/config.py | 176 +++++++ .../entity_disambiguation/manifest.py | 51 ++ .../entity_disambiguation/mlflow_logging.py | 111 +++++ .../entity_disambiguation/runner.py | 468 ++++++++++++++++++ 5 files changed, 807 insertions(+) create mode 100644 aymurai/experiments/entity_disambiguation/__init__.py create mode 100644 aymurai/experiments/entity_disambiguation/config.py create mode 100644 aymurai/experiments/entity_disambiguation/manifest.py create mode 100644 aymurai/experiments/entity_disambiguation/mlflow_logging.py create mode 100644 aymurai/experiments/entity_disambiguation/runner.py diff --git a/aymurai/experiments/entity_disambiguation/__init__.py b/aymurai/experiments/entity_disambiguation/__init__.py new file mode 100644 index 00000000..17dc9d09 --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/__init__.py @@ -0,0 +1 @@ +"""Entity disambiguation experiment helpers.""" diff --git a/aymurai/experiments/entity_disambiguation/config.py b/aymurai/experiments/entity_disambiguation/config.py new file mode 100644 index 00000000..68f54534 --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/config.py @@ -0,0 +1,176 @@ +import os +from datetime import datetime, timezone +from typing import Literal + +from pydantic import BaseModel, ConfigDict, Field + +from aymurai.utils.yaml_data import load_yaml + + +class ExperimentConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + name: str + run_name: str + + +class ModelConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + provider: str + name: str + temperature: float | None = None + max_tokens: int | None = None + + +class PromptSpec(BaseModel): + model_config = ConfigDict(extra="forbid") + + id: str + text: str | None = None + + +class PromptsConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + system: PromptSpec + user: PromptSpec + + +class DataManifestConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + enabled: bool = True + mode: Literal["metadata_only"] = "metadata_only" + + +class DataConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + ground_truth_dir: str + input_dir: str + dataset_id: str | None = None + manifest: DataManifestConfig = DataManifestConfig() + + +class PredictionsConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + output_base_dir: str + dir_name_template: str + + +class MLflowConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + tracking_uri: str + experiment_name: str + + +class LoggingPrivacyConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + log_prompt_text: bool = True + log_data_manifest: bool = False + log_per_doc_scores: bool = True + + +class PerDocScoresConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + id_strategy: str = "anon_filename" + + +class LoggingConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + mlflow: MLflowConfig + privacy: LoggingPrivacyConfig = LoggingPrivacyConfig() + per_doc_scores: PerDocScoresConfig = PerDocScoresConfig() + + +class EvaluationConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + function: str = "evaluate_disambiguation" + weights: dict[str, float] = Field( + default_factory=lambda: { + "w_ent": 0.4, + "w_alias": 0.35, + "w_label": 0.2, + "w_role": 0.05, + } + ) + per_doc_scores: bool = True + sim_threshold: float | None = None + normalize: bool = True + + +class ExperimentRunConfig(BaseModel): + model_config = ConfigDict(extra="forbid") + + experiment: ExperimentConfig + model: ModelConfig + prompts: PromptsConfig + data: DataConfig + predictions: PredictionsConfig + logging: LoggingConfig + evaluation: EvaluationConfig + + +def load_experiment_config(path: str) -> ExperimentRunConfig: + """ + Load an experiment configuration from a YAML file. + + Args: + path (str): Path to the YAML configuration file. + + Raises: + ValueError: If the MLflow tracking URI is not set in the environment or configuration. + + Returns: + ExperimentRunConfig: The loaded experiment configuration. + """ + data = load_yaml(path) + tracking_uri = os.getenv("MLFLOW_TRACKING_URI") + if tracking_uri: + logging_cfg = data.setdefault("logging", {}) + mlflow_cfg = logging_cfg.setdefault("mlflow", {}) + mlflow_cfg["tracking_uri"] = tracking_uri + else: + mlflow_cfg = data.get("logging", {}).get("mlflow", {}) + if "tracking_uri" not in mlflow_cfg: + raise ValueError( + "MLFLOW_TRACKING_URI is required but was not set in the environment." + ) + return ExperimentRunConfig.model_validate(data) + + +def render_run_name( + template: str, + model_name: str, + system_id: str, + user_id: str, + *, + timestamp: str | None = None, +) -> str: + """ + Render a run name based on a template and provided identifiers. + + Args: + template (str): The template string for the run name. + model_name (str): The name of the model. + system_id (str): The system identifier. + user_id (str): The user identifier. + timestamp (str | None, optional): The timestamp string. Defaults to None. + + Returns: + str: The rendered run name. + """ + timestamp = timestamp or datetime.now(timezone.utc).strftime("%y%m%d_%H%M") + return template.format( + model=model_name, + system_id=system_id, + user_id=user_id, + timestamp=timestamp, + ) diff --git a/aymurai/experiments/entity_disambiguation/manifest.py b/aymurai/experiments/entity_disambiguation/manifest.py new file mode 100644 index 00000000..2e2c37fa --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/manifest.py @@ -0,0 +1,51 @@ +import hashlib +import json +from dataclasses import dataclass +from pathlib import Path + + +@dataclass(frozen=True) +class DatasetInfo: + dataset_hash: str + dataset_count: int + dataset_bytes_total: int + manifest: dict | None = None + + +def build_metadata_manifest(root_dir: Path) -> DatasetInfo: + """ + Build a metadata manifest for the dataset located at the given root directory. + + Args: + root_dir (Path): The root directory of the dataset. + + Returns: + DatasetInfo: An object containing dataset hash, count, total bytes, and manifest. + """ + files = [] + total_bytes = 0 + + for path in sorted(root_dir.rglob("*")): + if not path.is_file(): + continue + stat = path.stat() + rel_path = path.relative_to(root_dir).as_posix() + files.append( + { + "path": rel_path, + "size_bytes": stat.st_size, + "mtime": int(stat.st_mtime), + } + ) + total_bytes += stat.st_size + + manifest = {"files": files, "summary": {"count": len(files), "bytes": total_bytes}} + manifest_bytes = json.dumps(files, sort_keys=True).encode("utf-8") + dataset_hash = hashlib.sha256(manifest_bytes).hexdigest() + + return DatasetInfo( + dataset_hash=dataset_hash, + dataset_count=len(files), + dataset_bytes_total=total_bytes, + manifest=manifest, + ) diff --git a/aymurai/experiments/entity_disambiguation/mlflow_logging.py b/aymurai/experiments/entity_disambiguation/mlflow_logging.py new file mode 100644 index 00000000..b9e0a799 --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/mlflow_logging.py @@ -0,0 +1,111 @@ +import json +import tempfile +from pathlib import Path + +import mlflow + +from aymurai.experiments.entity_disambiguation.config import ExperimentRunConfig +from aymurai.experiments.entity_disambiguation.manifest import DatasetInfo +from aymurai.utils.yaml_data import save_yaml + + +def configure_mlflow(config: ExperimentRunConfig) -> None: + """ + Configure MLflow tracking URI and experiment name. + + Args: + config (ExperimentRunConfig): Experiment run configuration. + """ + mlflow.set_tracking_uri(config.logging.mlflow.tracking_uri) + mlflow.set_experiment(config.logging.mlflow.experiment_name) + + +def log_run_metadata( + config: ExperimentRunConfig, + *, + run_name: str | None = None, + preds_dir_name: str | None = None, + dataset_info: DatasetInfo | None = None, + metrics: dict[str, float] | None = None, + per_doc_scores: dict[str, object] | None = None, +) -> None: + """ + Log run metadata to MLflow. + + Args: + config (ExperimentRunConfig): Experiment run configuration. + run_name (str | None, optional): Run name. Defaults to None. + preds_dir_name (str | None, optional): Predictions directory name. Defaults to None. + dataset_info (DatasetInfo | None, optional): Dataset information. Defaults to None. + metrics (dict[str, float] | None, optional): Metrics to log. Defaults to None. + per_doc_scores (dict[str, object] | None, optional): Per-document scores to log. Defaults to None. + """ + params = { + "model_provider": config.model.provider, + "model_name": config.model.name, + "system_prompt_id": config.prompts.system.id, + "user_prompt_id": config.prompts.user.id, + "preds_dir_template": config.predictions.dir_name_template, + } + if run_name: + params["run_name"] = run_name + if preds_dir_name: + params["preds_dir_name"] = preds_dir_name + if config.model.temperature is not None: + params["temperature"] = config.model.temperature + if config.model.max_tokens is not None: + params["max_tokens"] = config.model.max_tokens + if config.data.dataset_id: + params["dataset_id"] = config.data.dataset_id + + if dataset_info: + params.update( + { + "dataset_hash": dataset_info.dataset_hash, + "dataset_count": dataset_info.dataset_count, + "dataset_bytes_total": dataset_info.dataset_bytes_total, + } + ) + + mlflow.log_params(params) + + if metrics: + mlflow.log_metrics(metrics) + + with tempfile.TemporaryDirectory() as tmp_dir: + tmp_path = Path(tmp_dir) + config_payload = config.model_dump(mode="json") + if not config.logging.privacy.log_prompt_text: + config_payload["prompts"]["system"]["text"] = "" + config_payload["prompts"]["user"]["text"] = "" + config_path = tmp_path / "config.yaml" + save_yaml(config_payload, str(config_path)) + mlflow.log_artifact(str(config_path), artifact_path="config") + + if config.logging.privacy.log_prompt_text: + system_path = tmp_path / "system_prompt.txt" + user_path = tmp_path / "user_prompt.txt" + system_path.write_text(config.prompts.system.text or "", encoding="utf-8") + user_path.write_text(config.prompts.user.text or "", encoding="utf-8") + mlflow.log_artifact(str(system_path), artifact_path="prompts") + mlflow.log_artifact(str(user_path), artifact_path="prompts") + + if ( + config.logging.privacy.log_data_manifest + and dataset_info + and dataset_info.manifest + ): + manifest_path = tmp_path / "manifest.json" + manifest_path.write_text( + json.dumps(dataset_info.manifest, indent=2, sort_keys=True), + encoding="utf-8", + ) + mlflow.log_artifact(str(manifest_path), artifact_path="data") + + if config.logging.privacy.log_per_doc_scores and per_doc_scores: + scores_path = tmp_path / "per_doc_scores.json" + scores_path.write_text( + json.dumps(per_doc_scores, indent=2, sort_keys=True), + encoding="utf-8", + ) + mlflow.log_artifact(str(scores_path), artifact_path="metrics") diff --git a/aymurai/experiments/entity_disambiguation/runner.py b/aymurai/experiments/entity_disambiguation/runner.py new file mode 100644 index 00000000..2cc372ce --- /dev/null +++ b/aymurai/experiments/entity_disambiguation/runner.py @@ -0,0 +1,468 @@ +import argparse +import json +import mimetypes +import os +import re +import time +from pathlib import Path +from typing import Any, Iterable + +import mlflow +import requests +from more_itertools import unique_everseen +from tqdm import tqdm + +from aymurai.evaluation.metrics import evaluate_disambiguation +from aymurai.experiments.entity_disambiguation.config import ( + load_experiment_config, + render_run_name, +) +from aymurai.experiments.entity_disambiguation.manifest import build_metadata_manifest +from aymurai.experiments.entity_disambiguation.mlflow_logging import ( + configure_mlflow, + log_run_metadata, +) +from aymurai.llm_providers import OllamaLLMProvider +from aymurai.logger import get_logger +from aymurai.meta.entities import CanonicalEntities, CanonicalEntity +from aymurai.utils.json_data import get_pretty, load_json, save_json +from aymurai.utils.paths import prediction_filename_for_test, test_id_from_filename + +logger = get_logger(__name__) + +DOC_EXTENSIONS = {".pdf", ".docx"} + + +def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]: + """ + Discover documents in a directory with given extensions. + + Args: + root (Path): Root directory to search for documents. + extensions (Iterable[str]): File extensions to include. + + Returns: + list[Path]: List of discovered document paths with the specified extensions. + """ + extensions = {ext.lower() for ext in extensions} + return sorted( + path + for path in root.rglob("*") + if path.is_file() and path.suffix.lower() in extensions + ) + + +def call_extraction_api( + session: requests.Session, endpoint: str, file_path: Path, timeout_s: float +) -> dict[str, object]: + """ + Call the extraction API with a document file. + + Args: + session (requests.Session): HTTP session for making requests. + endpoint (str): URL of the extraction API endpoint. + file_path (Path): Path to the document file to be processed. + timeout_s (float): Request timeout in seconds. + + Returns: + dict[str, object]: Payload containing the response details. + """ + payload: dict[str, object] = { + "path": str(file_path), + "status": "failure", + "status_code": None, + "elapsed_s": None, + "detail": None, + } + + if not file_path.exists(): + payload["detail"] = "File does not exist" + return payload + + mime_type = mimetypes.guess_type(file_path.name)[0] or "application/octet-stream" + files = { + "file": (file_path.name, file_path.open("rb"), mime_type), + } + + try: + start = time.perf_counter() + response = session.post( + endpoint, + files=files, + timeout=timeout_s, + ) + elapsed = time.perf_counter() - start + except requests.RequestException as exc: + payload["detail"] = f"Request failed: {exc}" + return payload + finally: + files["file"][1].close() + + payload["status_code"] = response.status_code + payload["elapsed_s"] = elapsed + + try: + response_body = response.json() + except ValueError: + response_body = {"raw": response.text[:500]} + + if response.ok: + payload["status"] = "success" + payload["detail"] = { + "document_id": response_body.get("document_id"), + "document": response_body.get("document", []), + } + else: + payload["detail"] = response_body + + return payload + + +def get_predictions( + session: requests.Session, endpoint: str, sample: str, timeout_s: float +) -> dict: + """ + Get predictions from the prediction API for a given text sample. + + Args: + session (requests.Session): HTTP session for making requests. + endpoint (str): URL of the prediction API endpoint. + sample (str): Text sample to be predicted. + timeout_s (float): Request timeout in seconds. + + Returns: + dict: Prediction response as a dictionary. + """ + response = session.post(url=endpoint, json={"text": sample}, timeout=timeout_s) + response.raise_for_status() + return response.json() + + +def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]: + """ + Parse prediction labels to extract unique aymurai labels and their alternative texts. + + Args: + predictions (list[dict[str, Any]]): List of prediction dictionaries. + + Returns: + list[dict[str, str]]: List of dictionaries containing unique aymurai labels and their alternative texts. + """ + attrs_stream = ( + label.get("attrs") or {} + for label in (label for pred in predictions for label in pred.get("labels", ())) + ) + + unique_pairs = unique_everseen( + ( + attrs.get("aymurai_label"), + attrs.get("aymurai_alt_text"), + ) + for attrs in attrs_stream + if attrs.get("aymurai_label") and attrs.get("aymurai_alt_text") + ) + + return sorted( + ({"aymurai_label": label, "text": text} for label, text in unique_pairs), + key=lambda item: (item["aymurai_label"], item["text"]), + ) + + +def sanitize_filename(path: Path) -> str: + """ + Sanitize a filename by replacing spaces and underscores with hyphens and collapsing multiple hyphens. + + Args: + path (Path): Path object representing the file. + + Returns: + str: Sanitized filename as a string. + """ + base = os.path.splitext(path.name)[0] + target = re.sub(r"\s+|_", "-", base) + target = re.sub(r"-{2,}", "-", target) + return target + + +def extract_canonical_entities( + *, + session: requests.Session, + doc_path: Path, + extract_endpoint: str, + predict_endpoint: str, + timeout_s: float, + model_name: str, + system_prompt: str, + user_prompt_template: str, + temperature: float | None, + max_tokens: int | None, +) -> list[CanonicalEntity]: + """ + Extract canonical entities from a document using extraction and prediction APIs. + + Args: + session (requests.Session): HTTP session for making requests. + doc_path (Path): Path to the document file. + extract_endpoint (str): URL of the extraction API endpoint. + predict_endpoint (str): URL of the prediction API endpoint. + timeout_s (float): Request timeout in seconds. + model_name (str): Name of the LLM model to use. + system_prompt (str): System prompt text. + user_prompt_template (str): User prompt template text. + temperature (float | None): Temperature setting for the LLM. + max_tokens (int | None): Maximum tokens setting for the LLM. + + Raises: + ValueError: If the document text is empty or not found. + + Returns: + list[CanonicalEntity]: List of extracted canonical entities. + """ + document_payload = call_extraction_api( + session, + extract_endpoint, + doc_path, + timeout_s, + ) + document = document_payload.get("detail", {}).get("document") + + if not document: + raise ValueError("Document text is empty or not found.") + + ner_predictions = [ + get_predictions(session, predict_endpoint, paragraph, timeout_s) + for paragraph in tqdm(document, desc=f"NER {doc_path.name}") + ] + parsed_ner_labels = parse_prediction_labels(ner_predictions) + ner_output_json = get_pretty(parsed_ner_labels) + + user_prompt = user_prompt_template.format( + document_text="\n".join(document).strip(), + ner_output_json=ner_output_json, + ) + + provider = OllamaLLMProvider(model=model_name) + options: dict[str, object] = {} + if temperature is not None: + options["temperature"] = temperature + if max_tokens is not None: + options["num_predict"] = max_tokens + + generate_kwargs: dict[str, object] = { + "messages": [ + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt}, + ], + "format": CanonicalEntities.model_json_schema(), + } + if options: + generate_kwargs["options"] = options + + response = provider.generate(**generate_kwargs) + + payload = json.loads(response.text) + canonical_entities = [ + CanonicalEntity.model_validate(output) + for output in payload.get("canonical_entities", []) + ] + + return canonical_entities + + +def run_experiment(config_path: str) -> None: + """ + Run the entity disambiguation experiment based on the provided configuration. + + Args: + config_path (str): Path to the experiment configuration file. + + Raises: + FileNotFoundError: If the input directory is not found. + FileNotFoundError: If the ground truth directory is not found. + RuntimeError: If no documents are found in the input directory. + ValueError: If there is an error in processing the documents. + """ + config = load_experiment_config(config_path) + + input_dir = Path(config.data.input_dir) + ground_truth_dir = Path(config.data.ground_truth_dir) + + if not input_dir.exists(): + raise FileNotFoundError(f"Input directory not found: {input_dir}") + if not ground_truth_dir.exists(): + raise FileNotFoundError(f"Ground truth directory not found: {ground_truth_dir}") + + documents = discover_documents(input_dir, DOC_EXTENSIONS) + if not documents: + raise RuntimeError(f"No documents found under {input_dir}") + + timestamp = time.strftime("%y%m%d_%H%M") + run_name = render_run_name( + config.experiment.run_name, + config.model.name, + config.prompts.system.id, + config.prompts.user.id, + timestamp=timestamp, + ) + preds_dir_name = render_run_name( + config.predictions.dir_name_template, + config.model.name, + config.prompts.system.id, + config.prompts.user.id, + timestamp=timestamp, + ) + output_dir = Path(config.predictions.output_base_dir) / preds_dir_name + output_dir.mkdir(parents=True, exist_ok=False) + + dataset_info = ( + build_metadata_manifest(ground_truth_dir) + if config.data.manifest.enabled + else None + ) + + api_base_url = os.getenv("API_BASE_URL", "http://localhost:8899") + extract_endpoint = f"{api_base_url}/misc/document-extract" + predict_endpoint = f"{api_base_url}/anonymizer/predict" + timeout_s = float(os.getenv("REQUEST_TIMEOUT", "30")) + + logger.info(f"Processing {len(documents)} documents from {input_dir}") + logger.info(f"Predictions will be stored in {output_dir}") + + configure_mlflow(config) + + per_doc_scores: dict[str, object] = {} + metrics_summary: dict[str, float] = {} + + with mlflow.start_run(run_name=run_name): + session = requests.Session() + + processed = 0 + failed = 0 + + for doc_path in documents: + logger.info(f"Processing document: {doc_path.name}") + try: + canonical_entities = extract_canonical_entities( + session=session, + doc_path=doc_path, + extract_endpoint=extract_endpoint, + predict_endpoint=predict_endpoint, + timeout_s=timeout_s, + model_name=config.model.name, + system_prompt=config.prompts.system.text or "", + user_prompt_template=config.prompts.user.text or "", + temperature=config.model.temperature, + max_tokens=config.model.max_tokens, + ) + target_filename = sanitize_filename(doc_path) + target_path = output_dir / f"{target_filename}.json" + save_json( + [ + entity.model_dump() + | { + "entity_id": entity.entity_id.hex + if entity.entity_id + else None + } + for entity in canonical_entities + ], + str(target_path), + ) + processed += 1 + except Exception as exc: + failed += 1 + logger.warning(f"Error processing {doc_path.name}: {exc}") + + if config.evaluation.function != "evaluate_disambiguation": + raise ValueError( + f"Unsupported evaluation function: {config.evaluation.function}" + ) + + results = [] + if output_dir.exists(): + for test_path in sorted(ground_truth_dir.glob("*.json")): + doc_id = test_id_from_filename(test_path) + pred_path = output_dir / prediction_filename_for_test(test_path) + + if not pred_path.exists(): + logger.warning( + f"Prediction for {test_path.name} was not found; skipping." + ) + continue + + gold_data = load_json(str(test_path)) + pred_data = load_json(str(pred_path)) + + score, metrics = evaluate_disambiguation( + gold_data, + pred_data, + w_ent=config.evaluation.weights.get("w_ent", 0.4), + w_alias=config.evaluation.weights.get("w_alias", 0.35), + w_label=config.evaluation.weights.get("w_label", 0.2), + w_role=config.evaluation.weights.get("w_role", 0.05), + sim_threshold=config.evaluation.sim_threshold or 0.3, + normalize=config.evaluation.normalize, + ) + results.append((doc_id, score, metrics)) + + average = ( + sum(score for _, score, _ in results) / len(results) + if results + else float("nan") + ) + + if results: + metrics_summary["score_avg"] = average + metrics_summary["doc_count"] = float(len(results)) + + metric_names = set(results[0][2].keys()) + for metric_name in metric_names: + metrics_summary[f"{metric_name}_avg"] = sum( + metrics.get(metric_name, 0.0) for _, _, metrics in results + ) / len(results) + + for doc_id, score, metrics in results: + per_doc_scores[doc_id] = {"score": score, **metrics} + + metrics_summary["docs_processed"] = float(processed) + metrics_summary["docs_failed"] = float(failed) + + log_run_metadata( + config, + run_name=run_name, + preds_dir_name=preds_dir_name, + dataset_info=dataset_info, + metrics=metrics_summary if metrics_summary else None, + per_doc_scores=per_doc_scores if per_doc_scores else None, + ) + + +def build_arg_parser() -> argparse.ArgumentParser: + """ + Build the argument parser for the entity disambiguation experiment. + + Returns: + argparse.ArgumentParser: The configured argument parser. + """ + parser = argparse.ArgumentParser( + description="Run entity disambiguation experiment from a YAML config.", + ) + parser.add_argument( + "--config", + required=True, + help="Path to the experiment YAML config.", + ) + return parser + + +def main() -> None: + """ + Main entry point for the entity disambiguation experiment script. + Parses command-line arguments and runs the experiment. + """ + args = build_arg_parser().parse_args() + run_experiment(args.config) + + +if __name__ == "__main__": + main() From 9afde5031d605ec7ae811b08dde8449a466b07f7 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Fri, 20 Feb 2026 11:32:34 -0300 Subject: [PATCH 065/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20aymurai/experi?= =?UTF-8?q?ments/entity=5Fdisambiguation=20for=20release/v1.5.0=20compatib?= =?UTF-8?q?ility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity_disambiguation/__init__.py | 1 - .../entity_disambiguation/config.py | 176 ------- .../entity_disambiguation/manifest.py | 51 -- .../entity_disambiguation/mlflow_logging.py | 111 ----- .../entity_disambiguation/runner.py | 468 ------------------ 5 files changed, 807 deletions(-) delete mode 100644 aymurai/experiments/entity_disambiguation/__init__.py delete mode 100644 aymurai/experiments/entity_disambiguation/config.py delete mode 100644 aymurai/experiments/entity_disambiguation/manifest.py delete mode 100644 aymurai/experiments/entity_disambiguation/mlflow_logging.py delete mode 100644 aymurai/experiments/entity_disambiguation/runner.py diff --git a/aymurai/experiments/entity_disambiguation/__init__.py b/aymurai/experiments/entity_disambiguation/__init__.py deleted file mode 100644 index 17dc9d09..00000000 --- a/aymurai/experiments/entity_disambiguation/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Entity disambiguation experiment helpers.""" diff --git a/aymurai/experiments/entity_disambiguation/config.py b/aymurai/experiments/entity_disambiguation/config.py deleted file mode 100644 index 68f54534..00000000 --- a/aymurai/experiments/entity_disambiguation/config.py +++ /dev/null @@ -1,176 +0,0 @@ -import os -from datetime import datetime, timezone -from typing import Literal - -from pydantic import BaseModel, ConfigDict, Field - -from aymurai.utils.yaml_data import load_yaml - - -class ExperimentConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - name: str - run_name: str - - -class ModelConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - provider: str - name: str - temperature: float | None = None - max_tokens: int | None = None - - -class PromptSpec(BaseModel): - model_config = ConfigDict(extra="forbid") - - id: str - text: str | None = None - - -class PromptsConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - system: PromptSpec - user: PromptSpec - - -class DataManifestConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - enabled: bool = True - mode: Literal["metadata_only"] = "metadata_only" - - -class DataConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - ground_truth_dir: str - input_dir: str - dataset_id: str | None = None - manifest: DataManifestConfig = DataManifestConfig() - - -class PredictionsConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - output_base_dir: str - dir_name_template: str - - -class MLflowConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - tracking_uri: str - experiment_name: str - - -class LoggingPrivacyConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - log_prompt_text: bool = True - log_data_manifest: bool = False - log_per_doc_scores: bool = True - - -class PerDocScoresConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - id_strategy: str = "anon_filename" - - -class LoggingConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - mlflow: MLflowConfig - privacy: LoggingPrivacyConfig = LoggingPrivacyConfig() - per_doc_scores: PerDocScoresConfig = PerDocScoresConfig() - - -class EvaluationConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - function: str = "evaluate_disambiguation" - weights: dict[str, float] = Field( - default_factory=lambda: { - "w_ent": 0.4, - "w_alias": 0.35, - "w_label": 0.2, - "w_role": 0.05, - } - ) - per_doc_scores: bool = True - sim_threshold: float | None = None - normalize: bool = True - - -class ExperimentRunConfig(BaseModel): - model_config = ConfigDict(extra="forbid") - - experiment: ExperimentConfig - model: ModelConfig - prompts: PromptsConfig - data: DataConfig - predictions: PredictionsConfig - logging: LoggingConfig - evaluation: EvaluationConfig - - -def load_experiment_config(path: str) -> ExperimentRunConfig: - """ - Load an experiment configuration from a YAML file. - - Args: - path (str): Path to the YAML configuration file. - - Raises: - ValueError: If the MLflow tracking URI is not set in the environment or configuration. - - Returns: - ExperimentRunConfig: The loaded experiment configuration. - """ - data = load_yaml(path) - tracking_uri = os.getenv("MLFLOW_TRACKING_URI") - if tracking_uri: - logging_cfg = data.setdefault("logging", {}) - mlflow_cfg = logging_cfg.setdefault("mlflow", {}) - mlflow_cfg["tracking_uri"] = tracking_uri - else: - mlflow_cfg = data.get("logging", {}).get("mlflow", {}) - if "tracking_uri" not in mlflow_cfg: - raise ValueError( - "MLFLOW_TRACKING_URI is required but was not set in the environment." - ) - return ExperimentRunConfig.model_validate(data) - - -def render_run_name( - template: str, - model_name: str, - system_id: str, - user_id: str, - *, - timestamp: str | None = None, -) -> str: - """ - Render a run name based on a template and provided identifiers. - - Args: - template (str): The template string for the run name. - model_name (str): The name of the model. - system_id (str): The system identifier. - user_id (str): The user identifier. - timestamp (str | None, optional): The timestamp string. Defaults to None. - - Returns: - str: The rendered run name. - """ - timestamp = timestamp or datetime.now(timezone.utc).strftime("%y%m%d_%H%M") - return template.format( - model=model_name, - system_id=system_id, - user_id=user_id, - timestamp=timestamp, - ) diff --git a/aymurai/experiments/entity_disambiguation/manifest.py b/aymurai/experiments/entity_disambiguation/manifest.py deleted file mode 100644 index 2e2c37fa..00000000 --- a/aymurai/experiments/entity_disambiguation/manifest.py +++ /dev/null @@ -1,51 +0,0 @@ -import hashlib -import json -from dataclasses import dataclass -from pathlib import Path - - -@dataclass(frozen=True) -class DatasetInfo: - dataset_hash: str - dataset_count: int - dataset_bytes_total: int - manifest: dict | None = None - - -def build_metadata_manifest(root_dir: Path) -> DatasetInfo: - """ - Build a metadata manifest for the dataset located at the given root directory. - - Args: - root_dir (Path): The root directory of the dataset. - - Returns: - DatasetInfo: An object containing dataset hash, count, total bytes, and manifest. - """ - files = [] - total_bytes = 0 - - for path in sorted(root_dir.rglob("*")): - if not path.is_file(): - continue - stat = path.stat() - rel_path = path.relative_to(root_dir).as_posix() - files.append( - { - "path": rel_path, - "size_bytes": stat.st_size, - "mtime": int(stat.st_mtime), - } - ) - total_bytes += stat.st_size - - manifest = {"files": files, "summary": {"count": len(files), "bytes": total_bytes}} - manifest_bytes = json.dumps(files, sort_keys=True).encode("utf-8") - dataset_hash = hashlib.sha256(manifest_bytes).hexdigest() - - return DatasetInfo( - dataset_hash=dataset_hash, - dataset_count=len(files), - dataset_bytes_total=total_bytes, - manifest=manifest, - ) diff --git a/aymurai/experiments/entity_disambiguation/mlflow_logging.py b/aymurai/experiments/entity_disambiguation/mlflow_logging.py deleted file mode 100644 index b9e0a799..00000000 --- a/aymurai/experiments/entity_disambiguation/mlflow_logging.py +++ /dev/null @@ -1,111 +0,0 @@ -import json -import tempfile -from pathlib import Path - -import mlflow - -from aymurai.experiments.entity_disambiguation.config import ExperimentRunConfig -from aymurai.experiments.entity_disambiguation.manifest import DatasetInfo -from aymurai.utils.yaml_data import save_yaml - - -def configure_mlflow(config: ExperimentRunConfig) -> None: - """ - Configure MLflow tracking URI and experiment name. - - Args: - config (ExperimentRunConfig): Experiment run configuration. - """ - mlflow.set_tracking_uri(config.logging.mlflow.tracking_uri) - mlflow.set_experiment(config.logging.mlflow.experiment_name) - - -def log_run_metadata( - config: ExperimentRunConfig, - *, - run_name: str | None = None, - preds_dir_name: str | None = None, - dataset_info: DatasetInfo | None = None, - metrics: dict[str, float] | None = None, - per_doc_scores: dict[str, object] | None = None, -) -> None: - """ - Log run metadata to MLflow. - - Args: - config (ExperimentRunConfig): Experiment run configuration. - run_name (str | None, optional): Run name. Defaults to None. - preds_dir_name (str | None, optional): Predictions directory name. Defaults to None. - dataset_info (DatasetInfo | None, optional): Dataset information. Defaults to None. - metrics (dict[str, float] | None, optional): Metrics to log. Defaults to None. - per_doc_scores (dict[str, object] | None, optional): Per-document scores to log. Defaults to None. - """ - params = { - "model_provider": config.model.provider, - "model_name": config.model.name, - "system_prompt_id": config.prompts.system.id, - "user_prompt_id": config.prompts.user.id, - "preds_dir_template": config.predictions.dir_name_template, - } - if run_name: - params["run_name"] = run_name - if preds_dir_name: - params["preds_dir_name"] = preds_dir_name - if config.model.temperature is not None: - params["temperature"] = config.model.temperature - if config.model.max_tokens is not None: - params["max_tokens"] = config.model.max_tokens - if config.data.dataset_id: - params["dataset_id"] = config.data.dataset_id - - if dataset_info: - params.update( - { - "dataset_hash": dataset_info.dataset_hash, - "dataset_count": dataset_info.dataset_count, - "dataset_bytes_total": dataset_info.dataset_bytes_total, - } - ) - - mlflow.log_params(params) - - if metrics: - mlflow.log_metrics(metrics) - - with tempfile.TemporaryDirectory() as tmp_dir: - tmp_path = Path(tmp_dir) - config_payload = config.model_dump(mode="json") - if not config.logging.privacy.log_prompt_text: - config_payload["prompts"]["system"]["text"] = "" - config_payload["prompts"]["user"]["text"] = "" - config_path = tmp_path / "config.yaml" - save_yaml(config_payload, str(config_path)) - mlflow.log_artifact(str(config_path), artifact_path="config") - - if config.logging.privacy.log_prompt_text: - system_path = tmp_path / "system_prompt.txt" - user_path = tmp_path / "user_prompt.txt" - system_path.write_text(config.prompts.system.text or "", encoding="utf-8") - user_path.write_text(config.prompts.user.text or "", encoding="utf-8") - mlflow.log_artifact(str(system_path), artifact_path="prompts") - mlflow.log_artifact(str(user_path), artifact_path="prompts") - - if ( - config.logging.privacy.log_data_manifest - and dataset_info - and dataset_info.manifest - ): - manifest_path = tmp_path / "manifest.json" - manifest_path.write_text( - json.dumps(dataset_info.manifest, indent=2, sort_keys=True), - encoding="utf-8", - ) - mlflow.log_artifact(str(manifest_path), artifact_path="data") - - if config.logging.privacy.log_per_doc_scores and per_doc_scores: - scores_path = tmp_path / "per_doc_scores.json" - scores_path.write_text( - json.dumps(per_doc_scores, indent=2, sort_keys=True), - encoding="utf-8", - ) - mlflow.log_artifact(str(scores_path), artifact_path="metrics") diff --git a/aymurai/experiments/entity_disambiguation/runner.py b/aymurai/experiments/entity_disambiguation/runner.py deleted file mode 100644 index 2cc372ce..00000000 --- a/aymurai/experiments/entity_disambiguation/runner.py +++ /dev/null @@ -1,468 +0,0 @@ -import argparse -import json -import mimetypes -import os -import re -import time -from pathlib import Path -from typing import Any, Iterable - -import mlflow -import requests -from more_itertools import unique_everseen -from tqdm import tqdm - -from aymurai.evaluation.metrics import evaluate_disambiguation -from aymurai.experiments.entity_disambiguation.config import ( - load_experiment_config, - render_run_name, -) -from aymurai.experiments.entity_disambiguation.manifest import build_metadata_manifest -from aymurai.experiments.entity_disambiguation.mlflow_logging import ( - configure_mlflow, - log_run_metadata, -) -from aymurai.llm_providers import OllamaLLMProvider -from aymurai.logger import get_logger -from aymurai.meta.entities import CanonicalEntities, CanonicalEntity -from aymurai.utils.json_data import get_pretty, load_json, save_json -from aymurai.utils.paths import prediction_filename_for_test, test_id_from_filename - -logger = get_logger(__name__) - -DOC_EXTENSIONS = {".pdf", ".docx"} - - -def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]: - """ - Discover documents in a directory with given extensions. - - Args: - root (Path): Root directory to search for documents. - extensions (Iterable[str]): File extensions to include. - - Returns: - list[Path]: List of discovered document paths with the specified extensions. - """ - extensions = {ext.lower() for ext in extensions} - return sorted( - path - for path in root.rglob("*") - if path.is_file() and path.suffix.lower() in extensions - ) - - -def call_extraction_api( - session: requests.Session, endpoint: str, file_path: Path, timeout_s: float -) -> dict[str, object]: - """ - Call the extraction API with a document file. - - Args: - session (requests.Session): HTTP session for making requests. - endpoint (str): URL of the extraction API endpoint. - file_path (Path): Path to the document file to be processed. - timeout_s (float): Request timeout in seconds. - - Returns: - dict[str, object]: Payload containing the response details. - """ - payload: dict[str, object] = { - "path": str(file_path), - "status": "failure", - "status_code": None, - "elapsed_s": None, - "detail": None, - } - - if not file_path.exists(): - payload["detail"] = "File does not exist" - return payload - - mime_type = mimetypes.guess_type(file_path.name)[0] or "application/octet-stream" - files = { - "file": (file_path.name, file_path.open("rb"), mime_type), - } - - try: - start = time.perf_counter() - response = session.post( - endpoint, - files=files, - timeout=timeout_s, - ) - elapsed = time.perf_counter() - start - except requests.RequestException as exc: - payload["detail"] = f"Request failed: {exc}" - return payload - finally: - files["file"][1].close() - - payload["status_code"] = response.status_code - payload["elapsed_s"] = elapsed - - try: - response_body = response.json() - except ValueError: - response_body = {"raw": response.text[:500]} - - if response.ok: - payload["status"] = "success" - payload["detail"] = { - "document_id": response_body.get("document_id"), - "document": response_body.get("document", []), - } - else: - payload["detail"] = response_body - - return payload - - -def get_predictions( - session: requests.Session, endpoint: str, sample: str, timeout_s: float -) -> dict: - """ - Get predictions from the prediction API for a given text sample. - - Args: - session (requests.Session): HTTP session for making requests. - endpoint (str): URL of the prediction API endpoint. - sample (str): Text sample to be predicted. - timeout_s (float): Request timeout in seconds. - - Returns: - dict: Prediction response as a dictionary. - """ - response = session.post(url=endpoint, json={"text": sample}, timeout=timeout_s) - response.raise_for_status() - return response.json() - - -def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]: - """ - Parse prediction labels to extract unique aymurai labels and their alternative texts. - - Args: - predictions (list[dict[str, Any]]): List of prediction dictionaries. - - Returns: - list[dict[str, str]]: List of dictionaries containing unique aymurai labels and their alternative texts. - """ - attrs_stream = ( - label.get("attrs") or {} - for label in (label for pred in predictions for label in pred.get("labels", ())) - ) - - unique_pairs = unique_everseen( - ( - attrs.get("aymurai_label"), - attrs.get("aymurai_alt_text"), - ) - for attrs in attrs_stream - if attrs.get("aymurai_label") and attrs.get("aymurai_alt_text") - ) - - return sorted( - ({"aymurai_label": label, "text": text} for label, text in unique_pairs), - key=lambda item: (item["aymurai_label"], item["text"]), - ) - - -def sanitize_filename(path: Path) -> str: - """ - Sanitize a filename by replacing spaces and underscores with hyphens and collapsing multiple hyphens. - - Args: - path (Path): Path object representing the file. - - Returns: - str: Sanitized filename as a string. - """ - base = os.path.splitext(path.name)[0] - target = re.sub(r"\s+|_", "-", base) - target = re.sub(r"-{2,}", "-", target) - return target - - -def extract_canonical_entities( - *, - session: requests.Session, - doc_path: Path, - extract_endpoint: str, - predict_endpoint: str, - timeout_s: float, - model_name: str, - system_prompt: str, - user_prompt_template: str, - temperature: float | None, - max_tokens: int | None, -) -> list[CanonicalEntity]: - """ - Extract canonical entities from a document using extraction and prediction APIs. - - Args: - session (requests.Session): HTTP session for making requests. - doc_path (Path): Path to the document file. - extract_endpoint (str): URL of the extraction API endpoint. - predict_endpoint (str): URL of the prediction API endpoint. - timeout_s (float): Request timeout in seconds. - model_name (str): Name of the LLM model to use. - system_prompt (str): System prompt text. - user_prompt_template (str): User prompt template text. - temperature (float | None): Temperature setting for the LLM. - max_tokens (int | None): Maximum tokens setting for the LLM. - - Raises: - ValueError: If the document text is empty or not found. - - Returns: - list[CanonicalEntity]: List of extracted canonical entities. - """ - document_payload = call_extraction_api( - session, - extract_endpoint, - doc_path, - timeout_s, - ) - document = document_payload.get("detail", {}).get("document") - - if not document: - raise ValueError("Document text is empty or not found.") - - ner_predictions = [ - get_predictions(session, predict_endpoint, paragraph, timeout_s) - for paragraph in tqdm(document, desc=f"NER {doc_path.name}") - ] - parsed_ner_labels = parse_prediction_labels(ner_predictions) - ner_output_json = get_pretty(parsed_ner_labels) - - user_prompt = user_prompt_template.format( - document_text="\n".join(document).strip(), - ner_output_json=ner_output_json, - ) - - provider = OllamaLLMProvider(model=model_name) - options: dict[str, object] = {} - if temperature is not None: - options["temperature"] = temperature - if max_tokens is not None: - options["num_predict"] = max_tokens - - generate_kwargs: dict[str, object] = { - "messages": [ - {"role": "system", "content": system_prompt}, - {"role": "user", "content": user_prompt}, - ], - "format": CanonicalEntities.model_json_schema(), - } - if options: - generate_kwargs["options"] = options - - response = provider.generate(**generate_kwargs) - - payload = json.loads(response.text) - canonical_entities = [ - CanonicalEntity.model_validate(output) - for output in payload.get("canonical_entities", []) - ] - - return canonical_entities - - -def run_experiment(config_path: str) -> None: - """ - Run the entity disambiguation experiment based on the provided configuration. - - Args: - config_path (str): Path to the experiment configuration file. - - Raises: - FileNotFoundError: If the input directory is not found. - FileNotFoundError: If the ground truth directory is not found. - RuntimeError: If no documents are found in the input directory. - ValueError: If there is an error in processing the documents. - """ - config = load_experiment_config(config_path) - - input_dir = Path(config.data.input_dir) - ground_truth_dir = Path(config.data.ground_truth_dir) - - if not input_dir.exists(): - raise FileNotFoundError(f"Input directory not found: {input_dir}") - if not ground_truth_dir.exists(): - raise FileNotFoundError(f"Ground truth directory not found: {ground_truth_dir}") - - documents = discover_documents(input_dir, DOC_EXTENSIONS) - if not documents: - raise RuntimeError(f"No documents found under {input_dir}") - - timestamp = time.strftime("%y%m%d_%H%M") - run_name = render_run_name( - config.experiment.run_name, - config.model.name, - config.prompts.system.id, - config.prompts.user.id, - timestamp=timestamp, - ) - preds_dir_name = render_run_name( - config.predictions.dir_name_template, - config.model.name, - config.prompts.system.id, - config.prompts.user.id, - timestamp=timestamp, - ) - output_dir = Path(config.predictions.output_base_dir) / preds_dir_name - output_dir.mkdir(parents=True, exist_ok=False) - - dataset_info = ( - build_metadata_manifest(ground_truth_dir) - if config.data.manifest.enabled - else None - ) - - api_base_url = os.getenv("API_BASE_URL", "http://localhost:8899") - extract_endpoint = f"{api_base_url}/misc/document-extract" - predict_endpoint = f"{api_base_url}/anonymizer/predict" - timeout_s = float(os.getenv("REQUEST_TIMEOUT", "30")) - - logger.info(f"Processing {len(documents)} documents from {input_dir}") - logger.info(f"Predictions will be stored in {output_dir}") - - configure_mlflow(config) - - per_doc_scores: dict[str, object] = {} - metrics_summary: dict[str, float] = {} - - with mlflow.start_run(run_name=run_name): - session = requests.Session() - - processed = 0 - failed = 0 - - for doc_path in documents: - logger.info(f"Processing document: {doc_path.name}") - try: - canonical_entities = extract_canonical_entities( - session=session, - doc_path=doc_path, - extract_endpoint=extract_endpoint, - predict_endpoint=predict_endpoint, - timeout_s=timeout_s, - model_name=config.model.name, - system_prompt=config.prompts.system.text or "", - user_prompt_template=config.prompts.user.text or "", - temperature=config.model.temperature, - max_tokens=config.model.max_tokens, - ) - target_filename = sanitize_filename(doc_path) - target_path = output_dir / f"{target_filename}.json" - save_json( - [ - entity.model_dump() - | { - "entity_id": entity.entity_id.hex - if entity.entity_id - else None - } - for entity in canonical_entities - ], - str(target_path), - ) - processed += 1 - except Exception as exc: - failed += 1 - logger.warning(f"Error processing {doc_path.name}: {exc}") - - if config.evaluation.function != "evaluate_disambiguation": - raise ValueError( - f"Unsupported evaluation function: {config.evaluation.function}" - ) - - results = [] - if output_dir.exists(): - for test_path in sorted(ground_truth_dir.glob("*.json")): - doc_id = test_id_from_filename(test_path) - pred_path = output_dir / prediction_filename_for_test(test_path) - - if not pred_path.exists(): - logger.warning( - f"Prediction for {test_path.name} was not found; skipping." - ) - continue - - gold_data = load_json(str(test_path)) - pred_data = load_json(str(pred_path)) - - score, metrics = evaluate_disambiguation( - gold_data, - pred_data, - w_ent=config.evaluation.weights.get("w_ent", 0.4), - w_alias=config.evaluation.weights.get("w_alias", 0.35), - w_label=config.evaluation.weights.get("w_label", 0.2), - w_role=config.evaluation.weights.get("w_role", 0.05), - sim_threshold=config.evaluation.sim_threshold or 0.3, - normalize=config.evaluation.normalize, - ) - results.append((doc_id, score, metrics)) - - average = ( - sum(score for _, score, _ in results) / len(results) - if results - else float("nan") - ) - - if results: - metrics_summary["score_avg"] = average - metrics_summary["doc_count"] = float(len(results)) - - metric_names = set(results[0][2].keys()) - for metric_name in metric_names: - metrics_summary[f"{metric_name}_avg"] = sum( - metrics.get(metric_name, 0.0) for _, _, metrics in results - ) / len(results) - - for doc_id, score, metrics in results: - per_doc_scores[doc_id] = {"score": score, **metrics} - - metrics_summary["docs_processed"] = float(processed) - metrics_summary["docs_failed"] = float(failed) - - log_run_metadata( - config, - run_name=run_name, - preds_dir_name=preds_dir_name, - dataset_info=dataset_info, - metrics=metrics_summary if metrics_summary else None, - per_doc_scores=per_doc_scores if per_doc_scores else None, - ) - - -def build_arg_parser() -> argparse.ArgumentParser: - """ - Build the argument parser for the entity disambiguation experiment. - - Returns: - argparse.ArgumentParser: The configured argument parser. - """ - parser = argparse.ArgumentParser( - description="Run entity disambiguation experiment from a YAML config.", - ) - parser.add_argument( - "--config", - required=True, - help="Path to the experiment YAML config.", - ) - return parser - - -def main() -> None: - """ - Main entry point for the entity disambiguation experiment script. - Parses command-line arguments and runs the experiment. - """ - args = build_arg_parser().parse_args() - run_experiment(args.config) - - -if __name__ == "__main__": - main() From c9e14843b94ff3262a89ed74fabfb1edff39f80a Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Fri, 20 Feb 2026 11:36:20 -0300 Subject: [PATCH 066/104] =?UTF-8?q?=F0=9F=90=9B=20Bug=20fixed=20in=20exper?= =?UTF-8?q?iments/entity-disambiguation/10-anonymize-document-render-polic?= =?UTF-8?q?y.ipynb=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../10-anonymize-document-render-policy.ipynb | 135 +++++++++++++++++- 1 file changed, 130 insertions(+), 5 deletions(-) diff --git a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb index 1b3566f9..0a5b279e 100644 --- a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb +++ b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb @@ -22,10 +22,6 @@ "import requests\n", "from tqdm import tqdm\n", "\n", - "from aymurai.experiments.entity_disambiguation.runner import (\n", - " call_extraction_api as extract_document,\n", - ")\n", - "\n", "API_URL = \"http://localhost:8000\" # Url for debugger. change it to your own\n", "DATA_ROOT = Path(\n", " os.getenv(\n", @@ -78,6 +74,135 @@ "## /document-extract endpoint output\n" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import mimetypes\n", + "import time\n", + "from pathlib import Path\n", + "from typing import Any, Iterable\n", + "\n", + "from more_itertools import unique_everseen\n", + "\n", + "\n", + "def discover_documents(root: Path, extensions: Iterable[str]) -> list[Path]:\n", + " \"\"\"\n", + " Discover documents in a directory with given extensions.\n", + "\n", + " Args:\n", + " root (Path): Root directory to search for documents.\n", + " extensions (Iterable[str]): File extensions to include.\n", + "\n", + " Returns:\n", + " list[Path]: List of discovered document paths with the specified extensions.\n", + " \"\"\"\n", + " extensions = {ext.lower() for ext in extensions}\n", + " return sorted(\n", + " path\n", + " for path in root.rglob(\"*\")\n", + " if path.is_file() and path.suffix.lower() in extensions\n", + " )\n", + "\n", + "\n", + "def call_extraction_api(\n", + " session: requests.Session, endpoint: str, file_path: Path, timeout_s: float\n", + ") -> dict[str, object]:\n", + " \"\"\"\n", + " Call the extraction API with a document file.\n", + "\n", + " Args:\n", + " session (requests.Session): HTTP session for making requests.\n", + " endpoint (str): URL of the extraction API endpoint.\n", + " file_path (Path): Path to the document file to be processed.\n", + " timeout_s (float): Request timeout in seconds.\n", + "\n", + " Returns:\n", + " dict[str, object]: Payload containing the response details.\n", + " \"\"\"\n", + " payload: dict[str, object] = {\n", + " \"path\": str(file_path),\n", + " \"status\": \"failure\",\n", + " \"status_code\": None,\n", + " \"elapsed_s\": None,\n", + " \"detail\": None,\n", + " }\n", + "\n", + " if not file_path.exists():\n", + " payload[\"detail\"] = \"File does not exist\"\n", + " return payload\n", + "\n", + " mime_type = mimetypes.guess_type(file_path.name)[0] or \"application/octet-stream\"\n", + " files = {\n", + " \"file\": (file_path.name, file_path.open(\"rb\"), mime_type),\n", + " }\n", + "\n", + " try:\n", + " start = time.perf_counter()\n", + " response = session.post(\n", + " endpoint,\n", + " files=files,\n", + " timeout=timeout_s,\n", + " )\n", + " elapsed = time.perf_counter() - start\n", + " except requests.RequestException as exc:\n", + " payload[\"detail\"] = f\"Request failed: {exc}\"\n", + " return payload\n", + " finally:\n", + " files[\"file\"][1].close()\n", + "\n", + " payload[\"status_code\"] = response.status_code\n", + " payload[\"elapsed_s\"] = elapsed\n", + "\n", + " try:\n", + " response_body = response.json()\n", + " except ValueError:\n", + " response_body = {\"raw\": response.text[:500]}\n", + "\n", + " if response.ok:\n", + " payload[\"status\"] = \"success\"\n", + " payload[\"detail\"] = {\n", + " \"document_id\": response_body.get(\"document_id\"),\n", + " \"document\": response_body.get(\"document\", []),\n", + " }\n", + " else:\n", + " payload[\"detail\"] = response_body\n", + "\n", + " return payload\n", + "\n", + "\n", + "def parse_prediction_labels(predictions: list[dict[str, Any]]) -> list[dict[str, str]]:\n", + " \"\"\"\n", + " Parse prediction labels to extract unique aymurai labels and their alternative texts.\n", + "\n", + " Args:\n", + " predictions (list[dict[str, Any]]): List of prediction dictionaries.\n", + "\n", + " Returns:\n", + " list[dict[str, str]]: List of dictionaries containing unique aymurai labels and their alternative texts.\n", + " \"\"\"\n", + " attrs_stream = (\n", + " label.get(\"attrs\") or {}\n", + " for label in (label for pred in predictions for label in pred.get(\"labels\", ()))\n", + " )\n", + "\n", + " unique_pairs = unique_everseen(\n", + " (\n", + " attrs.get(\"aymurai_label\"),\n", + " attrs.get(\"aymurai_alt_text\"),\n", + " )\n", + " for attrs in attrs_stream\n", + " if attrs.get(\"aymurai_label\") and attrs.get(\"aymurai_alt_text\")\n", + " )\n", + "\n", + " return sorted(\n", + " ({\"aymurai_label\": label, \"text\": text} for label, text in unique_pairs),\n", + " key=lambda item: (item[\"aymurai_label\"], item[\"text\"]),\n", + " )" + ] + }, { "cell_type": "code", "execution_count": null, @@ -86,7 +211,7 @@ "source": [ "# /document-extract endpoint output\n", "session = requests.Session()\n", - "document = extract_document(\n", + "document = call_extraction_api(\n", " session,\n", " endpoint=f\"{API_URL}/misc/document-extract\",\n", " file_path=doc_path,\n", From d02e20fe3bc3728009d6969220fe8dd51cbe25ad Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:37:39 +0000 Subject: [PATCH 067/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20TESSDATA=5FPRE?= =?UTF-8?q?FIX=20from=20.env.common?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.common | 2 -- 1 file changed, 2 deletions(-) diff --git a/.env.common b/.env.common index 1eec416e..493770c9 100644 --- a/.env.common +++ b/.env.common @@ -4,7 +4,5 @@ AYMURAI_CACHE_BASEPATH=/resources/cache/aymurai HF_HOME=/resources/cache/huggingface TOKENIZERS_PARALLELISM=1 -TESSDATA_PREFIX=/usr/local/share/tessdata - AYMURAI_RESTRICTED_DOCUMENT_PDFS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO-pdf" AYMURAI_RESTRICTED_DOCUMENT_DOCS_PATH="/resources/data/restricted/ar-juz-pcyf-10/RESOLUCIONES DEL JUZGADO" From eef81c606dddece830fb1f966dad8d26f91ddb3f Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:43:27 +0000 Subject: [PATCH 068/104] =?UTF-8?q?=F0=9F=99=88=20Update=20.gitignore=20to?= =?UTF-8?q?=20include=20notebooks=20directory=20while=20excluding=20subdir?= =?UTF-8?q?ectories=20and=20non-IPYNB=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 5f22f5f3..effd04a3 100755 --- a/.gitignore +++ b/.gitignore @@ -128,3 +128,7 @@ resources .venv aymurai/version.py + +notebooks/** +!notebooks/**/ +!notebooks/**/*.ipynb From 7f8ebfa57a936eca7126e8082caa8079485f9b38 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:43:43 +0000 Subject: [PATCH 069/104] =?UTF-8?q?=F0=9F=94=80=20Synthesize=20docker-comp?= =?UTF-8?q?ose=20from=2026033a8f/00709164=20after=20b05b768=20rollback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 83 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 20 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 3ce7c536..0f7775ee 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,29 +1,72 @@ +x-api-lite: &api-lite + image: ghcr.io/aymurai/api:latest + build: + context: . + dockerfile: ./docker/api/Dockerfile + target: aymurai-api + shm_size: "2gb" + ports: + - "8899:8899" + volumes: + - ./resources/cache:/resources/cache + env_file: + - .env + - .env.common + +x-api-full: &api-full + image: ghcr.io/aymurai/api:full + build: + context: . + dockerfile: ./docker/api/Dockerfile + target: aymurai-api-full + shm_size: "2gb" + ports: + - "8899:8899" + restart: always + deploy: + resources: + limits: + memory: 4g + cpus: "4.0" + services: aymurai-api: - image: ghcr.io/aymurai/api:latest - ports: - - "8899:8899" - build: - context: . - dockerfile: ./docker/api/Dockerfile - target: aymurai-api - env_file: - - .env - - .env.common - volumes: - - ./resources/cache:/resources/cache + <<: *api-lite + container_name: aymurai-api + environment: + TORCH_DEVICE: cpu + + aymurai-api-gpu: + <<: *api-lite + container_name: aymurai-api-gpu + environment: + TORCH_DEVICE: cuda + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] aymurai-api-full: - image: ghcr.io/aymurai/api:full - ports: - - "8899:8899" - build: - context: . - dockerfile: ./docker/api/Dockerfile - target: aymurai-api-full - restart: always + <<: *api-full + container_name: aymurai-api-full + environment: + TORCH_DEVICE: cpu + + aymurai-api-full-gpu: + <<: *api-full + container_name: aymurai-api-full-gpu + environment: + TORCH_DEVICE: cuda deploy: resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] limits: memory: 4g cpus: "4.0" From b0233e59387b2c285e6e1c9057169e66390f1f7c Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:43:52 +0000 Subject: [PATCH 070/104] =?UTF-8?q?=F0=9F=94=80=20Synthesize=20Makefile=20?= =?UTF-8?q?from=20afbfda9/d80f74b/26033a8f=20after=20f645881=20rollback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 0f132348..816c1c5b 100644 --- a/Makefile +++ b/Makefile @@ -3,21 +3,37 @@ export $(shell sed 's/=.*//' .env) include .env.common export $(shell sed 's/=.*//' .env.common) +# Select which API service to control (override with API_SERVICE=aymurai-api-gpu) +API_SERVICE ?= aymurai-api +# Select which full API service to control (override with API_FULL_SERVICE=aymurai-api-full-gpu) +API_FULL_SERVICE ?= aymurai-api-full api-build: - docker compose build aymurai-api-dev + docker compose build $(API_SERVICE) api-run: - docker compose run --service-ports aymurai-api-dev + docker compose run --service-ports $(API_SERVICE) +api-up: + docker compose up -d $(API_SERVICE) +api-stop: + docker compose stop $(API_SERVICE) +api-logs: + docker compose logs -f $(API_SERVICE) api-pull: - docker compose pull aymurai-api + docker compose pull $(API_SERVICE) api-full-build: - docker compose build aymurai-api-full + docker compose build $(API_FULL_SERVICE) api-full-run: - docker compose run aymurai-api-full + docker compose run --service-ports $(API_FULL_SERVICE) +api-full-up: + docker compose up -d $(API_FULL_SERVICE) +api-full-stop: + docker compose stop $(API_FULL_SERVICE) +api-full-logs: + docker compose logs -f $(API_FULL_SERVICE) api-full-pull: - docker compose pull aymurai-api-full + docker compose pull $(API_FULL_SERVICE) stress-test: locust -f locustfile.py --host http://localhost:8899 @@ -27,4 +43,4 @@ alembic-regenerate: rm -rvf aymurai/database/versions/* && \ cd aymurai && \ uv run alembic revision --autogenerate -m "Create database" && \ - uv run alembic upgrade head \ No newline at end of file + uv run alembic upgrade head From ca04d8bdc5113bf0b434a4a4684e1db5078999d0 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:44:59 +0000 Subject: [PATCH 071/104] =?UTF-8?q?=F0=9F=94=A7=20Fix=20repository=20URL?= =?UTF-8?q?=20case=20sensitivity=20in=20pyproject.toml=20and=20remove=20un?= =?UTF-8?q?used=20dependencies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8a94a2b9..1879831c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,6 @@ maintainers = [ description = "The backend API and machine learning models of AymurAI." readme = "README.md" license = { file = "LICENSE.md" } -# homepage = "https://github.com/AymurAI/backend" keywords = [ "api", "deep-learning", @@ -89,7 +88,7 @@ dependencies = [ [project.urls] Homepage = "https://www.aymurai.info/" -Repository = "https://github.com/aymurAI/backend" +Repository = "https://github.com/AymurAI/backend" Issues = "https://github.com/AymurAI/backend/issues" [dependency-groups] @@ -102,9 +101,6 @@ dev = [ "nbstripout>=0.8.0", "jupyter>=1.1.1", "pip>=24.3.1", - "streamlit>=1.21.0", - "dspy>=3.0.4", - "playwright==1.56.0" ] [tool.setuptools.packages.find] From 203f33ef549324cdd77e6d86c6902cc453c8d239 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:45:12 +0000 Subject: [PATCH 072/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20tasks.json=20co?= =?UTF-8?q?nfiguration=20for=20Ollama=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/tasks.json | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 .vscode/tasks.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index 6283a7ed..00000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "2.0.0", - "tasks": [ - { - "label": "Start Ollama service", - "type": "shell", - "command": "make", - "args": [ - "ollama-up" - ], - "options": { - "cwd": "${workspaceFolder}" - }, - "problemMatcher": [] - } - ] -} \ No newline at end of file From 24825e105914a0b61f841f9f407a66b8f2c138f8 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:45:57 +0000 Subject: [PATCH 073/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20scraper=20and?= =?UTF-8?q?=20documentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scraper/README.md | 97 ----- scraper/playwright_scraper.py | 739 ---------------------------------- 2 files changed, 836 deletions(-) delete mode 100644 scraper/README.md delete mode 100644 scraper/playwright_scraper.py diff --git a/scraper/README.md b/scraper/README.md deleted file mode 100644 index dc965075..00000000 --- a/scraper/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Scraper Playwright - Gestión Documental PJN - -Este repositorio contiene un script en Python que usa **Playwright** para automatizar la recolección -de documentos PDF publicados en la sección de gestión documental del Poder Judicial de la Nación -(https://www.pjn.gov.ar/gestion-documental). El scraper reproduce las llamadas AJAX que genera el front-end, -mantiene las cookies que requiere el API y descarga los adjuntos desde el servicio oficial. - -## Requisitos - -1. Python 3.8+ -2. Playwright y el navegador Chromium. - -```bash -python -m pip install --upgrade pip -pip install playwright -playwright install chromium -``` - -## Uso básico - -```bash -python playwright_scraper.py --output-dir datos --max-pages 5 --per-page 50 --pdf-template "https://pjn-documento-api.pjn.gov.ar/api/documento/adjunto/{id}" -``` - -El script hará: - -- Abrirá una sesión de Playwright y visitará la página oficial. -- Detectará automáticamente qué llamada REST obtiene los documentos. -- Iterará páginas y descargará los PDFs dentro del directorio `datos`. - -## Aplicar filtros desde la línea de comandos - -La interfaz web permite limitar por dependencia, categorías y rango de fechas. El scraper replica ese comportamiento con los argumentos: - -- `--dependencia "Fueros Federales"` aplica ese texto tanto a `dependencia` como a `dependenciaTexto`. -- `--category` se puede repetir para simular clics en categorías/subcategorías anidadas (por ejemplo `--category Reglamentos --category Normativa`). -- `--desde` y `--hasta` definen los campos `fechaDesde`/`fechaHasta` (o `desde`/`hasta`) que el backend espera. -- `--filter clave=valor` te deja añadir cualquier parámetro extra (por ejemplo `--filter orden=desc`, `--filter tipoDocumento=Resolución`). -- `--simulate-ui` simula los clicks sobre filtros, expande los botones “Mostrar más” y rellena las fechas como lo hace la UI antes de capturar la llamada AJAX. Úsalo si necesitás replicar exactamente la interacción de navegación para los filtros que ves en pantalla. -- `--debug-ui` habilita registros detallados sobre cada intento de clic/expansión para que puedas ver en consola qué filtros se están tocando en tiempo real. - -Los filtros se mezclan automáticamente en la query y en el cuerpo de la petición, así que puedes combinar varios `-f` en el mismo comando. - -## Estructura de almacenamiento guiada por filtros - -Los documentos descargados se organizan siguiendo los filtros aplicados y la metadata del registro: - -- Cada PDF se guarda en `ruta-de-salida///`, usando la dependencia que especifiques o la que entrega el API. -- La categoría se extrae de campos como `rubro`, `categoria` o `tipo` cuando están presentes. -- Si pasás `--category` el scraper usa esa secuencia de categorías/subcategorías como niveles adicionales (en lugar de los valores devueltos por el API), lo que refleja la navegación que aplicaste en los filtros. -- Si falta dependencia o año, se usan nombres como `sin-dependencia` o `sin-anio` para evitar colisiones. -- Los nombres de archivo ahora conservan acentos y caracteres especiales porque la normalización usa Unicode completo (`NFC`) antes de reemplazar espacios; así el título original permanece íntegro para tu pipeline de metadata. - -Esto facilita tener directorios alineados con las dependencias del Poder Judicial y continuar el pipeline de anonimización con una estructura consistente. - -Puedes ajustar el número de páginas, el retraso entre peticiones o el límite de documentos con -`--delay`, `--max-documents`, `--max-pages`. - -## Firma manual del API - -Si lo prefieres, puedes evitar la detección automática y proporcionar un JSON con la firma de las peticiones. -Esto es útil cuando ya sabes qué endpoint se usa o necesitas definir filtros específicos. - -```json -{ - "method": "POST", - "base_url": "https://www.pjn.gov.ar/api/documento/paginado", - "headers": { - "Accept": "application/json", - "Referer": "https://www.pjn.gov.ar/gestion-documental" - }, - "query_params": { - "orden": "desc" - }, - "json_body": { - "pagina": 0, - "size": 25, - "dependencia": "Fueros Federales" - }, - "listing_path": ["data", "registros"], - "page_keys": { - "pagina": 0 - }, - "size_keys": { - "size": 25 - }, - "body_type": "json" -} -``` - -Guarda ese JSON y pásalo al script con `--signature-file firma.json`. - -## Siguientes pasos - -1. Define reglas de nombrado y almacenamiento según tu pipeline de anonimización. -2. Agrega paralelismo/control de errores si necesitas escalar la descarga. -3. Encadena el dump resultante con los módulos de extracción y validación de Aymurai. diff --git a/scraper/playwright_scraper.py b/scraper/playwright_scraper.py deleted file mode 100644 index f108563e..00000000 --- a/scraper/playwright_scraper.py +++ /dev/null @@ -1,739 +0,0 @@ -#!/usr/bin/env python3 -""" -Playwright scraper para la sección “Gestión Documental” del Poder Judicial de la Nación. - -Este script usa Playwright para capturar las cabeceras y cookies que el frontend genera -y después reproduce las llamadas al API para descargar en lote los PDFs que se enumeran -en la interfaz. Se detecta de forma dinámica el endpoint y los parámetros de paginación, -pero también puede recibir una firma manual si así se prefiere. -""" - -import argparse -import asyncio -import copy -import json -import logging -import re -import unicodedata -import urllib.parse -from dataclasses import dataclass -from datetime import datetime -from pathlib import Path -from typing import Any, Dict, Iterable, List, Optional, Tuple - -from playwright.async_api import APIRequestContext, Page, async_playwright - -logging.basicConfig( - level=logging.INFO, - format="[%(asctime)s] %(levelname)s %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", -) -logger = logging.getLogger(__name__) - - -PAGE_KEYWORDS = ( - "pagina", - "page", - "pageindex", - "pagenumber", - "paginaactual", - "numeropagina", - "offset", -) -SIZE_KEYWORDS = ( - "size", - "pagesize", - "tamanio", - "cantidad", - "limit", - "perpage", - "per_page", -) - -MORE_BUTTON_SELECTOR = "text=/Mostrar\\s+m[aá]s/i" - - -def safe_filename(value: str) -> str: - clean = unicodedata.normalize("NFC", value.strip()) - clean = re.sub(r"\s+", "-", clean) - clean = re.sub(r"[^\w\-\.]", "", clean) - return clean[:120] - - -def detect_numeric_fields( - container: Dict[str, Any], keywords: Iterable[str] -) -> Dict[str, int]: - matches: Dict[str, int] = {} - for key, value in container.items(): - lowered = key.lower() - if any(keyword in lowered for keyword in keywords): - try: - matches[key] = int(value) - except (TypeError, ValueError): - continue - return matches - - -def update_values( - container: Dict[str, Any], keys: Iterable[str], new_value: int -) -> None: - for key in keys: - if key in container: - container[key] = new_value - - -def strip_sensitive_headers(headers: Dict[str, str]) -> Dict[str, str]: - blocked = { - "content-length", - "origin", - "connection", - "accept-encoding", - } - return {k: v for k, v in headers.items() if k.lower() not in blocked} - - -def load_signature_from_file(path: Path) -> Dict[str, Any]: - with path.open("r", encoding="utf-8") as fh: - return json.load(fh) - - -def extract_attachment_id(record: Dict[str, Any]) -> Optional[str]: - candidates = ( - "idAdjunto", - "adjunto", - "idDocumento", - "documentoAdjunto", - "id", - "adjuntoId", - ) - for key in candidates: - value = record.get(key) - if isinstance(value, dict): - nested = value.get("id") or value.get("codigo") - if nested: - return str(nested) - elif value: - return str(value) - return None - - -def record_field(record: Dict[str, Any], keys: Iterable[str]) -> Optional[str]: - for key in keys: - if key in record and record[key]: - return str(record[key]) - return None - - -def find_listing_path( - payload: Any, path: Tuple[str, ...] = () -) -> Optional[Tuple[Tuple[str, ...], List[Dict[str, Any]]]]: - if isinstance(payload, dict): - for key, value in payload.items(): - if ( - isinstance(value, list) - and value - and all(isinstance(item, dict) for item in value) - ): - if any( - any( - "id" in field.lower() or "adjunto" in field.lower() - for field in item.keys() - ) - for item in value - ): - return path + (key,), value - child = find_listing_path(value, path + (key,)) - if child: - return child - elif isinstance(payload, list): - if payload and all(isinstance(item, dict) for item in payload): - if any( - any( - "id" in field.lower() or "adjunto" in field.lower() - for field in item.keys() - ) - for item in payload - ): - return path, payload - return None - - -def extract_records_by_path( - payload: Dict[str, Any], path: Tuple[str, ...] -) -> List[Dict[str, Any]]: - current: Any = payload - for key in path: - if not isinstance(current, dict): - return [] - current = current.get(key) - if current is None: - return [] - if isinstance(current, list): - return [item for item in current if isinstance(item, dict)] - return [] - - -def derive_pdf_url(template: str, attachment_id: str) -> str: - if "{id}" in template: - return template.format(id=attachment_id) - return template.rstrip("/") + "/" + attachment_id - - -@dataclass -class SearchSignature: - method: str - base_url: str - headers: Dict[str, str] - query_params: Dict[str, str] - json_body: Optional[Dict[str, Any]] - listing_path: Tuple[str, ...] - example_record: Dict[str, Any] - page_keys: Dict[str, int] - size_keys: Dict[str, int] - body_type: str - - -def build_signature_from_request( - request, - listing_path: Tuple[str, ...], - example_record: Dict[str, Any], - response_payload: Dict[str, Any], -) -> SearchSignature: - parsed = urllib.parse.urlparse(request.url) - base_url = urllib.parse.urlunparse(parsed._replace(query="")) - query_params = dict(urllib.parse.parse_qsl(parsed.query, keep_blank_values=True)) - method = request.method - headers = strip_sensitive_headers(dict(request.headers)) - json_body: Optional[Dict[str, Any]] = None - post_data = request.post_data - content_type = request.headers.get("content-type", "") - if post_data: - if "x-www-form-urlencoded" in content_type: - json_body = dict(urllib.parse.parse_qsl(post_data)) - else: - try: - json_body = json.loads(post_data) - except json.JSONDecodeError: - logger.debug("No se pudo parsear cuerpo JSON de la petición inicial.") - initial_container = {} - initial_container.update(query_params) - if isinstance(json_body, dict): - initial_container.update(json_body) - page_keys = detect_numeric_fields(initial_container, PAGE_KEYWORDS) - size_keys = detect_numeric_fields(initial_container, SIZE_KEYWORDS) - if not listing_path: - found = find_listing_path(response_payload) - if not found: - raise RuntimeError( - "No se pudo determinar la ruta de listado de documentos." - ) - listing_path = found[0] - if post_data: - if "x-www-form-urlencoded" in content_type: - body_type = "form" - else: - body_type = "json" - else: - body_type = "none" - return SearchSignature( - method=method.upper(), - base_url=base_url, - headers=headers, - query_params=query_params, - json_body=json_body, - listing_path=listing_path, - example_record=example_record, - page_keys=page_keys, - size_keys=size_keys, - body_type=body_type, - ) - - -async def capture_signature( - page: Page, args: argparse.Namespace, timeout: float = 20.0 -) -> SearchSignature: - future = asyncio.get_running_loop().create_future() - - async def inspect_response(response): - if future.done(): - return - if response.status != 200: - return - if response.request.resource_type != "xhr": - return - content_type = response.headers.get("content-type", "") - if "application/json" not in content_type: - return - try: - payload = await response.json() - except Exception: - return - found = find_listing_path(payload) - if not found: - return - records = found[1] - if not records: - return - future.set_result((response.request, found[0], records[0], payload)) - - page.on( - "response", - lambda response: asyncio.create_task(inspect_response(response)), - ) - await page.goto( - "https://www.pjn.gov.ar/gestion-documental", wait_until="networkidle" - ) - if args.simulate_ui: - try: - await apply_ui_filters(page, args) - except Exception as exc: # pragma: no cover - best effort - logger.warning("Error al aplicar filtros UI: %s", exc) - try: - await asyncio.wait_for(future, timeout=timeout) - except asyncio.TimeoutError: - logger.warning( - "No se detectó automáticamente la llamada al API. Asegúrate de navegar en la página." - ) - raise - - request, listing_path, sample_record, payload = future.result() - signature = build_signature_from_request( - request, listing_path, sample_record, payload - ) - logger.info("Firma detectada: %s %s", signature.method, signature.base_url) - logger.debug("Campos página: %s", signature.page_keys) - logger.debug("Campos tamaño: %s", signature.size_keys) - return signature - - -def load_signature(source: Dict[str, Any]) -> SearchSignature: - signature = SearchSignature( - method=source["method"].upper(), - base_url=source["base_url"], - headers=source.get("headers", {}), - query_params=source.get("query_params", {}), - json_body=source.get("json_body"), - listing_path=tuple(source["listing_path"]), - example_record=source.get("example_record", {}), - page_keys={k: int(v) for k, v in source.get("page_keys", {}).items()}, - size_keys={k: int(v) for k, v in source.get("size_keys", {}).items()}, - body_type=source.get("body_type", "json"), - ) - return signature - - -def prepare_page_payload( - signature: SearchSignature, - page_value: int, - page_size: int, -) -> Tuple[Dict[str, str], Optional[Dict[str, Any]]]: - query_params = signature.query_params.copy() - if signature.json_body is not None: - body_payload = copy.deepcopy(signature.json_body) - else: - body_payload = None - if signature.page_keys: - update_values(query_params, signature.page_keys.keys(), page_value) - if body_payload is not None: - update_values(body_payload, signature.page_keys.keys(), page_value) - if signature.size_keys: - update_values(query_params, signature.size_keys.keys(), page_size) - if body_payload is not None: - update_values(body_payload, signature.size_keys.keys(), page_size) - return query_params, body_payload - - -def apply_filter_overrides( - query_params: Dict[str, str], - body_payload: Optional[Dict[str, Any]], - overrides: Dict[str, str], -) -> None: - if not overrides: - return - for key, value in overrides.items(): - query_params[key] = value - if body_payload is not None: - body_payload[key] = value - - -def build_filter_overrides( - raw_filters: Iterable[str], - dependencia: Optional[str], - desde: Optional[str], - hasta: Optional[str], -) -> Dict[str, str]: - overrides: Dict[str, str] = {} - for option in raw_filters: - if "=" not in option: - raise ValueError(f"Filtro inválido: {option!r}. Use clave=valor.") - key, value = option.split("=", 1) - overrides[key] = value - if dependencia: - overrides.setdefault("dependencia", dependencia) - overrides.setdefault("dependenciaTexto", dependencia) - if desde: - overrides.setdefault("fechaDesde", desde) - overrides.setdefault("desde", desde) - if hasta: - overrides.setdefault("fechaHasta", hasta) - overrides.setdefault("hasta", hasta) - return overrides - - -def ui_debug(args: argparse.Namespace, message: str) -> None: - if getattr(args, "debug_ui", False): - logger.info("[UI] %s", message) - - -async def expand_more_filters(page: Page, args: argparse.Namespace) -> None: - while True: - locator = page.locator(MORE_BUTTON_SELECTOR) - if not await locator.count(): - break - ui_debug(args, "Expandiendo filtros con 'Mostrar más'") - await locator.first.click() - await page.wait_for_timeout(250) - - -async def click_filter_option(page: Page, args: argparse.Namespace, text: str) -> bool: - text = text.strip() - if not text: - return False - strategies = [ - ("role=button", page.get_by_role("button", name=text, exact=False)), - ("role=link", page.get_by_role("link", name=text, exact=False)), - ("text-match", page.get_by_text(text, exact=False)), - ("button:has-text", page.locator(f'button:has-text("{text}")')), - ("div:has-text", page.locator(f'div:has-text("{text}")')), - ] - ui_debug( - args, - f"Intentando seleccionar filtro '{text}' usando {len(strategies)} estrategias", - ) - for description, locator in strategies: - ui_debug(args, f"Probando estrategia '{description}' para '{text}'") - if await locator.count(): - ui_debug(args, f"Clic en '{text}' usando '{description}'") - await locator.first.click() - await page.wait_for_timeout(400) - return True - ui_debug(args, f"No se encontró '{text}' con '{description}'") - return False - - -def normalize_ui_date(value: str) -> str: - try: - parsed = datetime.fromisoformat(value) - return parsed.strftime("%d/%m/%Y") - except ValueError: - return value - - -async def apply_ui_filters(page: Page, args: argparse.Namespace) -> None: - await expand_more_filters(page, args) - if args.dependencia: - clicked = await click_filter_option(page, args, args.dependencia) - if not clicked: - logger.warning( - "No se encontró la dependencia %s en el filtro UI.", args.dependencia - ) - await expand_more_filters(page, args) - for category in getattr(args, "category_path", []): - await expand_more_filters(page, args) - clicked = await click_filter_option(page, args, category) - if not clicked: - logger.warning("No se encontró la categoría %s en el filtro UI.", category) - await expand_more_filters(page, args) - if args.desde: - desde_input = page.locator("input[placeholder='Desde']") - if await desde_input.count(): - await desde_input.fill(normalize_ui_date(args.desde)) - if args.hasta: - hasta_input = page.locator("input[placeholder='Hasta']") - if await hasta_input.count(): - await hasta_input.fill(normalize_ui_date(args.hasta)) - apply_button = page.locator("button:has-text('Aplicar')") - if not await apply_button.count(): - apply_button = page.locator("button:has-text('Buscar')") - if await apply_button.count(): - ui_debug(args, "Aplicando filtros (botón 'Aplicar'/'Buscar')") - await apply_button.first.click() - else: - await page.keyboard.press("Enter") - await page.wait_for_timeout(1500) - - -def extract_year(value: Optional[str]) -> str: - if not value: - return "sin-anio" - match = re.search(r"(19|20)\d{2}", value) - return match.group(0) if match else "sin-anio" - - -def determine_document_path( - args: argparse.Namespace, record: Dict[str, Any], document: Dict[str, str] -) -> Path: - dependency = ( - args.dependencia - or document.get("dependency") - or record_field(record, ("dependencia", "origen", "tribunal")) - or "sin-dependencia" - ) - category = record_field( - record, ("rubro", "categoria", "tipo", "clasificacion", "subcategoria") - ) - year = extract_year(document.get("date")) - segments = [args.output_dir, safe_filename(dependency)] - if getattr(args, "category_path", None): - segments.extend( - safe_filename(part) for part in args.category_path if part and part.strip() - ) - elif category: - segments.append(safe_filename(category)) - segments.append(year) - return Path(*segments) / document["file_name"] - - -def build_document( - record: Dict[str, Any], pdf_template: str -) -> Optional[Dict[str, str]]: - attachment_id = extract_attachment_id(record) - if not attachment_id: - return None - pdf_url = derive_pdf_url(pdf_template, attachment_id) - document_date = record_field(record, ("fecha", "fechaDocumento", "fechaResolucion")) - title = record_field(record, ("titulo", "descripcion", "tituloDocumento", "nombre")) - dependency = record_field( - record, ("dependencia", "dependenciaTexto", "origen", "tribunal") - ) - parts = [ - document_date or "fecha-desconocida", - title or "sin-titulo", - dependency or "dependencia", - attachment_id, - ] - name = safe_filename("_".join(part for part in parts if part)) - return { - "attachment_id": attachment_id, - "pdf_url": pdf_url, - "file_name": f"{name}.pdf", - "title": title or "", - "date": document_date or "", - "dependency": dependency or "", - } - - -async def download_document( - context: APIRequestContext, destination: Path, document: Dict[str, str] -) -> None: - destination.parent.mkdir(parents=True, exist_ok=True) - if destination.exists(): - logger.info("Salteando %s, ya existe", destination.name) - return - response = await context.get( - document["pdf_url"], headers={"Referer": "https://www.pjn.gov.ar/"} - ) - response_ok = response.ok - if not response_ok: - logger.warning( - "Error al obtener %s (%s)", - document["attachment_id"], - response.status, - ) - return - content = await response.body() - destination.write_bytes(content) - logger.info("Descargado %s (%s)", destination.name, len(content)) - - -async def run_scraping( - args: argparse.Namespace, - signature: SearchSignature, - context_request: APIRequestContext, -) -> None: - documents_downloaded = 0 - page_start = ( - args.page_start - if args.page_start is not None - else next(iter(signature.page_keys.values()), 0) - ) - page_size = ( - args.page_size - if args.page_size is not None - else next(iter(signature.size_keys.values()), args.per_page) - ) - for page_index in range(args.max_pages): - if args.max_documents and documents_downloaded >= args.max_documents: - logger.info("Se alcanzó el límite de documentos solicitado.") - break - page_value = page_start + page_index - query_params, body_payload = prepare_page_payload( - signature, page_value, page_size - ) - apply_filter_overrides(query_params, body_payload, args.filter_overrides) - if signature.method == "GET": - response = await context_request.get( - signature.base_url, - params=query_params, - headers=signature.headers, - ) - else: - if body_payload is not None: - if signature.body_type == "form": - response = await context_request.post( - signature.base_url, - params=query_params, - data=body_payload, - headers=signature.headers, - ) - else: - response = await context_request.post( - signature.base_url, - params=query_params, - json=body_payload, - headers=signature.headers, - ) - else: - response = await context_request.post( - signature.base_url, - params=query_params, - headers=signature.headers, - ) - if not response.ok: - logger.warning("Respuesta %s en página %s", response.status, page_value) - break - payload = await response.json() - records = extract_records_by_path(payload, signature.listing_path) - if not records: - logger.info("No hay registros en la página %s", page_value) - break - logger.info("Procesando página %s (%d registros)", page_value, len(records)) - for record in records: - if args.max_documents and documents_downloaded >= args.max_documents: - break - doc = build_document(record, args.pdf_template) - if not doc: - continue - destination = determine_document_path(args, record, doc) - await download_document(context_request, destination, doc) - documents_downloaded += 1 - await asyncio.sleep(args.delay) - - -def parse_args() -> argparse.Namespace: - parser = argparse.ArgumentParser( - description="Scraper de gestión documental usando Playwright" - ) - parser.add_argument( - "--output-dir", - type=Path, - default=Path("descargas"), - help="Carpeta donde se guardan los PDFs", - ) - parser.add_argument( - "--pdf-template", - default="https://pjn-documento-api.pjn.gov.ar/api/documento/adjunto/{id}", - ) - parser.add_argument("--max-pages", type=int, default=20) - parser.add_argument("--per-page", type=int, default=25) - parser.add_argument( - "-f", - "--filter", - action="append", - default=[], - help="Filtros adicionales como clave=valor (aplica a query y/o cuerpo).", - ) - parser.add_argument( - "--dependencia", - help="Filtra por dependencia (ej. 'Fueros Federales' o 'Consejo de la Magistratura').", - ) - parser.add_argument( - "--desde", - help="Fecha mínima de publicación en formato ISO o compatible con el backend.", - ) - parser.add_argument( - "--hasta", - help="Fecha máxima de publicación en formato ISO o compatible con el backend.", - ) - parser.add_argument( - "--category", - action="append", - default=[], - help="Secuencia de categorías/subcategorías a seleccionar tras la dependencia.", - ) - parser.add_argument( - "--simulate-ui", - action="store_true", - help="Simula clicks/fechas en la UI antes de detectar la llamada REST.", - ) - parser.add_argument( - "--debug-ui", - action="store_true", - help="Imprime en consola cada intento de interacción con los filtros.", - ) - parser.add_argument( - "--delay", - type=float, - default=1.5, - help="Retraso entre páginas para respetar al servidor", - ) - parser.add_argument( - "--max-documents", - type=int, - default=0, - help="Máximo de PDFs a guardar (0 = infinito)", - ) - parser.add_argument( - "--headless", - action="store_true", - help="Ejecutar Playwright en modo headless", - ) - parser.add_argument( - "--signature-file", - type=Path, - help="Ruta a un JSON con la firma del API", - ) - parser.add_argument( - "--page-start", - type=int, - help="Valor base para el primer número de página", - ) - parser.add_argument( - "--page-size", type=int, help="Cantidad de registros por página" - ) - return parser.parse_args() - - -def main() -> None: - args = parse_args() - if args.max_documents < 0: - raise ValueError("max-documents debe ser positivo o cero.") - args.output_dir.mkdir(parents=True, exist_ok=True) - args.category_path = args.category or [] - args.filter_overrides = build_filter_overrides( - args.filter, args.dependencia, args.desde, args.hasta - ) - - async def run(): - async with async_playwright() as p: - browser = await p.chromium.launch(headless=args.headless) - context = await browser.new_context(viewport={"width": 1400, "height": 900}) - page = await context.new_page() - signature: SearchSignature - if args.signature_file: - signature_data = load_signature_from_file(args.signature_file) - signature = load_signature(signature_data) - await page.goto( - "https://www.pjn.gov.ar/gestion-documental", - wait_until="networkidle", - ) - else: - signature = await capture_signature(page, args) - await run_scraping(args, signature, context.request) - await browser.close() - - asyncio.run(run()) - - -if __name__ == "__main__": - main() From a6986fee3d19546171bd4bdb4e6e6d02571d73e2 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:47:00 +0000 Subject: [PATCH 074/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20experiment=20mo?= =?UTF-8?q?dule?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/experiments/__init__.py | 1 - 1 file changed, 1 deletion(-) delete mode 100644 aymurai/experiments/__init__.py diff --git a/aymurai/experiments/__init__.py b/aymurai/experiments/__init__.py deleted file mode 100644 index 78e64a4b..00000000 --- a/aymurai/experiments/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Experiment modules and helpers.""" From 968344d97f9200a5408646d80ed5c9c5964ad898 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:48:36 +0000 Subject: [PATCH 075/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20path=20utility?= =?UTF-8?q?=20functions=20from=20paths.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/evaluation/metrics.py | 1 - aymurai/utils/paths.py | 40 ----------------------------------- 2 files changed, 41 deletions(-) delete mode 100644 aymurai/utils/paths.py diff --git a/aymurai/evaluation/metrics.py b/aymurai/evaluation/metrics.py index bea0a785..ced35d99 100644 --- a/aymurai/evaluation/metrics.py +++ b/aymurai/evaluation/metrics.py @@ -7,7 +7,6 @@ from aymurai.logger import get_logger from aymurai.utils.json_data import load_json -from aymurai.utils.paths import prediction_filename_for_test, test_id_from_filename logger = get_logger(__name__) diff --git a/aymurai/utils/paths.py b/aymurai/utils/paths.py deleted file mode 100644 index 0677c72e..00000000 --- a/aymurai/utils/paths.py +++ /dev/null @@ -1,40 +0,0 @@ -from pathlib import Path - -TEST_SUFFIX = "-test" - - -def test_id_from_filename(test_path: Path, *, test_suffix: str = TEST_SUFFIX) -> str: - """ - Convert a test filename like "document-1-test.json" into "document-1". - Falls back to stripping ".json" when the suffix is not present. - - Args: - test_path (Path): Path to the test file. - test_suffix (str, optional): Suffix indicating test files. Defaults to "-test". - - Returns: - str: The test identifier extracted from the filename. - """ - name = Path(test_path).name - suffix_with_ext = f"{test_suffix}.json" - if name.endswith(suffix_with_ext): - return name[: -len(suffix_with_ext)] - if name.endswith(".json"): - return name[: -len(".json")] - return name - - -def prediction_filename_for_test( - test_path: Path, *, test_suffix: str = TEST_SUFFIX -) -> str: - """ - Return the prediction filename that should correspond to the test file. - - Args: - test_path (Path): Path to the test file. - test_suffix (str, optional): Suffix indicating test files. Defaults to "-test". - - Returns: - str: The prediction filename corresponding to the test file. - """ - return f"{test_id_from_filename(test_path, test_suffix=test_suffix)}.json" From 6c3514377083bd99e51c12b9f500651260522f0a Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:50:10 +0000 Subject: [PATCH 076/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20unused=20Prompt?= =?UTF-8?q?Set=20and=20PromptLibrary=20classes,=20and=20simplify=20disambi?= =?UTF-8?q?guation=20options=20in=20LabelPolicy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/meta/api_interfaces.py | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/aymurai/meta/api_interfaces.py b/aymurai/meta/api_interfaces.py index 1caa6509..ab1e8845 100644 --- a/aymurai/meta/api_interfaces.py +++ b/aymurai/meta/api_interfaces.py @@ -1,12 +1,10 @@ import uuid +from typing import Literal from pydantic import UUID5, BaseModel, Field, RootModel -from typing import Literal from aymurai.meta.entities import EntityAttributes -from functools import cached_property - class SuccessResponse(BaseModel): id: int | uuid.UUID | None = None @@ -49,7 +47,7 @@ class LabelPolicy(BaseModel): """Per-label policy for disambiguation and anonymization.""" anonymize: bool | None = None - disambiguation: Literal["none", "fuzzy", "llm"] | None = None + disambiguation: Literal["none", "fuzzy"] | None = None use_subclass_when_available: bool | None = None @@ -79,20 +77,3 @@ class Document(BaseModel): document_id: UUID5 header: list[str] | None = None footer: list[str] | None = None - - -class PromptSet(BaseModel): - label: str - system: str - user: str - - -class PromptLibrary(RootModel): - root: list[PromptSet] = Field(default_factory=list) - - @cached_property - def as_dict(self) -> dict[str, PromptSet]: - return {p.label: p for p in self.root} - - def get(self, label: str) -> PromptSet | None: - return self.as_dict.get(label) From 4d28e03dd261a0d7c595e5ee62fa32bdc128b906 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:50:28 +0000 Subject: [PATCH 077/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20EntityRelation?= =?UTF-8?q?=20class=20and=20its=20associated=20methods=20from=20entities.p?= =?UTF-8?q?y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/meta/entities.py | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/aymurai/meta/entities.py b/aymurai/meta/entities.py index 871ee462..759167c2 100644 --- a/aymurai/meta/entities.py +++ b/aymurai/meta/entities.py @@ -63,45 +63,6 @@ class Entity(BaseModel): attrs: EntityAttributes | None = None -class EntityRelation(BaseModel): - """Semantic relation between canonical entities.""" - - relation_id: UUID | None = Field( - None, description="Unique identifier of the relation" - ) - relation_type: str = Field( - description="Type of relation (e.g. identifies, resides_in)" - ) - subject_entity_id: UUID = Field( - description="Identifier of the subject entity participating in the relation" - ) - object_entity_id: UUID = Field( - description="Identifier of the object entity participating in the relation" - ) - attributes: dict[str, Any] = Field( - default_factory=dict, - description="Additional attributes captured for the relation", - ) - - @model_validator(mode="after") - def assign_relation_id(self) -> EntityRelation: - """Populate relation_id deterministically when not provided.""" - - if self.relation_id is not None: - return self - - payload = { - "relation_type": self.relation_type, - "subject_entity_id": str(self.subject_entity_id), - "object_entity_id": str(self.object_entity_id), - "attributes": self.attributes, - } - seed = json.dumps(payload, sort_keys=True, separators=(",", ":")) - object.__setattr__(self, "relation_id", uuid5(NAMESPACE_URL, seed)) - - return self - - class CanonicalEntity(BaseModel): """Canonical representation of an entity cluster.""" From e6f32baf1ebf241db34e5b27f60c723fa4c2052a Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 17:51:19 +0000 Subject: [PATCH 078/104] =?UTF-8?q?=F0=9F=93=9D=20Enhance=20documentation?= =?UTF-8?q?=20with=20detailed=20docstrings=20for=20various=20functions=20a?= =?UTF-8?q?cross=20multiple=20modules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/utils/alignment/core.py | 48 ++++++++++++++---- aymurai/utils/alignment/ia2.py | 53 +++++++++++++++++++- aymurai/utils/cache.py | 8 ++- aymurai/utils/display/pandas.py | 13 ++++- aymurai/utils/download.py | 7 ++- aymurai/utils/entity_disambiguation/core.py | 8 +-- aymurai/utils/entity_disambiguation/fuzzy.py | 7 +-- aymurai/utils/json_data.py | 9 ++-- aymurai/utils/json_encoding.py | 40 +++++++++++++-- aymurai/utils/misc.py | 50 ++++++++++++------ aymurai/utils/pickle_data.py | 18 ++++++- 11 files changed, 208 insertions(+), 53 deletions(-) diff --git a/aymurai/utils/alignment/core.py b/aymurai/utils/alignment/core.py index c8eeeed2..65a3004c 100644 --- a/aymurai/utils/alignment/core.py +++ b/aymurai/utils/alignment/core.py @@ -11,6 +11,15 @@ def tokenize(text: str) -> list[str]: + """ + Split multi-line text into whitespace-delimited tokens. + + Args: + text (str): Input text to tokenize. + + Returns: + list[str]: Tokens extracted from the text. + """ tokens = map(str.split, text.splitlines()) tokens = flatten(tokens) return list(tokens) @@ -21,15 +30,17 @@ def align_text( target_text: str, columns: tuple[str, str] = ("source", "target"), ) -> pd.DataFrame: - """align source and target text into a table + """ + Align source and target text into a token-level mapping table. Args: - source_text (str): reference text - target_text (str): second text to align with - columns (tuple[str, str]): names of columns on output + source_text (str): Reference text. + target_text (str): Text to align against `source_text`. + columns (tuple[str, str], optional): Output column names. + Defaults to ("source", "target"). Returns: - pd.DataFrame: alignment table + pd.DataFrame: Alignment table. """ source_tokens = [t.strip() for t in tokenize(source_text)] target_tokens = [t.strip() for t in tokenize(target_text)] @@ -78,15 +89,22 @@ def align_docs( columns: tuple[str, str] = ("source", "target"), source_preprocess: Callable[[str], str] | None = None, target_preprocess: Callable[[str], str] | None = None, -): - """align two documents word to word +) -> pd.DataFrame: + """ + Align two documents word by word. Args: - source_path (str | Path): source document path (reference) - target_path (str | Path): target document path (target) + source_path (str | Path): Source document path (reference). + target_path (str | Path): Target document path. + columns (tuple[str, str], optional): Output column names. + Defaults to ("source", "target"). + source_preprocess (Callable[[str], str] | None, optional): Preprocessing + function applied to extracted source text. Defaults to None. + target_preprocess (Callable[[str], str] | None, optional): Preprocessing + function applied to extracted target text. Defaults to None. Returns: - pd.DataFrame: alignment table + pd.DataFrame: Alignment table. """ source: str = extract_document(source_path, errors="raise") # type: ignore target: str = extract_document(target_path, errors="raise") # type: ignore @@ -140,6 +158,16 @@ def add_empty_lines_between_paragraphs( reference: str, mapping: pd.DataFrame, ) -> pd.DataFrame: + """ + Insert empty rows in an alignment table at paragraph break boundaries. + + Args: + reference (str): Reference text used to infer paragraph boundaries. + mapping (pd.DataFrame): Alignment table to augment. + + Returns: + pd.DataFrame: Alignment table with inserted empty rows. + """ mapping = mapping.copy() reference = re.sub(r"\n+", "\n", reference) splitted = reference.splitlines() diff --git a/aymurai/utils/alignment/ia2.py b/aymurai/utils/alignment/ia2.py index f94af1a3..68f7755a 100644 --- a/aymurai/utils/alignment/ia2.py +++ b/aymurai/utils/alignment/ia2.py @@ -1,5 +1,6 @@ import os import re +from typing import Any import numpy as np import pandas as pd @@ -7,12 +8,31 @@ def normalize(text: str) -> str: + """ + Normalize text by removing accents and non-word characters. + + Args: + text (str): Input text. + + Returns: + str: Normalized text. + """ text = unidecode(text) text = re.sub(r"\W", "", text) return text -def norm_ia2_label(text, labels: list[str]) -> str | float: +def norm_ia2_label(text: Any, labels: list[str]) -> str | float: + """ + Extract a single matching IA2 label from text. + + Args: + text (Any): Input text containing IA2 label content. + labels (list[str]): Valid label patterns to match. + + Returns: + str | float: The matched label when unique, otherwise `np.nan`. + """ if not isinstance(text, str): return np.nan @@ -27,6 +47,15 @@ def norm_ia2_label(text, labels: list[str]) -> str | float: def label_to_conll_format(labels: pd.Series) -> pd.Series: + """ + Convert label sequences to CONLL BIO tags. + + Args: + labels (pd.Series): Sequence of labels. + + Returns: + pd.Series: Labels converted to BIO format. + """ labels = labels.copy() if len(labels.dropna()) == 0: @@ -43,6 +72,15 @@ def label_to_conll_format(labels: pd.Series) -> pd.Series: def ia2_text_preprocess(text: str) -> str: + """ + Insert whitespace after IA2 XML-like tags when missing. + + Args: + text (str): Input text. + + Returns: + str: Preprocessed text. + """ text = re.sub(r"(<\w+>)(\S)", r"\g<1> \g<2>", text) return text @@ -52,7 +90,18 @@ def mapping2conll( filename: str, text_column: str = "original", label_column: str = "label", -): +) -> None: + """ + Write token-label mappings to a CONLL-style file. + + Args: + df (pd.DataFrame): DataFrame containing token and label columns. + filename (str): Output file path. + text_column (str, optional): Column name containing tokens. + Defaults to "original". + label_column (str, optional): Column name containing labels. + Defaults to "label". + """ dir = os.path.dirname(filename) os.makedirs(dir, exist_ok=True) with open(filename, "w") as file: diff --git a/aymurai/utils/cache.py b/aymurai/utils/cache.py index be653042..6d1928eb 100644 --- a/aymurai/utils/cache.py +++ b/aymurai/utils/cache.py @@ -21,7 +21,7 @@ def flatten_dict(current: dict, key: str = "", result: dict = {}) -> dict: Args: current (dict): Source dictionary to flatten. - key (str): Parent key prefix. Defaults to "". + key (str, optional): Parent key prefix. Defaults to "". result (dict, optional): Accumulator reused across recursion. Defaults to {}. Returns: @@ -53,7 +53,8 @@ def get_cache_key(item: Any, context: Any = "") -> str: Args: item (Any): Value to hash into the key namespace. - context (Any): Additional context used to scope the key. Defaults to "". + context (Any, optional): Additional context used to scope the key. + Defaults to "". Returns: str: Deterministic hash suitable for cache lookups. @@ -91,9 +92,6 @@ def cache_save(data_item: Any, key: str) -> None: Args: data_item (Any): Serializable payload to store. key (str): Cache key under which the payload is saved. - - Returns: - None: This function does not return a value. """ data = pickle.dumps(data_item) diff --git a/aymurai/utils/display/pandas.py b/aymurai/utils/display/pandas.py index 2f83742b..d2abc054 100644 --- a/aymurai/utils/display/pandas.py +++ b/aymurai/utils/display/pandas.py @@ -1,7 +1,18 @@ +from typing import ContextManager + import pandas as pd from more_itertools import flatten -def pandas_context(**kwargs): +def pandas_context(**kwargs) -> ContextManager[None]: + """ + Build a pandas option context manager from keyword options. + + Args: + **kwargs: Pandas option names mapped to values. + + Returns: + ContextManager[None]: Context manager that applies the provided options. + """ options = flatten(kwargs.items()) return pd.option_context(*options) # type: ignore diff --git a/aymurai/utils/download.py b/aymurai/utils/download.py index 9ce6ea6a..52d2a7f3 100644 --- a/aymurai/utils/download.py +++ b/aymurai/utils/download.py @@ -19,11 +19,14 @@ def download(url: str, output: str) -> str: Skips download when the target exists and NO_DOWNLOAD_IF_EXISTS is truthy. Args: - url: URL to download. - output: Path to save the downloaded file. + url (str): URL to download. + output (str): Path to save the downloaded file. Returns: str: Path to the downloaded file. + + Raises: + requests.HTTPError: If the download request returns an HTTP error status. """ output_path = Path(output) diff --git a/aymurai/utils/entity_disambiguation/core.py b/aymurai/utils/entity_disambiguation/core.py index 22982c6c..f12bedc4 100644 --- a/aymurai/utils/entity_disambiguation/core.py +++ b/aymurai/utils/entity_disambiguation/core.py @@ -58,10 +58,10 @@ def map_canonical_entities_ner_preds( Args: predictions (DocumentAnnotations): Original predictions to update. canonical_entities (CanonicalEntities): Canonical entities with IDs/roles. - include_label_instances (bool): Whether to assign ordered label instance - indices (e.g., 1, 2). Defaults to True. - force_labels (set[str] | None): Labels to remap even if a canonical ID - already exists. + include_label_instances (bool, optional): Whether to assign ordered label + instance indices (e.g., 1, 2). Defaults to True. + force_labels (set[str] | None, optional): Labels to remap even if a + canonical ID already exists. Defaults to None. Returns: DocumentAnnotations: Updated predictions with canonical IDs, roles, and diff --git a/aymurai/utils/entity_disambiguation/fuzzy.py b/aymurai/utils/entity_disambiguation/fuzzy.py index 71ceed76..682810b6 100644 --- a/aymurai/utils/entity_disambiguation/fuzzy.py +++ b/aymurai/utils/entity_disambiguation/fuzzy.py @@ -33,9 +33,6 @@ def _union_parent(parent: list[int], left: int, right: int) -> None: parent (list[int]): Parent pointers for the union-find structure. left (int): First index to union. right (int): Second index to union. - - Returns: - None """ root_left, root_right = _find_parent(parent, left), _find_parent(parent, right) if root_left != root_right: @@ -167,8 +164,8 @@ def build_canonical_entities( Args: labels (Iterable[DocLabel]): NER labels to cluster. - target_labels (set[str] | None): Optional label filter; if provided, - only these labels are clustered. + target_labels (set[str] | None, optional): Label filter; if provided, + only these labels are clustered. Defaults to None. threshold (int): Minimum similarity threshold for clustering. Returns: diff --git a/aymurai/utils/json_data.py b/aymurai/utils/json_data.py index 7fda48d0..b69bf5d6 100644 --- a/aymurai/utils/json_data.py +++ b/aymurai/utils/json_data.py @@ -9,7 +9,7 @@ def json_serial(obj: Any) -> str: JSON serializer for objects not serializable by default JSON encoder. Args: - obj: The object to serialize. This function currently supports + obj (Any): The object to serialize. This function currently supports datetime.date and datetime.datetime objects. Returns: @@ -17,7 +17,7 @@ def json_serial(obj: Any) -> str: Raises: TypeError: If the object is not of type datetime.date or datetime.datetime. - """ # noqa: E501 + """ if isinstance(obj, (datetime, date)): return obj.isoformat() raise TypeError(f"Type {type(obj)} not serializable") @@ -28,17 +28,16 @@ def get_pretty(obj: dict | list[Any]) -> str: Returns a pretty json string. Args: - obj (Union[dict, list[Any]]): the object to be converted to json. + obj (dict | list[Any]): The object to be converted to JSON. Returns: - str: the pretty json string. + str: The pretty JSON string. """ return json.dumps(obj, indent=4, ensure_ascii=False, default=json_serial) def save_json(json_data: dict | list[dict], file_path: str) -> None: """ - Saves a JSON object to a file. Args: diff --git a/aymurai/utils/json_encoding.py b/aymurai/utils/json_encoding.py index c4b2e930..5ff367a9 100644 --- a/aymurai/utils/json_encoding.py +++ b/aymurai/utils/json_encoding.py @@ -3,6 +3,7 @@ import json import decimal import datetime +from typing import Any import pandas as pd @@ -12,7 +13,22 @@ class EnhancedJSONEncoder(json.JSONEncoder): - def default(self, obj): + """JSON encoder with support for datetime, timedelta, decimal, and NA values.""" + + def default(self, obj: Any) -> Any: + """ + Encode unsupported Python objects into JSON-serializable payloads. + + Args: + obj (Any): Object to encode. + + Returns: + Any: JSON-serializable representation of `obj`. + + Raises: + TypeError: If `obj` cannot be encoded by the custom logic or parent + JSON encoder. + """ if isinstance(obj, datetime.datetime): ARGS = ("year", "month", "day", "hour", "minute", "second", "microsecond") return { @@ -55,10 +71,28 @@ def default(self, obj): class EnhancedJSONDecoder(json.JSONDecoder): - def __init__(self, *args, **kwargs): + """JSON decoder that reconstructs objects serialized by `EnhancedJSONEncoder`.""" + + def __init__(self, *args, **kwargs) -> None: + """ + Initialize decoder with a custom object hook. + + Args: + *args: Positional arguments forwarded to `json.JSONDecoder`. + **kwargs: Keyword arguments forwarded to `json.JSONDecoder`. + """ super().__init__(*args, object_hook=self.object_hook, **kwargs) - def object_hook(self, d): + def object_hook(self, d: dict) -> Any: + """ + Decode typed payloads into native Python objects. + + Args: + d (dict): Decoded dictionary from JSON. + + Returns: + Any: Reconstructed object when `__type__` is present, else `d`. + """ if "__type__" not in d: return d o = sys.modules[__name__] diff --git a/aymurai/utils/misc.py b/aymurai/utils/misc.py index 286d30f4..6d665e80 100644 --- a/aymurai/utils/misc.py +++ b/aymurai/utils/misc.py @@ -1,25 +1,31 @@ import re -from typing import Any, Union +from typing import Any def get_element( - obj, - levels: Union[list, Any] = [], + obj: Any, + levels: list[Any] | Any = [], default: Any = None, *, ignore_errors: bool = True, -): +) -> Any: """ - retrieve element hierarchically + Retrieve an element from a nested object using hierarchical keys. Args: - obj (object): parent object to retrieve to - levels (Union[list, Any], optional): hierarchy levels. Defaults to []. - default (Any, optional): default value to return - ignore_errors (str, optional): raise errors or ignore them. Defaults to True. + obj (Any): Parent object to traverse. + levels (list[Any] | Any, optional): Hierarchy levels to access. Defaults to []. + default (Any, optional): Value returned when traversal fails and + `ignore_errors` is True. Defaults to None. + ignore_errors (bool, optional): Whether to suppress lookup errors. + Defaults to True. Returns: - _type_: element or None (in case child element doesnt exist and `ignore_errors=True`) + Any: Retrieved element, or `default` when traversal fails and + `ignore_errors` is True. + + Raises: + Exception: Propagates the underlying error when `ignore_errors` is False. """ # if levels not a list handle it has a key @@ -40,7 +46,16 @@ def get_element( raise -def is_url(text: str): +def is_url(text: str) -> bool: + """ + Check whether a string contains a URL-like pattern. + + Args: + text (str): Text to evaluate. + + Returns: + bool: True when a URL-like pattern is found, otherwise False. + """ match = re.findall( r"(http(s)?:\/\/.)(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)", text, @@ -49,11 +64,16 @@ def is_url(text: str): # Taken from https://stackoverflow.com/a/20254842 -def get_recursively(search_dict: dict, field: str) -> list: +def get_recursively(search_dict: dict, field: str) -> list[Any]: """ - Takes a dict with nested lists and dicts, - and searches all dicts for a key of the field - provided. + Search nested dictionaries and lists for values under a target key. + + Args: + search_dict (dict): Dictionary to search recursively. + field (str): Key name to collect. + + Returns: + list[Any]: Values found for `field` across the nested structure. """ fields_found = [] diff --git a/aymurai/utils/pickle_data.py b/aymurai/utils/pickle_data.py index 4d5ceebb..09169ab1 100644 --- a/aymurai/utils/pickle_data.py +++ b/aymurai/utils/pickle_data.py @@ -3,12 +3,28 @@ from typing import Any -def save_pickle(object_: Any, output_path: str): +def save_pickle(object_: Any, output_path: str) -> None: + """ + Serialize and save a Python object to a pickle file. + + Args: + object_ (Any): Object to serialize. + output_path (str): Output file path. + """ with open(output_path, "wb") as f: pickle.dump(object_, f) def load_pickle(input_path: str) -> Any: + """ + Load and deserialize a Python object from a pickle file. + + Args: + input_path (str): Input file path. + + Returns: + Any: Deserialized Python object. + """ with (open(input_path, "rb")) as f: object_ = pickle.load(f) return object_ From 4559764c87b394381b97d061cd438e0b4c311fc3 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Fri, 20 Feb 2026 15:20:09 -0300 Subject: [PATCH 079/104] =?UTF-8?q?=F0=9F=94=A5=20Removed=20PromptLibrary?= =?UTF-8?q?=20class=20from=20aymurai/api/endpoints/routers/anonymizer/anon?= =?UTF-8?q?ymizer.py=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔥 Removed `llm` disambiguation label policy for release/v1.5.0 compatibility --- aymurai/api/endpoints/routers/anonymizer/anonymizer.py | 7 ------- docs/anonymization/README.md | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index c90da84c..6a07fea4 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -27,7 +27,6 @@ DocumentAnnotations, DocumentInformation, LabelPolicy, - PromptLibrary, RenderPolicy, TextRequest, ) @@ -346,12 +345,6 @@ async def anonymizer_disambiguate( "List of per-paragraph predictions returned by /anonymizer/predict." ), ), - custom_prompts: PromptLibrary = Body( - default_factory=PromptLibrary, - description=( - "Set of prompts, user and system, for each label if it is provided." - ), - ), label_policies: dict[str, LabelPolicy] | None = Body( None, diff --git a/docs/anonymization/README.md b/docs/anonymization/README.md index 19603da6..4632d900 100644 --- a/docs/anonymization/README.md +++ b/docs/anonymization/README.md @@ -30,7 +30,7 @@ Se incorpora un esquema de políticas por etiqueta que permite decidir: - `anonymize`: `true | false` -- `disambiguation`: `"none" | "fuzzy" | "llm"` +- `disambiguation`: `"none" | "fuzzy"` - `use_subclass_when_available`: `true | false` Estas políticas pueden venir de: From 35412a47e5db94312ec2ce51b3c0b144300a0fb2 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Fri, 20 Feb 2026 16:02:36 -0300 Subject: [PATCH 080/104] =?UTF-8?q?=F0=9F=8E=A8=20Changed=20map=5Fcanonica?= =?UTF-8?q?l=5Fentities=5Fner=5Fpreds=20function=20in=20aymurai/utils/enti?= =?UTF-8?q?ty=5Fdisambiguation/core.py=20discarding=20the=20role=20assignm?= =?UTF-8?q?ent=20for=20release/v1.5.0=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🎨 Changed aymurai/api/endpoints/routers/anonymizer/anonymizer.py discarding all the validations that had to do with LLM disambiguation for release/v1.5.0 compatibility 🎨 Minor changes in the rest of documents regarding to experimentation with the release/v1.5.0 API --- .../routers/anonymizer/anonymizer.py | 39 +- aymurai/meta/entities.py | 4 +- aymurai/utils/entity_disambiguation/core.py | 68 +-- docs/anonymization/README.md | 6 +- .../10-anonymize-document-render-policy.ipynb | 48 +- uv.lock | 422 ------------------ 6 files changed, 58 insertions(+), 529 deletions(-) diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 6a07fea4..5d9b3cdc 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -352,29 +352,16 @@ async def anonymizer_disambiguate( "Optional per-label policy overrides for disambiguation/anonymization." ), ), - target_labels: list[str] - | None = Query( - None, - description=( - "Optional label filter for LLM refinement (e.g., PER,DNI). " - "Fuzzy clustering still runs across all detected labels." - ), - ), session: Session = Depends(get_session), ) -> DocumentAnnotations: """ - Performs canonical entity disambiguation using fuzzy matching and LLM refinement. + Performs canonical entity disambiguation using fuzzy matching. Args: paragraphs: A list of DocumentInformation objects containing the NER predictions per paragraph that need to be disambiguated. - custom_prompts: A PromptLibrary object containing optional system and - user prompts. If not provided, the service uses the default prompts - configured in the environment. label_policies: Optional per-label disambiguation/anonymization policies. - target_labels: An optional list of entity labels to refine via LLM - (e.g., ["PER", "DNI"]). Fuzzy clustering still runs across all - detected labels. + session: Database session dependency for caching results. Returns: DocumentAnnotations: The original annotations enriched with 'canonical_entity_id' and 'role' fields for each resolved mention. @@ -397,41 +384,28 @@ async def anonymizer_disambiguate( and effective_label_policies.get(label.attrs.aymurai_label).anonymize } - default_llm_labels = target_labels if target_labels else [] - - llm_labels: list[str] = [] fuzzy_labels: set[str] = set() for label in all_detected_labels: policy = effective_label_policies.get(label) - if policy and policy.disambiguation == "llm": - llm_labels.append(label) - fuzzy_labels.add(label) - continue if policy and policy.disambiguation == "fuzzy": fuzzy_labels.add(label) continue if policy and policy.disambiguation == "none": continue - if label in default_llm_labels: - llm_labels.append(label) - fuzzy_labels.add(label) - else: - fuzzy_labels.add(label) + fuzzy_labels.add(label) effective_disambiguation_by_label: dict[str, str] = {} for label in all_detected_labels: - if label in llm_labels: - effective_disambiguation_by_label[label] = "llm" - elif label in fuzzy_labels: + if label in fuzzy_labels: effective_disambiguation_by_label[label] = "fuzzy" else: effective_disambiguation_by_label[label] = "none" logger.info( - "disambiguation targets: detected=%s llm=%s", + "disambiguation targets: detected=%s fuzzy=%s", sorted(all_detected_labels), - llm_labels, + sorted(fuzzy_labels), ) canonical_entities = ( @@ -461,7 +435,6 @@ async def anonymizer_disambiguate( predictions = map_canonical_entities_ner_preds( predictions=paragraphs, canonical_entities=canonical_entities, - force_labels=set(llm_labels), ) for document in predictions: diff --git a/aymurai/meta/entities.py b/aymurai/meta/entities.py index 759167c2..56393e29 100644 --- a/aymurai/meta/entities.py +++ b/aymurai/meta/entities.py @@ -38,9 +38,7 @@ class EntityAttributes(BaseModel): ) aymurai_disambiguation: str | None = Field( None, - description=( - "Override disambiguation mode for this entity (none, fuzzy, llm)." - ), + description=("Override disambiguation mode for this entity (none, fuzzy)."), ) aymurai_anonymize: bool | None = Field( None, diff --git a/aymurai/utils/entity_disambiguation/core.py b/aymurai/utils/entity_disambiguation/core.py index f12bedc4..ffa156fc 100644 --- a/aymurai/utils/entity_disambiguation/core.py +++ b/aymurai/utils/entity_disambiguation/core.py @@ -50,7 +50,6 @@ def map_canonical_entities_ner_preds( canonical_entities: CanonicalEntities, *, include_label_instances: bool = True, - force_labels: set[str] | None = None, ) -> DocumentAnnotations: """ Applies canonical entity IDs and roles back onto NER predictions. @@ -60,15 +59,12 @@ def map_canonical_entities_ner_preds( canonical_entities (CanonicalEntities): Canonical entities with IDs/roles. include_label_instances (bool, optional): Whether to assign ordered label instance indices (e.g., 1, 2). Defaults to True. - force_labels (set[str] | None, optional): Labels to remap even if a - canonical ID already exists. Defaults to None. Returns: DocumentAnnotations: Updated predictions with canonical IDs, roles, and optionally `aymurai_label_instance`. """ predictions_mapped = copy.deepcopy(predictions) - force_labels = force_labels or set() new_ids_map = {} @@ -80,47 +76,31 @@ def map_canonical_entities_ner_preds( if not label.attrs: continue - if label.attrs.aymurai_label_subclass is None: - label.attrs.aymurai_label_subclass = [] - - force_remap = label.attrs.aymurai_label in force_labels - if force_remap: - label.attrs.canonical_entity_id = None - label.attrs.aymurai_label_subclass = [] - - if ( - label.attrs.canonical_entity_id is None - and len(label.attrs.aymurai_label_subclass) == 0 - ): - for ce in canonical_entities: - if label.attrs.aymurai_label == ce.aymurai_label: - entity_id = ce.entity_id - attributes = ce.attributes or {} - role = attributes.get("role") - aliases = ce.aliases - - clean_aliases = [str(a).strip().lower() for a in aliases] - label_text = ( - str(label.attrs.aymurai_alt_text or label.text) - .strip() - .lower() - ) - - if label_text in clean_aliases: - label.attrs.canonical_entity_id = entity_id - if ce.aymurai_label == "PER" and role is not None: - label.attrs.aymurai_label_subclass.append(role) - break - - elif label.attrs.canonical_entity_id is None: - key = ( - label.attrs.aymurai_label, - str(label.attrs.aymurai_alt_text).strip(), - ) - if key not in new_ids_map: - new_ids_map[key] = uuid.uuid4() + for ce in canonical_entities: + if label.attrs.aymurai_label == ce.aymurai_label: + entity_id = ce.entity_id + aliases = ce.aliases + + clean_aliases = [str(a).strip().lower() for a in aliases] + label_text = ( + str(label.attrs.aymurai_alt_text or label.text).strip().lower() + ) + + if label_text in clean_aliases: + label.attrs.canonical_entity_id = entity_id + break + + if label.attrs.canonical_entity_id is not None: + continue + + key = ( + label.attrs.aymurai_label, + str(label.attrs.aymurai_alt_text).strip(), + ) + if key not in new_ids_map: + new_ids_map[key] = uuid.uuid4() - label.attrs.canonical_entity_id = new_ids_map[key] + label.attrs.canonical_entity_id = new_ids_map[key] if include_label_instances: return assign_label_instances(predictions_mapped) diff --git a/docs/anonymization/README.md b/docs/anonymization/README.md index 4632d900..29deee42 100644 --- a/docs/anonymization/README.md +++ b/docs/anonymization/README.md @@ -21,8 +21,8 @@ - `canonical_entity_id`: UUID de la entidad canónica asignada a cada mención. - `aymurai_label_instance`: índice entero por orden de aparición del `canonical_entity_id` dentro de un mismo label (1, 2, 3...). -- `aymurai_label_subclass`: lista de roles inferidos por LLM (p. ej. "Denunciante", "Juez/a"). -- `aymurai_disambiguation`: método aplicado para la desambiguación efectiva del label (`llm`, `fuzzy`, `none`). +- `aymurai_label_subclass`: en el caso de fechas donde encuentra el patrón se escribe la fecha en formato DD/MM/YYYY. +- `aymurai_disambiguation`: método aplicado para la desambiguación efectiva del label (`fuzzy`, `none`). - `aymurai_anonymize`: flag efectivo de anonimización (True/False). ### Políticas por label (nueva interfaz) @@ -59,7 +59,7 @@ El `render_policy` puede definirse por entorno (`RENDER_POLICY`) o por request y - **Nuevo input opcional**: `label_policies`. - **Nuevo output**: `label_policies` y metadatos efectivos en cada `DocLabel` (`aymurai_disambiguation`, `aymurai_anonymize`). -- La selección de labels para LLM/fuzzy se define por políticas, no por un modo global. +- La selección de labels para fuzzy se define por políticas, no por un modo global. ### `/anonymizer/anonymize-document` diff --git a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb index 0a5b279e..a9949050 100644 --- a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb +++ b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb @@ -64,7 +64,7 @@ "\n", "print(f\"Found {len(documents)} documents\")\n", "\n", - "doc_path = documents[16]" + "doc_path = documents[1]" ] }, { @@ -315,7 +315,7 @@ " with open(out_path, \"wb\") as file:\n", " file.write(response.content)\n", "\n", - " return out_path" + " return disambiguated, out_path" ] }, { @@ -337,33 +337,33 @@ " \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", " \"FECHA\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", "}\n", - "out_all_fuzzy = disambiguate_and_export(\n", + "disambiguated_labels_fuzzy, out_all_fuzzy = disambiguate_and_export(\n", " \"all-fuzzy\", label_policies_all_fuzzy, render_policy\n", ")\n", "\n", - "# 2) FECHAs excluded\n", - "label_policies_no_fecha = {\n", - " \"PER\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": True},\n", - " \"DNI\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"LOC\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"FECHA\": {\"disambiguation\": \"none\", \"anonymize\": False, \"use_subclass_when_available\": False},\n", - "}\n", - "out_no_fecha = disambiguate_and_export(\n", - " \"no-fecha\", label_policies_no_fecha, render_policy\n", - ")\n", + "# # 2) FECHAs excluded\n", + "# label_policies_no_fecha = {\n", + "# \"PER\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": True},\n", + "# \"DNI\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + "# \"LOC\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + "# \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + "# \"FECHA\": {\"disambiguation\": \"none\", \"anonymize\": False, \"use_subclass_when_available\": False},\n", + "# }\n", + "# disambiguated_labels_no_fecha, out_no_fecha = disambiguate_and_export(\n", + "# \"no-fecha\", label_policies_no_fecha, render_policy\n", + "# )\n", "\n", - "# 3) PER llm-disambiguated\n", - "label_policies_per_llm = {\n", - " \"PER\": {\"disambiguation\": \"llm\", \"anonymize\": False, \"use_subclass_when_available\": True},\n", - " \"DNI\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"LOC\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"FECHA\": {\"disambiguation\": \"none\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - "}\n", - "out_per_llm = disambiguate_and_export(\"per-llm\", label_policies_per_llm, render_policy)\n", "\n", - "out_all_fuzzy, out_no_fecha, out_per_llm" + "# out_all_fuzzy, out_no_fecha" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "disambiguated_labels_fuzzy" ] } ], diff --git a/uv.lock b/uv.lock index dbcc39c0..538334fc 100644 --- a/uv.lock +++ b/uv.lock @@ -98,22 +98,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554, upload-time = "2025-11-14T20:35:05.699Z" }, ] -[[package]] -name = "altair" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "narwhals" }, - { name = "packaging" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f7/c0/184a89bd5feba14ff3c41cfaf1dd8a82c05f5ceedbc92145e17042eb08a4/altair-6.0.0.tar.gz", hash = "sha256:614bf5ecbe2337347b590afb111929aa9c16c9527c4887d96c9bc7f6640756b4", size = 763834, upload-time = "2025-11-12T08:59:11.519Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/33/ef2f2409450ef6daa61459d5de5c08128e7d3edb773fefd0a324d1310238/altair-6.0.0-py3-none-any.whl", hash = "sha256:09ae95b53d5fe5b16987dccc785a7af8588f2dca50de1e7a156efa8a461515f8", size = 795410, upload-time = "2025-11-12T08:59:09.804Z" }, -] - [[package]] name = "annotated-doc" version = "0.0.4" @@ -236,18 +220,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, ] -[[package]] -name = "asyncer" -version = "0.0.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ff/67/7ea59c3e69eaeee42e7fc91a5be67ca5849c8979acac2b920249760c6af2/asyncer-0.0.8.tar.gz", hash = "sha256:a589d980f57e20efb07ed91d0dbe67f1d2fd343e7142c66d3a099f05c620739c", size = 18217, upload-time = "2024-08-24T23:15:36.449Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/04/15b6ca6b7842eda2748bda0a0af73f2d054e9344320f8bba01f994294bcb/asyncer-0.0.8-py3-none-any.whl", hash = "sha256:5920d48fc99c8f8f0f1576e1882f5022885589c5fcbc46ce4224ec3e53776eeb", size = 9209, upload-time = "2024-08-24T23:15:35.317Z" }, -] - [[package]] name = "attrs" version = "25.4.0" @@ -299,17 +271,14 @@ dependencies = [ [package.dev-dependencies] dev = [ - { name = "dspy" }, { name = "jupyter" }, { name = "matplotlib" }, { name = "nbstripout" }, { name = "pip" }, - { name = "playwright" }, { name = "plotly" }, { name = "pre-commit" }, { name = "rich" }, { name = "seaborn" }, - { name = "streamlit" }, ] [package.metadata] @@ -352,17 +321,14 @@ requires-dist = [ [package.metadata.requires-dev] dev = [ - { name = "dspy", specifier = ">=3.0.4" }, { name = "jupyter", specifier = ">=1.1.1" }, { name = "matplotlib", specifier = ">=3.10.0" }, { name = "nbstripout", specifier = ">=0.8.0" }, { name = "pip", specifier = ">=24.3.1" }, - { name = "playwright", specifier = "==1.56.0" }, { name = "plotly", specifier = ">=5.24.1" }, { name = "pre-commit", specifier = ">=4.0.1" }, { name = "rich", specifier = ">=13.9.4" }, { name = "seaborn", specifier = ">=0.13.2" }, - { name = "streamlit", specifier = ">=1.21.0" }, ] [[package]] @@ -420,15 +386,6 @@ css = [ { name = "tinycss2" }, ] -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - [[package]] name = "boto3" version = "1.42.23" @@ -544,15 +501,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] -[[package]] -name = "cloudpickle" -version = "3.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/27/fb/576f067976d320f5f0114a8d9fa1215425441bb35627b1993e5afd8111e5/cloudpickle-3.1.2.tar.gz", hash = "sha256:7fda9eb655c9c230dab534f1983763de5835249750e85fbcef43aaa30a9a2414", size = 22330, upload-time = "2025-11-03T09:25:26.604Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, -] - [[package]] name = "colorama" version = "0.4.6" @@ -562,18 +510,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, ] -[[package]] -name = "colorlog" -version = "6.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a2/61/f083b5ac52e505dfc1c624eafbf8c7589a0d7f32daa398d2e7590efa5fda/colorlog-6.10.1.tar.gz", hash = "sha256:eb4ae5cb65fe7fec7773c2306061a8e63e02efc2c72eba9d27b0fa23c94f1321", size = 17162, upload-time = "2025-10-16T16:14:11.978Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/c1/e419ef3723a074172b68aaa89c9f3de486ed4c2399e2dbd8113a4fdcaf9e/colorlog-6.10.1-py3-none-any.whl", hash = "sha256:2d7e8348291948af66122cff006c9f8da6255d224e7cf8e37d8de2df3bad8c9c", size = 11743, upload-time = "2025-10-16T16:14:10.512Z" }, -] - [[package]] name = "comm" version = "0.2.3" @@ -725,15 +661,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] -[[package]] -name = "distro" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, -] - [[package]] name = "dnspython" version = "2.8.0" @@ -758,35 +685,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025, upload-time = "2025-03-24T20:59:24.394Z" }, ] -[[package]] -name = "dspy" -version = "3.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "asyncer" }, - { name = "cachetools" }, - { name = "cloudpickle" }, - { name = "diskcache" }, - { name = "gepa" }, - { name = "json-repair" }, - { name = "litellm" }, - { name = "numpy" }, - { name = "openai" }, - { name = "optuna" }, - { name = "orjson" }, - { name = "pydantic" }, - { name = "regex" }, - { name = "requests" }, - { name = "tenacity" }, - { name = "tqdm" }, - { name = "xxhash" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d9/bd/339e1d949aa24e50b6edca8574cf8afbff005a1dfadc2d5b82a0003fa7da/dspy-3.1.0.tar.gz", hash = "sha256:3c1660cb687411f064509cd7ac47ed0231761f50ed92823cbbb59b3af2885702", size = 242611, upload-time = "2026-01-06T18:50:18.655Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/34/64e900657cad3c4df8a417fccbc4370ca851864edbd0f468210f1b57d084/dspy-3.1.0-py3-none-any.whl", hash = "sha256:b9f4d42cad9ac32b13fdf085dd3246c8ee8339c759cb291c5e7b7f9f5fb5dd72", size = 291317, upload-time = "2026-01-06T18:50:17.559Z" }, -] - [[package]] name = "email-validator" version = "2.3.0" @@ -943,25 +841,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, ] -[[package]] -name = "fastuuid" -version = "0.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c3/7d/d9daedf0f2ebcacd20d599928f8913e9d2aea1d56d2d355a93bfa2b611d7/fastuuid-0.14.0.tar.gz", hash = "sha256:178947fc2f995b38497a74172adee64fdeb8b7ec18f2a5934d037641ba265d26", size = 18232, upload-time = "2025-10-19T22:19:22.402Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/b2/731a6696e37cd20eed353f69a09f37a984a43c9713764ee3f7ad5f57f7f9/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6e6243d40f6c793c3e2ee14c13769e341b90be5ef0c23c82fa6515a96145181a", size = 516760, upload-time = "2025-10-19T22:25:21.509Z" }, - { url = "https://files.pythonhosted.org/packages/c5/79/c73c47be2a3b8734d16e628982653517f80bbe0570e27185d91af6096507/fastuuid-0.14.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:13ec4f2c3b04271f62be2e1ce7e95ad2dd1cf97e94503a3760db739afbd48f00", size = 264748, upload-time = "2025-10-19T22:41:52.873Z" }, - { url = "https://files.pythonhosted.org/packages/24/c5/84c1eea05977c8ba5173555b0133e3558dc628bcf868d6bf1689ff14aedc/fastuuid-0.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b2fdd48b5e4236df145a149d7125badb28e0a383372add3fbaac9a6b7a394470", size = 254537, upload-time = "2025-10-19T22:33:55.603Z" }, - { url = "https://files.pythonhosted.org/packages/0e/23/4e362367b7fa17dbed646922f216b9921efb486e7abe02147e4b917359f8/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f74631b8322d2780ebcf2d2d75d58045c3e9378625ec51865fe0b5620800c39d", size = 278994, upload-time = "2025-10-19T22:26:17.631Z" }, - { url = "https://files.pythonhosted.org/packages/b2/72/3985be633b5a428e9eaec4287ed4b873b7c4c53a9639a8b416637223c4cd/fastuuid-0.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83cffc144dc93eb604b87b179837f2ce2af44871a7b323f2bfed40e8acb40ba8", size = 280003, upload-time = "2025-10-19T22:23:45.415Z" }, - { url = "https://files.pythonhosted.org/packages/b3/6d/6ef192a6df34e2266d5c9deb39cd3eea986df650cbcfeaf171aa52a059c3/fastuuid-0.14.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a771f135ab4523eb786e95493803942a5d1fc1610915f131b363f55af53b219", size = 303583, upload-time = "2025-10-19T22:26:00.756Z" }, - { url = "https://files.pythonhosted.org/packages/9d/11/8a2ea753c68d4fece29d5d7c6f3f903948cc6e82d1823bc9f7f7c0355db3/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4edc56b877d960b4eda2c4232f953a61490c3134da94f3c28af129fb9c62a4f6", size = 460955, upload-time = "2025-10-19T22:36:25.196Z" }, - { url = "https://files.pythonhosted.org/packages/23/42/7a32c93b6ce12642d9a152ee4753a078f372c9ebb893bc489d838dd4afd5/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bcc96ee819c282e7c09b2eed2b9bd13084e3b749fdb2faf58c318d498df2efbe", size = 480763, upload-time = "2025-10-19T22:24:28.451Z" }, - { url = "https://files.pythonhosted.org/packages/b9/e9/a5f6f686b46e3ed4ed3b93770111c233baac87dd6586a411b4988018ef1d/fastuuid-0.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7a3c0bca61eacc1843ea97b288d6789fbad7400d16db24e36a66c28c268cfe3d", size = 452613, upload-time = "2025-10-19T22:25:06.827Z" }, - { url = "https://files.pythonhosted.org/packages/b4/c9/18abc73c9c5b7fc0e476c1733b678783b2e8a35b0be9babd423571d44e98/fastuuid-0.14.0-cp310-cp310-win32.whl", hash = "sha256:7f2f3efade4937fae4e77efae1af571902263de7b78a0aee1a1653795a093b2a", size = 155045, upload-time = "2025-10-19T22:28:32.732Z" }, - { url = "https://files.pythonhosted.org/packages/5e/8a/d9e33f4eb4d4f6d9f2c5c7d7e96b5cdbb535c93f3b1ad6acce97ee9d4bf8/fastuuid-0.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ae64ba730d179f439b0736208b4c279b8bc9c089b102aec23f86512ea458c8a4", size = 156122, upload-time = "2025-10-19T22:23:15.59Z" }, -] - [[package]] name = "filelock" version = "3.20.2" @@ -1111,39 +990,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/54/70/e07c381e6488a77094f04c85c9caf1c8008cdc30778f7019bc52e5285ef0/gdown-5.2.0-py3-none-any.whl", hash = "sha256:33083832d82b1101bdd0e9df3edd0fbc0e1c5f14c9d8c38d2a35bf1683b526d6", size = 18235, upload-time = "2024-05-12T06:45:10.017Z" }, ] -[[package]] -name = "gepa" -version = "0.0.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ae/be/9a4c31c65c4910e73bd4a316df99347681bce4f2ef6d10877cc1ed8d57da/gepa-0.0.22.tar.gz", hash = "sha256:0b13a644efd2af52186e456eaad2ae28fcf88c6f796a9c999910c587863d4315", size = 116337, upload-time = "2025-11-10T21:39:27.044Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/0e/d41272b28f2163f5bf840b508cbaf4a0bc01eaeaa6e5d447558d1050eb3b/gepa-0.0.22-py3-none-any.whl", hash = "sha256:ff57ee0442399a5cc62d01411935476bc80cfa8f1c318bed82e3db4c2c834665", size = 119666, upload-time = "2025-11-10T21:39:26.028Z" }, -] - -[[package]] -name = "gitdb" -version = "4.0.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "smmap" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/72/94/63b0fc47eb32792c7ba1fe1b694daec9a63620db1e313033d18140c2320a/gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571", size = 394684, upload-time = "2025-01-02T07:20:46.413Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf", size = 62794, upload-time = "2025-01-02T07:20:43.624Z" }, -] - -[[package]] -name = "gitpython" -version = "3.1.46" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "gitdb" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/b5/59d16470a1f0dfe8c793f9ef56fd3826093fc52b3bd96d6b9d6c26c7e27b/gitpython-3.1.46.tar.gz", hash = "sha256:400124c7d0ef4ea03f7310ac2fbf7151e09ff97f2a3288d64a440c584a29c37f", size = 215371, upload-time = "2026-01-01T15:37:32.073Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/09/e21df6aef1e1ffc0c816f0522ddc3f6dcded766c3261813131c78a704470/gitpython-3.1.46-py3-none-any.whl", hash = "sha256:79812ed143d9d25b6d176a10bb511de0f9c67b1fa641d82097b0ab90398a2058", size = 208620, upload-time = "2026-01-01T15:37:30.574Z" }, -] - [[package]] name = "greenlet" version = "3.3.0" @@ -1264,18 +1110,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, ] -[[package]] -name = "importlib-metadata" -version = "8.7.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "zipp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/49/3b30cad09e7771a4982d9975a8cbf64f00d4a1ececb53297f1d9a7be1b10/importlib_metadata-8.7.1.tar.gz", hash = "sha256:49fef1ae6440c182052f407c8d34a68f72efc36db9ca90dc0113398f2fdde8bb", size = 57107, upload-time = "2025-12-21T10:00:19.278Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, -] - [[package]] name = "intervaltree" version = "3.2.1" @@ -1386,26 +1220,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] -[[package]] -name = "jiter" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/45/9d/e0660989c1370e25848bb4c52d061c71837239738ad937e83edca174c273/jiter-0.12.0.tar.gz", hash = "sha256:64dfcd7d5c168b38d3f9f8bba7fc639edb3418abcc74f22fdbe6b8938293f30b", size = 168294, upload-time = "2025-11-09T20:49:23.302Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/91/13cb9505f7be74a933f37da3af22e029f6ba64f5669416cb8b2774bc9682/jiter-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:e7acbaba9703d5de82a2c98ae6a0f59ab9770ab5af5fa35e43a303aee962cf65", size = 316652, upload-time = "2025-11-09T20:46:41.021Z" }, - { url = "https://files.pythonhosted.org/packages/4e/76/4e9185e5d9bb4e482cf6dec6410d5f78dfeb374cfcecbbe9888d07c52daa/jiter-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:364f1a7294c91281260364222f535bc427f56d4de1d8ffd718162d21fbbd602e", size = 319829, upload-time = "2025-11-09T20:46:43.281Z" }, - { url = "https://files.pythonhosted.org/packages/86/af/727de50995d3a153138139f259baae2379d8cb0522c0c00419957bc478a6/jiter-0.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85ee4d25805d4fb23f0a5167a962ef8e002dbfb29c0989378488e32cf2744b62", size = 350568, upload-time = "2025-11-09T20:46:45.075Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c1/d6e9f4b7a3d5ac63bcbdfddeb50b2dcfbdc512c86cffc008584fdc350233/jiter-0.12.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:796f466b7942107eb889c08433b6e31b9a7ed31daceaecf8af1be26fb26c0ca8", size = 369052, upload-time = "2025-11-09T20:46:46.818Z" }, - { url = "https://files.pythonhosted.org/packages/eb/be/00824cd530f30ed73fa8a4f9f3890a705519e31ccb9e929f1e22062e7c76/jiter-0.12.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35506cb71f47dba416694e67af996bbdefb8e3608f1f78799c2e1f9058b01ceb", size = 481585, upload-time = "2025-11-09T20:46:48.319Z" }, - { url = "https://files.pythonhosted.org/packages/74/b6/2ad7990dff9504d4b5052eef64aa9574bd03d722dc7edced97aad0d47be7/jiter-0.12.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:726c764a90c9218ec9e4f99a33d6bf5ec169163f2ca0fc21b654e88c2abc0abc", size = 380541, upload-time = "2025-11-09T20:46:49.643Z" }, - { url = "https://files.pythonhosted.org/packages/b5/c7/f3c26ecbc1adbf1db0d6bba99192143d8fe8504729d9594542ecc4445784/jiter-0.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa47810c5565274810b726b0dc86d18dce5fd17b190ebdc3890851d7b2a0e74", size = 364423, upload-time = "2025-11-09T20:46:51.731Z" }, - { url = "https://files.pythonhosted.org/packages/18/51/eac547bf3a2d7f7e556927278e14c56a0604b8cddae75815d5739f65f81d/jiter-0.12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ec0259d3f26c62aed4d73b198c53e316ae11f0f69c8fbe6682c6dcfa0fcce2", size = 389958, upload-time = "2025-11-09T20:46:53.432Z" }, - { url = "https://files.pythonhosted.org/packages/2c/1f/9ca592e67175f2db156cff035e0d817d6004e293ee0c1d73692d38fcb596/jiter-0.12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:79307d74ea83465b0152fa23e5e297149506435535282f979f18b9033c0bb025", size = 522084, upload-time = "2025-11-09T20:46:54.848Z" }, - { url = "https://files.pythonhosted.org/packages/83/ff/597d9cdc3028f28224f53e1a9d063628e28b7a5601433e3196edda578cdd/jiter-0.12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cf6e6dd18927121fec86739f1a8906944703941d000f0639f3eb6281cc601dca", size = 513054, upload-time = "2025-11-09T20:46:56.487Z" }, - { url = "https://files.pythonhosted.org/packages/24/6d/1970bce1351bd02e3afcc5f49e4f7ef3dabd7fb688f42be7e8091a5b809a/jiter-0.12.0-cp310-cp310-win32.whl", hash = "sha256:b6ae2aec8217327d872cbfb2c1694489057b9433afce447955763e6ab015b4c4", size = 206368, upload-time = "2025-11-09T20:46:58.638Z" }, - { url = "https://files.pythonhosted.org/packages/e3/6b/eb1eb505b2d86709b59ec06681a2b14a94d0941db091f044b9f0e16badc0/jiter-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:c7f49ce90a71e44f7e1aa9e7ec415b9686bbc6a5961e57eab511015e6759bc11", size = 204847, upload-time = "2025-11-09T20:47:00.295Z" }, -] - [[package]] name = "jiwer" version = "3.0.5" @@ -1437,15 +1251,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, ] -[[package]] -name = "json-repair" -version = "0.55.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/74/0f39677fa7c0127129c3f1a37c94d05c30a968ba3047200e54dea375b09a/json_repair-0.55.0.tar.gz", hash = "sha256:9fafb47d92582ef4bdd3520656bdb0fcb37b46cf6aa99c1926b7895abc0a3a4b", size = 38828, upload-time = "2026-01-01T20:29:02.684Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/00/d7d6b6b3257f9b1f997a558b6f7087b8af7c0a2f525f4fbd864c267a88ab/json_repair-0.55.0-py3-none-any.whl", hash = "sha256:bcf4880f5e6ad21a0f70ab034e3d1d398c2ae9698dc5717d7015afbac77b8ed7", size = 29570, upload-time = "2026-01-01T20:29:01.042Z" }, -] - [[package]] name = "json5" version = "0.13.0" @@ -1772,29 +1577,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594, upload-time = "2022-09-06T16:09:04.658Z" }, ] -[[package]] -name = "litellm" -version = "1.80.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "click" }, - { name = "fastuuid" }, - { name = "httpx" }, - { name = "importlib-metadata" }, - { name = "jinja2" }, - { name = "jsonschema" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "tiktoken" }, - { name = "tokenizers" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/bd/8c/48d533affdbc6d485b7ad4221cd3b40b8c12f9f5568edfe0be0b11e7b945/litellm-1.80.0.tar.gz", hash = "sha256:eeac733eb6b226f9e5fb020f72fe13a32b3354b001dc62bcf1bc4d9b526d6231", size = 11591976, upload-time = "2025-11-16T00:03:51.812Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ea/53/aa31e4d057b3746b3c323ca993003d6cf15ef987e7fe7ceb53681695ae87/litellm-1.80.0-py3-none-any.whl", hash = "sha256:fd0009758f4772257048d74bf79bb64318859adb4ea49a8b66fdbc718cd80b6e", size = 10492975, upload-time = "2025-11-16T00:03:49.182Z" }, -] - [[package]] name = "lxml" version = "6.0.2" @@ -2297,64 +2079,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045, upload-time = "2020-01-18T16:55:48.852Z" } -[[package]] -name = "openai" -version = "1.109.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "httpx" }, - { name = "jiter" }, - { name = "pydantic" }, - { name = "sniffio" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/a1/a303104dc55fc546a3f6914c842d3da471c64eec92043aef8f652eb6c524/openai-1.109.1.tar.gz", hash = "sha256:d173ed8dbca665892a6db099b4a2dfac624f94d20a93f46eb0b56aae940ed869", size = 564133, upload-time = "2025-09-24T13:00:53.075Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/2a/7dd3d207ec669cacc1f186fd856a0f61dbc255d24f6fdc1a6715d6051b0f/openai-1.109.1-py3-none-any.whl", hash = "sha256:6bcaf57086cf59159b8e27447e4e7dd019db5d29a438072fbd49c290c7e65315", size = 948627, upload-time = "2025-09-24T13:00:50.754Z" }, -] - -[[package]] -name = "optuna" -version = "4.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "alembic" }, - { name = "colorlog" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "sqlalchemy" }, - { name = "tqdm" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6b/81/08f90f194eed78178064a9383432eca95611e2c5331e7b01e2418ce4b15a/optuna-4.6.0.tar.gz", hash = "sha256:89e38c2447c7f793a726617b8043f01e31f0bad54855040db17eb3b49404a369", size = 477444, upload-time = "2025-11-10T05:14:30.151Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/de/3d8455b08cb6312f8cc46aacdf16c71d4d881a1db4a4140fc5ef31108422/optuna-4.6.0-py3-none-any.whl", hash = "sha256:4c3a9facdef2b2dd7e3e2a8ae3697effa70fae4056fcf3425cfc6f5a40feb069", size = 404708, upload-time = "2025-11-10T05:14:28.6Z" }, -] - -[[package]] -name = "orjson" -version = "3.11.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/b8/333fdb27840f3bf04022d21b654a35f58e15407183aeb16f3b41aa053446/orjson-3.11.5.tar.gz", hash = "sha256:82393ab47b4fe44ffd0a7659fa9cfaacc717eb617c93cde83795f14af5c2e9d5", size = 5972347, upload-time = "2025-12-06T15:55:39.458Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/19/b22cf9dad4db20c8737041046054cbd4f38bb5a2d0e4bb60487832ce3d76/orjson-3.11.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:df9eadb2a6386d5ea2bfd81309c505e125cfc9ba2b1b99a97e60985b0b3665d1", size = 245719, upload-time = "2025-12-06T15:53:43.877Z" }, - { url = "https://files.pythonhosted.org/packages/03/2e/b136dd6bf30ef5143fbe76a4c142828b55ccc618be490201e9073ad954a1/orjson-3.11.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc70da619744467d8f1f49a8cadae5ec7bbe054e5232d95f92ed8737f8c5870", size = 132467, upload-time = "2025-12-06T15:53:45.379Z" }, - { url = "https://files.pythonhosted.org/packages/ae/fc/ae99bfc1e1887d20a0268f0e2686eb5b13d0ea7bbe01de2b566febcd2130/orjson-3.11.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:073aab025294c2f6fc0807201c76fdaed86f8fc4be52c440fb78fbb759a1ac09", size = 130702, upload-time = "2025-12-06T15:53:46.659Z" }, - { url = "https://files.pythonhosted.org/packages/6e/43/ef7912144097765997170aca59249725c3ab8ef6079f93f9d708dd058df5/orjson-3.11.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:835f26fa24ba0bb8c53ae2a9328d1706135b74ec653ed933869b74b6909e63fd", size = 135907, upload-time = "2025-12-06T15:53:48.487Z" }, - { url = "https://files.pythonhosted.org/packages/3f/da/24d50e2d7f4092ddd4d784e37a3fa41f22ce8ed97abc9edd222901a96e74/orjson-3.11.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667c132f1f3651c14522a119e4dd631fad98761fa960c55e8e7430bb2a1ba4ac", size = 139935, upload-time = "2025-12-06T15:53:49.88Z" }, - { url = "https://files.pythonhosted.org/packages/02/4a/b4cb6fcbfff5b95a3a019a8648255a0fac9b221fbf6b6e72be8df2361feb/orjson-3.11.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42e8961196af655bb5e63ce6c60d25e8798cd4dfbc04f4203457fa3869322c2e", size = 137541, upload-time = "2025-12-06T15:53:51.226Z" }, - { url = "https://files.pythonhosted.org/packages/a5/99/a11bd129f18c2377c27b2846a9d9be04acec981f770d711ba0aaea563984/orjson-3.11.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75412ca06e20904c19170f8a24486c4e6c7887dea591ba18a1ab572f1300ee9f", size = 139031, upload-time = "2025-12-06T15:53:52.309Z" }, - { url = "https://files.pythonhosted.org/packages/64/29/d7b77d7911574733a036bb3e8ad7053ceb2b7d6ea42208b9dbc55b23b9ed/orjson-3.11.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6af8680328c69e15324b5af3ae38abbfcf9cbec37b5346ebfd52339c3d7e8a18", size = 141622, upload-time = "2025-12-06T15:53:53.606Z" }, - { url = "https://files.pythonhosted.org/packages/93/41/332db96c1de76b2feda4f453e91c27202cd092835936ce2b70828212f726/orjson-3.11.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a86fe4ff4ea523eac8f4b57fdac319faf037d3c1be12405e6a7e86b3fbc4756a", size = 413800, upload-time = "2025-12-06T15:53:54.866Z" }, - { url = "https://files.pythonhosted.org/packages/76/e1/5a0d148dd1f89ad2f9651df67835b209ab7fcb1118658cf353425d7563e9/orjson-3.11.5-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e607b49b1a106ee2086633167033afbd63f76f2999e9236f638b06b112b24ea7", size = 151198, upload-time = "2025-12-06T15:53:56.383Z" }, - { url = "https://files.pythonhosted.org/packages/0d/96/8db67430d317a01ae5cf7971914f6775affdcfe99f5bff9ef3da32492ecc/orjson-3.11.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7339f41c244d0eea251637727f016b3d20050636695bc78345cce9029b189401", size = 141984, upload-time = "2025-12-06T15:53:57.746Z" }, - { url = "https://files.pythonhosted.org/packages/71/49/40d21e1aa1ac569e521069228bb29c9b5a350344ccf922a0227d93c2ed44/orjson-3.11.5-cp310-cp310-win32.whl", hash = "sha256:8be318da8413cdbbce77b8c5fac8d13f6eb0f0db41b30bb598631412619572e8", size = 135272, upload-time = "2025-12-06T15:53:59.769Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7e/d0e31e78be0c100e08be64f48d2850b23bcb4d4c70d114f4e43b39f6895a/orjson-3.11.5-cp310-cp310-win_amd64.whl", hash = "sha256:b9f86d69ae822cabc2a0f6c099b43e8733dda788405cba2665595b7e8dd8d167", size = 133360, upload-time = "2025-12-06T15:54:01.25Z" }, -] - [[package]] name = "overrides" version = "7.7.0" @@ -2468,25 +2192,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, ] -[[package]] -name = "playwright" -version = "1.56.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "greenlet" }, - { name = "pyee" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/31/a5362cee43f844509f1f10d8a27c9cc0e2f7bdce5353d304d93b2151c1b1/playwright-1.56.0-py3-none-macosx_10_13_x86_64.whl", hash = "sha256:b33eb89c516cbc6723f2e3523bada4a4eb0984a9c411325c02d7016a5d625e9c", size = 40611424, upload-time = "2025-11-11T18:39:10.175Z" }, - { url = "https://files.pythonhosted.org/packages/ef/95/347eef596d8778fb53590dc326c344d427fa19ba3d42b646fce2a4572eb3/playwright-1.56.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:b228b3395212b9472a4ee5f1afe40d376eef9568eb039fcb3e563de8f4f4657b", size = 39400228, upload-time = "2025-11-11T18:39:13.915Z" }, - { url = "https://files.pythonhosted.org/packages/b9/54/6ad97b08b2ca1dfcb4fbde4536c4f45c0d9d8b1857a2d20e7bbfdf43bf15/playwright-1.56.0-py3-none-macosx_11_0_universal2.whl", hash = "sha256:0ef7e6fd653267798a8a968ff7aa2dcac14398b7dd7440ef57524e01e0fbbd65", size = 40611424, upload-time = "2025-11-11T18:39:17.093Z" }, - { url = "https://files.pythonhosted.org/packages/e4/76/6d409e37e82cdd5dda3df1ab958130ae32b46e42458bd4fc93d7eb8749cb/playwright-1.56.0-py3-none-manylinux1_x86_64.whl", hash = "sha256:404be089b49d94bc4c1fe0dfb07664bda5ffe87789034a03bffb884489bdfb5c", size = 46263122, upload-time = "2025-11-11T18:39:20.619Z" }, - { url = "https://files.pythonhosted.org/packages/4f/84/fb292cc5d45f3252e255ea39066cd1d2385c61c6c1596548dfbf59c88605/playwright-1.56.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64cda7cf4e51c0d35dab55190841bfcdfb5871685ec22cb722cd0ad2df183e34", size = 46110645, upload-time = "2025-11-11T18:39:24.005Z" }, - { url = "https://files.pythonhosted.org/packages/61/bd/8c02c3388ae14edc374ac9f22cbe4e14826c6a51b2d8eaf86e89fabee264/playwright-1.56.0-py3-none-win32.whl", hash = "sha256:d87b79bcb082092d916a332c27ec9732e0418c319755d235d93cc6be13bdd721", size = 35639837, upload-time = "2025-11-11T18:39:27.174Z" }, - { url = "https://files.pythonhosted.org/packages/64/27/f13b538fbc6b7a00152f4379054a49f6abc0bf55ac86f677ae54bc49fb82/playwright-1.56.0-py3-none-win_amd64.whl", hash = "sha256:3c7fc49bb9e673489bf2622855f9486d41c5101bbed964638552b864c4591f94", size = 35639843, upload-time = "2025-11-11T18:39:30.851Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c7/3ee8b556107995846576b4fe42a08ed49b8677619421f2afacf6ee421138/playwright-1.56.0-py3-none-win_arm64.whl", hash = "sha256:2745490ae8dd58d27e5ea4d9aa28402e8e2991eb84fb4b2fd5fbde2106716f6f", size = 31248959, upload-time = "2025-11-11T18:39:33.998Z" }, -] - [[package]] name = "plotly" version = "6.5.0" @@ -2718,31 +2423,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, ] -[[package]] -name = "pydeck" -version = "0.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jinja2" }, - { name = "numpy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/ca/40e14e196864a0f61a92abb14d09b3d3da98f94ccb03b49cf51688140dab/pydeck-0.9.1.tar.gz", hash = "sha256:f74475ae637951d63f2ee58326757f8d4f9cd9f2a457cf42950715003e2cb605", size = 3832240, upload-time = "2024-05-10T15:36:21.153Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl", hash = "sha256:b3f75ba0d273fc917094fa61224f3f6076ca8752b93d46faf3bcfd9f9d59b038", size = 6900403, upload-time = "2024-05-10T15:36:17.36Z" }, -] - -[[package]] -name = "pyee" -version = "13.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/03/1fd98d5841cd7964a27d729ccf2199602fe05eb7a405c1462eb7277945ed/pyee-13.0.0.tar.gz", hash = "sha256:b391e3c5a434d1f5118a25615001dbc8f669cf410ab67d04c4d4e07c55481c37", size = 31250, upload-time = "2025-03-17T18:53:15.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/4d/b9add7c84060d4c1906abe9a7e5359f2a60f7a9a4f67268b2766673427d8/pyee-13.0.0-py3-none-any.whl", hash = "sha256:48195a3cddb3b1515ce0695ed76036b5ccc2ef3a9f963ff9f77aec0139845498", size = 15730, upload-time = "2025-03-17T18:53:14.532Z" }, -] - [[package]] name = "pygments" version = "2.19.2" @@ -3342,24 +3022,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] -[[package]] -name = "smmap" -version = "5.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/44/cd/a040c4b3119bbe532e5b0732286f805445375489fceaec1f48306068ee3b/smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5", size = 22329, upload-time = "2025-01-02T07:14:40.909Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e", size = 24303, upload-time = "2025-01-02T07:14:38.724Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - [[package]] name = "sortedcontainers" version = "2.4.0" @@ -3444,35 +3106,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, ] -[[package]] -name = "streamlit" -version = "1.52.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "altair" }, - { name = "blinker" }, - { name = "cachetools" }, - { name = "click" }, - { name = "gitpython" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pandas" }, - { name = "pillow" }, - { name = "protobuf" }, - { name = "pyarrow" }, - { name = "pydeck" }, - { name = "requests" }, - { name = "tenacity" }, - { name = "toml" }, - { name = "tornado" }, - { name = "typing-extensions" }, - { name = "watchdog", marker = "sys_platform != 'darwin'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/43/20/434aaceccc6e1912671d869926103051330437adba72d538d787a07727ef/streamlit-1.52.2.tar.gz", hash = "sha256:64a4dda8bc5cdd37bfd490e93bb53da35aaef946fcfc283a7980dacdf165108b", size = 8584178, upload-time = "2025-12-17T17:07:59.642Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/95/6b7873f0267973ebd55ba9cd33a690b35a116f2779901ef6185a0e21864d/streamlit-1.52.2-py3-none-any.whl", hash = "sha256:a16bb4fbc9781e173ce9dfbd8ffb189c174f148f9ca4fb8fa56423e84e193fc8", size = 9025937, upload-time = "2025-12-17T17:07:57.67Z" }, -] - [[package]] name = "sympy" version = "1.14.0" @@ -3549,25 +3182,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, ] -[[package]] -name = "tiktoken" -version = "0.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991, upload-time = "2025-10-06T20:21:34.098Z" }, - { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798, upload-time = "2025-10-06T20:21:35.579Z" }, - { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865, upload-time = "2025-10-06T20:21:36.675Z" }, - { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856, upload-time = "2025-10-06T20:21:37.873Z" }, - { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308, upload-time = "2025-10-06T20:21:39.577Z" }, - { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697, upload-time = "2025-10-06T20:21:41.154Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375, upload-time = "2025-10-06T20:21:43.201Z" }, -] - [[package]] name = "tinycss2" version = "1.4.0" @@ -3610,15 +3224,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" }, ] -[[package]] -name = "toml" -version = "0.10.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/ba/1f744cdc819428fc6b5084ec34d9b30660f6f9daaf70eead706e3203ec3c/toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f", size = 22253, upload-time = "2020-11-01T01:40:22.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/44/6f/7120676b6d73228c96e17f1f794d8ab046fc910d781c8d151120c3f1569e/toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", size = 16588, upload-time = "2020-11-01T01:40:20.672Z" }, -] - [[package]] name = "tomli" version = "2.3.0" @@ -3895,24 +3500,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, ] -[[package]] -name = "watchdog" -version = "6.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/db/7d/7f3d619e951c88ed75c6037b246ddcf2d322812ee8ea189be89511721d54/watchdog-6.0.0.tar.gz", hash = "sha256:9ddf7c82fda3ae8e24decda1338ede66e1c99883db93711d8fb941eaa2d8c282", size = 131220, upload-time = "2024-11-01T14:07:13.037Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/c7/ca4bf3e518cb57a686b2feb4f55a1892fd9a3dd13f470fca14e00f80ea36/watchdog-6.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7607498efa04a3542ae3e05e64da8202e58159aa1fa4acddf7678d34a35d4f13", size = 79079, upload-time = "2024-11-01T14:06:59.472Z" }, - { url = "https://files.pythonhosted.org/packages/5c/51/d46dc9332f9a647593c947b4b88e2381c8dfc0942d15b8edc0310fa4abb1/watchdog-6.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:9041567ee8953024c83343288ccc458fd0a2d811d6a0fd68c4c22609e3490379", size = 79078, upload-time = "2024-11-01T14:07:01.431Z" }, - { url = "https://files.pythonhosted.org/packages/d4/57/04edbf5e169cd318d5f07b4766fee38e825d64b6913ca157ca32d1a42267/watchdog-6.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:82dc3e3143c7e38ec49d61af98d6558288c415eac98486a5c581726e0737c00e", size = 79076, upload-time = "2024-11-01T14:07:02.568Z" }, - { url = "https://files.pythonhosted.org/packages/ab/cc/da8422b300e13cb187d2203f20b9253e91058aaf7db65b74142013478e66/watchdog-6.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:212ac9b8bf1161dc91bd09c048048a95ca3a4c4f5e5d4a7d1b1a7d5752a7f96f", size = 79077, upload-time = "2024-11-01T14:07:03.893Z" }, - { url = "https://files.pythonhosted.org/packages/2c/3b/b8964e04ae1a025c44ba8e4291f86e97fac443bca31de8bd98d3263d2fcf/watchdog-6.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:e3df4cbb9a450c6d49318f6d14f4bbc80d763fa587ba46ec86f99f9e6876bb26", size = 79078, upload-time = "2024-11-01T14:07:05.189Z" }, - { url = "https://files.pythonhosted.org/packages/62/ae/a696eb424bedff7407801c257d4b1afda455fe40821a2be430e173660e81/watchdog-6.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:2cce7cfc2008eb51feb6aab51251fd79b85d9894e98ba847408f662b3395ca3c", size = 79077, upload-time = "2024-11-01T14:07:06.376Z" }, - { url = "https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:20ffe5b202af80ab4266dcd3e91aae72bf2da48c0d33bdb15c66658e685e94e2", size = 79078, upload-time = "2024-11-01T14:07:07.547Z" }, - { url = "https://files.pythonhosted.org/packages/07/f6/d0e5b343768e8bcb4cda79f0f2f55051bf26177ecd5651f84c07567461cf/watchdog-6.0.0-py3-none-win32.whl", hash = "sha256:07df1fdd701c5d4c8e55ef6cf55b8f0120fe1aef7ef39a1c6fc6bc2e606d517a", size = 79065, upload-time = "2024-11-01T14:07:09.525Z" }, - { url = "https://files.pythonhosted.org/packages/db/d9/c495884c6e548fce18a8f40568ff120bc3a4b7b99813081c8ac0c936fa64/watchdog-6.0.0-py3-none-win_amd64.whl", hash = "sha256:cbafb470cf848d93b5d013e2ecb245d4aa1c8fd0504e863ccefa32445359d680", size = 79070, upload-time = "2024-11-01T14:07:10.686Z" }, - { url = "https://files.pythonhosted.org/packages/33/e8/e40370e6d74ddba47f002a32919d91310d6074130fe4e17dabcafc15cbf1/watchdog-6.0.0-py3-none-win_ia64.whl", hash = "sha256:a1914259fa9e1454315171103c6a30961236f508b9b623eae470268bbcc6a22f", size = 79067, upload-time = "2024-11-01T14:07:11.845Z" }, -] - [[package]] name = "watchfiles" version = "1.1.1" @@ -4102,12 +3689,3 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, ] - -[[package]] -name = "zipp" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, -] From 014b28e115a43d4d6b656d25554ecde35646642d Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 19:50:49 +0000 Subject: [PATCH 081/104] =?UTF-8?q?=F0=9F=94=80=20Synthesize=20document=5F?= =?UTF-8?q?extract=20from=20d349c69=20after=203c55d8e:=20remove=20extracto?= =?UTF-8?q?r=20config=20passthrough=20and=20restore=20fixed=20timeout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routers/misc/document_extract.py | 37 ++++--------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/aymurai/api/endpoints/routers/misc/document_extract.py b/aymurai/api/endpoints/routers/misc/document_extract.py index 11354a0e..37b7d0a4 100644 --- a/aymurai/api/endpoints/routers/misc/document_extract.py +++ b/aymurai/api/endpoints/routers/misc/document_extract.py @@ -19,32 +19,24 @@ router = APIRouter() -def extraction( - path: str, - use_cache: bool = True, - **kwargs, -) -> str: +def extraction(path: str) -> str: """ Wrapper function to call the extract_document function. This is necessary to ensure that the function can be pickled and run in a separate process. Args: path (str): Path to the file to be processed. - use_cache (bool): Whether to use caching for the extraction. - **kwargs: Extractor-specific configuration overrides. Returns: str: Extracted text from the document. """ - text = extract_document(path, use_cache=use_cache, **kwargs) + text = extract_document(path) return document_normalize(text) if text else "" def run_safe_text_extraction( path: str, - timeout_s: float | None = None, - use_cache: bool = True, - **kwargs, + timeout_s: float | None = 30, ) -> str: """ Runs the text extraction in a separate process to avoid blocking the main thread. @@ -53,9 +45,7 @@ def run_safe_text_extraction( Args: path (str): Path to the file to be processed. timeout_s (float | None): Timeout in seconds for the extraction process. - If None, waits indefinitely. Defaults to None. - use_cache (bool): Whether to use caching for the extraction. - **kwargs: Extractor-specific configuration overrides. + If None, waits indefinitely. Defaults to 30. Returns: str: Extracted text from the document. @@ -64,7 +54,7 @@ def run_safe_text_extraction( TimeoutError: If the extraction process exceeds the specified timeout. """ with concurrent.futures.ProcessPoolExecutor(max_workers=1) as executor: - future = executor.submit(extraction, path, use_cache, **kwargs) + future = executor.submit(extraction, path) try: return future.result(timeout=timeout_s) except concurrent.futures.TimeoutError: @@ -74,20 +64,12 @@ def run_safe_text_extraction( @router.post("/document-extract", response_model=Document) -def plain_text_extractor( - file: UploadFile, - use_cache: bool = True, - y_tolerance: float | None = None, - debug: bool | None = None, -) -> Document: +def plain_text_extractor(file: UploadFile) -> Document: """ Extract plain text from an uploaded document. Args: file (UploadFile): Incoming document upload. - use_cache (bool): Whether to use caching for the extraction. Defaults to True. - y_tolerance (float | None): Optional vertical tolerance for PDF paragraph merging. Defaults to None. - debug (bool | None): Optional override for marker debug mode. Defaults to None. Returns: Document: Extracted and normalized document payload. @@ -109,12 +91,7 @@ def plain_text_extractor( logger.info(f"saved temp file on local storage => {tmp_filename}") - document = run_safe_text_extraction( - tmp_filename, - use_cache=use_cache, - y_tolerance=y_tolerance, - debug=debug, - ) + document = run_safe_text_extraction(tmp_filename) except concurrent.futures.TimeoutError: logger.error(f"Timeout while extracting text from {file.filename}") From 91d2c100c221e2e0bb30539ba9c826c45ac1df5a Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 19:51:25 +0000 Subject: [PATCH 082/104] =?UTF-8?q?=F0=9F=94=80=20Synthesize=20PDF=20extra?= =?UTF-8?q?ction=20flow=20from=20d349c69/26033a8:=20remove=20cache/debug?= =?UTF-8?q?=20path?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/text/extractors/pdf.py | 72 ++++---------------------------- aymurai/text/extractors/utils.py | 21 ++++------ 2 files changed, 15 insertions(+), 78 deletions(-) diff --git a/aymurai/text/extractors/pdf.py b/aymurai/text/extractors/pdf.py index 19cec025..11708e2e 100644 --- a/aymurai/text/extractors/pdf.py +++ b/aymurai/text/extractors/pdf.py @@ -1,12 +1,7 @@ -from hashlib import blake2b from pathlib import Path -from aymurai.logger import get_logger from aymurai.text.extractors.base import BaseExtractor, InvalidFile, register_extractor from aymurai.text.extractors.utils import pdf_to_text -from aymurai.utils.cache import cache_load, cache_save, get_cache_key - -logger = get_logger(__file__) @register_extractor @@ -17,80 +12,27 @@ def extract( self, path: Path, y_tolerance: float | None = None, - *, - use_cache: bool = True, - debug: bool | None = None, ) -> str: """ Extract normalized text from a PDF document. Args: path (Path): Input document path. - use_cache (bool): Toggle extractor-level caching. Defaults to True. - debug (bool | None): Optional override for marker debug mode. Defaults to None. + y_tolerance (float | None, optional): Maximum vertical gap used to + merge nearby text blocks. If None, it is estimated from the + document. Defaults to None. Returns: str: Cleaned textual content. + + Raises: + InvalidFile: If the file is unreadable or extraction fails. """ file_path = self.ensure_file(path) - # Check cache first when enabled - cache_key = self._cache_key(file_path) if use_cache else None - if use_cache and cache_key: - cached_text = cache_load(cache_key) - if cached_text is not None: - logger.debug("PDF cache hit for %s", file_path) - return cached_text - try: - text = pdf_to_text( - file_path, - y_tolerance=y_tolerance, - debug=debug, - ) + return pdf_to_text(file_path, y_tolerance=y_tolerance) except (OSError, ValueError) as exc: raise InvalidFile(str(exc)) from exc except Exception as exc: raise InvalidFile(str(exc)) from exc - if use_cache and cache_key: - cache_save(text, key=cache_key) - logger.debug("PDF cache stored for %s", file_path) - - return text - - @staticmethod - def _cache_key(file_path: Path) -> str | None: - """ - Compute a stable cache key for the PDF payload. - - Args: - file_path (Path): Location of the PDF file to fingerprint. - - Returns: - str | None: Deterministic cache key, or ``None`` when the file is unreadable. - """ - try: - stat = file_path.stat() - except OSError as exc: - logger.warning("Unable to stat PDF %s for caching: %s", file_path, exc) - return None - - try: - hasher = blake2b(digest_size=32) - with file_path.open("rb") as handle: - for chunk in iter(lambda: handle.read(65536), b""): - hasher.update(chunk) - fingerprint = hasher.hexdigest() - except OSError as exc: - logger.warning("Unable to hash PDF %s for caching: %s", file_path, exc) - fingerprint = None - - item = fingerprint or file_path.resolve().as_posix() - context = { - "component": "pdf-extractor", - "size": stat.st_size, - } - if fingerprint is None: - context["mtime_ns"] = stat.st_mtime_ns - - return get_cache_key(item, context=context) diff --git a/aymurai/text/extractors/utils.py b/aymurai/text/extractors/utils.py index 881b0633..009b562d 100644 --- a/aymurai/text/extractors/utils.py +++ b/aymurai/text/extractors/utils.py @@ -1,26 +1,22 @@ +import statistics import unicodedata import xml.etree.ElementTree as ET import zipfile from pathlib import Path from typing import Any +import numpy as np +import pymupdf import xmltodict from lxml import etree from more_itertools import flatten -import pymupdf -import statistics -import numpy as np - from aymurai.logger import get_logger from aymurai.utils.misc import get_element, get_recursively logger = get_logger(__file__) -BLOCK_TAGS = {"h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "blockquote", "pre"} - - ODT_NS = {"text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0"} @@ -75,12 +71,13 @@ def _compute_median_margin_between_blocks(pdf_path: str) -> float: return 0.0 # Return 0 if no margins were found -def _extract_and_merge_paragraphs(pdf_path: str, y_tolerance=5) -> list[str]: +def _extract_and_merge_paragraphs(pdf_path: str, y_tolerance: float = 5) -> list[str]: """ Extracts and merges paragraphs from a PDF by grouping close text blocks. Args: pdf_path (str): Path to the PDF file. - y_tolerance (float): Maximum vertical gap (in points) to consider blocks part of the same paragraph. + y_tolerance (float, optional): Maximum vertical gap (in points) to consider blocks part of the same paragraph. + Defaults to 5. Returns: list[str]: A list of merged paragraphs as strings. """ @@ -118,16 +115,14 @@ def _extract_and_merge_paragraphs(pdf_path: str, y_tolerance=5) -> list[str]: def pdf_to_text( file_path: Path | str, y_tolerance: float | None = None, - debug: bool | None = None, ) -> str: """ Extract text from a PDF file and return normalized plain text. Args: file_path (Path): Path to the PDF document. - y_tolerance (float, optional): - Maximum vertical gap (in points) to consider blocks part of the same paragraph. - debug (bool | None): Optional override for marker debug mode. Defaults to None. + y_tolerance (float, optional): Maximum vertical gap (in points) to consider blocks part of the same paragraph. + If None, it will be computed as the median margin between blocks. Defaults to None. Returns: str: Cleaned textual content extracted from the PDF. From 000215ed6b7d412aaf6528c62e2f5e4c855edfe9 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 19:52:41 +0000 Subject: [PATCH 083/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20text=20extracti?= =?UTF-8?q?on=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/text/test_extraction.py | 94 -------------------- test/text/test_extractors.py | 164 ----------------------------------- 2 files changed, 258 deletions(-) delete mode 100644 test/text/test_extraction.py delete mode 100644 test/text/test_extractors.py diff --git a/test/text/test_extraction.py b/test/text/test_extraction.py deleted file mode 100644 index 69df8f7e..00000000 --- a/test/text/test_extraction.py +++ /dev/null @@ -1,94 +0,0 @@ -import tempfile -import unittest -from pathlib import Path -from unittest.mock import patch - -from aymurai.text.extraction import ERRORS, InvalidFile, extract_document, get_extension - - -class ExtractionTestCase(unittest.TestCase): - def setUp(self) -> None: - self.tempdir = tempfile.TemporaryDirectory() - self.addCleanup(self.tempdir.cleanup) - self.tmp_path = Path(self.tempdir.name) - - def test_extract_document_dispatches(self): - source = self.tmp_path / "document.docx" - source.write_text("dummy") - - class DummyExtractor: - def __init__(self) -> None: - self.called = False - self.called_path: Path | None = None - - def extract(self, path: Path, **_: object) -> str: - self.called = True - self.called_path = path - return "ok" - - dummy = DummyExtractor() - - with patch( - "aymurai.text.extraction.get_extractor", - return_value=dummy, - ): - result = extract_document(source) - - self.assertEqual(result, "ok") - self.assertTrue(dummy.called) - self.assertEqual(dummy.called_path, source) - - def test_extract_document_missing_file_raises(self): - missing = Path("/no/such/file.pdf") - with self.assertRaises(InvalidFile): - extract_document(missing, errors="raise") - - def test_extract_document_handles_invalid_file(self): - source = self.tmp_path / "document.pdf" - source.write_text("dummy") - - class BoomExtractor: - def extract(self, _path: Path, **_: object) -> str: - raise InvalidFile("boom") - - with patch( - "aymurai.text.extraction.get_extractor", - return_value=BoomExtractor(), - ): - result = extract_document(source, errors="ignore") - - self.assertIsNone(result) - - def test_extract_document_raises_unexpected(self): - source = self.tmp_path / "document.odt" - source.write_text("dummy") - - class BoomExtractor: - def extract(self, _path: Path, **_: object) -> str: - raise RuntimeError("boom") - - with patch( - "aymurai.text.extraction.get_extractor", - return_value=BoomExtractor(), - ): - with self.assertRaises(RuntimeError): - extract_document(source, errors="raise") - - def test_get_extension_basic(self): - cases = [ - ("file.pdf", "pdf"), - ("file.docx", "docx"), - ("file.odt", "odt"), - ("file.unknown", "unknown"), - ] - - for filename, expected in cases: - with self.subTest(filename=filename): - self.assertEqual(get_extension(filename), expected) - - def test_errors_configured(self): - self.assertEqual(set(ERRORS), {"ignore", "coerce", "raise"}) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/text/test_extractors.py b/test/text/test_extractors.py deleted file mode 100644 index 37c883d8..00000000 --- a/test/text/test_extractors.py +++ /dev/null @@ -1,164 +0,0 @@ -import tempfile -import unittest -from pathlib import Path -from unittest.mock import patch - -from aymurai.text.extractors.base import InvalidFile -from aymurai.text.extractors.docx import DocxExtractor -from aymurai.text.extractors.odt import OdtExtractor -from aymurai.text.extractors.pdf import PdfExtractor - - -class ExtractorTestCase(unittest.TestCase): - def setUp(self) -> None: - self.tempdir = tempfile.TemporaryDirectory() - self.addCleanup(self.tempdir.cleanup) - self.tmp_path = Path(self.tempdir.name) - - def test_docx_extractor_appends_footnotes(self): - file_path = self.tmp_path / "sample.docx" - file_path.write_bytes(b"fake docx content") - - with ( - patch( - "aymurai.text.extractors.docx.docx2txt.process", - return_value="Document body", - ), - patch( - "aymurai.text.extractors.docx.get_footnotes", - return_value=["Footnote one", ""], - ), - ): - extractor = DocxExtractor() - result = extractor.extract(file_path) - - self.assertIn("Document body", result) - self.assertTrue(result.strip().endswith("Footnote one")) - - def test_docx_extractor_raises_invalid_file(self): - file_path = self.tmp_path / "broken.docx" - file_path.write_bytes(b"") - - with patch( - "aymurai.text.extractors.docx.docx2txt.process", - side_effect=OSError("boom"), - ): - extractor = DocxExtractor() - with self.assertRaises(InvalidFile): - extractor.extract(file_path) - - def test_odt_extractor_prepends_header(self): - file_path = self.tmp_path / "sample.odt" - file_path.write_bytes(b"fake odt content") - - with ( - patch( - "aymurai.text.extractors.odt.odt_to_text", - return_value="Paragraph one", - ), - patch( - "aymurai.text.extractors.odt.get_header", - return_value=["Header"], - ), - ): - extractor = OdtExtractor() - result = extractor.extract(file_path) - - self.assertTrue(result.startswith("Header")) - self.assertIn("Paragraph one", result) - - def test_odt_extractor_invalid_file(self): - file_path = self.tmp_path / "broken.odt" - file_path.write_bytes(b"") - - with patch( - "aymurai.text.extractors.odt.odt_to_text", - side_effect=ValueError("bad xml"), - ): - extractor = OdtExtractor() - with self.assertRaises(InvalidFile): - extractor.extract(file_path) - - def test_pdf_extractor_delegates(self): - file_path = self.tmp_path / "sample.pdf" - file_path.write_bytes(b"fake pdf") - - with patch( - "aymurai.text.extractors.pdf.pdf_to_text", - return_value="PDF text", - ): - extractor = PdfExtractor() - result = extractor.extract(file_path) - - self.assertEqual(result, "PDF text") - - def test_pdf_extractor_passes_config(self): - file_path = self.tmp_path / "sample.pdf" - file_path.write_bytes(b"fake pdf") - - with patch( - "aymurai.text.extractors.pdf.pdf_to_text", - return_value="PDF text", - ) as pdf_to_text: - extractor = PdfExtractor() - extractor.extract( - file_path, - use_cache=False, - layout_batch_size=4, - detection_batch_size=5, - table_rec_batch_size=6, - recognition_batch_size=7, - ocr_error_batch_size=8, - force_ocr=False, - strip_existing_ocr=False, - torch_device="cpu", - debug=True, - ) - - pdf_to_text.assert_called_once_with( - file_path, - layout_batch_size=4, - detection_batch_size=5, - table_rec_batch_size=6, - recognition_batch_size=7, - ocr_error_batch_size=8, - force_ocr=False, - strip_existing_ocr=False, - torch_device="cpu", - debug=True, - ) - - def test_pdf_extractor_wraps_errors(self): - file_path = self.tmp_path / "broken.pdf" - file_path.write_bytes(b"") - - with patch( - "aymurai.text.extractors.pdf.pdf_to_text", - side_effect=ValueError("invalid"), - ): - extractor = PdfExtractor() - with self.assertRaises(InvalidFile): - extractor.extract(file_path) - - def test_odt_extractor_ignores_extra_kwargs(self): - file_path = self.tmp_path / "sample.odt" - file_path.write_bytes(b"fake odt content") - - with ( - patch( - "aymurai.text.extractors.odt.odt_to_text", - return_value="Paragraph one", - ), - patch( - "aymurai.text.extractors.odt.get_header", - return_value=[], - ), - ): - extractor = OdtExtractor() - result = extractor.extract(file_path, layout_batch_size=4) - - self.assertIn("Paragraph one", result) - - -if __name__ == "__main__": - unittest.main() From 0d3aae5ea1e0e5ab79b82d7257575fa7f087673a Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 20:14:02 +0000 Subject: [PATCH 084/104] =?UTF-8?q?=F0=9F=93=9D=20Update=20description=20f?= =?UTF-8?q?ormatting=20for=20aymurai=5Fdisambiguation=20field=20in=20Entit?= =?UTF-8?q?yAttributes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/meta/entities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aymurai/meta/entities.py b/aymurai/meta/entities.py index 56393e29..fe36b762 100644 --- a/aymurai/meta/entities.py +++ b/aymurai/meta/entities.py @@ -38,7 +38,7 @@ class EntityAttributes(BaseModel): ) aymurai_disambiguation: str | None = Field( None, - description=("Override disambiguation mode for this entity (none, fuzzy)."), + description="Override disambiguation mode for this entity (none, fuzzy).", ) aymurai_anonymize: bool | None = Field( None, From efecf50d954c97bc7ebe23d27467304ea76731cd Mon Sep 17 00:00:00 2001 From: jansaldo Date: Fri, 20 Feb 2026 20:23:57 +0000 Subject: [PATCH 085/104] =?UTF-8?q?=F0=9F=A6=96=20Update=20PdfExtractor.ex?= =?UTF-8?q?tract=20method=20to=20include=20ignored=20keyword=20arguments?= =?UTF-8?q?=20for=20backward=20compatibility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/text/extractors/pdf.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/aymurai/text/extractors/pdf.py b/aymurai/text/extractors/pdf.py index 11708e2e..0e83c30d 100644 --- a/aymurai/text/extractors/pdf.py +++ b/aymurai/text/extractors/pdf.py @@ -1,4 +1,5 @@ from pathlib import Path +from typing import Any from aymurai.text.extractors.base import BaseExtractor, InvalidFile, register_extractor from aymurai.text.extractors.utils import pdf_to_text @@ -8,11 +9,7 @@ class PdfExtractor(BaseExtractor): extension = "pdf" - def extract( - self, - path: Path, - y_tolerance: float | None = None, - ) -> str: + def extract(self, path: Path, y_tolerance: float | None = None, **_: Any) -> str: """ Extract normalized text from a PDF document. @@ -21,6 +18,7 @@ def extract( y_tolerance (float | None, optional): Maximum vertical gap used to merge nearby text blocks. If None, it is estimated from the document. Defaults to None. + **_ (Any): Ignored extra keyword arguments for backward compatibility. Returns: str: Cleaned textual content. From 837c639d47a2cc15c1cb0bfc57a640cf6f9d53dd Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 23 Feb 2026 18:35:01 +0000 Subject: [PATCH 086/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20unused=20static?= =?UTF-8?q?=20logo=20file=20from=20API=20resources?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/api/Dockerfile | 2 -- resources/api/static/logo256-text.ico | Bin 1711 -> 0 bytes 2 files changed, 2 deletions(-) delete mode 100644 resources/api/static/logo256-text.ico diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 660e5a7e..560e1290 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -73,7 +73,6 @@ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ COPY --from=builder --chown=app:app /app/.venv /app/.venv # Copy static resources -COPY resources/api/static /resources/api/static COPY resources/pipelines /resources/pipelines # Set working directory @@ -94,7 +93,6 @@ ENV TF_CPP_MIN_LOG_LEVEL=3 \ RESOURCES_BASEPATH=resources # Copy additional resources -COPY ./resources/api resources/api COPY ./resources/pipelines/production resources/pipelines/production # Initialize application to download models diff --git a/resources/api/static/logo256-text.ico b/resources/api/static/logo256-text.ico deleted file mode 100644 index 9ff327f6d05389074da828615bd4afcf200f5945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1711 zcmd^=|3A|S9LGPC2)TG%i*&b9W6hNu;j-dGm=9rLzLg14lXY3XjD_J4uBMN##bc{k zL|U>U^Chc0?s)hTy7Fz5d>OXYsfm0!{*CVae!O0f=i~8y{qXwj4FHIZ-5dm<58PA% zfL$A$MRX@GW)VP-#G9 zj2!pYx~o*Ge#zLh5@_52tsmbY^^LE3A-GBdDT?+zP-v`iOKd4(}{wTBa3Z<;nglNzoCA ze`tFl$CwC2XC0N=_S$m(;2F)JGP<_ZsC$K(Kn4~P=KSO`C*-3s z6d&8OAKNc9(hZ=1pMOo^=JP0KH+bBd=aszkA$4}Ni&#=TUae>{h?EpSf_b#q)}v&J zt2SpE&JWjtd7ozxrp`>a6wYzZi!}NT=h3;B+%DLuy;`ui>N?0iP-V4ecq;5l0N)Vj zWqrf?YXy=x1s`@h&bd72V3zZJ!KupKNZ6!o*!N^+RedJ7lsG*w`|SK|3s%`Lqw;JI zh!kg8j#$04ki^IJzn8r|hY##Vqhx*e_`a1GLyBH^;YJPkL7H#q*6lZyv2cF0;C1)m zVuyCYMcN6@tS}G^dKDwM?KW1bY}h3ms+0EJd#5N%=k=dReL2I%c$#A~_MXxk>dBFn zm++eHCH4^+9`RtBua!R|vWzMwS;iVzf=r8e1B;$SfyrZBFfJWuDy3m#=|)g(Nj~Zg zd&$iBKE2PvYBLCG$8@9qC5?1)J&Q}qN00sO&RTwAm35tpj^4eIAPfXCn+vL=!YT)( zS0l+nk}hHa^#rxQwQVSVFVf$&QPngTL#i$aShf*KMwVYyU z_r`r^I^6%h0d_NjI^Zh*aSobHi5M+$^<1LL!|HZq`{)Gw6Mw&{!cebC%;op<_pckp z1i76y!BCM@}Mf)+(pquwu{AAZQ#4$9Y(==xp?R0!WzfQhJVFkQ^ z%U6~q{TIGYoL3VLyR3D%5q5o;SnN)p{E$#_2){>EKe*&0P3Un{RR8G#hL#PnU6|4| zc8u(3_G^V9zNYO`%sKrAwXvdAr{bj8j#Rleo|~jpcqqoim3t*P?J1r(79N#1B>FTR z*+Ui?HBHZ5Ft-XJe7b|WGKaD$g!?kZi^ykH?>YJlzinTgm?0P5#T;B7D-NrWHS)?> z%!me9MH9&0cbzGXBZV1KdVw$KZ8K}`*774;;T4^A1KJ}lBVFB@e_802_{$XL>A_^& z5eg)tI1gnfHiPUF%auYfIL_g{O~Y!^XEX0?hbtWGpYXp DBCgg( From 846ae17ab2fe98ab2f21bcc05c81bc9af58619a8 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 23 Feb 2026 18:35:12 +0000 Subject: [PATCH 087/104] =?UTF-8?q?=F0=9F=94=A7=20Add=20version=5Fscheme?= =?UTF-8?q?=20configuration=20to=20setuptools=5Fscm=20in=20pyproject.toml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 1879831c..4e6e0475 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,6 +115,7 @@ aymurai-api = "aymurai.api.main:main" [tool.setuptools_scm] version_file = "aymurai/version.py" +version_scheme = "only-version" local_scheme = "no-local-version" From 63e96ea05ecb34287c1959d9cc2d2e39fdfa3b02 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 23 Feb 2026 18:35:50 +0000 Subject: [PATCH 088/104] =?UTF-8?q?=F0=9F=93=8C=20Update=20uv.lock?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uv.lock | 2350 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 1188 insertions(+), 1162 deletions(-) diff --git a/uv.lock b/uv.lock index 538334fc..738af2d2 100644 --- a/uv.lock +++ b/uv.lock @@ -1,12 +1,5 @@ version = 1 -revision = 3 requires-python = "==3.10.*" -resolution-markers = [ - "sys_platform == 'darwin'", - "python_version < '0'", - "platform_machine == 'aarch64' and sys_platform == 'linux'", - "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')", -] [[package]] name = "accelerate" @@ -21,18 +14,18 @@ dependencies = [ { name = "safetensors" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/8e/ac2a9566747a93f8be36ee08532eb0160558b07630a081a6056a9f89bf1d/accelerate-1.12.0.tar.gz", hash = "sha256:70988c352feb481887077d2ab845125024b2a137a5090d6d7a32b57d03a45df6", size = 398399, upload-time = "2025-11-21T11:27:46.973Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/8e/ac2a9566747a93f8be36ee08532eb0160558b07630a081a6056a9f89bf1d/accelerate-1.12.0.tar.gz", hash = "sha256:70988c352feb481887077d2ab845125024b2a137a5090d6d7a32b57d03a45df6", size = 398399 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/d2/c581486aa6c4fbd7394c23c47b83fa1a919d34194e16944241daf9e762dd/accelerate-1.12.0-py3-none-any.whl", hash = "sha256:3e2091cd341423207e2f084a6654b1efcd250dc326f2a37d6dde446e07cabb11", size = 380935, upload-time = "2025-11-21T11:27:44.522Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d2/c581486aa6c4fbd7394c23c47b83fa1a919d34194e16944241daf9e762dd/accelerate-1.12.0-py3-none-any.whl", hash = "sha256:3e2091cd341423207e2f084a6654b1efcd250dc326f2a37d6dde446e07cabb11", size = 380935 }, ] [[package]] name = "aiohappyeyeballs" version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265 }, ] [[package]] @@ -49,25 +42,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556 } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950, upload-time = "2026-01-03T17:29:13.002Z" }, - { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099, upload-time = "2026-01-03T17:29:15.268Z" }, - { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072, upload-time = "2026-01-03T17:29:16.922Z" }, - { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588, upload-time = "2026-01-03T17:29:18.539Z" }, - { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334, upload-time = "2026-01-03T17:29:21.028Z" }, - { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656, upload-time = "2026-01-03T17:29:22.531Z" }, - { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625, upload-time = "2026-01-03T17:29:24.276Z" }, - { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604, upload-time = "2026-01-03T17:29:26.099Z" }, - { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370, upload-time = "2026-01-03T17:29:28.121Z" }, - { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023, upload-time = "2026-01-03T17:29:30.002Z" }, - { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680, upload-time = "2026-01-03T17:29:31.782Z" }, - { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407, upload-time = "2026-01-03T17:29:33.392Z" }, - { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047, upload-time = "2026-01-03T17:29:34.855Z" }, - { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264, upload-time = "2026-01-03T17:29:36.389Z" }, - { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275, upload-time = "2026-01-03T17:29:38.162Z" }, - { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053, upload-time = "2026-01-03T17:29:40.074Z" }, - { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687, upload-time = "2026-01-03T17:29:41.819Z" }, + { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950 }, + { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099 }, + { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072 }, + { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588 }, + { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334 }, + { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656 }, + { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625 }, + { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604 }, + { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370 }, + { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023 }, + { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680 }, + { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407 }, + { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047 }, + { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264 }, + { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275 }, + { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053 }, + { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687 }, ] [[package]] @@ -78,14 +71,14 @@ dependencies = [ { name = "frozenlist" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490 }, ] [[package]] name = "alembic" -version = "1.17.2" +version = "1.18.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mako" }, @@ -93,27 +86,27 @@ dependencies = [ { name = "tomli" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/a6/74c8cadc2882977d80ad756a13857857dbcf9bd405bc80b662eb10651282/alembic-1.17.2.tar.gz", hash = "sha256:bbe9751705c5e0f14877f02d46c53d10885e377e3d90eda810a016f9baa19e8e", size = 1988064, upload-time = "2025-11-14T20:35:04.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/88/6237e97e3385b57b5f1528647addea5cc03d4d65d5979ab24327d41fb00d/alembic-1.17.2-py3-none-any.whl", hash = "sha256:f483dd1fe93f6c5d49217055e4d15b905b425b6af906746abb35b69c1996c4e6", size = 248554, upload-time = "2025-11-14T20:35:05.699Z" }, + { url = "https://files.pythonhosted.org/packages/d2/29/6533c317b74f707ea28f8d633734dbda2119bbadfc61b2f3640ba835d0f7/alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", size = 263893 }, ] [[package]] name = "annotated-doc" version = "0.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303 }, ] [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, ] [[package]] @@ -125,18 +118,18 @@ dependencies = [ { name = "idna" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592 }, ] [[package]] name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, ] [[package]] @@ -146,9 +139,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, ] [[package]] @@ -158,23 +151,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, - { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549, upload-time = "2025-07-30T10:02:00.101Z" }, - { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539, upload-time = "2025-07-30T10:02:00.929Z" }, - { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467, upload-time = "2025-07-30T10:02:02.08Z" }, - { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355, upload-time = "2025-07-30T10:02:02.867Z" }, - { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187, upload-time = "2025-07-30T10:02:03.674Z" }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, + { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549 }, + { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539 }, + { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467 }, + { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355 }, + { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187 }, ] [[package]] @@ -185,52 +178,53 @@ dependencies = [ { name = "python-dateutil" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797 }, ] [[package]] name = "asttokens" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, ] [[package]] name = "async-lru" -version = "2.0.5" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b2/4d/71ec4d3939dc755264f680f6c2b4906423a304c3d18e96853f0a595dfe97/async_lru-2.0.5.tar.gz", hash = "sha256:481d52ccdd27275f42c43a928b4a50c3bfb2d67af4e78b170e3e0bb39c66e5bb", size = 10380, upload-time = "2025-03-16T17:25:36.919Z" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8a/ca724066c32a53fa75f59e0f21aa822fdaa8a0dffa112d223634e3caabf9/async_lru-2.2.0.tar.gz", hash = "sha256:80abae2a237dbc6c60861d621619af39f0d920aea306de34cb992c879e01370c", size = 14654 } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/49/d10027df9fce941cb8184e78a02857af36360d33e1721df81c5ed2179a1a/async_lru-2.0.5-py3-none-any.whl", hash = "sha256:ab95404d8d2605310d345932697371a5f40def0487c03d6d0ad9138de52c9943", size = 6069, upload-time = "2025-03-16T17:25:35.422Z" }, + { url = "https://files.pythonhosted.org/packages/13/5c/af990f019b8dd11c5492a6371fe74a5b0276357370030b67254a87329944/async_lru-2.2.0-py3-none-any.whl", hash = "sha256:e2c1cf731eba202b59c5feedaef14ffd9d02ad0037fcda64938699f2c380eafe", size = 7890 }, ] [[package]] name = "async-timeout" version = "5.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, ] [[package]] name = "attrs" version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615 }, ] [[package]] name = "aymurai" +version = "1.5.0rc1" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -333,11 +327,11 @@ dev = [ [[package]] name = "babel" -version = "2.17.0" +version = "2.18.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" }, + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845 }, ] [[package]] @@ -348,9 +342,9 @@ dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 }, ] [[package]] @@ -364,9 +358,9 @@ dependencies = [ { name = "lxml" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924, upload-time = "2023-08-15T22:34:59.047Z" } +sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419, upload-time = "2023-08-15T22:34:56.022Z" }, + { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419 }, ] [[package]] @@ -376,9 +370,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437 }, ] [package.optional-dependencies] @@ -388,48 +382,48 @@ css = [ [[package]] name = "boto3" -version = "1.42.23" +version = "1.42.54" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0d/df/17828670134e56ffca8cf8b017477f16d1a9df7ecfc3870d02aa6d4d2e20/boto3-1.42.23.tar.gz", hash = "sha256:f681a8d43b46b3d8acf0be4f3894eb85e40e75945431d0dfe0542edda7025512", size = 112845, upload-time = "2026-01-06T20:28:51.006Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/53/2e0a325e080bd83f5dfd8f964b70b93badc284bcb5680bee75327771ad4a/boto3-1.42.54.tar.gz", hash = "sha256:fe3d8ec586c39a0c96327fd317c77ca601ec5f991e9ba7211cacae8db4c07a73", size = 112747 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/8b/8e028dbf6c4bf36defe899882a00c11a8d22fcb7348e88058900c13b72a0/boto3-1.42.23-py3-none-any.whl", hash = "sha256:2ed797bdb394b08550f6269babf0a31bbeb853684bb2cb67116620df0ed632dc", size = 140574, upload-time = "2026-01-06T20:28:48.992Z" }, + { url = "https://files.pythonhosted.org/packages/4f/d6/695283df0a613cb723a05745cd565061add2bc5655d3493341b8b5c6b81d/boto3-1.42.54-py3-none-any.whl", hash = "sha256:71194e855bfc81a21872cbe29c41f52ffdbe67e0a184a52c13346ef00b328939", size = 140555 }, ] [[package]] name = "botocore" -version = "1.42.23" +version = "1.42.54" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/2c/db33716f86b67c514f895c60694a25cd7428d2137b574b59d09d626b0e2e/botocore-1.42.23.tar.gz", hash = "sha256:453ce449bd1021acd67e75c814aae1b132b1ab3ee0ecff248de863bf19e58be8", size = 14878387, upload-time = "2026-01-06T20:28:40.151Z" } +sdist = { url = "https://files.pythonhosted.org/packages/be/9a/5ab14330e5d1c3489e91f32f6ece40f3b58cf82d2aafe1e4a61711f616b0/botocore-1.42.54.tar.gz", hash = "sha256:ab203d4e57d22913c8386a695d048e003b7508a8a4a7a46c9ddf4ebd67a20b69", size = 14921929 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e6/114d66f81fc4b77a8c1e45e6fcf0021018d1f4eefca0905b3da8023c9a47/botocore-1.42.23-py3-none-any.whl", hash = "sha256:d5042e0252b81f25ca1152fff9ed25463bab2438fbc4530ba53d5390d00ca1b1", size = 14551561, upload-time = "2026-01-06T20:28:36.418Z" }, + { url = "https://files.pythonhosted.org/packages/86/29/cdf4ba5d0f626b7c5a74d6a615b977469960eae8c67f8e4213941f5f3dfd/botocore-1.42.54-py3-none-any.whl", hash = "sha256:853a0822de66d060aeebafa07ca13a03799f7958313d1b29f8dc7e2e1be8f527", size = 14594249 }, ] [[package]] name = "cachetools" -version = "6.2.4" +version = "7.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/1d/ede8680603f6016887c062a2cf4fc8fdba905866a3ab8831aa8aa651320c/cachetools-6.2.4.tar.gz", hash = "sha256:82c5c05585e70b6ba2d3ae09ea60b79548872185d2f24ae1f2709d37299fd607", size = 31731, upload-time = "2025-12-15T18:24:53.744Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/07/56595285564e90777d758ebd383d6b0b971b87729bbe2184a849932a3736/cachetools-7.0.1.tar.gz", hash = "sha256:e31e579d2c5b6e2944177a0397150d312888ddf4e16e12f1016068f0c03b8341", size = 36126 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/fc/1d7b80d0eb7b714984ce40efc78859c022cd930e402f599d8ca9e39c78a4/cachetools-6.2.4-py3-none-any.whl", hash = "sha256:69a7a52634fed8b8bf6e24a050fb60bff1c9bd8f6d24572b99c32d4e71e62a51", size = 11551, upload-time = "2025-12-15T18:24:52.332Z" }, + { url = "https://files.pythonhosted.org/packages/ed/9e/5faefbf9db1db466d633735faceda1f94aa99ce506ac450d232536266b32/cachetools-7.0.1-py3-none-any.whl", hash = "sha256:8f086515c254d5664ae2146d14fc7f65c9a4bce75152eb247e5a9c5e6d7b2ecf", size = 13484 }, ] [[package]] name = "certifi" version = "2026.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900 }, ] [[package]] @@ -439,54 +433,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283 }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504 }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811 }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402 }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217 }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079 }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475 }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829 }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211 }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184 }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790 }, ] [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, ] [[package]] name = "charset-normalizer" version = "3.4.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709, upload-time = "2025-10-14T04:40:11.385Z" }, - { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814, upload-time = "2025-10-14T04:40:13.135Z" }, - { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467, upload-time = "2025-10-14T04:40:14.728Z" }, - { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280, upload-time = "2025-10-14T04:40:16.14Z" }, - { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454, upload-time = "2025-10-14T04:40:17.567Z" }, - { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609, upload-time = "2025-10-14T04:40:19.08Z" }, - { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849, upload-time = "2025-10-14T04:40:20.607Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586, upload-time = "2025-10-14T04:40:21.719Z" }, - { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290, upload-time = "2025-10-14T04:40:23.069Z" }, - { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663, upload-time = "2025-10-14T04:40:24.17Z" }, - { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964, upload-time = "2025-10-14T04:40:25.368Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064, upload-time = "2025-10-14T04:40:26.806Z" }, - { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015, upload-time = "2025-10-14T04:40:28.284Z" }, - { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792, upload-time = "2025-10-14T04:40:29.613Z" }, - { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198, upload-time = "2025-10-14T04:40:30.644Z" }, - { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262, upload-time = "2025-10-14T04:40:32.108Z" }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, + { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709 }, + { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814 }, + { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467 }, + { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280 }, + { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454 }, + { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609 }, + { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586 }, + { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290 }, + { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663 }, + { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964 }, + { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064 }, + { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015 }, + { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792 }, + { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198 }, + { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262 }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, ] [[package]] @@ -494,38 +488,38 @@ name = "click" version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] [[package]] name = "comm" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, ] [[package]] name = "conllu" version = "4.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768, upload-time = "2023-06-19T12:37:49.632Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098, upload-time = "2023-06-19T12:37:47.885Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098 }, ] [[package]] @@ -535,35 +529,55 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, - { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, - { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, - { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, - { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, - { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, - { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, - { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, - { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, - { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, - { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, - { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, - { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061 }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956 }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872 }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027 }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641 }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075 }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534 }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188 }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681 }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101 }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599 }, +] + +[[package]] +name = "cuda-bindings" +version = "12.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cuda-pathfinder" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/37/31/bfcc870f69c6a017c4ad5c42316207fc7551940db6f3639aa4466ec5faf3/cuda_bindings-12.9.4-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a022c96b8bd847e8dc0675523431149a4c3e872f440e3002213dbb9e08f0331a", size = 11800959 }, + { url = "https://files.pythonhosted.org/packages/7a/d8/b546104b8da3f562c1ff8ab36d130c8fe1dd6a045ced80b4f6ad74f7d4e1/cuda_bindings-12.9.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d3c842c2a4303b2a580fe955018e31aea30278be19795ae05226235268032e5", size = 12148218 }, +] + +[[package]] +name = "cuda-pathfinder" +version = "1.3.4" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b8/5e/db279a3bfbd18d59d0598922a3b3c1454908d0969e8372260afec9736376/cuda_pathfinder-1.3.4-py3-none-any.whl", hash = "sha256:fb983f6e0d43af27ef486e14d5989b5f904ef45cedf40538bfdcbffa6bb01fb2", size = 30878 }, ] [[package]] name = "cycler" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, ] [[package]] name = "datasets" -version = "4.4.2" +version = "4.5.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, @@ -581,9 +595,9 @@ dependencies = [ { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/54/9359803da96bc65439a28fbb014dc2c90b7d4d8034a93b72362b0d40191f/datasets-4.4.2.tar.gz", hash = "sha256:9de16e415c4ba4713eac0493f7c7dc74f3aa21599297f00cc6ddab409cb7b24b", size = 586474, upload-time = "2025-12-19T15:03:09.129Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/bf/bb927bde63d649296c83e883171ae77074717c1b80fe2868b328bd0dbcbb/datasets-4.5.0.tar.gz", hash = "sha256:00c698ce1c2452e646cc5fad47fef39d3fe78dd650a8a6eb205bb45eb63cd500", size = 588384 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/b5/fefa518c809de7bced5cddb7c21c010da66fa2ae494bda96844a280cc6ce/datasets-4.4.2-py3-none-any.whl", hash = "sha256:6f5ef3417504d9cd663c71c1b90b9a494ff4c2076a2cd6a6e40ceee6ad95befc", size = 512268, upload-time = "2025-12-19T15:03:07.087Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d5/0d563ea3c205eee226dc8053cf7682a8ac588db8acecd0eda2b587987a0b/datasets-4.5.0-py3-none-any.whl", hash = "sha256:b5d7e08096ffa407dd69e58b1c0271c9b2506140839b8d99af07375ad31b6726", size = 515196 }, ] [[package]] @@ -593,33 +607,33 @@ source = { git = "https://github.com/jedzill4/datetime_matcher#0e5793e8d1e3653f7 [[package]] name = "debugpy" -version = "1.8.19" +version = "1.8.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/75/9e12d4d42349b817cd545b89247696c67917aab907012ae5b64bbfea3199/debugpy-1.8.19.tar.gz", hash = "sha256:eea7e5987445ab0b5ed258093722d5ecb8bb72217c5c9b1e21f64efe23ddebdb", size = 1644590, upload-time = "2025-12-15T21:53:28.044Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/98/d57054371887f37d3c959a7a8dc3c76b763acb65f5e78d849d7db7cadc5b/debugpy-1.8.19-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:fce6da15d73be5935b4438435c53adb512326a3e11e4f90793ea87cd9f018254", size = 2098493, upload-time = "2025-12-15T21:53:30.149Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dd/c517b9aa3500157a30e4f4c4f5149f880026bd039d2b940acd2383a85d8e/debugpy-1.8.19-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:e24b1652a1df1ab04d81e7ead446a91c226de704ff5dde6bd0a0dbaab07aa3f2", size = 3087875, upload-time = "2025-12-15T21:53:31.511Z" }, - { url = "https://files.pythonhosted.org/packages/d8/57/3d5a5b0da9b63445253107ead151eff29190c6ad7440c68d1a59d56613aa/debugpy-1.8.19-cp310-cp310-win32.whl", hash = "sha256:327cb28c3ad9e17bc925efc7f7018195fd4787c2fe4b7af1eec11f1d19bdec62", size = 5239378, upload-time = "2025-12-15T21:53:32.979Z" }, - { url = "https://files.pythonhosted.org/packages/a6/36/7f9053c4c549160c87ae7e43800138f2695578c8b65947114c97250983b6/debugpy-1.8.19-cp310-cp310-win_amd64.whl", hash = "sha256:b7dd275cf2c99e53adb9654f5ae015f70415bbe2bacbe24cfee30d54b6aa03c5", size = 5271129, upload-time = "2025-12-15T21:53:35.085Z" }, - { url = "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", hash = "sha256:360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38", size = 5292321, upload-time = "2025-12-15T21:54:16.024Z" }, + { url = "https://files.pythonhosted.org/packages/71/be/8bd693a0b9d53d48c8978fa5d889e06f3b5b03e45fd1ea1e78267b4887cb/debugpy-1.8.20-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:157e96ffb7f80b3ad36d808646198c90acb46fdcfd8bb1999838f0b6f2b59c64", size = 2099192 }, + { url = "https://files.pythonhosted.org/packages/77/1b/85326d07432086a06361d493d2743edd0c4fc2ef62162be7f8618441ac37/debugpy-1.8.20-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:c1178ae571aff42e61801a38b007af504ec8e05fde1c5c12e5a7efef21009642", size = 3088568 }, + { url = "https://files.pythonhosted.org/packages/e8/60/3e08462ee3eccd10998853eb35947c416e446bfe2bc37dbb886b9044586c/debugpy-1.8.20-cp310-cp310-win32.whl", hash = "sha256:c29dd9d656c0fbd77906a6e6a82ae4881514aa3294b94c903ff99303e789b4a2", size = 5284399 }, + { url = "https://files.pythonhosted.org/packages/72/43/09d49106e770fe558ced5e80df2e3c2ebee10e576eda155dcc5670473663/debugpy-1.8.20-cp310-cp310-win_amd64.whl", hash = "sha256:3ca85463f63b5dd0aa7aaa933d97cbc47c174896dcae8431695872969f981893", size = 5316388 }, + { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658 }, ] [[package]] name = "decorator" version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, ] [[package]] name = "defusedxml" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, ] [[package]] @@ -629,60 +643,60 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298 }, ] [[package]] name = "dill" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976 } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668 }, ] [[package]] name = "diskcache" version = "5.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" }, + { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550 }, ] [[package]] name = "distlib" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, ] [[package]] name = "dnspython" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094 }, ] [[package]] name = "docopt" version = "0.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901 } [[package]] name = "docx2txt" version = "0.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613, upload-time = "2025-03-24T20:59:25.21Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025, upload-time = "2025-03-24T20:59:24.394Z" }, + { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025 }, ] [[package]] @@ -693,9 +707,9 @@ dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238 } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604 }, ] [[package]] @@ -705,18 +719,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, ] [[package]] name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, ] [[package]] @@ -726,24 +740,25 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644, upload-time = "2023-06-27T15:24:28.075Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644 } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039, upload-time = "2023-06-27T15:24:24.869Z" }, + { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039 }, ] [[package]] name = "fastapi" -version = "0.128.0" +version = "0.132.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, + { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/08/8c8508db6c7b9aae8f7175046af41baad690771c9bcde676419965e338c7/fastapi-0.128.0.tar.gz", hash = "sha256:1cc179e1cef10a6be60ffe429f79b829dce99d8de32d7acb7e6c8dfdf7f2645a", size = 365682, upload-time = "2025-12-27T15:21:13.714Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/55/f1b4d4e478a0a1b4b1113d0f610a1b08e539b69900f97fdc97155d62fdee/fastapi-0.132.0.tar.gz", hash = "sha256:ef687847936d8a57ea6ea04cf9a85fe5f2c6ba64e22bfa721467094b69d48d92", size = 372422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5c/05/5cbb59154b093548acd0f4c7c474a118eda06da25aa75c616b72d8fcd92a/fastapi-0.128.0-py3-none-any.whl", hash = "sha256:aebd93f9716ee3b4f4fcfe13ffb7cf308d99c9f3ab5622d8877441072561582d", size = 103094, upload-time = "2025-12-27T15:21:12.154Z" }, + { url = "https://files.pythonhosted.org/packages/a8/de/6171c3363bbc5e01686e200e0880647c9270daa476d91030435cf14d32f5/fastapi-0.132.0-py3-none-any.whl", hash = "sha256:3c487d5afce196fa8ea509ae1531e96ccd5cdd2fd6eae78b73e2c20fba706689", size = 104652 }, ] [package.optional-dependencies] @@ -760,7 +775,7 @@ standard = [ [[package]] name = "fastapi-cli" -version = "0.0.20" +version = "0.0.23" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "rich-toolkit" }, @@ -768,9 +783,9 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d3/ca/d90fb3bfbcbd6e56c77afd9d114dd6ce8955d8bb90094399d1c70e659e40/fastapi_cli-0.0.20.tar.gz", hash = "sha256:d17c2634f7b96b6b560bc16b0035ed047d523c912011395f49f00a421692bc3a", size = 19786, upload-time = "2025-12-22T17:13:33.794Z" } +sdist = { url = "https://files.pythonhosted.org/packages/71/9f/cbd463e57de4e977b8ea0403f95347f9150441568b1d3fe3e4949ef80ef3/fastapi_cli-0.0.23.tar.gz", hash = "sha256:210ac280ea41e73aac5a57688781256beb23c2cba3a41266896fa43e6445c8e7", size = 19763 } wheels = [ - { url = "https://files.pythonhosted.org/packages/08/89/5c4eef60524d0fd704eb0706885b82cd5623a43396b94e4a5b17d3a3f516/fastapi_cli-0.0.20-py3-none-any.whl", hash = "sha256:e58b6a0038c0b1532b7a0af690656093dee666201b6b19d3c87175b358e9f783", size = 12390, upload-time = "2025-12-22T17:13:31.708Z" }, + { url = "https://files.pythonhosted.org/packages/68/89/19dcfd5cd289b306abdcabac68b88a4f54b7710a2c33adc16a337ecdcdfa/fastapi_cli-0.0.23-py3-none-any.whl", hash = "sha256:7e9634fc212da0b6cfc75bd3ac366cc9dfdb43b5e9ec12e58bfd1acdd2697f25", size = 12305 }, ] [package.optional-dependencies] @@ -781,7 +796,7 @@ standard = [ [[package]] name = "fastapi-cloud-cli" -version = "0.8.0" +version = "0.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastar" }, @@ -793,61 +808,61 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/51/5d/3b33438de35521fab4968b232caa9a4bd568a5078f2b2dfb7bb8a4528603/fastapi_cloud_cli-0.8.0.tar.gz", hash = "sha256:cf07c502528bfd9e6b184776659f05d9212811d76bbec9fbb6bf34bed4c7456f", size = 30257, upload-time = "2025-12-23T12:08:33.904Z" } +sdist = { url = "https://files.pythonhosted.org/packages/de/0b/f07f4976784978ef159fd2e8f5c16f1f9d610578fb1fd976ff1315c11ea6/fastapi_cloud_cli-0.13.0.tar.gz", hash = "sha256:4d8f42337e8021c648f6cb0672de7d5b31b0fc7387a83d7b12f974600ac3f2fd", size = 38436 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/8e/abb95ef59e91bb5adaa2d18fbf9ea70fd524010bb03f406a2dd2a4775ef9/fastapi_cloud_cli-0.8.0-py3-none-any.whl", hash = "sha256:e9f40bee671d985fd25d7a5409b56d4f103777bf8a0c6d746ea5fbf97a8186d9", size = 22306, upload-time = "2025-12-23T12:08:32.68Z" }, + { url = "https://files.pythonhosted.org/packages/b4/88/71a1e989d17b9edb483f32e28b7891ffdd3005271518c98ba6415987c430/fastapi_cloud_cli-0.13.0-py3-none-any.whl", hash = "sha256:874a9ed8dba34ec828f198c72de9f9a38de77ac1b15083d6bc3a4d772b0bc477", size = 27631 }, ] [[package]] name = "fastar" version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524, upload-time = "2025-11-26T02:36:00.72Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536, upload-time = "2025-11-26T02:34:35.236Z" }, - { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235, upload-time = "2025-11-26T02:34:19.367Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386, upload-time = "2025-11-26T02:33:47.613Z" }, - { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955, upload-time = "2025-11-26T02:32:44.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987, upload-time = "2025-11-26T02:32:59.701Z" }, - { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900, upload-time = "2025-11-26T02:33:16.059Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523, upload-time = "2025-11-26T02:33:30.897Z" }, - { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268, upload-time = "2025-11-26T02:34:04.003Z" }, - { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286, upload-time = "2025-11-26T02:34:50.279Z" }, - { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921, upload-time = "2025-11-26T02:35:07.292Z" }, - { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302, upload-time = "2025-11-26T02:35:24.995Z" }, - { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141, upload-time = "2025-11-26T02:35:42.449Z" }, - { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544, upload-time = "2025-11-26T02:36:23.801Z" }, - { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701, upload-time = "2025-11-26T02:36:09.625Z" }, - { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544, upload-time = "2025-11-26T02:34:46.195Z" }, - { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020, upload-time = "2025-11-26T02:34:31.085Z" }, - { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735, upload-time = "2025-11-26T02:34:00.088Z" }, - { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779, upload-time = "2025-11-26T02:32:55.109Z" }, - { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755, upload-time = "2025-11-26T02:33:11.595Z" }, - { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732, upload-time = "2025-11-26T02:33:27.122Z" }, - { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571, upload-time = "2025-11-26T02:33:42.986Z" }, - { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440, upload-time = "2025-11-26T02:34:15.439Z" }, - { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424, upload-time = "2025-11-26T02:35:02.742Z" }, - { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675, upload-time = "2025-11-26T02:35:20.252Z" }, - { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098, upload-time = "2025-11-26T02:35:37.643Z" }, - { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397, upload-time = "2025-11-26T02:35:56.215Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536 }, + { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235 }, + { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386 }, + { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955 }, + { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987 }, + { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900 }, + { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523 }, + { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268 }, + { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286 }, + { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921 }, + { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302 }, + { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141 }, + { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544 }, + { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701 }, + { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544 }, + { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020 }, + { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735 }, + { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779 }, + { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755 }, + { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732 }, + { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571 }, + { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440 }, + { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424 }, + { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675 }, + { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098 }, + { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397 }, ] [[package]] name = "fastjsonschema" version = "2.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024 }, ] [[package]] name = "filelock" -version = "3.20.2" +version = "3.24.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c1/e0/a75dbe4bca1e7d41307323dad5ea2efdd95408f74ab2de8bd7dba9b51a1a/filelock-3.20.2.tar.gz", hash = "sha256:a2241ff4ddde2a7cebddf78e39832509cb045d18ec1a09d7248d6bfc6bfbbe64", size = 19510, upload-time = "2026-01-02T15:33:32.582Z" } +sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9a/30/ab407e2ec752aa541704ed8f93c11e2a5d92c168b8a755d818b74a3c5c2d/filelock-3.20.2-py3-none-any.whl", hash = "sha256:fbba7237d6ea277175a32c54bb71ef814a8546d8601269e1bfc388de333974e8", size = 16697, upload-time = "2026-01-02T15:33:31.133Z" }, + { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331 }, ] [[package]] @@ -857,9 +872,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "termcolor" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720, upload-time = "2025-08-16T20:20:24.175Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945, upload-time = "2025-08-16T20:20:22.87Z" }, + { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945 }, ] [[package]] @@ -893,69 +908,69 @@ dependencies = [ { name = "transformers", extra = ["sentencepiece"] }, { name = "wikipedia-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607, upload-time = "2025-02-05T14:45:44.322Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604, upload-time = "2025-02-05T14:45:41.788Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, ] [[package]] name = "fonttools" version = "4.61.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756, upload-time = "2025-12-12T17:31:24.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799, upload-time = "2025-12-12T17:29:27.5Z" }, - { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032, upload-time = "2025-12-12T17:29:30.115Z" }, - { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863, upload-time = "2025-12-12T17:29:32.535Z" }, - { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076, upload-time = "2025-12-12T17:29:34.907Z" }, - { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623, upload-time = "2025-12-12T17:29:37.33Z" }, - { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327, upload-time = "2025-12-12T17:29:39.781Z" }, - { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180, upload-time = "2025-12-12T17:29:42.217Z" }, - { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654, upload-time = "2025-12-12T17:29:44.564Z" }, - { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996, upload-time = "2025-12-12T17:31:21.03Z" }, + { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799 }, + { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032 }, + { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863 }, + { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076 }, + { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623 }, + { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327 }, + { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180 }, + { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654 }, + { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996 }, ] [[package]] name = "fqdn" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121 }, ] [[package]] name = "frozenlist" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875 } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230 }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621 }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889 }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464 }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649 }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188 }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748 }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351 }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767 }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887 }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785 }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312 }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650 }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659 }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837 }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989 }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, ] [[package]] name = "fsspec" version = "2025.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285, upload-time = "2025-10-30T14:58:44.036Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285 } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966, upload-time = "2025-10-30T14:58:42.53Z" }, + { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966 }, ] [package.optional-dependencies] @@ -970,14 +985,14 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927, upload-time = "2024-10-26T00:50:35.149Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821, upload-time = "2024-10-26T00:50:33.425Z" }, + { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821 }, ] [[package]] name = "gdown" -version = "5.2.0" +version = "5.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -985,49 +1000,49 @@ dependencies = [ { name = "requests", extra = ["socks"] }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/6a/37e6b70c5bda3161e40265861e63b64a86bfc6ca6a8f1c35328a675c84fd/gdown-5.2.0.tar.gz", hash = "sha256:2145165062d85520a3cd98b356c9ed522c5e7984d408535409fd46f94defc787", size = 284647, upload-time = "2024-05-12T06:45:12.725Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/cf/919a9fa16faf8e4572a24d941353edaf4d54e3ddcd048e6c1aeb8c7a9903/gdown-5.2.1.tar.gz", hash = "sha256:247c2ad1f579db5b66b54c04e6a871995fc8fd7021708b950b8ba7b32cf90323", size = 284743 } wheels = [ - { url = "https://files.pythonhosted.org/packages/54/70/e07c381e6488a77094f04c85c9caf1c8008cdc30778f7019bc52e5285ef0/gdown-5.2.0-py3-none-any.whl", hash = "sha256:33083832d82b1101bdd0e9df3edd0fbc0e1c5f14c9d8c38d2a35bf1683b526d6", size = 18235, upload-time = "2024-05-12T06:45:10.017Z" }, + { url = "https://files.pythonhosted.org/packages/87/21/35dd0a0b7428bd67b12b358d7b4277f693493a3839b071d540a4c8357b78/gdown-5.2.1-py3-none-any.whl", hash = "sha256:391f0480d495fb87644d1a1ee3ddfeb2144e1de31408fbc74f7e3b3ba927052b", size = 18241 }, ] [[package]] name = "greenlet" -version = "3.3.0" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/e5/40dbda2736893e3e53d25838e0f19a2b417dfc122b9989c91918db30b5d3/greenlet-3.3.0.tar.gz", hash = "sha256:a82bb225a4e9e4d653dd2fb7b8b2d36e4fb25bc0165422a11e48b88e9e6f78fb", size = 190651, upload-time = "2025-12-04T14:49:44.05Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267 } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/6a/33d1702184d94106d3cdd7bfb788e19723206fce152e303473ca3b946c7b/greenlet-3.3.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:6f8496d434d5cb2dce025773ba5597f71f5410ae499d5dd9533e0653258cdb3d", size = 273658, upload-time = "2025-12-04T14:23:37.494Z" }, - { url = "https://files.pythonhosted.org/packages/d6/b7/2b5805bbf1907c26e434f4e448cd8b696a0b71725204fa21a211ff0c04a7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b96dc7eef78fd404e022e165ec55327f935b9b52ff355b067eb4a0267fc1cffb", size = 574810, upload-time = "2025-12-04T14:50:04.154Z" }, - { url = "https://files.pythonhosted.org/packages/94/38/343242ec12eddf3d8458c73f555c084359883d4ddc674240d9e61ec51fd6/greenlet-3.3.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73631cd5cccbcfe63e3f9492aaa664d278fda0ce5c3d43aeda8e77317e38efbd", size = 586248, upload-time = "2025-12-04T14:57:39.35Z" }, - { url = "https://files.pythonhosted.org/packages/f0/d0/0ae86792fb212e4384041e0ef8e7bc66f59a54912ce407d26a966ed2914d/greenlet-3.3.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b299a0cb979f5d7197442dccc3aee67fce53500cd88951b7e6c35575701c980b", size = 597403, upload-time = "2025-12-04T15:07:10.831Z" }, - { url = "https://files.pythonhosted.org/packages/b6/a8/15d0aa26c0036a15d2659175af00954aaaa5d0d66ba538345bd88013b4d7/greenlet-3.3.0-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7dee147740789a4632cace364816046e43310b59ff8fb79833ab043aefa72fd5", size = 586910, upload-time = "2025-12-04T14:25:59.705Z" }, - { url = "https://files.pythonhosted.org/packages/e1/9b/68d5e3b7ccaba3907e5532cf8b9bf16f9ef5056a008f195a367db0ff32db/greenlet-3.3.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:39b28e339fc3c348427560494e28d8a6f3561c8d2bcf7d706e1c624ed8d822b9", size = 1547206, upload-time = "2025-12-04T15:04:21.027Z" }, - { url = "https://files.pythonhosted.org/packages/66/bd/e3086ccedc61e49f91e2cfb5ffad9d8d62e5dc85e512a6200f096875b60c/greenlet-3.3.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b3c374782c2935cc63b2a27ba8708471de4ad1abaa862ffdb1ef45a643ddbb7d", size = 1613359, upload-time = "2025-12-04T14:27:26.548Z" }, - { url = "https://files.pythonhosted.org/packages/f4/6b/d4e73f5dfa888364bbf02efa85616c6714ae7c631c201349782e5b428925/greenlet-3.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:b49e7ed51876b459bd645d83db257f0180e345d3f768a35a85437a24d5a49082", size = 300740, upload-time = "2025-12-04T14:47:52.773Z" }, + { url = "https://files.pythonhosted.org/packages/38/3f/9859f655d11901e7b2996c6e3d33e0caa9a1d4572c3bc61ed0faa64b2f4c/greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d", size = 277747 }, + { url = "https://files.pythonhosted.org/packages/fb/07/cb284a8b5c6498dbd7cba35d31380bb123d7dceaa7907f606c8ff5993cbf/greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13", size = 579202 }, + { url = "https://files.pythonhosted.org/packages/ed/45/67922992b3a152f726163b19f890a85129a992f39607a2a53155de3448b8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e", size = 590620 }, + { url = "https://files.pythonhosted.org/packages/03/5f/6e2a7d80c353587751ef3d44bb947f0565ec008a2e0927821c007e96d3a7/greenlet-3.3.2-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7", size = 602132 }, + { url = "https://files.pythonhosted.org/packages/ad/55/9f1ebb5a825215fadcc0f7d5073f6e79e3007e3282b14b22d6aba7ca6cb8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f", size = 591729 }, + { url = "https://files.pythonhosted.org/packages/24/b4/21f5455773d37f94b866eb3cf5caed88d6cea6dd2c6e1f9c34f463cba3ec/greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef", size = 1551946 }, + { url = "https://files.pythonhosted.org/packages/00/68/91f061a926abead128fe1a87f0b453ccf07368666bd59ffa46016627a930/greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca", size = 1618494 }, + { url = "https://files.pythonhosted.org/packages/ac/78/f93e840cbaef8becaf6adafbaf1319682a6c2d8c1c20224267a5c6c8c891/greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f", size = 230092 }, ] [[package]] name = "h11" version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, ] [[package]] name = "hf-xet" version = "1.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020, upload-time = "2025-10-24T19:04:32.129Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020 } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099, upload-time = "2025-10-24T19:04:15.366Z" }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178, upload-time = "2025-10-24T19:04:13.695Z" }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214, upload-time = "2025-10-24T19:04:03.596Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054, upload-time = "2025-10-24T19:04:01.949Z" }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812, upload-time = "2025-10-24T19:04:24.585Z" }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920, upload-time = "2025-10-24T19:04:26.927Z" }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735, upload-time = "2025-10-24T19:04:35.928Z" }, + { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099 }, + { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178 }, + { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214 }, + { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054 }, + { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812 }, + { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920 }, + { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735 }, ] [[package]] @@ -1038,24 +1053,24 @@ dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, ] [[package]] name = "httptools" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531, upload-time = "2025-10-10T03:54:20.887Z" }, - { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408, upload-time = "2025-10-10T03:54:22.455Z" }, - { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889, upload-time = "2025-10-10T03:54:23.753Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460, upload-time = "2025-10-10T03:54:25.313Z" }, - { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267, upload-time = "2025-10-10T03:54:26.81Z" }, - { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429, upload-time = "2025-10-10T03:54:28.174Z" }, - { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173, upload-time = "2025-10-10T03:54:29.5Z" }, + { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531 }, + { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408 }, + { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889 }, + { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460 }, + { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267 }, + { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429 }, + { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173 }, ] [[package]] @@ -1068,14 +1083,14 @@ dependencies = [ { name = "httpcore" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, ] [[package]] name = "huggingface-hub" -version = "0.36.0" +version = "0.36.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, @@ -1087,27 +1102,27 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/63/4910c5fa9128fdadf6a9c5ac138e8b1b6cee4ca44bf7915bbfbce4e355ee/huggingface_hub-0.36.0.tar.gz", hash = "sha256:47b3f0e2539c39bf5cde015d63b72ec49baff67b6931c3d97f3f84532e2b8d25", size = 463358, upload-time = "2025-10-23T12:12:01.413Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/bd/1a875e0d592d447cbc02805fd3fe0f497714d6a2583f59d14fa9ebad96eb/huggingface_hub-0.36.0-py3-none-any.whl", hash = "sha256:7bcc9ad17d5b3f07b57c78e79d527102d08313caa278a641993acddcb894548d", size = 566094, upload-time = "2025-10-23T12:11:59.557Z" }, + { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395 }, ] [[package]] name = "identify" -version = "2.6.15" +version = "2.6.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/e7/685de97986c916a6d93b3876139e00eef26ad5bbbd61925d670ae8013449/identify-2.6.15.tar.gz", hash = "sha256:e4f4864b96c6557ef2a1e1c951771838f4edc9df3a72ec7118b338801b11c7bf", size = 99311, upload-time = "2025-10-02T17:43:40.631Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/1c/e5fd8f973d4f375adb21565739498e2e9a1e54c858a97b9a8ccfdc81da9b/identify-2.6.15-py2.py3-none-any.whl", hash = "sha256:1181ef7608e00704db228516541eb83a88a9f94433a8c80bb9b5bd54b1d81757", size = 99183, upload-time = "2025-10-02T17:43:39.137Z" }, + { url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202 }, ] [[package]] name = "idna" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, ] [[package]] @@ -1117,17 +1132,17 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531, upload-time = "2025-12-24T04:25:06.773Z" } +sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531 } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929, upload-time = "2025-12-24T04:25:05.298Z" }, + { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929 }, ] [[package]] name = "ipykernel" -version = "7.1.0" +version = "7.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "appnope", marker = "platform_system == 'Darwin'" }, { name = "comm" }, { name = "debugpy" }, { name = "ipython" }, @@ -1141,9 +1156,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/a4/4948be6eb88628505b83a1f2f40d90254cab66abf2043b3c40fa07dfce0f/ipykernel-7.1.0.tar.gz", hash = "sha256:58a3fc88533d5930c3546dc7eac66c6d288acde4f801e2001e65edc5dc9cf0db", size = 174579, upload-time = "2025-10-27T09:46:39.471Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e", size = 176046 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/17/20c2552266728ceba271967b87919664ecc0e33efca29c3efc6baf88c5f9/ipykernel-7.1.0-py3-none-any.whl", hash = "sha256:763b5ec6c5b7776f6a8d7ce09b267693b4e5ce75cb50ae696aaefb3c85e1ea4c", size = 117968, upload-time = "2025-10-27T09:46:37.805Z" }, + { url = "https://files.pythonhosted.org/packages/82/b9/e73d5d9f405cba7706c539aa8b311b49d4c2f3d698d9c12f815231169c71/ipykernel-7.2.0-py3-none-any.whl", hash = "sha256:3bbd4420d2b3cc105cbdf3756bfc04500b1e52f090a90716851f3916c62e1661", size = 118788 }, ] [[package]] @@ -1163,9 +1178,9 @@ dependencies = [ { name = "traitlets" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996, upload-time = "2026-01-05T10:59:06.901Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813, upload-time = "2026-01-05T10:59:04.239Z" }, + { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813 }, ] [[package]] @@ -1179,9 +1194,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808 }, ] [[package]] @@ -1191,9 +1206,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arrow" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, ] [[package]] @@ -1203,9 +1218,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, ] [[package]] @@ -1215,9 +1230,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, ] [[package]] @@ -1228,36 +1243,36 @@ dependencies = [ { name = "click" }, { name = "rapidfuzz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537, upload-time = "2024-11-01T16:18:57.337Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990, upload-time = "2024-11-01T16:18:55.928Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990 }, ] [[package]] name = "jmespath" -version = "1.0.1" +version = "1.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377 } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419 }, ] [[package]] name = "joblib" version = "1.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071 }, ] [[package]] name = "json5" version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441, upload-time = "2026-01-01T19:42:14.99Z" } +sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163, upload-time = "2026-01-01T19:42:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163 }, ] [[package]] @@ -1267,18 +1282,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359, upload-time = "2023-09-01T12:34:44.187Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701, upload-time = "2023-09-01T12:34:42.563Z" }, + { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701 }, ] [[package]] name = "jsonpointer" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114 } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595 }, ] [[package]] @@ -1291,9 +1306,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630 }, ] [package.optional-dependencies] @@ -1316,9 +1331,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855 } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437 }, ] [[package]] @@ -1333,14 +1348,14 @@ dependencies = [ { name = "nbconvert" }, { name = "notebook" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959 } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657 }, ] [[package]] name = "jupyter-client" -version = "8.7.0" +version = "8.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-core" }, @@ -1349,9 +1364,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/27/d10de45e8ad4ce872372c4a3a37b7b35b6b064f6f023a5c14ffcced4d59d/jupyter_client-8.7.0.tar.gz", hash = "sha256:3357212d9cbe01209e59190f67a3a7e1f387a4f4e88d1e0433ad84d7b262531d", size = 344691, upload-time = "2025-12-09T18:37:01.953Z" } +sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/f5/fddaec430367be9d62a7ed125530e133bfd4a1c0350fe221149ee0f2b526/jupyter_client-8.7.0-py3-none-any.whl", hash = "sha256:3671a94fd25e62f5f2f554f5e95389c2294d89822378a5f2dd24353e1494a9e0", size = 106215, upload-time = "2025-12-09T18:37:00.024Z" }, + { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371 }, ] [[package]] @@ -1368,9 +1383,9 @@ dependencies = [ { name = "pyzmq" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510 }, ] [[package]] @@ -1381,9 +1396,9 @@ dependencies = [ { name = "platformdirs" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, ] [[package]] @@ -1400,9 +1415,9 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, ] [[package]] @@ -1412,9 +1427,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687 }, ] [[package]] @@ -1434,7 +1449,7 @@ dependencies = [ { name = "overrides" }, { name = "packaging" }, { name = "prometheus-client" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, { name = "pyzmq" }, { name = "send2trash" }, { name = "terminado" }, @@ -1442,27 +1457,27 @@ dependencies = [ { name = "traitlets" }, { name = "websocket-client" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221 }, ] [[package]] name = "jupyter-server-terminals" -version = "0.5.3" +version = "0.5.4" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, { name = "terminado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fc/d5/562469734f476159e99a55426d697cbf8e7eb5efe89fb0e0b4f83a3d3459/jupyter_server_terminals-0.5.3.tar.gz", hash = "sha256:5ae0295167220e9ace0edcfdb212afd2b01ee8d179fe6f23c899590e9b8a5269", size = 31430, upload-time = "2024-03-12T14:37:03.049Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f4/a7/bcd0a9b0cbba88986fe944aaaf91bfda603e5a50bda8ed15123f381a3b2f/jupyter_server_terminals-0.5.4.tar.gz", hash = "sha256:bbda128ed41d0be9020349f9f1f2a4ab9952a73ed5f5ac9f1419794761fb87f5", size = 31770 } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/2d/2b32cdbe8d2a602f697a649798554e4f072115438e92249624e532e8aca6/jupyter_server_terminals-0.5.3-py3-none-any.whl", hash = "sha256:41ee0d7dc0ebf2809c668e0fc726dfaf258fcd3e769568996ca731b6194ae9aa", size = 13656, upload-time = "2024-03-12T14:37:00.708Z" }, + { url = "https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl", hash = "sha256:55be353fc74a80bc7f3b20e6be50a55a61cd525626f578dcb66a5708e2007d14", size = 13704 }, ] [[package]] name = "jupyterlab" -version = "4.5.1" +version = "4.5.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-lru" }, @@ -1480,18 +1495,18 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/21/413d142686a4e8f4268d985becbdb4daf060524726248e73be4773786987/jupyterlab-4.5.1.tar.gz", hash = "sha256:09da1ddfbd9eec18b5101dbb8515612aa1e47443321fb99503725a88e93d20d9", size = 23992251, upload-time = "2025-12-15T16:58:59.361Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7c/6b/21af7c0512bdf67e0c54c121779a1f2a97a164a7657e13fced79db8fa5a0/jupyterlab-4.5.4.tar.gz", hash = "sha256:c215f48d8e4582bd2920ad61cc6a40d8ebfef7e5a517ae56b8a9413c9789fdfb", size = 23943597 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/c3/acced767eecc11a70c65c45295db5396c4f0c1937874937d5a76d7b177b6/jupyterlab-4.5.1-py3-none-any.whl", hash = "sha256:31b059de96de0754ff1f2ce6279774b6aab8c34d7082e9752db58207c99bd514", size = 12384821, upload-time = "2025-12-15T16:58:55.563Z" }, + { url = "https://files.pythonhosted.org/packages/f5/9f/a70972ece62ead2d81acc6223188f6d18a92f665ccce17796a0cdea4fcf5/jupyterlab-4.5.4-py3-none-any.whl", hash = "sha256:cc233f70539728534669fb0015331f2a3a87656207b3bb2d07916e9289192f12", size = 12391867 }, ] [[package]] name = "jupyterlab-pygments" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, ] [[package]] @@ -1507,44 +1522,44 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830 }, ] [[package]] name = "jupyterlab-widgets" version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, ] [[package]] name = "kiwisolver" version = "1.4.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159, upload-time = "2025-08-10T21:25:35.472Z" }, - { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578, upload-time = "2025-08-10T21:25:36.73Z" }, - { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312, upload-time = "2025-08-10T21:25:37.658Z" }, - { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458, upload-time = "2025-08-10T21:25:39.067Z" }, - { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640, upload-time = "2025-08-10T21:25:40.489Z" }, - { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074, upload-time = "2025-08-10T21:25:42.221Z" }, - { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036, upload-time = "2025-08-10T21:25:43.801Z" }, - { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310, upload-time = "2025-08-10T21:25:45.045Z" }, - { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943, upload-time = "2025-08-10T21:25:46.393Z" }, - { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488, upload-time = "2025-08-10T21:25:48.074Z" }, - { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787, upload-time = "2025-08-10T21:25:49.442Z" }, - { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730, upload-time = "2025-08-10T21:25:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036, upload-time = "2025-08-10T21:25:52.063Z" }, - { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183, upload-time = "2025-08-10T21:27:37.669Z" }, - { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675, upload-time = "2025-08-10T21:27:39.031Z" }, - { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277, upload-time = "2025-08-10T21:27:40.129Z" }, - { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994, upload-time = "2025-08-10T21:27:41.181Z" }, - { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744, upload-time = "2025-08-10T21:27:42.254Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159 }, + { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578 }, + { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312 }, + { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458 }, + { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640 }, + { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074 }, + { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036 }, + { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310 }, + { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943 }, + { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488 }, + { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787 }, + { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730 }, + { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036 }, + { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183 }, + { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675 }, + { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277 }, + { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994 }, + { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744 }, ] [[package]] @@ -1554,15 +1569,15 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474 } [[package]] name = "lark" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732 } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, ] [[package]] @@ -1572,39 +1587,39 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fire" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292, upload-time = "2022-09-06T16:09:06.607Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594, upload-time = "2022-09-06T16:09:04.658Z" }, + { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594 }, ] [[package]] name = "lxml" version = "6.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, - { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, - { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, - { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, - { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, - { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, - { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, - { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, - { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, - { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, - { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, - { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, - { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, - { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, - { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, - { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, - { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, - { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, - { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589 }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671 }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961 }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087 }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620 }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664 }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397 }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178 }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148 }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035 }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111 }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662 }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973 }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953 }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695 }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051 }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264 }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435 }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913 }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357 }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295 }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913 }, ] [[package]] @@ -1614,9 +1629,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509 }, ] [[package]] @@ -1626,28 +1641,28 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070 } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321 }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631 }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057 }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050 }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681 }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705 }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524 }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282 }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745 }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571 }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056 }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932 }, ] [[package]] @@ -1665,17 +1680,17 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269 } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828, upload-time = "2025-12-10T22:55:02.313Z" }, - { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050, upload-time = "2025-12-10T22:55:04.997Z" }, - { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452, upload-time = "2025-12-10T22:55:07.47Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928, upload-time = "2025-12-10T22:55:10.566Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377, upload-time = "2025-12-10T22:55:12.362Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127, upload-time = "2025-12-10T22:55:14.436Z" }, - { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252, upload-time = "2025-12-10T22:56:39.529Z" }, - { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693, upload-time = "2025-12-10T22:56:41.758Z" }, - { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205, upload-time = "2025-12-10T22:56:43.415Z" }, + { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828 }, + { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050 }, + { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452 }, + { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928 }, + { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377 }, + { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127 }, + { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252 }, + { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693 }, + { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205 }, ] [[package]] @@ -1685,18 +1700,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516 }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] [[package]] @@ -1706,18 +1721,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, + { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598 }, ] [[package]] name = "more-itertools" version = "10.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 }, ] [[package]] @@ -1728,48 +1743,48 @@ dependencies = [ { name = "jinja2" }, { name = "matplotlib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433, upload-time = "2025-11-05T18:12:24.183Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051, upload-time = "2025-11-05T18:12:22.527Z" }, + { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, ] [[package]] name = "multidict" -version = "6.7.0" +version = "6.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/1e/5492c365f222f907de1039b91f922b93fa4f764c713ee858d235495d8f50/multidict-6.7.0.tar.gz", hash = "sha256:c6e99d9a65ca282e578dfea819cfa9c0a62b2499d8677392e09feaf305e9e6f5", size = 101834, upload-time = "2025-10-06T14:52:30.657Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/63/7bdd4adc330abcca54c85728db2327130e49e52e8c3ce685cec44e0f2e9f/multidict-6.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:9f474ad5acda359c8758c8accc22032c6abe6dc87a8be2440d097785e27a9349", size = 77153, upload-time = "2025-10-06T14:48:26.409Z" }, - { url = "https://files.pythonhosted.org/packages/3f/bb/b6c35ff175ed1a3142222b78455ee31be71a8396ed3ab5280fbe3ebe4e85/multidict-6.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a9db5a870f780220e931d0002bbfd88fb53aceb6293251e2c839415c1b20e", size = 44993, upload-time = "2025-10-06T14:48:28.4Z" }, - { url = "https://files.pythonhosted.org/packages/e0/1f/064c77877c5fa6df6d346e68075c0f6998547afe952d6471b4c5f6a7345d/multidict-6.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03ca744319864e92721195fa28c7a3b2bc7b686246b35e4078c1e4d0eb5466d3", size = 44607, upload-time = "2025-10-06T14:48:29.581Z" }, - { url = "https://files.pythonhosted.org/packages/04/7a/bf6aa92065dd47f287690000b3d7d332edfccb2277634cadf6a810463c6a/multidict-6.7.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f0e77e3c0008bc9316e662624535b88d360c3a5d3f81e15cf12c139a75250046", size = 241847, upload-time = "2025-10-06T14:48:32.107Z" }, - { url = "https://files.pythonhosted.org/packages/94/39/297a8de920f76eda343e4ce05f3b489f0ab3f9504f2576dfb37b7c08ca08/multidict-6.7.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:08325c9e5367aa379a3496aa9a022fe8837ff22e00b94db256d3a1378c76ab32", size = 242616, upload-time = "2025-10-06T14:48:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/39/3a/d0eee2898cfd9d654aea6cb8c4addc2f9756e9a7e09391cfe55541f917f7/multidict-6.7.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e2862408c99f84aa571ab462d25236ef9cb12a602ea959ba9c9009a54902fc73", size = 222333, upload-time = "2025-10-06T14:48:35.9Z" }, - { url = "https://files.pythonhosted.org/packages/05/48/3b328851193c7a4240815b71eea165b49248867bbb6153a0aee227a0bb47/multidict-6.7.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d72a9a2d885f5c208b0cb91ff2ed43636bb7e345ec839ff64708e04f69a13cc", size = 253239, upload-time = "2025-10-06T14:48:37.302Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ca/0706a98c8d126a89245413225ca4a3fefc8435014de309cf8b30acb68841/multidict-6.7.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:478cc36476687bac1514d651cbbaa94b86b0732fb6855c60c673794c7dd2da62", size = 251618, upload-time = "2025-10-06T14:48:38.963Z" }, - { url = "https://files.pythonhosted.org/packages/5e/4f/9c7992f245554d8b173f6f0a048ad24b3e645d883f096857ec2c0822b8bd/multidict-6.7.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6843b28b0364dc605f21481c90fadb5f60d9123b442eb8a726bb74feef588a84", size = 241655, upload-time = "2025-10-06T14:48:40.312Z" }, - { url = "https://files.pythonhosted.org/packages/31/79/26a85991ae67efd1c0b1fc2e0c275b8a6aceeb155a68861f63f87a798f16/multidict-6.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23bfeee5316266e5ee2d625df2d2c602b829435fc3a235c2ba2131495706e4a0", size = 239245, upload-time = "2025-10-06T14:48:41.848Z" }, - { url = "https://files.pythonhosted.org/packages/14/1e/75fa96394478930b79d0302eaf9a6c69f34005a1a5251ac8b9c336486ec9/multidict-6.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:680878b9f3d45c31e1f730eef731f9b0bc1da456155688c6745ee84eb818e90e", size = 233523, upload-time = "2025-10-06T14:48:43.749Z" }, - { url = "https://files.pythonhosted.org/packages/b2/5e/085544cb9f9c4ad2b5d97467c15f856df8d9bac410cffd5c43991a5d878b/multidict-6.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:eb866162ef2f45063acc7a53a88ef6fe8bf121d45c30ea3c9cd87ce7e191a8d4", size = 243129, upload-time = "2025-10-06T14:48:45.225Z" }, - { url = "https://files.pythonhosted.org/packages/b9/c3/e9d9e2f20c9474e7a8fcef28f863c5cbd29bb5adce6b70cebe8bdad0039d/multidict-6.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:df0e3bf7993bdbeca5ac25aa859cf40d39019e015c9c91809ba7093967f7a648", size = 248999, upload-time = "2025-10-06T14:48:46.703Z" }, - { url = "https://files.pythonhosted.org/packages/b5/3f/df171b6efa3239ae33b97b887e42671cd1d94d460614bfb2c30ffdab3b95/multidict-6.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:661709cdcd919a2ece2234f9bae7174e5220c80b034585d7d8a755632d3e2111", size = 243711, upload-time = "2025-10-06T14:48:48.146Z" }, - { url = "https://files.pythonhosted.org/packages/3c/2f/9b5564888c4e14b9af64c54acf149263721a283aaf4aa0ae89b091d5d8c1/multidict-6.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:096f52730c3fb8ed419db2d44391932b63891b2c5ed14850a7e215c0ba9ade36", size = 237504, upload-time = "2025-10-06T14:48:49.447Z" }, - { url = "https://files.pythonhosted.org/packages/6c/3a/0bd6ca0f7d96d790542d591c8c3354c1e1b6bfd2024d4d92dc3d87485ec7/multidict-6.7.0-cp310-cp310-win32.whl", hash = "sha256:afa8a2978ec65d2336305550535c9c4ff50ee527914328c8677b3973ade52b85", size = 41422, upload-time = "2025-10-06T14:48:50.789Z" }, - { url = "https://files.pythonhosted.org/packages/00/35/f6a637ea2c75f0d3b7c7d41b1189189acff0d9deeb8b8f35536bb30f5e33/multidict-6.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:b15b3afff74f707b9275d5ba6a91ae8f6429c3ffb29bbfd216b0b375a56f13d7", size = 46050, upload-time = "2025-10-06T14:48:51.938Z" }, - { url = "https://files.pythonhosted.org/packages/e7/b8/f7bf8329b39893d02d9d95cf610c75885d12fc0f402b1c894e1c8e01c916/multidict-6.7.0-cp310-cp310-win_arm64.whl", hash = "sha256:4b73189894398d59131a66ff157837b1fafea9974be486d036bb3d32331fdbf0", size = 43153, upload-time = "2025-10-06T14:48:53.146Z" }, - { url = "https://files.pythonhosted.org/packages/b7/da/7d22601b625e241d4f23ef1ebff8acfc60da633c9e7e7922e24d10f592b3/multidict-6.7.0-py3-none-any.whl", hash = "sha256:394fc5c42a333c9ffc3e421a4c85e08580d990e08b99f6bf35b4132114c5dcb3", size = 12317, upload-time = "2025-10-06T14:52:29.272Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176 }, + { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996 }, + { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631 }, + { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561 }, + { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223 }, + { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322 }, + { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005 }, + { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173 }, + { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273 }, + { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956 }, + { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477 }, + { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615 }, + { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930 }, + { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807 }, + { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103 }, + { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416 }, + { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022 }, + { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238 }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319 }, ] [[package]] @@ -1779,23 +1794,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083, upload-time = "2025-04-17T03:11:04.223Z" }, - { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128, upload-time = "2025-04-17T03:11:06.045Z" }, - { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132, upload-time = "2025-04-17T03:11:07.533Z" }, - { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, - { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, - { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, + { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083 }, + { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128 }, + { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132 }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948 }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636 }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478 }, ] [[package]] name = "narwhals" -version = "2.15.0" +version = "2.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/6d/b57c64e5038a8cf071bce391bb11551657a74558877ac961e7fa905ece27/narwhals-2.15.0.tar.gz", hash = "sha256:a9585975b99d95084268445a1fdd881311fa26ef1caa18020d959d5b2ff9a965", size = 603479, upload-time = "2026-01-06T08:10:13.27Z" } +sdist = { url = "https://files.pythonhosted.org/packages/75/59/81d0f4cad21484083466f278e6b392addd9f4205b48d45b5c8771670ebf8/narwhals-2.17.0.tar.gz", hash = "sha256:ebd5bc95bcfa2f8e89a8ac09e2765a63055162837208e67b42d6eeb6651d5e67", size = 620306 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/2e/cf2ffeb386ac3763526151163ad7da9f1b586aac96d2b4f7de1eaebf0c61/narwhals-2.15.0-py3-none-any.whl", hash = "sha256:cbfe21ca19d260d9fd67f995ec75c44592d1f106933b03ddd375df7ac841f9d6", size = 432856, upload-time = "2026-01-06T08:10:11.511Z" }, + { url = "https://files.pythonhosted.org/packages/4b/27/20770bd6bf8fbe1e16f848ba21da9df061f38d2e6483952c29d2bb5d1d8b/narwhals-2.17.0-py3-none-any.whl", hash = "sha256:2ac5307b7c2b275a7d66eeda906b8605e3d7a760951e188dcfff86e8ebe083dd", size = 444897 }, ] [[package]] @@ -1808,14 +1823,14 @@ dependencies = [ { name = "nbformat" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } +sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554 } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, + { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465 }, ] [[package]] name = "nbconvert" -version = "7.16.6" +version = "7.17.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "beautifulsoup4" }, @@ -1833,9 +1848,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a3/59/f28e15fc47ffb73af68a8d9b47367a8630d76e97ae85ad18271b9db96fdf/nbconvert-7.16.6.tar.gz", hash = "sha256:576a7e37c6480da7b8465eefa66c17844243816ce1ccc372633c6b71c3c0f582", size = 857715, upload-time = "2025-01-28T09:29:14.724Z" } +sdist = { url = "https://files.pythonhosted.org/packages/38/47/81f886b699450d0569f7bc551df2b1673d18df7ff25cc0c21ca36ed8a5ff/nbconvert-7.17.0.tar.gz", hash = "sha256:1b2696f1b5be12309f6c7d707c24af604b87dfaf6d950794c7b07acab96dda78", size = 862855 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/9a/cd673b2f773a12c992f41309ef81b99da1690426bd2f96957a7ade0d3ed7/nbconvert-7.16.6-py3-none-any.whl", hash = "sha256:1375a7b67e0c2883678c48e506dc320febb57685e5ee67faa51b18a90f3a712b", size = 258525, upload-time = "2025-01-28T09:29:12.551Z" }, + { url = "https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl", hash = "sha256:4f99a63b337b9a23504347afdab24a11faa7d86b405e5c8f9881cd313336d518", size = 261510 }, ] [[package]] @@ -1848,53 +1863,53 @@ dependencies = [ { name = "jupyter-core" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, ] [[package]] name = "nbstripout" -version = "0.8.2" +version = "0.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nbformat" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/95/09/cea5360a0788f94337d1b65c313ff0a448fb6a444b65cab89378eb8f7d5c/nbstripout-0.8.2.tar.gz", hash = "sha256:2876530eb684bf93a5b48fe6d92b2163f78d040721c76b37d5b9e1514d38fc69", size = 27747, upload-time = "2025-11-16T17:38:55.6Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/6f/b52c4da26babeb521078c08c78c3187a59197098ffc7a70b0fe76851813a/nbstripout-0.9.1.tar.gz", hash = "sha256:313bbb4217c8e38998567e5d790b6bd6c3a17a8c39073b205b84dadfc5d756dc", size = 32356 } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/e5/838eb1004fb9b6f0383c47c0d902eb698fda052e8e64ca48c70a2144a48c/nbstripout-0.8.2-py2.py3-none-any.whl", hash = "sha256:5f06f9138cb64daed3e91c5359ff0fff85bab4d0db7d72723be1da6f51b890ae", size = 17122, upload-time = "2025-11-16T17:38:54.164Z" }, + { url = "https://files.pythonhosted.org/packages/20/16/e777eadfa0c0305878c36fae1d5e6db474fbb15dae202b9ec378809dfb4d/nbstripout-0.9.1-py3-none-any.whl", hash = "sha256:ca027ee45742ee77e4f8e9080254f9a707f1161ba11367b82fdf4a29892c759e", size = 19136 }, ] [[package]] name = "nest-asyncio" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, ] [[package]] name = "networkx" version = "3.4.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, ] [[package]] name = "nodeenv" version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611 } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438 }, ] [[package]] name = "notebook" -version = "7.5.1" +version = "7.5.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, @@ -1903,9 +1918,9 @@ dependencies = [ { name = "notebook-shim" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/a9/882707b0aa639e6d7d3e7df4bfbe07479d832e9a8f02d8471002a4ea6d65/notebook-7.5.1.tar.gz", hash = "sha256:b2fb4cef4d47d08c33aecce1c6c6e84be05436fbd791f88fce8df9fbca088b75", size = 14058696, upload-time = "2025-12-16T07:38:59.223Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/cb/cc7f4df5cee315dd126a47eb60890690a0438d5e0dd40c32d60ce16de377/notebook-7.5.3.tar.gz", hash = "sha256:393ceb269cf9fdb02a3be607a57d7bd5c2c14604f1818a17dbeb38e04f98cbfa", size = 14073140 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/86/ca516cb58ad2cb2064124d31cf0fd8b012fca64bebeb26da2d2ddf03fc79/notebook-7.5.1-py3-none-any.whl", hash = "sha256:f4e2451c19910c33b88709b84537e11f6368c1cdff1aa0c43db701aea535dd44", size = 14468080, upload-time = "2025-12-16T07:38:55.644Z" }, + { url = "https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl", hash = "sha256:c997bfa1a2a9eb58c9bbb7e77d50428befb1033dd6f02c482922e96851d67354", size = 14481744 }, ] [[package]] @@ -1915,25 +1930,25 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 }, ] [[package]] name = "numpy" version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, - { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411, upload-time = "2024-02-05T23:48:29.038Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016, upload-time = "2024-02-05T23:48:54.098Z" }, - { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889, upload-time = "2024-02-05T23:49:25.361Z" }, - { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746, upload-time = "2024-02-05T23:49:51.983Z" }, - { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620, upload-time = "2024-02-05T23:50:22.515Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659, upload-time = "2024-02-05T23:50:35.834Z" }, - { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905, upload-time = "2024-02-05T23:51:03.701Z" }, + { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468 }, + { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411 }, + { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016 }, + { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889 }, + { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746 }, + { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620 }, + { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659 }, + { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, ] [[package]] @@ -1941,7 +1956,8 @@ name = "nvidia-cublas-cu12" version = "12.8.4.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, + { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, ] [[package]] @@ -1949,7 +1965,8 @@ name = "nvidia-cuda-cupti-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, ] [[package]] @@ -1957,7 +1974,8 @@ name = "nvidia-cuda-nvrtc-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, + { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, ] [[package]] @@ -1965,7 +1983,8 @@ name = "nvidia-cuda-runtime-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, + { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, ] [[package]] @@ -1973,10 +1992,11 @@ name = "nvidia-cudnn-cu12" version = "9.10.2.21" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cublas-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, + { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, ] [[package]] @@ -1984,10 +2004,11 @@ name = "nvidia-cufft-cu12" version = "11.3.3.83" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, + { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, ] [[package]] @@ -1995,7 +2016,8 @@ name = "nvidia-cufile-cu12" version = "1.13.1.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, + { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, ] [[package]] @@ -2003,7 +2025,8 @@ name = "nvidia-curand-cu12" version = "10.3.9.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, + { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, ] [[package]] @@ -2011,12 +2034,13 @@ name = "nvidia-cusolver-cu12" version = "11.7.3.90" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, - { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, + { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, ] [[package]] @@ -2024,10 +2048,11 @@ name = "nvidia-cusparse-cu12" version = "12.5.8.93" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, + { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, ] [[package]] @@ -2035,7 +2060,8 @@ name = "nvidia-cusparselt-cu12" version = "0.7.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, + { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, ] [[package]] @@ -2043,7 +2069,8 @@ name = "nvidia-nccl-cu12" version = "2.27.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, + { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, ] [[package]] @@ -2051,15 +2078,17 @@ name = "nvidia-nvjitlink-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, + { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, ] [[package]] name = "nvidia-nvshmem-cu12" -version = "3.3.20" +version = "3.4.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" }, + { url = "https://files.pythonhosted.org/packages/1d/6a/03aa43cc9bd3ad91553a88b5f6fb25ed6a3752ae86ce2180221962bc2aa5/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b48363fc6964dede448029434c6abed6c5e37f823cb43c3bcde7ecfc0457e15", size = 138936938 }, + { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095 }, ] [[package]] @@ -2067,7 +2096,8 @@ name = "nvidia-nvtx-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, ] [[package]] @@ -2077,24 +2107,24 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "defusedxml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045, upload-time = "2020-01-18T16:55:48.852Z" } +sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045 } [[package]] name = "overrides" version = "7.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832 }, ] [[package]] name = "packaging" -version = "25.0" +version = "26.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416 } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366 }, ] [[package]] @@ -2107,33 +2137,33 @@ dependencies = [ { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, - { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, - { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, - { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, - { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, - { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, - { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, + { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763 }, + { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217 }, + { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791 }, + { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373 }, + { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444 }, + { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459 }, + { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086 }, ] [[package]] name = "pandocfilters" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, ] [[package]] name = "parso" -version = "0.8.5" +version = "0.8.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621 } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, + { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894 }, ] [[package]] @@ -2143,73 +2173,66 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, ] [[package]] name = "pillow" -version = "10.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/74/ad3d526f3bf7b6d3f408b73fde271ec69dfac8b81341a318ce825f2b3812/pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06", size = 46555059, upload-time = "2024-07-01T09:48:43.583Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/69/a31cccd538ca0b5272be2a38347f8839b97a14be104ea08b0db92f749c74/pillow-10.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:4d9667937cfa347525b319ae34375c37b9ee6b525440f3ef48542fcf66f2731e", size = 3509271, upload-time = "2024-07-01T09:45:22.07Z" }, - { url = "https://files.pythonhosted.org/packages/9a/9e/4143b907be8ea0bce215f2ae4f7480027473f8b61fcedfda9d851082a5d2/pillow-10.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:543f3dc61c18dafb755773efc89aae60d06b6596a63914107f75459cf984164d", size = 3375658, upload-time = "2024-07-01T09:45:25.292Z" }, - { url = "https://files.pythonhosted.org/packages/8a/25/1fc45761955f9359b1169aa75e241551e74ac01a09f487adaaf4c3472d11/pillow-10.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7928ecbf1ece13956b95d9cbcfc77137652b02763ba384d9ab508099a2eca856", size = 4332075, upload-time = "2024-07-01T09:45:27.94Z" }, - { url = "https://files.pythonhosted.org/packages/5e/dd/425b95d0151e1d6c951f45051112394f130df3da67363b6bc75dc4c27aba/pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f", size = 4444808, upload-time = "2024-07-01T09:45:30.305Z" }, - { url = "https://files.pythonhosted.org/packages/b1/84/9a15cc5726cbbfe7f9f90bfb11f5d028586595907cd093815ca6644932e3/pillow-10.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:6c762a5b0997f5659a5ef2266abc1d8851ad7749ad9a6a5506eb23d314e4f46b", size = 4356290, upload-time = "2024-07-01T09:45:32.868Z" }, - { url = "https://files.pythonhosted.org/packages/b5/5b/6651c288b08df3b8c1e2f8c1152201e0b25d240e22ddade0f1e242fc9fa0/pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc", size = 4525163, upload-time = "2024-07-01T09:45:35.279Z" }, - { url = "https://files.pythonhosted.org/packages/07/8b/34854bf11a83c248505c8cb0fcf8d3d0b459a2246c8809b967963b6b12ae/pillow-10.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:812f7342b0eee081eaec84d91423d1b4650bb9828eb53d8511bcef8ce5aecf1e", size = 4463100, upload-time = "2024-07-01T09:45:37.74Z" }, - { url = "https://files.pythonhosted.org/packages/78/63/0632aee4e82476d9cbe5200c0cdf9ba41ee04ed77887432845264d81116d/pillow-10.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ac1452d2fbe4978c2eec89fb5a23b8387aba707ac72810d9490118817d9c0b46", size = 4592880, upload-time = "2024-07-01T09:45:39.89Z" }, - { url = "https://files.pythonhosted.org/packages/df/56/b8663d7520671b4398b9d97e1ed9f583d4afcbefbda3c6188325e8c297bd/pillow-10.4.0-cp310-cp310-win32.whl", hash = "sha256:bcd5e41a859bf2e84fdc42f4edb7d9aba0a13d29a2abadccafad99de3feff984", size = 2235218, upload-time = "2024-07-01T09:45:42.771Z" }, - { url = "https://files.pythonhosted.org/packages/f4/72/0203e94a91ddb4a9d5238434ae6c1ca10e610e8487036132ea9bf806ca2a/pillow-10.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:ecd85a8d3e79cd7158dec1c9e5808e821feea088e2f69a974db5edf84dc53141", size = 2554487, upload-time = "2024-07-01T09:45:45.176Z" }, - { url = "https://files.pythonhosted.org/packages/bd/52/7e7e93d7a6e4290543f17dc6f7d3af4bd0b3dd9926e2e8a35ac2282bc5f4/pillow-10.4.0-cp310-cp310-win_arm64.whl", hash = "sha256:ff337c552345e95702c5fde3158acb0625111017d0e5f24bf3acdb9cc16b90d1", size = 2243219, upload-time = "2024-07-01T09:45:47.274Z" }, - { url = "https://files.pythonhosted.org/packages/38/30/095d4f55f3a053392f75e2eae45eba3228452783bab3d9a920b951ac495c/pillow-10.4.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5b4815f2e65b30f5fbae9dfffa8636d992d49705723fe86a3661806e069352d4", size = 3493889, upload-time = "2024-07-01T09:48:04.815Z" }, - { url = "https://files.pythonhosted.org/packages/f3/e8/4ff79788803a5fcd5dc35efdc9386af153569853767bff74540725b45863/pillow-10.4.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8f0aef4ef59694b12cadee839e2ba6afeab89c0f39a3adc02ed51d109117b8da", size = 3346160, upload-time = "2024-07-01T09:48:07.206Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ac/4184edd511b14f760c73f5bb8a5d6fd85c591c8aff7c2229677a355c4179/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f4727572e2918acaa9077c919cbbeb73bd2b3ebcfe033b72f858fc9fbef0026", size = 3435020, upload-time = "2024-07-01T09:48:09.66Z" }, - { url = "https://files.pythonhosted.org/packages/da/21/1749cd09160149c0a246a81d646e05f35041619ce76f6493d6a96e8d1103/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff25afb18123cea58a591ea0244b92eb1e61a1fd497bf6d6384f09bc3262ec3e", size = 3490539, upload-time = "2024-07-01T09:48:12.529Z" }, - { url = "https://files.pythonhosted.org/packages/b6/f5/f71fe1888b96083b3f6dfa0709101f61fc9e972c0c8d04e9d93ccef2a045/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:dc3e2db6ba09ffd7d02ae9141cfa0ae23393ee7687248d46a7507b75d610f4f5", size = 3476125, upload-time = "2024-07-01T09:48:14.891Z" }, - { url = "https://files.pythonhosted.org/packages/96/b9/c0362c54290a31866c3526848583a2f45a535aa9d725fd31e25d318c805f/pillow-10.4.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", size = 3579373, upload-time = "2024-07-01T09:48:17.601Z" }, - { url = "https://files.pythonhosted.org/packages/52/3b/ce7a01026a7cf46e5452afa86f97a5e88ca97f562cafa76570178ab56d8d/pillow-10.4.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0755ffd4a0c6f267cccbae2e9903d95477ca2f77c4fcf3a3a09570001856c8a5", size = 2554661, upload-time = "2024-07-01T09:48:20.293Z" }, +version = "12.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/30/5bd3d794762481f8c8ae9c80e7b76ecea73b916959eb587521358ef0b2f9/pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0", size = 5304099 }, + { url = "https://files.pythonhosted.org/packages/bd/c1/aab9e8f3eeb4490180e357955e15c2ef74b31f64790ff356c06fb6cf6d84/pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713", size = 4657880 }, + { url = "https://files.pythonhosted.org/packages/f1/0a/9879e30d56815ad529d3985aeff5af4964202425c27261a6ada10f7cbf53/pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b", size = 6222587 }, + { url = "https://files.pythonhosted.org/packages/5a/5f/a1b72ff7139e4f89014e8d451442c74a774d5c43cd938fb0a9f878576b37/pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b", size = 8027678 }, + { url = "https://files.pythonhosted.org/packages/e2/c2/c7cb187dac79a3d22c3ebeae727abee01e077c8c7d930791dc592f335153/pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4", size = 6335777 }, + { url = "https://files.pythonhosted.org/packages/0c/7b/f9b09a7804ec7336effb96c26d37c29d27225783dc1501b7d62dcef6ae25/pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4", size = 7027140 }, + { url = "https://files.pythonhosted.org/packages/98/b2/2fa3c391550bd421b10849d1a2144c44abcd966daadd2f7c12e19ea988c4/pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e", size = 6449855 }, + { url = "https://files.pythonhosted.org/packages/96/ff/9caf4b5b950c669263c39e96c78c0d74a342c71c4f43fd031bb5cb7ceac9/pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff", size = 7151329 }, + { url = "https://files.pythonhosted.org/packages/7b/f8/4b24841f582704da675ca535935bccb32b00a6da1226820845fac4a71136/pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40", size = 6325574 }, + { url = "https://files.pythonhosted.org/packages/f8/f9/9f6b01c0881d7036063aa6612ef04c0e2cad96be21325a1e92d0203f8e91/pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23", size = 7032347 }, + { url = "https://files.pythonhosted.org/packages/79/13/c7922edded3dcdaf10c59297540b72785620abc0538872c819915746757d/pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9", size = 2453457 }, ] [[package]] name = "pip" -version = "25.3" +version = "26.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/6e/74a3f0179a4a73a53d66ce57fdb4de0080a8baa1de0063de206d6167acc2/pip-25.3.tar.gz", hash = "sha256:8d0538dbbd7babbd207f261ed969c65de439f6bc9e5dbd3b3b9a77f25d95f343", size = 1803014, upload-time = "2025-10-25T00:55:41.394Z" } +sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747 } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/3c/d717024885424591d5376220b5e836c2d5293ce2011523c9de23ff7bf068/pip-25.3-py3-none-any.whl", hash = "sha256:9655943313a94722b7774661c21049070f6bbb0a1516bf02f7c8d5d9201514cd", size = 1778622, upload-time = "2025-10-25T00:55:39.247Z" }, + { url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723 }, ] [[package]] name = "platformdirs" -version = "4.5.1" +version = "4.9.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394 } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, + { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168 }, ] [[package]] name = "plotly" -version = "6.5.0" +version = "6.5.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "narwhals" }, { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/05/1199e2a03ce6637960bc1e951ca0f928209a48cfceb57355806a88f214cf/plotly-6.5.0.tar.gz", hash = "sha256:d5d38224883fd38c1409bef7d6a8dc32b74348d39313f3c52ca998b8e447f5c8", size = 7013624, upload-time = "2025-11-17T18:39:24.523Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/4f/8a10a9b9f5192cb6fdef62f1d77fa7d834190b2c50c0cd256bd62879212b/plotly-6.5.2.tar.gz", hash = "sha256:7478555be0198562d1435dee4c308268187553cc15516a2f4dd034453699e393", size = 7015695 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/c3/3031c931098de393393e1f93a38dc9ed6805d86bb801acc3cf2d5bd1e6b7/plotly-6.5.0-py3-none-any.whl", hash = "sha256:5ac851e100367735250206788a2b1325412aa4a4917a4fe3e6f0bc5aa6f3d90a", size = 9893174, upload-time = "2025-11-17T18:39:20.351Z" }, + { url = "https://files.pythonhosted.org/packages/8a/67/f95b5460f127840310d2187f916cf0023b5875c0717fdf893f71e1325e87/plotly-6.5.2-py3-none-any.whl", hash = "sha256:91757653bd9c550eeea2fa2404dba6b85d1e366d54804c340b2c874e5a7eb4a4", size = 9895973 }, ] [[package]] name = "pptree" version = "3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043, upload-time = "2020-04-15T18:28:53.362Z" } +sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043 } [[package]] name = "pre-commit" @@ -2222,18 +2245,18 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" } +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437 }, ] [[package]] name = "prometheus-client" -version = "0.23.1" +version = "0.24.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/23/53/3edb5d68ecf6b38fcbcc1ad28391117d2a322d9a1a3eff04bfdb184d8c3b/prometheus_client-0.23.1.tar.gz", hash = "sha256:6ae8f9081eaaaf153a2e959d2e6c4f4fb57b12ef76c8c7980202f1e57b48b2ce", size = 80481, upload-time = "2025-09-18T20:47:25.043Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/db/14bafcb4af2139e046d03fd00dea7873e48eafe18b7d2797e73d6681f210/prometheus_client-0.23.1-py3-none-any.whl", hash = "sha256:dd1913e6e76b59cfe44e7a4b83e01afc9873c1bdfd2ed8739f1e76aeca115f99", size = 61145, upload-time = "2025-09-18T20:47:23.875Z" }, + { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057 }, ] [[package]] @@ -2243,105 +2266,105 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, ] [[package]] name = "propcache" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534 }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526 }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263 }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012 }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491 }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319 }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856 }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241 }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552 }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113 }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778 }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047 }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093 }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638 }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229 }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, ] [[package]] name = "protobuf" -version = "6.33.2" +version = "6.33.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/34/44/e49ecff446afeec9d1a66d6bbf9adc21e3c7cea7803a920ca3773379d4f6/protobuf-6.33.2.tar.gz", hash = "sha256:56dc370c91fbb8ac85bc13582c9e373569668a290aa2e66a590c2a0d35ddb9e4", size = 444296, upload-time = "2025-12-06T00:17:53.311Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/91/1e3a34881a88697a7354ffd177e8746e97a722e5e8db101544b47e84afb1/protobuf-6.33.2-cp310-abi3-win32.whl", hash = "sha256:87eb388bd2d0f78febd8f4c8779c79247b26a5befad525008e49a6955787ff3d", size = 425603, upload-time = "2025-12-06T00:17:41.114Z" }, - { url = "https://files.pythonhosted.org/packages/64/20/4d50191997e917ae13ad0a235c8b42d8c1ab9c3e6fd455ca16d416944355/protobuf-6.33.2-cp310-abi3-win_amd64.whl", hash = "sha256:fc2a0e8b05b180e5fc0dd1559fe8ebdae21a27e81ac77728fb6c42b12c7419b4", size = 436930, upload-time = "2025-12-06T00:17:43.278Z" }, - { url = "https://files.pythonhosted.org/packages/b2/ca/7e485da88ba45c920fb3f50ae78de29ab925d9e54ef0de678306abfbb497/protobuf-6.33.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d9b19771ca75935b3a4422957bc518b0cecb978b31d1dd12037b088f6bcc0e43", size = 427621, upload-time = "2025-12-06T00:17:44.445Z" }, - { url = "https://files.pythonhosted.org/packages/7d/4f/f743761e41d3b2b2566748eb76bbff2b43e14d5fcab694f494a16458b05f/protobuf-6.33.2-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:b5d3b5625192214066d99b2b605f5783483575656784de223f00a8d00754fc0e", size = 324460, upload-time = "2025-12-06T00:17:45.678Z" }, - { url = "https://files.pythonhosted.org/packages/b1/fa/26468d00a92824020f6f2090d827078c09c9c587e34cbfd2d0c7911221f8/protobuf-6.33.2-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8cd7640aee0b7828b6d03ae518b5b4806fdfc1afe8de82f79c3454f8aef29872", size = 339168, upload-time = "2025-12-06T00:17:46.813Z" }, - { url = "https://files.pythonhosted.org/packages/56/13/333b8f421738f149d4fe5e49553bc2a2ab75235486259f689b4b91f96cec/protobuf-6.33.2-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:1f8017c48c07ec5859106533b682260ba3d7c5567b1ca1f24297ce03384d1b4f", size = 323270, upload-time = "2025-12-06T00:17:48.253Z" }, - { url = "https://files.pythonhosted.org/packages/0e/15/4f02896cc3df04fc465010a4c6a0cd89810f54617a32a70ef531ed75d61c/protobuf-6.33.2-py3-none-any.whl", hash = "sha256:7636aad9bb01768870266de5dc009de2d1b936771b38a793f73cbbf279c91c5c", size = 170501, upload-time = "2025-12-06T00:17:52.211Z" }, + { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769 }, + { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118 }, + { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766 }, + { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638 }, + { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411 }, + { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465 }, + { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687 }, ] [[package]] name = "psutil" version = "6.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565, upload-time = "2024-10-17T21:31:45.68Z" } +sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762, upload-time = "2024-10-17T21:32:05.991Z" }, - { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777, upload-time = "2024-10-17T21:32:07.872Z" }, - { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259, upload-time = "2024-10-17T21:32:10.177Z" }, - { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255, upload-time = "2024-10-17T21:32:11.964Z" }, - { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804, upload-time = "2024-10-17T21:32:13.785Z" }, - { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386, upload-time = "2024-10-17T21:32:21.399Z" }, - { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228, upload-time = "2024-10-17T21:32:23.88Z" }, + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, ] [[package]] name = "pyarrow" -version = "22.0.0" +version = "23.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } +sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, - { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085, upload-time = "2025-10-24T10:03:38.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613, upload-time = "2025-10-24T10:03:46.516Z" }, - { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059, upload-time = "2025-10-24T10:03:55.353Z" }, - { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043, upload-time = "2025-10-24T10:04:05.408Z" }, - { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505, upload-time = "2025-10-24T10:04:15.786Z" }, - { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641, upload-time = "2025-10-24T10:04:22.57Z" }, + { url = "https://files.pythonhosted.org/packages/bc/a8/24e5dc6855f50a62936ceb004e6e9645e4219a8065f304145d7fb8a79d5d/pyarrow-23.0.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:3fab8f82571844eb3c460f90a75583801d14ca0cc32b1acc8c361650e006fd56", size = 34307390 }, + { url = "https://files.pythonhosted.org/packages/bc/8e/4be5617b4aaae0287f621ad31c6036e5f63118cfca0dc57d42121ff49b51/pyarrow-23.0.1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:3f91c038b95f71ddfc865f11d5876c42f343b4495535bd262c7b321b0b94507c", size = 35853761 }, + { url = "https://files.pythonhosted.org/packages/2e/08/3e56a18819462210432ae37d10f5c8eed3828be1d6c751b6e6a2e93c286a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d0744403adabef53c985a7f8a082b502a368510c40d184df349a0a8754533258", size = 44493116 }, + { url = "https://files.pythonhosted.org/packages/f8/82/c40b68001dbec8a3faa4c08cd8c200798ac732d2854537c5449dc859f55a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c33b5bf406284fd0bba436ed6f6c3ebe8e311722b441d89397c54f871c6863a2", size = 47564532 }, + { url = "https://files.pythonhosted.org/packages/20/bc/73f611989116b6f53347581b02177f9f620efdf3cd3f405d0e83cdf53a83/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ddf743e82f69dcd6dbbcb63628895d7161e04e56794ef80550ac6f3315eeb1d5", size = 48183685 }, + { url = "https://files.pythonhosted.org/packages/b0/cc/6c6b3ecdae2a8c3aced99956187e8302fc954cc2cca2a37cf2111dad16ce/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e052a211c5ac9848ae15d5ec875ed0943c0221e2fcfe69eee80b604b4e703222", size = 50605582 }, + { url = "https://files.pythonhosted.org/packages/8d/94/d359e708672878d7638a04a0448edf7c707f9e5606cee11e15aaa5c7535a/pyarrow-23.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:5abde149bb3ce524782d838eb67ac095cd3fd6090eba051130589793f1a7f76d", size = 27521148 }, ] [[package]] name = "pycparser" -version = "2.23" +version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172 }, ] [[package]] @@ -2354,9 +2377,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591 } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580 }, ] [package.optional-dependencies] @@ -2371,29 +2394,37 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, - { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, - { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, - { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, - { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, - { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, - { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, - { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, - { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, - { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, - { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, - { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, - { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, - { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, - { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, - { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, - { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, - { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, - { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298 }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475 }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815 }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567 }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442 }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956 }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253 }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050 }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178 }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833 }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156 }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378 }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622 }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441 }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291 }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632 }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905 }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495 }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388 }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879 }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017 }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351 }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363 }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615 }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369 }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218 }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951 }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428 }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009 }, ] [[package]] @@ -2404,87 +2435,87 @@ dependencies = [ { name = "pydantic" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226, upload-time = "2025-12-31T16:18:27.944Z" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296, upload-time = "2025-12-31T16:18:26.38Z" }, + { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296 }, ] [[package]] name = "pydantic-settings" -version = "2.12.0" +version = "2.13.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/43/4b/ac7e0aae12027748076d72a8764ff1c9d82ca75a7a52622e67ed3f765c54/pydantic_settings-2.12.0.tar.gz", hash = "sha256:005538ef951e3c2a68e1c08b292b5f2e71490def8589d4221b95dab00dafcfd0", size = 194184, upload-time = "2025-11-10T14:25:47.013Z" } +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/60/5d4751ba3f4a40a6891f24eec885f51afd78d208498268c734e256fb13c4/pydantic_settings-2.12.0-py3-none-any.whl", hash = "sha256:fddb9fd99a5b18da837b29710391e945b1e30c135477f484084ee513adb93809", size = 51880, upload-time = "2025-11-10T14:25:45.546Z" }, + { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929 }, ] [[package]] name = "pygments" version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, ] [[package]] name = "pymupdf" -version = "1.26.7" +version = "1.27.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/d6/09b28f027b510838559f7748807192149c419b30cb90e6d5f0cf916dc9dc/pymupdf-1.26.7.tar.gz", hash = "sha256:71add8bdc8eb1aaa207c69a13400693f06ad9b927bea976f5d5ab9df0bb489c3", size = 84327033, upload-time = "2025-12-11T21:48:50.694Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/0c/40dda0cc4bd2220a2ef75f8c53dd7d8ed1e29681fcb3df75db6ee9677a7e/pymupdf-1.27.1.tar.gz", hash = "sha256:4afbde0769c336717a149ab0de3330dcb75378f795c1a8c5af55c1a628b17d55", size = 85303479 } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/35/cd74cea1787b2247702ef8522186bdef32e9cb30a099e6bb864627ef6045/pymupdf-1.26.7-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:07085718dfdae5ab83b05eb5eb397f863bcc538fe05135318a01ea353e7a1353", size = 23179369, upload-time = "2025-12-11T21:47:21.587Z" }, - { url = "https://files.pythonhosted.org/packages/72/74/448b6172927c829c6a3fba80078d7b0a016ebbe2c9ee528821f5ea21677a/pymupdf-1.26.7-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:31aa9c8377ea1eea02934b92f4dcf79fb2abba0bf41f8a46d64c3e31546a3c02", size = 22470101, upload-time = "2025-12-11T21:47:37.105Z" }, - { url = "https://files.pythonhosted.org/packages/65/e7/47af26f3ac76be7ac3dd4d6cc7ee105948a8355d774e5ca39857bf91c11c/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e419b609996434a14a80fa060adec72c434a1cca6a511ec54db9841bc5d51b3c", size = 23502486, upload-time = "2025-12-12T09:51:25.824Z" }, - { url = "https://files.pythonhosted.org/packages/2a/6b/3de1714d734ff949be1e90a22375d0598d3540b22ae73eb85c2d7d1f36a9/pymupdf-1.26.7-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:69dfc78f206a96e5b3ac22741263ebab945fdf51f0dbe7c5757c3511b23d9d72", size = 24115727, upload-time = "2025-12-11T21:47:51.274Z" }, - { url = "https://files.pythonhosted.org/packages/62/9b/f86224847949577a523be2207315ae0fd3155b5d909cd66c274d095349a3/pymupdf-1.26.7-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1d5106f46e1ca0d64d46bd51892372a4f82076bdc14a9678d33d630702abca36", size = 24324386, upload-time = "2025-12-12T14:58:45.483Z" }, - { url = "https://files.pythonhosted.org/packages/85/8e/a117d39092ca645fde8b903f4a941d9aa75b370a67b4f1f435f56393dc5a/pymupdf-1.26.7-cp310-abi3-win32.whl", hash = "sha256:7c9645b6f5452629c747690190350213d3e5bbdb6b2eca227d82702b327f6eee", size = 17203888, upload-time = "2025-12-12T13:59:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/dd/c3/d0047678146c294469c33bae167c8ace337deafb736b0bf97b9bc481aa65/pymupdf-1.26.7-cp310-abi3-win_amd64.whl", hash = "sha256:425b1befe40d41b72eb0fe211711c7ae334db5eb60307e9dd09066ed060cceba", size = 18405952, upload-time = "2025-12-11T21:48:02.947Z" }, + { url = "https://files.pythonhosted.org/packages/13/19/fde6ea4712a904b65e8f41124a0e4233879b87a770fe6a8ce857964de6d5/pymupdf-1.27.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bee9f95512f9556dbf2cacfd1413c61b29a55baa07fa7f8fc83d221d8419888a", size = 23986707 }, + { url = "https://files.pythonhosted.org/packages/75/c2/070dff91ad3f1bc16fd6c6ceff23495601fcce4c92d28be534417596418a/pymupdf-1.27.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:3de95a0889395b0966fafd11b94980b7543a816e89dd1c218597a08543ac3415", size = 23263493 }, + { url = "https://files.pythonhosted.org/packages/8e/db/937377f4b3e0fbf6273c17436a49f7db17df1a46b1be9e26653b6fafc0e1/pymupdf-1.27.1-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2c9d9353b840040cbc724341f4095fb7e2cc1a12a9147d0ec1a0a79f5d773147", size = 24317651 }, + { url = "https://files.pythonhosted.org/packages/72/d5/c701cf2d0cdd6e5d6bca3ca9188d7f5d7ce3ae67dd1368d658cd4bae2707/pymupdf-1.27.1-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:aeaed76e72cbc061149a825ab0811c5f4752970c56591c2938c5042ec06b26e1", size = 24945742 }, + { url = "https://files.pythonhosted.org/packages/2b/29/690202b38b93cf77b73a29c25a63a2b6f3fcb36b1f75006e50b8dee7c108/pymupdf-1.27.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4f1837554134fb45d390a44de8844b2ca9b6c901c82ccc90b340e3b7f3b126ca", size = 25167965 }, + { url = "https://files.pythonhosted.org/packages/8a/81/f937e6aa606fd263c3a45d0ff0f0bbdbf3fb779933091fc0f6179513cc93/pymupdf-1.27.1-cp310-abi3-win32.whl", hash = "sha256:fa33b512d82c6c4852edadf57f22d5f27d16243bb33dac0fbe4eb0f281c5b17e", size = 18006253 }, + { url = "https://files.pythonhosted.org/packages/3e/99/fe4a7752990bf65277718fffbead4478de9afd1c7288d7a6d643f79a6fa7/pymupdf-1.27.1-cp310-abi3-win_amd64.whl", hash = "sha256:4b6268dff3a9d713034eba5c2ffce0da37c62443578941ac5df433adcde57b2f", size = 19236703 }, ] [[package]] name = "pymupdf4llm" -version = "0.2.8" +version = "0.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pymupdf" }, { name = "tabulate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/ff/d2e856ff5db5fa57ebf13ae04de4da6c203f5fb17507c0dd21ffd0ae4a17/pymupdf4llm-0.2.8.tar.gz", hash = "sha256:c4f9815cff210cef45123e93ae3a6f802e0dc1d1ad4534a4a463c000aaec98fd", size = 66867, upload-time = "2026-01-04T16:38:30.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/9b/97c4fad642f0147af3e884126d80635a1fae02c836fde9c22f0efc053254/pymupdf4llm-0.3.4.tar.gz", hash = "sha256:48d396a5fb3c14351493c7f1dd25b2a843efdbdc4526e489ee100643a2cebec1", size = 74956 } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/d5/47e14346b6f57cbc7456cc24ded697b4037b399ff56ed12afccbd202361d/pymupdf4llm-0.2.8-py3-none-any.whl", hash = "sha256:e60587d151223fc9e118661a9c7bb04b04ae928187c201a14d60ac8a42963591", size = 68637, upload-time = "2026-01-04T16:38:32.412Z" }, + { url = "https://files.pythonhosted.org/packages/2b/67/4394de2e5967d80a9b01ec323049163410b3553185c42dea0c346fa27a41/pymupdf4llm-0.3.4-py3-none-any.whl", hash = "sha256:0517492f82af978541162ade20fc54649cdca52acd478e33b97cb6171d69956f", size = 78669 }, ] [[package]] name = "pypandoc" version = "1.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477, upload-time = "2025-11-13T16:30:29.608Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477 } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451, upload-time = "2025-11-13T16:30:07.66Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451 }, ] [[package]] name = "pyparsing" -version = "3.3.1" +version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/33/c1/1d9de9aeaa1b89b0186e5fe23294ff6517fce1bc69149185577cd31016b2/pyparsing-3.3.1.tar.gz", hash = "sha256:47fad0f17ac1e2cad3de3b458570fbc9b03560aa029ed5e16ee5554da9a2251c", size = 1550512, upload-time = "2025-12-23T03:14:04.391Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/40/2614036cdd416452f5bf98ec037f38a1afb17f327cb8e6b652d4729e0af8/pyparsing-3.3.1-py3-none-any.whl", hash = "sha256:023b5e7e5520ad96642e2c6db4cb683d3970bd640cdf7115049a6e9c3682df82", size = 121793, upload-time = "2025-12-23T03:14:02.103Z" }, + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781 }, ] [[package]] name = "pysocks" version = "1.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 }, ] [[package]] @@ -2494,9 +2525,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, ] [[package]] @@ -2507,36 +2538,36 @@ dependencies = [ { name = "lxml" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987 }, ] [[package]] name = "python-dotenv" version = "1.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221, upload-time = "2025-10-26T15:12:10.434Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, + { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, ] [[package]] name = "python-json-logger" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683 } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548 }, ] [[package]] name = "python-multipart" -version = "0.0.21" +version = "0.0.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/78/96/804520d0850c7db98e5ccb70282e29208723f0964e88ffd9d0da2f52ea09/python_multipart-0.0.21.tar.gz", hash = "sha256:7137ebd4d3bbf70ea1622998f902b97a29434a9e8dc40eb203bbcf7c2a2cba92", size = 37196, upload-time = "2025-12-17T09:24:22.446Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612 } wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" }, + { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579 }, ] [[package]] @@ -2555,9 +2586,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889, upload-time = "2022-11-25T19:33:07.958Z" } +sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949, upload-time = "2022-11-25T19:33:06.093Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949 }, ] [[package]] @@ -2568,44 +2599,45 @@ dependencies = [ { name = "numpy" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086, upload-time = "2021-01-09T17:35:49.131Z" } +sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564, upload-time = "2021-01-09T17:35:47.543Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564 }, ] [[package]] name = "pytz" version = "2025.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, ] [[package]] name = "pywinpty" -version = "3.0.2" +version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/bb/a7cc2967c5c4eceb6cc49cfe39447d4bfc56e6c865e7c2249b6eb978935f/pywinpty-3.0.2.tar.gz", hash = "sha256:1505cc4cb248af42cb6285a65c9c2086ee9e7e574078ee60933d5d7fa86fb004", size = 30669, upload-time = "2025-10-03T21:16:29.205Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/54/37c7370ba91f579235049dc26cd2c5e657d2a943e01820844ffc81f32176/pywinpty-3.0.3.tar.gz", hash = "sha256:523441dc34d231fb361b4b00f8c99d3f16de02f5005fd544a0183112bcc22412", size = 31309 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/f5/b17ae550841949c217ad557ee445b4a14e9c0b506ae51ee087eff53428a6/pywinpty-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:65db57fd3387d71e8372b6a54269cbcd0f6dfa6d4616a29e0af749ec19f5c558", size = 2050330, upload-time = "2025-10-03T21:20:15.656Z" }, + { url = "https://files.pythonhosted.org/packages/62/28/a652709bd76ca7533cd1c443b03add9f5051fdf71bc6bdb8801dddd4e7a3/pywinpty-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:ff05f12d775b142b11c6fe085129bdd759b61cf7d41da6c745e78e3a1ef5bf40", size = 2114320 }, + { url = "https://files.pythonhosted.org/packages/b2/13/a0181cc5c2d5635d3dbc3802b97bc8e3ad4fa7502ccef576651a5e08e54c/pywinpty-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:340ccacb4d74278a631923794ccd758471cfc8eeeeee4610b280420a17ad1e82", size = 235670 }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, ] [[package]] @@ -2615,52 +2647,52 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, - { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, - { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, - { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, - { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, - { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, - { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, - { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, - { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, - { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, - { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, - { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, - { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, - { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850 }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380 }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421 }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149 }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070 }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441 }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529 }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276 }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208 }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766 }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266 }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206 }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747 }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371 }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862 }, ] [[package]] name = "rapidfuzz" version = "3.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900, upload-time = "2025-11-01T11:54:52.321Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900 } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376, upload-time = "2025-11-01T11:52:29.175Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903, upload-time = "2025-11-01T11:52:31.239Z" }, - { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655, upload-time = "2025-11-01T11:52:32.852Z" }, - { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708, upload-time = "2025-11-01T11:52:34.618Z" }, - { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106, upload-time = "2025-11-01T11:52:36.069Z" }, - { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048, upload-time = "2025-11-01T11:52:37.936Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020, upload-time = "2025-11-01T11:52:39.657Z" }, - { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958, upload-time = "2025-11-01T11:52:41.017Z" }, - { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043, upload-time = "2025-11-01T11:52:42.465Z" }, - { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273, upload-time = "2025-11-01T11:52:44.005Z" }, - { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875, upload-time = "2025-11-01T11:52:45.405Z" }, + { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376 }, + { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903 }, + { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655 }, + { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708 }, + { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106 }, + { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048 }, + { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020 }, + { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958 }, + { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043 }, + { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273 }, + { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875 }, ] [[package]] @@ -2672,33 +2704,34 @@ dependencies = [ { name = "rpds-py" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766 }, ] [[package]] name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, +version = "2026.2.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ff/c0/d8079d4f6342e4cec5c3e7d7415b5cd3e633d5f4124f7a4626908dbe84c7/regex-2026.2.19.tar.gz", hash = "sha256:6fb8cb09b10e38f3ae17cc6dc04a1df77762bd0351b6ba9041438e7cc85ec310", size = 414973 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/de/f10b4506acfd684de4e42b0aa56ccea1a778a18864da8f6d319a40591062/regex-2026.2.19-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f5a37a17d110f9d5357a43aa7e3507cb077bf3143d1c549a45c4649e90e40a70", size = 488369 }, + { url = "https://files.pythonhosted.org/packages/8b/2f/b4eaef1f0b4d0bf2a73eaf07c08f6c13422918a4180c9211ce0521746d0c/regex-2026.2.19-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:676c4e6847a83a1d5732b4ed553881ad36f0a8133627bb695a89ecf3571499d3", size = 290743 }, + { url = "https://files.pythonhosted.org/packages/76/7c/805413bd0a88d04688c0725c222cfb811bd54a2f571004c24199a1ae55d6/regex-2026.2.19-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82336faeecac33297cd42857c3b36f12b91810e3fdd276befdd128f73a2b43fa", size = 288652 }, + { url = "https://files.pythonhosted.org/packages/08/ff/2c4cd530a878b1975398e76faef4285f11e7c9ccf1aaedfd528bfcc1f580/regex-2026.2.19-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:52136f5b71f095cb74b736cc3a1b578030dada2e361ef2f07ca582240b703946", size = 781759 }, + { url = "https://files.pythonhosted.org/packages/37/45/9608ab1b41f6740ff4076eabadde8e8b3f3400942b348ac41e8599ccc131/regex-2026.2.19-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4192464fe3e6cb0ef6751f7d3b16f886d8270d359ed1590dd555539d364f0ff7", size = 850947 }, + { url = "https://files.pythonhosted.org/packages/90/3a/66471b6c4f7cac17e14bf5300e46661bba2b17ffb0871bd2759e837a6f82/regex-2026.2.19-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e561dd47a85d2660d3d3af4e6cb2da825cf20f121e577147963f875b83d32786", size = 898794 }, + { url = "https://files.pythonhosted.org/packages/c2/d2/38c53929a5931f7398e5e49f5a5a3079cb2aba30119b4350608364cfad8c/regex-2026.2.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00ec994d7824bf01cd6c7d14c7a6a04d9aeaf7c42a2bc22d2359d715634d539b", size = 791922 }, + { url = "https://files.pythonhosted.org/packages/8b/bd/b046e065630fa25059d9c195b7b5308ea94da45eee65d40879772500f74c/regex-2026.2.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2cb00aabd96b345d56a8c2bc328c8d6c4d29935061e05078bf1f02302e12abf5", size = 783345 }, + { url = "https://files.pythonhosted.org/packages/d4/8f/045c643d2fa255a985e8f87d848e4be230b711a8935e4bdc58e60b8f7b84/regex-2026.2.19-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f374366ed35673ea81b86a8859c457d4fae6ba092b71024857e9e237410c7404", size = 768055 }, + { url = "https://files.pythonhosted.org/packages/72/9f/ab7ae9f5447559562f1a788bbc85c0e526528c5e6c20542d18e4afc86aad/regex-2026.2.19-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f9417fd853fcd00b7d55167e692966dd12d95ba1a88bf08a62002ccd85030790", size = 774955 }, + { url = "https://files.pythonhosted.org/packages/37/5c/f16fc23c56f60b6f4ff194604a6e53bb8aec7b6e8e4a23a482dee8d77235/regex-2026.2.19-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:12e86a01594031abf892686fcb309b041bf3de3d13d99eb7e2b02a8f3c687df1", size = 846010 }, + { url = "https://files.pythonhosted.org/packages/51/c8/6be4c854135d7c9f35d4deeafdaf124b039ecb4ffcaeb7ed0495ad2c97ca/regex-2026.2.19-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:79014115e6fdf18fd9b32e291d58181bf42d4298642beaa13fd73e69810e4cb6", size = 755938 }, + { url = "https://files.pythonhosted.org/packages/d6/8d/f683d49b9663a5324b95a328e69d397f6dade7cb84154eec116bf79fe150/regex-2026.2.19-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:31aefac2506967b7dd69af2c58eca3cc8b086d4110b66d6ac6e9026f0ee5b697", size = 835773 }, + { url = "https://files.pythonhosted.org/packages/16/cd/619224b90da09f167fe4497c350a0d0b30edc539ee9244bf93e604c073c3/regex-2026.2.19-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:49cef7bb2a491f91a8869c7cdd90babf0a417047ab0bf923cd038ed2eab2ccb8", size = 780075 }, + { url = "https://files.pythonhosted.org/packages/5b/88/19cfb0c262d6f9d722edef29157125418bf90eb3508186bf79335afeedae/regex-2026.2.19-cp310-cp310-win32.whl", hash = "sha256:3a039474986e7a314ace6efb9ce52f5da2bdb80ac4955358723d350ec85c32ad", size = 266004 }, + { url = "https://files.pythonhosted.org/packages/82/af/5b487e0287ef72545d7ae92edecdacbe3d44e531cac24fda7de5598ba8dd/regex-2026.2.19-cp310-cp310-win_amd64.whl", hash = "sha256:5b81ff4f9cad99f90c807a00c5882fbcda86d8b3edd94e709fb531fc52cb3d25", size = 277895 }, + { url = "https://files.pythonhosted.org/packages/4c/19/b6715a187ffca4d2979af92a46ce922445ba41f910bf187ccd666a2d52ef/regex-2026.2.19-cp310-cp310-win_arm64.whl", hash = "sha256:a032bc01a4bc73fc3cadba793fce28eb420da39338f47910c59ffcc11a5ba5ef", size = 270465 }, ] [[package]] @@ -2711,9 +2744,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, ] [package.optional-dependencies] @@ -2728,18 +2761,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490 }, ] [[package]] name = "rfc3986-validator" version = "0.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, ] [[package]] @@ -2749,92 +2782,92 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046 }, ] [[package]] name = "rich" -version = "14.2.0" +version = "14.3.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fb/d2/8920e102050a0de7bfabeb4c4614a49248cf8d5d7a8d01885fbb24dc767a/rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4", size = 219990, upload-time = "2025-10-09T14:16:53.064Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582 } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/7a/b0178788f8dc6cafce37a212c99565fa1fe7872c70c6c9c1e1a372d9d88f/rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd", size = 243393, upload-time = "2025-10-09T14:16:51.245Z" }, + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458 }, ] [[package]] name = "rich-toolkit" -version = "0.17.1" +version = "0.19.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/09/3f9b8d9daaf235195c626f21e03604c05b987404ee3bcacee0c1f67f2a8e/rich_toolkit-0.17.1.tar.gz", hash = "sha256:5af54df8d1dd9c8530e462e1bdcaed625c9b49f5a55b035aa0ba1c17bdb87c9a", size = 187925, upload-time = "2025-12-17T10:49:22.583Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/c9/4bbf4bfee195ed1b7d7a6733cc523ca61dbfb4a3e3c12ea090aaffd97597/rich_toolkit-0.19.4.tar.gz", hash = "sha256:52e23d56f9dc30d1343eb3b3f6f18764c313fbfea24e52e6a1d6069bec9c18eb", size = 193951 } wheels = [ - { url = "https://files.pythonhosted.org/packages/7f/7b/15e55fa8a76d0d41bf34d965af78acdaf80a315907adb30de8b63c272694/rich_toolkit-0.17.1-py3-none-any.whl", hash = "sha256:96d24bb921ecd225ffce7c526a9149e74006410c05e6d405bd74ffd54d5631ed", size = 31412, upload-time = "2025-12-17T10:49:21.793Z" }, + { url = "https://files.pythonhosted.org/packages/28/31/97d39719def09c134385bfcfbedfed255168b571e7beb3ad7765aae660ca/rich_toolkit-0.19.4-py3-none-any.whl", hash = "sha256:34ac344de8862801644be8b703e26becf44b047e687f208d7829e8f7cfc311d6", size = 32757 }, ] [[package]] name = "rignore" version = "0.7.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999, upload-time = "2025-11-05T20:42:38.373Z" }, - { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824, upload-time = "2025-11-05T20:42:22.1Z" }, - { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121, upload-time = "2025-11-05T20:40:48.94Z" }, - { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813, upload-time = "2025-11-05T20:41:04.71Z" }, - { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019, upload-time = "2025-11-05T20:41:20.723Z" }, - { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822, upload-time = "2025-11-05T20:41:36.99Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820, upload-time = "2025-11-05T20:42:06.364Z" }, - { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050, upload-time = "2025-11-05T20:41:51.124Z" }, - { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164, upload-time = "2025-11-05T21:40:10.368Z" }, - { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028, upload-time = "2025-11-05T21:40:27.977Z" }, - { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024, upload-time = "2025-11-05T21:40:45.148Z" }, - { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531, upload-time = "2025-11-05T21:41:02.734Z" }, - { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817, upload-time = "2025-11-05T21:41:47.51Z" }, - { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001, upload-time = "2025-11-05T21:41:32.778Z" }, - { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462, upload-time = "2025-11-05T20:42:50.804Z" }, - { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918, upload-time = "2025-11-05T20:42:33.689Z" }, - { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922, upload-time = "2025-11-05T20:41:00.361Z" }, - { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987, upload-time = "2025-11-05T20:41:16.219Z" }, - { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110, upload-time = "2025-11-05T20:41:32.631Z" }, - { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339, upload-time = "2025-11-05T20:41:47.128Z" }, - { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680, upload-time = "2025-11-05T20:42:18.061Z" }, - { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045, upload-time = "2025-11-05T20:42:02.315Z" }, - { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310, upload-time = "2025-11-05T21:40:23.184Z" }, - { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998, upload-time = "2025-11-05T21:40:40.603Z" }, - { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178, upload-time = "2025-11-05T21:40:57.585Z" }, - { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190, upload-time = "2025-11-05T21:41:16.403Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999 }, + { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824 }, + { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121 }, + { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813 }, + { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019 }, + { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822 }, + { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820 }, + { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050 }, + { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164 }, + { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028 }, + { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024 }, + { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531 }, + { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817 }, + { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001 }, + { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462 }, + { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918 }, + { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922 }, + { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987 }, + { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110 }, + { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339 }, + { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680 }, + { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045 }, + { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310 }, + { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998 }, + { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178 }, + { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190 }, ] [[package]] name = "rpds-py" version = "0.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469 } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, - { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, - { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, - { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, - { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, - { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, - { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, - { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, - { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, - { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, - { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, - { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490 }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751 }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696 }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136 }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699 }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022 }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522 }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579 }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305 }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503 }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322 }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792 }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901 }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823 }, ] [[package]] @@ -2844,35 +2877,35 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830 }, ] [[package]] name = "safetensors" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781 }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058 }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748 }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881 }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463 }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855 }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152 }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856 }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060 }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715 }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377 }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368 }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423 }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380 }, + { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430 }, + { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890 }, + { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885 }, ] [[package]] @@ -2885,13 +2918,13 @@ dependencies = [ { name = "scipy" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, - { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, - { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, - { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221 }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834 }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938 }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818 }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969 }, ] [[package]] @@ -2901,16 +2934,16 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870, upload-time = "2024-06-24T20:35:18.532Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226, upload-time = "2024-06-24T20:31:50.451Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893, upload-time = "2024-06-24T20:31:57.337Z" }, - { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258, upload-time = "2024-06-24T20:32:02.711Z" }, - { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715, upload-time = "2024-06-24T20:32:07.648Z" }, - { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038, upload-time = "2024-06-24T20:32:17.305Z" }, - { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959, upload-time = "2024-06-24T20:32:25.982Z" }, - { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514, upload-time = "2024-06-24T20:32:32.618Z" }, - { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252, upload-time = "2024-06-24T20:32:45.06Z" }, + { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226 }, + { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893 }, + { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258 }, + { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715 }, + { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038 }, + { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959 }, + { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514 }, + { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252 }, ] [[package]] @@ -2922,9 +2955,9 @@ dependencies = [ { name = "numpy" }, { name = "pandas" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 }, ] [[package]] @@ -2934,26 +2967,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244, upload-time = "2021-12-15T21:56:14.555Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332, upload-time = "2021-12-15T21:56:12.508Z" }, + { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332 }, ] [[package]] name = "send2trash" -version = "2.0.0" +version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/62/6e/421803dec0c0dfbf5a27e66491ebe6643a461e4f90422f00ea4c68ae24aa/send2trash-2.0.0.tar.gz", hash = "sha256:1761421da3f9930bfe51ed7c45343948573383ad4c27e3acebc91be324e7770d", size = 17206, upload-time = "2025-12-31T04:12:48.664Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/f0/184b4b5f8d00f2a92cf96eec8967a3d550b52cf94362dad1100df9e48d57/send2trash-2.1.0.tar.gz", hash = "sha256:1c72b39f09457db3c05ce1d19158c2cbef4c32b8bedd02c155e49282b7ea7459", size = 17255 } wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/5a/f2f2e5eda25579f754acd83399c522ee03d6acbe001dfe53c8a1ec928b44/send2trash-2.0.0-py3-none-any.whl", hash = "sha256:e70d5ce41dbb890882cc78bc25d137478330b39a391e756fadf82e34da4d85b8", size = 17642, upload-time = "2025-12-31T04:12:45.336Z" }, + { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610 }, ] [[package]] name = "sentence-transformers" -version = "5.2.0" +version = "5.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, + { name = "numpy" }, { name = "scikit-learn" }, { name = "scipy" }, { name = "torch" }, @@ -2961,110 +2995,110 @@ dependencies = [ { name = "transformers" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a2/a1/64e7b111e753307ffb7c5b6d039c52d4a91a47fa32a7f5bc377a49b22402/sentence_transformers-5.2.0.tar.gz", hash = "sha256:acaeb38717de689f3dab45d5e5a02ebe2f75960a4764ea35fea65f58a4d3019f", size = 381004, upload-time = "2025-12-11T14:12:31.038Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/30/21664028fc0776eb1ca024879480bbbab36f02923a8ff9e4cae5a150fa35/sentence_transformers-5.2.3.tar.gz", hash = "sha256:3cd3044e1f3fe859b6a1b66336aac502eaae5d3dd7d5c8fc237f37fbf58137c7", size = 381623 } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/d0/3b2897ef6a0c0c801e9fecca26bcc77081648e38e8c772885ebdd8d7d252/sentence_transformers-5.2.0-py3-none-any.whl", hash = "sha256:aa57180f053687d29b08206766ae7db549be5074f61849def7b17bf0b8025ca2", size = 493748, upload-time = "2025-12-11T14:12:29.516Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/dba4b3e18ebbe1eaa29d9f1764fbc7da0cd91937b83f2b7928d15c5d2d36/sentence_transformers-5.2.3-py3-none-any.whl", hash = "sha256:6437c62d4112b615ddebda362dfc16a4308d604c5b68125ed586e3e95d5b2e30", size = 494225 }, ] [[package]] name = "sentencepiece" version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106, upload-time = "2024-02-19T17:06:47.428Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979, upload-time = "2024-02-19T17:05:34.651Z" }, - { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845, upload-time = "2024-02-19T17:05:37.371Z" }, - { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472, upload-time = "2024-02-19T17:05:39.775Z" }, - { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151, upload-time = "2024-02-19T17:05:42.594Z" }, - { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931, upload-time = "2024-02-19T17:05:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537, upload-time = "2024-02-19T17:05:46.713Z" }, - { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747, upload-time = "2024-02-19T17:05:48.705Z" }, - { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525, upload-time = "2024-02-19T17:05:55.145Z" }, + { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979 }, + { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845 }, + { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472 }, + { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151 }, + { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931 }, + { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537 }, + { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747 }, + { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525 }, ] [[package]] name = "sentry-sdk" -version = "2.48.0" +version = "2.53.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/f0/0e9dc590513d5e742d7799e2038df3a05167cba084c6ca4f3cdd75b55164/sentry_sdk-2.48.0.tar.gz", hash = "sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473", size = 384828, upload-time = "2025-12-16T14:55:41.722Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/06/66c8b705179bc54087845f28fd1b72f83751b6e9a195628e2e9af9926505/sentry_sdk-2.53.0.tar.gz", hash = "sha256:6520ef2c4acd823f28efc55e43eb6ce2e6d9f954a95a3aa96b6fd14871e92b77", size = 412369 } wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/19/8d77f9992e5cbfcaa9133c3bf63b4fbbb051248802e1e803fed5c552fbb2/sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172", size = 414555, upload-time = "2025-12-16T14:55:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/47/d4/2fdf854bc3b9c7f55219678f812600a20a138af2dd847d99004994eada8f/sentry_sdk-2.53.0-py2.py3-none-any.whl", hash = "sha256:46e1ed8d84355ae54406c924f6b290c3d61f4048625989a723fd622aab838899", size = 437908 }, ] [[package]] name = "setuptools" -version = "80.9.0" +version = "82.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/f3/748f4d6f65d1756b9ae577f329c951cda23fb900e4de9f70900ced962085/setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb", size = 1144893 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, + { url = "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0", size = 1003468 }, ] [[package]] name = "shellingham" version = "1.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, ] [[package]] name = "sortedcontainers" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, ] [[package]] name = "soupsieve" -version = "2.8.1" +version = "2.8.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/89/23/adf3796d740536d63a6fbda113d07e60c734b6ed5d3058d1e47fc0495e47/soupsieve-2.8.1.tar.gz", hash = "sha256:4cf733bc50fa805f5df4b8ef4740fc0e0fa6218cf3006269afd3f9d6d80fd350", size = 117856, upload-time = "2025-12-18T13:50:34.655Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/f3/b67d6ea49ca9154453b6d70b34ea22f3996b9fa55da105a79d8732227adc/soupsieve-2.8.1-py3-none-any.whl", hash = "sha256:a11fe2a6f3d76ab3cf2de04eb339c1be5b506a8a47f2ceb6d139803177f85434", size = 36710, upload-time = "2025-12-18T13:50:33.267Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016 }, ] [[package]] name = "sqlalchemy" -version = "2.0.45" +version = "2.0.46" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/f9/5e4491e5ccf42f5d9cfc663741d261b3e6e1683ae7812114e7636409fcc6/sqlalchemy-2.0.45.tar.gz", hash = "sha256:1632a4bda8d2d25703fdad6363058d882541bdaaee0e5e3ddfa0cd3229efce88", size = 9869912, upload-time = "2025-12-09T21:05:16.737Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/70/75b1387d72e2847220441166c5eb4e9846dd753895208c13e6d66523b2d9/sqlalchemy-2.0.45-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c64772786d9eee72d4d3784c28f0a636af5b0a29f3fe26ff11f55efe90c0bd85", size = 2154148, upload-time = "2025-12-10T20:03:21.023Z" }, - { url = "https://files.pythonhosted.org/packages/d8/a4/7805e02323c49cb9d1ae5cd4913b28c97103079765f520043f914fca4cb3/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7ae64ebf7657395824a19bca98ab10eb9a3ecb026bf09524014f1bb81cb598d4", size = 3233051, upload-time = "2025-12-09T22:06:04.768Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ec/32ae09139f61bef3de3142e85c47abdee8db9a55af2bb438da54a4549263/sqlalchemy-2.0.45-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f02325709d1b1a1489f23a39b318e175a171497374149eae74d612634b234c0", size = 3232781, upload-time = "2025-12-09T22:09:54.435Z" }, - { url = "https://files.pythonhosted.org/packages/ad/bd/bf7b869b6f5585eac34222e1cf4405f4ba8c3b85dd6b1af5d4ce8bca695f/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d2c3684fca8a05f0ac1d9a21c1f4a266983a7ea9180efb80ffeb03861ecd01a0", size = 3182096, upload-time = "2025-12-09T22:06:06.169Z" }, - { url = "https://files.pythonhosted.org/packages/21/6a/c219720a241bb8f35c88815ccc27761f5af7fdef04b987b0e8a2c1a6dcaa/sqlalchemy-2.0.45-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:040f6f0545b3b7da6b9317fc3e922c9a98fc7243b2a1b39f78390fc0942f7826", size = 3205109, upload-time = "2025-12-09T22:09:55.969Z" }, - { url = "https://files.pythonhosted.org/packages/bd/c4/6ccf31b2bc925d5d95fab403ffd50d20d7c82b858cf1a4855664ca054dce/sqlalchemy-2.0.45-cp310-cp310-win32.whl", hash = "sha256:830d434d609fe7bfa47c425c445a8b37929f140a7a44cdaf77f6d34df3a7296a", size = 2114240, upload-time = "2025-12-09T21:29:54.007Z" }, - { url = "https://files.pythonhosted.org/packages/de/29/a27a31fca07316def418db6f7c70ab14010506616a2decef1906050a0587/sqlalchemy-2.0.45-cp310-cp310-win_amd64.whl", hash = "sha256:0209d9753671b0da74da2cfbb9ecf9c02f72a759e4b018b3ab35f244c91842c7", size = 2137615, upload-time = "2025-12-09T21:29:55.85Z" }, - { url = "https://files.pythonhosted.org/packages/bf/e1/3ccb13c643399d22289c6a9786c1a91e3dcbb68bce4beb44926ac2c557bf/sqlalchemy-2.0.45-py3-none-any.whl", hash = "sha256:5225a288e4c8cc2308dbdd874edad6e7d0fd38eac1e9e5f23503425c8eee20d0", size = 1936672, upload-time = "2025-12-09T21:54:52.608Z" }, + { url = "https://files.pythonhosted.org/packages/40/26/66ba59328dc25e523bfcb0f8db48bdebe2035e0159d600e1f01c0fc93967/sqlalchemy-2.0.46-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:895296687ad06dc9b11a024cf68e8d9d3943aa0b4964278d2553b86f1b267735", size = 2155051 }, + { url = "https://files.pythonhosted.org/packages/21/cd/9336732941df972fbbfa394db9caa8bb0cf9fe03656ec728d12e9cbd6edc/sqlalchemy-2.0.46-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab65cb2885a9f80f979b85aa4e9c9165a31381ca322cbde7c638fe6eefd1ec39", size = 3234666 }, + { url = "https://files.pythonhosted.org/packages/38/62/865ae8b739930ec433cd4123760bee7f8dafdc10abefd725a025604fb0de/sqlalchemy-2.0.46-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52fe29b3817bd191cc20bad564237c808967972c97fa683c04b28ec8979ae36f", size = 3232917 }, + { url = "https://files.pythonhosted.org/packages/24/38/805904b911857f2b5e00fdea44e9570df62110f834378706939825579296/sqlalchemy-2.0.46-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:09168817d6c19954d3b7655da6ba87fcb3a62bb575fb396a81a8b6a9fadfe8b5", size = 3185790 }, + { url = "https://files.pythonhosted.org/packages/69/4f/3260bb53aabd2d274856337456ea52f6a7eccf6cce208e558f870cec766b/sqlalchemy-2.0.46-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:be6c0466b4c25b44c5d82b0426b5501de3c424d7a3220e86cd32f319ba56798e", size = 3207206 }, + { url = "https://files.pythonhosted.org/packages/ce/b3/67c432d7f9d88bb1a61909b67e29f6354d59186c168fb5d381cf438d3b73/sqlalchemy-2.0.46-cp310-cp310-win32.whl", hash = "sha256:1bc3f601f0a818d27bfe139f6766487d9c88502062a2cd3a7ee6c342e81d5047", size = 2115296 }, + { url = "https://files.pythonhosted.org/packages/4a/8c/25fb284f570f9d48e6c240f0269a50cec9cf009a7e08be4c0aaaf0654972/sqlalchemy-2.0.46-cp310-cp310-win_amd64.whl", hash = "sha256:e0c05aff5c6b1bb5fb46a87e0f9d2f733f83ef6cbbbcd5c642b6c01678268061", size = 2138540 }, + { url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882 }, ] [[package]] name = "sqlitedict" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846, upload-time = "2022-12-03T13:39:13.102Z" } +sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846 } [[package]] name = "sqlmodel" @@ -3074,9 +3108,9 @@ dependencies = [ { name = "pydantic" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392, upload-time = "2024-08-31T09:43:24.088Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276, upload-time = "2024-08-31T09:43:22.358Z" }, + { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, ] [[package]] @@ -3088,22 +3122,22 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, ] [[package]] name = "starlette" -version = "0.50.0" +version = "0.52.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b8/73a0e6a6e079a9d9cfa64113d771e421640b6f679a52eeb9b32f72d871a1/starlette-0.50.0.tar.gz", hash = "sha256:a2a17b22203254bcbc2e1f926d2d55f3f9497f769416b3190768befe598fa3ca", size = 2646985, upload-time = "2025-11-01T15:25:27.516Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/52/1064f510b141bd54025f9b55105e26d1fa970b9be67ad766380a3c9b74b0/starlette-0.50.0-py3-none-any.whl", hash = "sha256:9e5391843ec9b6e472eed1365a78c8098cfceb7a74bfd4d6b1c0c0095efb3bca", size = 74033, upload-time = "2025-11-01T15:25:25.461Z" }, + { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272 }, ] [[package]] @@ -3113,27 +3147,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, ] [[package]] name = "tabulate" version = "0.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090, upload-time = "2022-10-06T17:21:48.54Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090 } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252, upload-time = "2022-10-06T17:21:44.262Z" }, + { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, ] [[package]] name = "tenacity" -version = "9.1.2" +version = "9.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0a/d4/2b0cd0fe285e14b36db076e78c93766ff1d529d70408bd1d2a5a84f1d929/tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb", size = 48036, upload-time = "2025-04-02T08:25:09.966Z" } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/30/643397144bfbfec6f6ef821f36f33e57d35946c44a2352d3c9f0ae847619/tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138", size = 28248, upload-time = "2025-04-02T08:25:07.678Z" }, + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926 }, ] [[package]] @@ -3145,18 +3179,18 @@ dependencies = [ { name = "packaging" }, { name = "protobuf" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2b/c5/d4cc6e293fb837aaf9f76dd7745476aeba8ef7ef5146c3b3f9ee375fe7a5/tensorboardx-2.6.4.tar.gz", hash = "sha256:b163ccb7798b31100b9f5fa4d6bc22dad362d7065c2f24b51e50731adde86828", size = 4769801, upload-time = "2025-06-10T22:37:07.419Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2b/c5/d4cc6e293fb837aaf9f76dd7745476aeba8ef7ef5146c3b3f9ee375fe7a5/tensorboardx-2.6.4.tar.gz", hash = "sha256:b163ccb7798b31100b9f5fa4d6bc22dad362d7065c2f24b51e50731adde86828", size = 4769801 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl", hash = "sha256:5970cf3a1f0a6a6e8b180ccf46f3fe832b8a25a70b86e5a237048a7c0beb18e2", size = 87201, upload-time = "2025-06-10T22:37:05.44Z" }, + { url = "https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl", hash = "sha256:5970cf3a1f0a6a6e8b180ccf46f3fe832b8a25a70b86e5a237048a7c0beb18e2", size = 87201 }, ] [[package]] name = "termcolor" version = "3.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434, upload-time = "2025-12-29T12:55:21.882Z" } +sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434 } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734, upload-time = "2025-12-29T12:55:20.718Z" }, + { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734 }, ] [[package]] @@ -3165,21 +3199,21 @@ version = "0.18.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess", marker = "os_name != 'nt'" }, - { name = "pywinpty", marker = "(os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" }, + { name = "pywinpty", marker = "os_name == 'nt'" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, ] [[package]] name = "threadpoolctl" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274 } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638 }, ] [[package]] @@ -3189,9 +3223,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, ] [[package]] @@ -3201,71 +3235,73 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, - { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, - { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, - { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, - { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, - { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, - { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, - { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, - { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, - { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, - { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, - { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, - { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, - { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, - { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, - { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301, upload-time = "2026-01-05T10:40:34.858Z" }, - { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308, upload-time = "2026-01-05T10:40:40.737Z" }, - { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964, upload-time = "2026-01-05T10:40:46.56Z" }, - { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275 }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472 }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736 }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835 }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673 }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818 }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195 }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982 }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245 }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069 }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263 }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429 }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363 }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786 }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133 }, + { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301 }, + { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308 }, + { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964 }, + { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542 }, ] [[package]] name = "tomli" -version = "2.3.0" +version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/52/ed/3f73f72945444548f33eba9a87fc7a6e969915e7b1acc8260b30e1f76a2f/tomli-2.3.0.tar.gz", hash = "sha256:64be704a875d2a59753d80ee8a533c3fe183e3f06807ff7dc2232938ccb01549", size = 17392, upload-time = "2025-10-08T22:01:47.119Z" } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477 } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/b8/0135fadc89e73be292b473cb820b4f5a08197779206b33191e801feeae40/tomli-2.3.0-py3-none-any.whl", hash = "sha256:e95b1af3c5b07d9e643909b5abbec77cd9f1217e6d0bca72b0234736b9fb1f1b", size = 14408, upload-time = "2025-10-08T22:01:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477 }, ] [[package]] name = "torch" -version = "2.9.1" +version = "2.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "cuda-bindings", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/56/9577683b23072075ed2e40d725c52c2019d71a972fab8e083763da8e707e/torch-2.9.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:1cc208435f6c379f9b8fdfd5ceb5be1e3b72a6bdf1cb46c0d2812aa73472db9e", size = 104207681, upload-time = "2025-11-12T15:19:56.48Z" }, - { url = "https://files.pythonhosted.org/packages/38/45/be5a74f221df8f4b609b78ff79dc789b0cc9017624544ac4dd1c03973150/torch-2.9.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:9fd35c68b3679378c11f5eb73220fdcb4e6f4592295277fbb657d31fd053237c", size = 899794036, upload-time = "2025-11-12T15:21:01.886Z" }, - { url = "https://files.pythonhosted.org/packages/67/95/a581e8a382596b69385a44bab2733f1273d45c842f5d4a504c0edc3133b6/torch-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:2af70e3be4a13becba4655d6cc07dcfec7ae844db6ac38d6c1dafeb245d17d65", size = 110969861, upload-time = "2025-11-12T15:21:30.145Z" }, - { url = "https://files.pythonhosted.org/packages/ad/51/1756dc128d2bf6ea4e0a915cb89ea5e730315ff33d60c1ff56fd626ba3eb/torch-2.9.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:a83b0e84cc375e3318a808d032510dde99d696a85fe9473fc8575612b63ae951", size = 74452222, upload-time = "2025-11-12T15:20:46.223Z" }, + { url = "https://files.pythonhosted.org/packages/5b/30/bfebdd8ec77db9a79775121789992d6b3b75ee5494971294d7b4b7c999bc/torch-2.10.0-2-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:2b980edd8d7c0a68c4e951ee1856334a43193f98730d97408fbd148c1a933313", size = 79411457 }, + { url = "https://files.pythonhosted.org/packages/0c/1a/c61f36cfd446170ec27b3a4984f072fd06dab6b5d7ce27e11adb35d6c838/torch-2.10.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5276fa790a666ee8becaffff8acb711922252521b28fbce5db7db5cf9cb2026d", size = 145992962 }, + { url = "https://files.pythonhosted.org/packages/b5/60/6662535354191e2d1555296045b63e4279e5a9dbad49acf55a5d38655a39/torch-2.10.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:aaf663927bcd490ae971469a624c322202a2a1e68936eb952535ca4cd3b90444", size = 915599237 }, + { url = "https://files.pythonhosted.org/packages/40/b8/66bbe96f0d79be2b5c697b2e0b187ed792a15c6c4b8904613454651db848/torch-2.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:a4be6a2a190b32ff5c8002a0977a25ea60e64f7ba46b1be37093c141d9c49aeb", size = 113720931 }, + { url = "https://files.pythonhosted.org/packages/76/bb/d820f90e69cda6c8169b32a0c6a3ab7b17bf7990b8f2c680077c24a3c14c/torch-2.10.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:35e407430795c8d3edb07a1d711c41cc1f9eaddc8b2f1cc0a165a6767a8fb73d", size = 79411450 }, ] [[package]] @@ -3277,49 +3313,49 @@ dependencies = [ { name = "packaging" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144, upload-time = "2023-03-10T22:02:20.455Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162, upload-time = "2023-03-10T22:02:18.818Z" }, + { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162 }, ] [[package]] name = "tornado" version = "6.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632, upload-time = "2025-12-15T19:21:03.836Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909, upload-time = "2025-12-15T19:20:48.382Z" }, - { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163, upload-time = "2025-12-15T19:20:49.791Z" }, - { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746, upload-time = "2025-12-15T19:20:51.491Z" }, - { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083, upload-time = "2025-12-15T19:20:52.778Z" }, - { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315, upload-time = "2025-12-15T19:20:53.996Z" }, - { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003, upload-time = "2025-12-15T19:20:56.101Z" }, - { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412, upload-time = "2025-12-15T19:20:57.398Z" }, - { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392, upload-time = "2025-12-15T19:20:58.692Z" }, - { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481, upload-time = "2025-12-15T19:21:00.008Z" }, - { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886, upload-time = "2025-12-15T19:21:01.287Z" }, - { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910, upload-time = "2025-12-15T19:21:02.571Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909 }, + { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163 }, + { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746 }, + { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083 }, + { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315 }, + { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003 }, + { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412 }, + { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392 }, + { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481 }, + { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886 }, + { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910 }, ] [[package]] name = "tqdm" -version = "4.67.1" +version = "4.67.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374 }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, ] [[package]] @@ -3330,14 +3366,14 @@ dependencies = [ { name = "torch" }, { name = "transformers", extra = ["sentencepiece", "torch"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754, upload-time = "2025-06-15T13:34:38.522Z" } +sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073, upload-time = "2025-06-15T13:34:37.468Z" }, + { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073 }, ] [[package]] name = "transformers" -version = "4.57.3" +version = "4.57.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, @@ -3351,9 +3387,9 @@ dependencies = [ { name = "tokenizers" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/dd/70/d42a739e8dfde3d92bb2fff5819cbf331fe9657323221e79415cd5eb65ee/transformers-4.57.3.tar.gz", hash = "sha256:df4945029aaddd7c09eec5cad851f30662f8bd1746721b34cc031d70c65afebc", size = 10139680, upload-time = "2025-11-25T15:51:30.139Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/6b/2f416568b3c4c91c96e5a365d164f8a4a4a88030aa8ab4644181fdadce97/transformers-4.57.3-py3-none-any.whl", hash = "sha256:c77d353a4851b1880191603d36acb313411d3577f6e2897814f333841f7003f4", size = 11993463, upload-time = "2025-11-25T15:51:26.493Z" }, + { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498 }, ] [package.optional-dependencies] @@ -3368,34 +3404,35 @@ torch = [ [[package]] name = "triton" -version = "3.5.1" +version = "3.6.0" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fd/6e/676ab5019b4dde8b9b7bab71245102fc02778ef3df48218b298686b9ffd6/triton-3.5.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fc53d849f879911ea13f4a877243afc513187bc7ee92d1f2c0f1ba3169e3c94", size = 170320692, upload-time = "2025-11-11T17:40:46.074Z" }, + { url = "https://files.pythonhosted.org/packages/44/ba/b1b04f4b291a3205d95ebd24465de0e5bf010a2df27a4e58a9b5f039d8f2/triton-3.6.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c723cfb12f6842a0ae94ac307dba7e7a44741d720a40cf0e270ed4a4e3be781", size = 175972180 }, + { url = "https://files.pythonhosted.org/packages/8c/f7/f1c9d3424ab199ac53c2da567b859bcddbb9c9e7154805119f8bd95ec36f/triton-3.6.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6550fae429e0667e397e5de64b332d1e5695b73650ee75a6146e2e902770bea", size = 188105201 }, ] [[package]] name = "typer" -version = "0.21.1" +version = "0.24.1" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "annotated-doc" }, { name = "click" }, { name = "rich" }, { name = "shellingham" }, - { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/36/bf/8825b5929afd84d0dabd606c67cd57b8388cb3ec385f7ef19c5cc2202069/typer-0.21.1.tar.gz", hash = "sha256:ea835607cd752343b6b2b7ce676893e5a0324082268b48f27aa058bdb7d2145d", size = 110371, upload-time = "2026-01-06T11:21:10.989Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, + { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085 }, ] [[package]] name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, ] [[package]] @@ -3405,59 +3442,59 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, ] [[package]] name = "tzdata" version = "2025.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521 }, ] [[package]] name = "unidecode" version = "1.3.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701, upload-time = "2024-01-11T11:58:35.609Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701 } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494, upload-time = "2024-01-11T11:58:33.012Z" }, + { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494 }, ] [[package]] name = "uri-template" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140 }, ] [[package]] name = "urllib3" -version = "2.6.2" +version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556 } wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584 }, ] [[package]] name = "uvicorn" -version = "0.40.0" +version = "0.41.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/d1/8f3c683c9561a4e6689dd3b1d345c815f10f86acd044ee1fb9a4dcd0b8c5/uvicorn-0.40.0.tar.gz", hash = "sha256:839676675e87e73694518b5574fd0f24c9d97b46bea16df7b8c05ea1a51071ea", size = 81761, upload-time = "2025-12-21T14:16:22.45Z" } +sdist = { url = "https://files.pythonhosted.org/packages/32/ce/eeb58ae4ac36fe09e3842eb02e0eb676bf2c53ae062b98f1b2531673efdd/uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", size = 82633 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/d8/2083a1daa7439a66f3a48589a57d576aa117726762618f6bb09fe3798796/uvicorn-0.40.0-py3-none-any.whl", hash = "sha256:c6c8f55bc8bf13eb6fa9ff87ad62308bbbc33d0b67f84293151efe87e0d5f2ee", size = 68502, upload-time = "2025-12-21T14:16:21.041Z" }, + { url = "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187", size = 68783 }, ] [package.optional-dependencies] @@ -3475,19 +3512,19 @@ standard = [ name = "uvloop" version = "0.22.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250 } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335, upload-time = "2025-10-16T22:16:11.43Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903, upload-time = "2025-10-16T22:16:12.979Z" }, - { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499, upload-time = "2025-10-16T22:16:14.451Z" }, - { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133, upload-time = "2025-10-16T22:16:16.272Z" }, - { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681, upload-time = "2025-10-16T22:16:18.07Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261, upload-time = "2025-10-16T22:16:19.596Z" }, + { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335 }, + { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903 }, + { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499 }, + { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133 }, + { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681 }, + { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261 }, ] [[package]] name = "virtualenv" -version = "20.35.4" +version = "20.39.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, @@ -3495,9 +3532,9 @@ dependencies = [ { name = "platformdirs" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/20/28/e6f1a6f655d620846bd9df527390ecc26b3805a0c5989048c210e22c5ca9/virtualenv-20.35.4.tar.gz", hash = "sha256:643d3914d73d3eeb0c552cbb12d7e82adf0e504dbf86a3182f8771a153a1971c", size = 6028799, upload-time = "2025-10-29T06:57:40.511Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/54/809199edc537dbace273495ac0884d13df26436e910a5ed4d0ec0a69806b/virtualenv-20.39.0.tar.gz", hash = "sha256:a15f0cebd00d50074fd336a169d53422436a12dfe15149efec7072cfe817df8b", size = 5869141 } wheels = [ - { url = "https://files.pythonhosted.org/packages/79/0c/c05523fa3181fdf0c9c52a6ba91a23fbf3246cc095f26f6516f9c60e6771/virtualenv-20.35.4-py3-none-any.whl", hash = "sha256:c21c9cede36c9753eeade68ba7d523529f228a403463376cf821eaae2b650f1b", size = 6005095, upload-time = "2025-10-29T06:57:37.598Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b4/8268da45f26f4fe84f6eae80a6ca1485ffb490a926afecff75fc48f61979/virtualenv-20.39.0-py3-none-any.whl", hash = "sha256:44888bba3775990a152ea1f73f8e5f566d49f11bbd1de61d426fd7732770043e", size = 5839121 }, ] [[package]] @@ -3507,157 +3544,146 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318, upload-time = "2025-10-14T15:04:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478, upload-time = "2025-10-14T15:04:20.297Z" }, - { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894, upload-time = "2025-10-14T15:04:21.527Z" }, - { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065, upload-time = "2025-10-14T15:04:22.795Z" }, - { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377, upload-time = "2025-10-14T15:04:24.138Z" }, - { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837, upload-time = "2025-10-14T15:04:25.057Z" }, - { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456, upload-time = "2025-10-14T15:04:26.497Z" }, - { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614, upload-time = "2025-10-14T15:04:27.539Z" }, - { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690, upload-time = "2025-10-14T15:04:28.495Z" }, - { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459, upload-time = "2025-10-14T15:04:29.491Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663, upload-time = "2025-10-14T15:04:30.435Z" }, - { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453, upload-time = "2025-10-14T15:04:31.53Z" }, - { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, - { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, - { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413, upload-time = "2025-10-14T15:06:09.209Z" }, + { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318 }, + { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478 }, + { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894 }, + { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065 }, + { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377 }, + { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837 }, + { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456 }, + { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614 }, + { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690 }, + { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459 }, + { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663 }, + { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453 }, + { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611 }, + { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889 }, + { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616 }, + { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413 }, ] [[package]] name = "wcwidth" -version = "0.2.14" +version = "0.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } +sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684 } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, + { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189 }, ] [[package]] name = "webcolors" version = "25.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491 } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905 }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, ] [[package]] name = "websocket-client" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, ] [[package]] name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, +version = "16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343 }, + { url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021 }, + { url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320 }, + { url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815 }, + { url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054 }, + { url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565 }, + { url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848 }, + { url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249 }, + { url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685 }, + { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598 }, ] [[package]] name = "widgetsnbextension" version = "4.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402 } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503 }, ] [[package]] name = "wikipedia-api" -version = "0.8.1" +version = "0.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/aa/2e35be124dfc7e581480705f912040172f6570cc12e68a245ba9258c32ef/wikipedia_api-0.8.1.tar.gz", hash = "sha256:b31e93b3f5407c1a1ba413ed7326a05379a3c270df6cf6a211aca67a14c5658b", size = 19934, upload-time = "2025-01-19T23:44:33.488Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/7b/8b775cf22f266086cefa762b58df0a35a4c4532de3f2f6a0b7432fd31fd1/wikipedia_api-0.9.0.tar.gz", hash = "sha256:6aabd1f9fe34f594f4d36f5af67e468b0a50d713aa9a1d102b4d996bc76dd58e", size = 20041 } [[package]] name = "wrapt" -version = "2.0.1" +version = "2.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/49/2a/6de8a50cb435b7f42c46126cf1a54b2aab81784e74c8595c8e025e8f36d3/wrapt-2.0.1.tar.gz", hash = "sha256:9c9c635e78497cacb81e84f8b11b23e0aacac7a136e73b8e5b2109a1d9fc468f", size = 82040, upload-time = "2025-11-07T00:45:33.312Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/37/ae31f40bec90de2f88d9597d0b5281e23ffe85b893a47ca5d9c05c63a4f6/wrapt-2.1.1.tar.gz", hash = "sha256:5fdcb09bf6db023d88f312bd0767594b414655d58090fc1c46b3414415f67fac", size = 81329 } wheels = [ - { url = "https://files.pythonhosted.org/packages/61/0d/12d8c803ed2ce4e5e7d5b9f5f602721f9dfef82c95959f3ce97fa584bb5c/wrapt-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:64b103acdaa53b7caf409e8d45d39a8442fe6dcfec6ba3f3d141e0cc2b5b4dbd", size = 77481, upload-time = "2025-11-07T00:43:11.103Z" }, - { url = "https://files.pythonhosted.org/packages/05/3e/4364ebe221ebf2a44d9fc8695a19324692f7dd2795e64bd59090856ebf12/wrapt-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:91bcc576260a274b169c3098e9a3519fb01f2989f6d3d386ef9cbf8653de1374", size = 60692, upload-time = "2025-11-07T00:43:13.697Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ff/ae2a210022b521f86a8ddcdd6058d137c051003812b0388a5e9a03d3fe10/wrapt-2.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ab594f346517010050126fcd822697b25a7031d815bb4fbc238ccbe568216489", size = 61574, upload-time = "2025-11-07T00:43:14.967Z" }, - { url = "https://files.pythonhosted.org/packages/c6/93/5cf92edd99617095592af919cb81d4bff61c5dbbb70d3c92099425a8ec34/wrapt-2.0.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:36982b26f190f4d737f04a492a68accbfc6fa042c3f42326fdfbb6c5b7a20a31", size = 113688, upload-time = "2025-11-07T00:43:18.275Z" }, - { url = "https://files.pythonhosted.org/packages/a0/0a/e38fc0cee1f146c9fb266d8ef96ca39fb14a9eef165383004019aa53f88a/wrapt-2.0.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23097ed8bc4c93b7bf36fa2113c6c733c976316ce0ee2c816f64ca06102034ef", size = 115698, upload-time = "2025-11-07T00:43:19.407Z" }, - { url = "https://files.pythonhosted.org/packages/b0/85/bef44ea018b3925fb0bcbe9112715f665e4d5309bd945191da814c314fd1/wrapt-2.0.1-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8bacfe6e001749a3b64db47bcf0341da757c95959f592823a93931a422395013", size = 112096, upload-time = "2025-11-07T00:43:16.5Z" }, - { url = "https://files.pythonhosted.org/packages/7c/0b/733a2376e413117e497aa1a5b1b78e8f3a28c0e9537d26569f67d724c7c5/wrapt-2.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8ec3303e8a81932171f455f792f8df500fc1a09f20069e5c16bd7049ab4e8e38", size = 114878, upload-time = "2025-11-07T00:43:20.81Z" }, - { url = "https://files.pythonhosted.org/packages/da/03/d81dcb21bbf678fcda656495792b059f9d56677d119ca022169a12542bd0/wrapt-2.0.1-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:3f373a4ab5dbc528a94334f9fe444395b23c2f5332adab9ff4ea82f5a9e33bc1", size = 111298, upload-time = "2025-11-07T00:43:22.229Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d5/5e623040e8056e1108b787020d56b9be93dbbf083bf2324d42cde80f3a19/wrapt-2.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f49027b0b9503bf6c8cdc297ca55006b80c2f5dd36cecc72c6835ab6e10e8a25", size = 113361, upload-time = "2025-11-07T00:43:24.301Z" }, - { url = "https://files.pythonhosted.org/packages/a1/f3/de535ccecede6960e28c7b722e5744846258111d6c9f071aa7578ea37ad3/wrapt-2.0.1-cp310-cp310-win32.whl", hash = "sha256:8330b42d769965e96e01fa14034b28a2a7600fbf7e8f0cc90ebb36d492c993e4", size = 58035, upload-time = "2025-11-07T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/21/15/39d3ca5428a70032c2ec8b1f1c9d24c32e497e7ed81aed887a4998905fcc/wrapt-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:1218573502a8235bb8a7ecaed12736213b22dcde9feab115fa2989d42b5ded45", size = 60383, upload-time = "2025-11-07T00:43:25.804Z" }, - { url = "https://files.pythonhosted.org/packages/43/c2/dfd23754b7f7a4dce07e08f4309c4e10a40046a83e9ae1800f2e6b18d7c1/wrapt-2.0.1-cp310-cp310-win_arm64.whl", hash = "sha256:eda8e4ecd662d48c28bb86be9e837c13e45c58b8300e43ba3c9b4fa9900302f7", size = 58894, upload-time = "2025-11-07T00:43:27.074Z" }, - { url = "https://files.pythonhosted.org/packages/15/d1/b51471c11592ff9c012bd3e2f7334a6ff2f42a7aed2caffcf0bdddc9cb89/wrapt-2.0.1-py3-none-any.whl", hash = "sha256:4d2ce1bf1a48c5277d7969259232b57645aae5686dba1eaeade39442277afbca", size = 44046, upload-time = "2025-11-07T00:45:32.116Z" }, + { url = "https://files.pythonhosted.org/packages/ca/21/293b657a27accfbbbb6007ebd78af0efa2083dac83e8f523272ea09b4638/wrapt-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e927375e43fd5a985b27a8992327c22541b6dede1362fc79df337d26e23604f", size = 60554 }, + { url = "https://files.pythonhosted.org/packages/25/e9/96dd77728b54a899d4ce2798d7b1296989ce687ed3c0cb917d6b3154bf5d/wrapt-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c99544b6a7d40ca22195563b6d8bc3986ee8bb82f272f31f0670fe9440c869", size = 61496 }, + { url = "https://files.pythonhosted.org/packages/44/79/4c755b45df6ef30c0dd628ecfaa0c808854be147ca438429da70a162833c/wrapt-2.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b2be3fa5f4efaf16ee7c77d0556abca35f5a18ad4ac06f0ef3904c3399010ce9", size = 113528 }, + { url = "https://files.pythonhosted.org/packages/9f/63/23ce28f7b841217d9a6337a340fbb8d4a7fbd67a89d47f377c8550fa34aa/wrapt-2.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67c90c1ae6489a6cb1a82058902caa8006706f7b4e8ff766f943e9d2c8e608d0", size = 115536 }, + { url = "https://files.pythonhosted.org/packages/23/7b/5ca8d3b12768670d16c8329e29960eedd56212770365a02a8de8bf73dc01/wrapt-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:05c0db35ccffd7480143e62df1e829d101c7b86944ae3be7e4869a7efa621f53", size = 114716 }, + { url = "https://files.pythonhosted.org/packages/c7/3a/9789ccb14a096d30bb847bf3ee137bf682cc9750c2ce155f4c5ae1962abf/wrapt-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0c2ec9f616755b2e1e0bf4d0961f59bb5c2e7a77407e7e2c38ef4f7d2fdde12c", size = 113200 }, + { url = "https://files.pythonhosted.org/packages/cf/e5/4ec3526ce6ce920b267c8d35d2c2f0874d3fad2744c8b7259353f1132baa/wrapt-2.1.1-cp310-cp310-win32.whl", hash = "sha256:203ba6b3f89e410e27dbd30ff7dccaf54dcf30fda0b22aa1b82d560c7f9fe9a1", size = 57876 }, + { url = "https://files.pythonhosted.org/packages/d1/4e/661c7c76ecd85375b2bc03488941a3a1078642af481db24949e2b9de01f4/wrapt-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:6f9426d9cfc2f8732922fc96198052e55c09bb9db3ddaa4323a18e055807410e", size = 60224 }, + { url = "https://files.pythonhosted.org/packages/5f/b7/53c7252d371efada4cb119e72e774fa2c6b3011fc33e3e552cdf48fb9488/wrapt-2.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:69c26f51b67076b40714cff81bdd5826c0b10c077fb6b0678393a6a2f952a5fc", size = 58645 }, + { url = "https://files.pythonhosted.org/packages/c4/da/5a086bf4c22a41995312db104ec2ffeee2cf6accca9faaee5315c790377d/wrapt-2.1.1-py3-none-any.whl", hash = "sha256:3b0f4629eb954394a3d7c7a1c8cca25f0b07cefe6aa8545e862e9778152de5b7", size = 43886 }, ] [[package]] name = "xmltodict" version = "0.14.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942, upload-time = "2024-10-16T06:10:29.683Z" } +sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942 } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981, upload-time = "2024-10-16T06:10:27.649Z" }, + { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981 }, ] [[package]] name = "xxhash" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160 } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, - { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, - { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, - { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, - { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, - { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, - { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, - { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, - { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, - { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, - { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, - { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, - { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, - { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845 }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807 }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786 }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830 }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606 }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872 }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217 }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139 }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669 }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018 }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058 }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628 }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577 }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487 }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863 }, ] [[package]] @@ -3669,23 +3695,23 @@ dependencies = [ { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169, upload-time = "2025-10-06T14:12:55.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517, upload-time = "2025-10-06T14:08:42.494Z" }, - { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495, upload-time = "2025-10-06T14:08:46.2Z" }, - { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400, upload-time = "2025-10-06T14:08:47.855Z" }, - { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545, upload-time = "2025-10-06T14:08:49.683Z" }, - { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598, upload-time = "2025-10-06T14:08:51.215Z" }, - { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893, upload-time = "2025-10-06T14:08:53.144Z" }, - { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240, upload-time = "2025-10-06T14:08:55.036Z" }, - { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965, upload-time = "2025-10-06T14:08:56.722Z" }, - { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026, upload-time = "2025-10-06T14:08:58.563Z" }, - { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637, upload-time = "2025-10-06T14:09:00.506Z" }, - { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082, upload-time = "2025-10-06T14:09:01.936Z" }, - { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811, upload-time = "2025-10-06T14:09:03.445Z" }, - { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223, upload-time = "2025-10-06T14:09:05.401Z" }, - { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118, upload-time = "2025-10-06T14:09:11.148Z" }, - { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852, upload-time = "2025-10-06T14:09:12.958Z" }, - { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012, upload-time = "2025-10-06T14:09:14.664Z" }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814, upload-time = "2025-10-06T14:12:53.872Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517 }, + { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495 }, + { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400 }, + { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545 }, + { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598 }, + { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893 }, + { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240 }, + { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965 }, + { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026 }, + { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637 }, + { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082 }, + { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811 }, + { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223 }, + { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118 }, + { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852 }, + { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012 }, + { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, ] From 8f507c8b0daa37c835fdff98d543cc496a20226b Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 2 Mar 2026 18:00:11 +0000 Subject: [PATCH 089/104] =?UTF-8?q?=F0=9F=93=9D=20Reorganize=20and=20updat?= =?UTF-8?q?e=20v1.5.0=20documentation=20(EN/ES)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.es.md | 161 ++ README.md | 165 +- docs/CONTRIBUTING.md | 95 +- docs/README.md | 28 + docs/SECURITY.md | 2 +- docs/anonymization/README.md | 81 - docs/api/README.md | 330 +++- docs/data/en/entities-table.md | 32 - docs/data/es/entities-table.md | 27 - docs/database/README.md | 175 +- docs/database/schema.excalidraw | 56 + docs/database/schema.jpg | Bin 142043 -> 0 bytes docs/database/schema.mmd | 53 + docs/database/schema.png | Bin 0 -> 67305 bytes docs/entities/README.md | 17 + docs/entities/anonymizer/README.md | 45 + docs/entities/datapublic/README.md | 47 + docs/es/README.md | 28 + docs/es/api/README.md | 321 +++ docs/es/database/README.md | 113 ++ docs/es/entities/README.md | 17 + docs/es/entities/anonymizer/README.md | 45 + docs/es/entities/datapublic/README.md | 47 + docs/es/models/README.md | 19 + docs/es/models/anonymizer-model-card.md | 172 ++ docs/es/models/decision-model-card.md | 217 ++ docs/es/models/flair-model-card.md | 166 ++ docs/es/pipelines/README.md | 25 + docs/es/pipelines/anonymizer/README.md | 68 + docs/es/pipelines/datapublic/README.md | 76 + docs/models/README.md | 19 + docs/models/anonymizer-model-card.md | 172 ++ .../assets/ner-schema.png | Bin docs/models/decision-model-card.md | 217 ++ docs/{pipeline => models}/flair-model-card.md | 66 +- docs/pipeline/README.md | 56 - .../assets/decision-confusion-matrix.png | Bin 15037 -> 0 bytes docs/pipeline/assets/decision-schema.png | Bin 189471 -> 0 bytes docs/pipeline/assets/inference-example.png | Bin 80766 -> 0 bytes .../assets/postprocessing-example.png | Bin 64041 -> 0 bytes docs/pipeline/decision-model-card.md | 161 -- docs/pipelines/README.md | 25 + docs/pipelines/anonymizer/README.md | 68 + docs/pipelines/anonymizer/pipeline.excalidraw | 1748 +++++++++++++++++ docs/pipelines/anonymizer/pipeline.png | Bin 0 -> 601943 bytes docs/pipelines/datapublic/README.md | 76 + .../datapublic}/pipeline.png | Bin notebooks/experiments/decision/README.md | 14 - notebooks/experiments/ner/flair/README.md | 16 - .../datapublic}/label-studio-config.xml | 0 tutorials/00-annotations/01-export-docs.ipynb | 147 -- .../00-annotations/02-doc-visualization.ipynb | 137 -- tutorials/00-annotations/README.md | 25 - tutorials/01-pipeline/01-evaluation.ipynb | 169 -- .../02-run-ner-from-huggingface.ipynb | 64 - tutorials/GET_STARTED.md | 4 - 56 files changed, 4658 insertions(+), 1154 deletions(-) create mode 100644 README.es.md create mode 100644 docs/README.md delete mode 100644 docs/anonymization/README.md delete mode 100644 docs/data/en/entities-table.md delete mode 100644 docs/data/es/entities-table.md create mode 100644 docs/database/schema.excalidraw delete mode 100644 docs/database/schema.jpg create mode 100644 docs/database/schema.mmd create mode 100644 docs/database/schema.png create mode 100644 docs/entities/README.md create mode 100644 docs/entities/anonymizer/README.md create mode 100644 docs/entities/datapublic/README.md create mode 100644 docs/es/README.md create mode 100644 docs/es/api/README.md create mode 100644 docs/es/database/README.md create mode 100644 docs/es/entities/README.md create mode 100644 docs/es/entities/anonymizer/README.md create mode 100644 docs/es/entities/datapublic/README.md create mode 100644 docs/es/models/README.md create mode 100644 docs/es/models/anonymizer-model-card.md create mode 100644 docs/es/models/decision-model-card.md create mode 100644 docs/es/models/flair-model-card.md create mode 100644 docs/es/pipelines/README.md create mode 100644 docs/es/pipelines/anonymizer/README.md create mode 100644 docs/es/pipelines/datapublic/README.md create mode 100644 docs/models/README.md create mode 100644 docs/models/anonymizer-model-card.md rename docs/{pipeline => models}/assets/ner-schema.png (100%) create mode 100644 docs/models/decision-model-card.md rename docs/{pipeline => models}/flair-model-card.md (69%) delete mode 100644 docs/pipeline/README.md delete mode 100644 docs/pipeline/assets/decision-confusion-matrix.png delete mode 100644 docs/pipeline/assets/decision-schema.png delete mode 100644 docs/pipeline/assets/inference-example.png delete mode 100644 docs/pipeline/assets/postprocessing-example.png delete mode 100644 docs/pipeline/decision-model-card.md create mode 100644 docs/pipelines/README.md create mode 100644 docs/pipelines/anonymizer/README.md create mode 100644 docs/pipelines/anonymizer/pipeline.excalidraw create mode 100644 docs/pipelines/anonymizer/pipeline.png create mode 100644 docs/pipelines/datapublic/README.md rename docs/{pipeline/assets => pipelines/datapublic}/pipeline.png (100%) delete mode 100644 notebooks/experiments/decision/README.md delete mode 100644 notebooks/experiments/ner/flair/README.md rename {docs/data => resources/annotations/label-studio/datapublic}/label-studio-config.xml (100%) delete mode 100644 tutorials/00-annotations/01-export-docs.ipynb delete mode 100644 tutorials/00-annotations/02-doc-visualization.ipynb delete mode 100644 tutorials/00-annotations/README.md delete mode 100644 tutorials/01-pipeline/01-evaluation.ipynb delete mode 100644 tutorials/01-pipeline/02-run-ner-from-huggingface.ipynb delete mode 100644 tutorials/GET_STARTED.md diff --git a/README.es.md b/README.es.md new file mode 100644 index 00000000..eb8acd07 --- /dev/null +++ b/README.es.md @@ -0,0 +1,161 @@ +# AymurAI Backend +Idioma: [English](README.md) | **Español** + +AymurAI Backend provee la API y los pipelines de ML usados para procesar resoluciones judiciales en dos flujos principales: + +- `anonymizer`: extracción de entidades y generación de documentos anonimizados. +- `data-public`: extracción de información estructurada para curación de dataset público. + +Este repositorio contiene el servicio FastAPI, configuraciones de pipelines de producción y persistencia en base de datos para ambos flujos. + +## Qué es AymurAI +AymurAI es un proyecto orientado a facilitar la generación de datos judiciales anonimizados y estructurados para casos de violencia de género (VG) en América Latina. El backend orquesta la ingesta de documentos, la inferencia de modelos, la persistencia de validaciones y la exportación de resultados para usos operativos y de investigación. + +Este repositorio está enfocado en el backend: expone APIs consumidas por el frontend y ejecuta los pipelines de producción de `anonymizer` y `data-public`. + +## Documentación +- Índice técnico: [docs/es/README.md](docs/es/README.md) +- Referencia de API: [docs/es/api/README.md](docs/es/api/README.md) +- Índice de pipelines: [docs/es/pipelines/README.md](docs/es/pipelines/README.md) +- Flujo anonymizer: [docs/es/pipelines/anonymizer/README.md](docs/es/pipelines/anonymizer/README.md) +- Flujo datapublic: [docs/es/pipelines/datapublic/README.md](docs/es/pipelines/datapublic/README.md) +- Esquema de base de datos interna: [docs/es/database/README.md](docs/es/database/README.md) + +## Inicio Rápido (imagen Docker) +Ejecutar la imagen full de la API (incluye recursos de producción): + +```bash +docker run -d --name aymurai-backend -p 8899:8899 ghcr.io/aymurai/api:full +``` + +Opcional: persistir DB/cache fuera del container (volumen host montado en `/resources/cache`): + +```bash +mkdir -p ./aymurai-cache + +docker run -d --name aymurai-backend -p 8899:8899 \ + -v "$(pwd)/aymurai-cache:/resources/cache" \ + ghcr.io/aymurai/api:full +``` + +Opcional: runtime con GPU (requiere NVIDIA Container Toolkit): + +```bash +docker run -d --name aymurai-backend-gpu --gpus all \ + -e TORCH_DEVICE=cuda \ + -p 8899:8899 \ + ghcr.io/aymurai/api:full +``` + +Abrir Swagger UI: + +```text +http://localhost:8899/docs +``` + +## Inicio Rápido (Docker Compose) +Usar los servicios definidos en `docker-compose.yml`: + +```bash +# CPU, perfil liviano +make api-up + +# CPU, perfil full +make api-full-up + +# GPU, perfil liviano +API_SERVICE=aymurai-api-gpu make api-up + +# GPU, perfil full +API_FULL_SERVICE=aymurai-api-full-gpu make api-full-up +``` + +Ver logs: + +```bash +make api-logs +# o make api-full-logs +``` + +## Resumen de runtime +- Framework: `FastAPI` +- Puerto por defecto: `8899` +- Motor de DB: `SQLModel` + migraciones Alembic al iniciar +- URI de DB por defecto: `sqlite:////resources/cache/sqlite/database.db` +- Configs de pipeline de producción: + - `resources/pipelines/production/flair-anonymizer/pipeline.json` + - `resources/pipelines/production/full-paragraph/pipeline.json` + +## Endpoints públicos principales +- `GET /server/healthcheck` +- `GET /server/stats/summary` +- `POST /misc/document-extract` (y alias deprecado `POST /document-extract`) +- `POST /anonymizer/predict` +- `POST /anonymizer/disambiguate` +- `POST /anonymizer/validation` +- `POST /anonymizer/anonymize-document` +- `POST /datapublic/predict/{document_id}` +- `GET /datapublic/validation/document/{document_id}` +- `POST /datapublic/validation/document/{document_id}` + +Para contratos request/response y ejemplos completos, ver [docs/es/api/README.md](docs/es/api/README.md). + +## Despliegue en red cerrada +Para mover una imagen a un entorno sin internet: + +```bash +docker image save ghcr.io/aymurai/api:full -o aymurai-api-full.tar +docker load -i aymurai-api-full.tar +``` + +## Contribución +Las contribuciones son bienvenidas en documentación, API y mejoras de pipelines. + +- Guía de contribución: [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) +- Seguridad y ética: [docs/SECURITY.md](docs/SECURITY.md) +- Código de conducta: [docs/CODE_OF_CONDUCT.md](docs/CODE_OF_CONDUCT.md) + +## Contribuidores +- **Julián Ansaldo** - [@jansaldo](https://github.com/jansaldo) at [collective.ai](https://collectiveai.io) ([email](mailto:juli@collectiveai.io)) +- **Raúl Barriga** - [@jedzill4](https://github.com/jedzill4) at [collective.ai](https://collectiveai.io) ([email](mailto:r@collectiveai.io)) +- **Sofía del Pozo** - [@sofiadelpozo](https://github.com/sofiadelpozo) at [collective.ai](https://collectiveai.io) ([email](mailto:sofia.delpozo@collectiveai.io)) +- **Paolo Donizetti** - [@padonizetti](https://github.com/padonizetti) at [collective.ai](https://collectiveai.io) ([email](mailto:paolo@collectiveai.io)) +- **Conrado Beatriz** - [@conrabeatriz](https://github.com/conrabeatriz) at [collective.ai](https://collectiveai.io) ([email](mailto:conrado@collectiveai.io)) + +## Citar AymurAI +Si usás AymurAI en investigación o publicaciones, por favor citá: + +```bibtex +@techreport{feldfeber2022, + author = {Feldfeber, Ivana and Quiroga, Yasm\'{\i}n Bel\'{e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} +} +``` + +``` +@inproceedings{10.1145/3706598.3713681, + author = {Ciolfi Felice, Marianela and Feldfeber, Ivana and Glasserman Apicella, Carolina and Quiroga, Yasm\'{\i}n Bel\'{e}n and Ansaldo, Juli\'{a}n and Lapenna, Luciano and Bezchinsky, Santiago and Barriga Rubio, Ra\'{u}l and Garc\'{\i}a, Mail\'{e}n}, + title = {Doing the Feminist Work in AI: Reflections from an AI Project in Latin America}, + booktitle = {Proceedings of the 2025 CHI Conference on Human Factors in Computing Systems}, + series = {CHI '25}, + year = {2025}, + isbn = {9798400713941}, + publisher = {Association for Computing Machinery}, + address = {New York, NY, USA}, + doi = {10.1145/3706598.3713681}, + url = {https://doi.org/10.1145/3706598.3713681}, + abstract = {The contemporary AI development landscape is dominated by big corporations, lacks diversity, and mostly centres the Global North, or applies extractivist logics in the South. This paper showcases a feminist process of AI development from Latin America, where we created an interactive, AI-powered tool that helps criminal court officers open justice data, addressing a data gap on gender-based violence. Through a collaborative autoethnography, drawing from Latin American feminisms, we unpack and visibilize the feminist work that was required, as a crucial step to counter hegemonic narratives. Foregrounding the subjugated knowledges of our experiences, we offer a concrete example of a feminist approach to AI development grounded in practice. With this, we aim to critically inspire those who consider building technology in service of social justice causes, or who choose to build AI systems otherwise.}, + articleno = {998}, + numpages = {18}, + keywords = {Global South, NGO, activism, critical HCI, critical computing, duoethnography, feminist AI, feminist research}, + location = {}, +} +``` + +Para usar la cita más actualizada, consulta la referencia del proyecto en el repositorio de la organización: [github.com/aymurai](https://github.com/aymurai). + +## Licencia +AymurAI es software de código abierto bajo licencia [MIT](LICENSE.md). Esta licencia permite modificar, distribuir y usar de forma privada el software, siempre que se mantenga el crédito correspondiente a la autoría original. diff --git a/README.md b/README.md index d140e5ad..a19c2224 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,162 @@ # AymurAI Backend -This repository contains the backend API and machine learning models for [AymurAI](https://www.aymurai.info), a tool designed to generate anonymized datasets from judicial rulings related to gender-based violence (GBV). +Language: **English** | [Español](README.es.md) -AymurAI's backend is responsible for managing the interaction between the frontend and the machine learning models. It provides an API that handles data input, automates the extraction of information from court rulings, and document edition for anonymization purposes. +AymurAI Backend provides the API and ML pipelines used to process judicial rulings for two main workflows: +- `anonymizer`: extract named entities and produce anonymized documents. +- `data-public`: extract structured information for public dataset curation. -## Table of Contents -* [About AymurAI, its Uses and Limitations](#about-aymurai-its-uses-and-limitations) -* [Deployment](#deployment) -* [Pipeline](#pipeline) -* [Tutorials](#tutorials) -* [Contributing](#contributing) -* [Contributors](#contributors) -* [Citing AymurAI](#citing-aymurai) -* [License](#license) +This repository contains the FastAPI service, production pipeline configs, and database persistence used by both workflows. +## About AymurAI +AymurAI is a project focused on supporting the generation of anonymized and structured judicial data for gender-based violence (GBV) cases in Latin America. The backend service orchestrates document ingestion, ML inference, validation persistence, and document export for downstream operational and research uses. -## About AymurAI, its Uses and Limitations -AymurAI is a tool designed to address the lack of available data in the judicial system regarding gender-based violence (GBV) rulings in Latin America. Its goal is to increase report levels, build trust in the justice system, and improve access to justice for women and LGBTIQ+ people. AymurAI generates and maintains anonymized datasets from legal rulings to better understand GBV and support policy-making, while also contributing to campaigns run by feminist collectives. +This repository is backend-focused: it exposes APIs consumed by the frontend and runs the production pipelines for `anonymizer` and `data-public`. -AymurAI is still a prototype and is currently only implemented in Criminal Court N°10 in the City of Buenos Aires, Argentina. Its capabilities are limited to semi-automated data collection and analysis. The quality, consistency, and availability of the data, as well as cooperation from court officials and the broader cultural and political context, may affect its results. +## Documentation +- Technical docs index: [docs/README.md](docs/README.md) +- API reference: [docs/api/README.md](docs/api/README.md) +- Pipelines index: [docs/pipelines/README.md](docs/pipelines/README.md) +- Anonymizer flow: [docs/pipelines/anonymizer/README.md](docs/pipelines/anonymizer/README.md) +- Datapublic flow: [docs/pipelines/datapublic/README.md](docs/pipelines/datapublic/README.md) +- Internal database schema: [docs/database/README.md](docs/database/README.md) -The models were trained using closed datasets from an Argentine criminal court and are specifically tailored to extract relevant information from GBV-related rulings. The domain-specific training ensures the models' accuracy within this legal and cultural context, though they may not be applicable to other regions with different legal systems or cultural norms. +## Quick Start (Docker Image) +Run the full API image (includes production resources): +```bash +docker run -d --name aymurai-backend -p 8899:8899 ghcr.io/aymurai/api:full +``` -## Deployment -AymurAI's backend is deployed using [Docker](https://www.docker.com/). The Docker images are available at the following registry: +Optional: persist DB/cache outside the container (host volume mounted at `/resources/cache`): ```bash -ghcr.io/aymurai/api:full +mkdir -p ./aymurai-cache + +docker run -d --name aymurai-backend -p 8899:8899 \ + -v "$(pwd)/aymurai-cache:/resources/cache" \ + ghcr.io/aymurai/api:full ``` -### Quick Start -To deploy a production-ready instance of the API, run: +Optional: GPU runtime (requires NVIDIA Container Toolkit): ```bash -docker run -d -p 8899:8899 ghcr.io/aymurai/api:full +docker run -d --name aymurai-backend-gpu --gpus all \ + -e TORCH_DEVICE=cuda \ + -p 8899:8899 \ + ghcr.io/aymurai/api:full ``` -This command will start the API on port `8899` on your local machine. You can access the API documentation through OpenAPI at: +Open Swagger UI: -``` +```text http://localhost:8899/docs ``` -Once it is deployed, it doesn't require an internet connection to work. - -### Running on a Closed Network -If you need to deploy in an environment without internet access, export the Docker image by running: +## Quick Start (Docker Compose) +Use the services defined in `docker-compose.yml`: ```bash -docker image save ghcr.io/aymurai/api:full -o aymurai-api.tar -``` - -Transfer the image to the target machine and load it: +# CPU, lightweight API profile +make api-up -```bash -docker load -i aymurai-api.tar -``` +# CPU, full API profile +make api-full-up -For more information on Docker deployment, refer to the [Docker documentation](https://docs.docker.com/). If you need further assistance, feel free to contact us at [aymurai@datagenero.org](mailto:aymurai@datagenero.org). +# GPU, lightweight API profile +API_SERVICE=aymurai-api-gpu make api-up +# GPU, full API profile +API_FULL_SERVICE=aymurai-api-full-gpu make api-full-up +``` -## Pipeline -AymurAI’s backend utilizes a structured data processing pipeline to handle anonymized legal rulings and extract relevant information. This data is processed and made accessible via the API. For more details, please refer to the [pipeline documentation](docs/pipeline/README.md). +Check logs: +```bash +make api-logs +# or make api-full-logs +``` -## Tutorials -To get started with AymurAI, refer to our [tutorials](tutorials/GET_STARTED.md). These guides provide step-by-step instructions on setting up and using the AymurAI backend, including configuration, example queries, and more. +## Runtime Overview +- Framework: `FastAPI` +- Default API port: `8899` +- DB engine: `SQLModel` + Alembic migrations on startup +- Default DB URI: `sqlite:////resources/cache/sqlite/database.db` +- Production pipeline configs: + - `resources/pipelines/production/flair-anonymizer/pipeline.json` + - `resources/pipelines/production/full-paragraph/pipeline.json` + +## Main Public Endpoints +- `GET /server/healthcheck` +- `GET /server/stats/summary` +- `POST /misc/document-extract` (and deprecated alias `POST /document-extract`) +- `POST /anonymizer/predict` +- `POST /anonymizer/disambiguate` +- `POST /anonymizer/validation` +- `POST /anonymizer/anonymize-document` +- `POST /datapublic/predict/{document_id}` +- `GET /datapublic/validation/document/{document_id}` +- `POST /datapublic/validation/document/{document_id}` + +For full request/response contracts and examples, see [docs/api/README.md](docs/api/README.md). + +## Closed-Network Deployment +To move an image into a closed environment: +```bash +docker image save ghcr.io/aymurai/api:full -o aymurai-api-full.tar +docker load -i aymurai-api-full.tar +``` ## Contributing -Thank you for your interest in contributing to AymurAI! There are many ways to get involved, from improving documentation to enhancing the codebase. To get started, please review our [contributor guidelines](docs/CONTRIBUTING.md) and our [code of conduct](docs/CODE_OF_CONDUCT.md). We welcome contributions in areas such as expanding the API and improving the data processing pipeline. +Contributions are welcome across documentation, API, and pipeline improvements. +- Contributing guide: [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) +- Security and ethics: [docs/SECURITY.md](docs/SECURITY.md) +- Code of conduct: [docs/CODE_OF_CONDUCT.md](docs/CODE_OF_CONDUCT.md) ## Contributors -* **Julián Ansaldo** - [@jansaldo](https://github.com/jansaldo) at [collective.ai](https://collectiveai.io) ([email](mailto:juli@collectiveai.io)) -* **Raúl Barriga** - [@jedzill4](https://github.com/jedzill4) at [collective.ai](https://collectiveai.io) ([email](mailto:r@collectiveai.io)) +- **Julián Ansaldo** - [@jansaldo](https://github.com/jansaldo) at [collective.ai](https://collectiveai.io) ([email](mailto:juli@collectiveai.io)) +- **Raúl Barriga** - [@jedzill4](https://github.com/jedzill4) at [collective.ai](https://collectiveai.io) ([email](mailto:r@collectiveai.io)) +- **Sofía del Pozo** - [@sofiadelpozo](https://github.com/sofiadelpozo) at [collective.ai](https://collectiveai.io) ([email](mailto:sofia.delpozo@collectiveai.io)) +- **Paolo Donizetti** - [@padonizetti](https://github.com/padonizetti) at [collective.ai](https://collectiveai.io) ([email](mailto:paolo@collectiveai.io)) +- **Conrado Beatriz** - [@conrabeatriz](https://github.com/conrabeatriz) at [collective.ai](https://collectiveai.io) ([email](mailto:conrado@collectiveai.io)) ## Citing AymurAI -If you use AymurAI in your research or any publication, please cite the following paper to acknowledge our work: +If you use AymurAI in research or publications, please cite: ```bibtex @techreport{feldfeber2022, - author = "Feldfeber, Ivana and Quiroga, Yasmín Belén and Guevara, Clarissa and Ciolfi Felice, Marianela", - title = "Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico", - institution = "DataGenero", - year = "2022", - url = "https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view" + author = {Feldfeber, Ivana and Quiroga, Yasm\'{\i}n Bel\'{e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} +} +``` + +``` +@inproceedings{10.1145/3706598.3713681, + author = {Ciolfi Felice, Marianela and Feldfeber, Ivana and Glasserman Apicella, Carolina and Quiroga, Yasm\'{\i}n Bel\'{e}n and Ansaldo, Juli\'{a}n and Lapenna, Luciano and Bezchinsky, Santiago and Barriga Rubio, Ra\'{u}l and Garc\'{\i}a, Mail\'{e}n}, + title = {Doing the Feminist Work in AI: Reflections from an AI Project in Latin America}, + booktitle = {Proceedings of the 2025 CHI Conference on Human Factors in Computing Systems}, + series = {CHI '25}, + year = {2025}, + isbn = {9798400713941}, + publisher = {Association for Computing Machinery}, + address = {New York, NY, USA}, + doi = {10.1145/3706598.3713681}, + url = {https://doi.org/10.1145/3706598.3713681}, + abstract = {The contemporary AI development landscape is dominated by big corporations, lacks diversity, and mostly centres the Global North, or applies extractivist logics in the South. This paper showcases a feminist process of AI development from Latin America, where we created an interactive, AI-powered tool that helps criminal court officers open justice data, addressing a data gap on gender-based violence. Through a collaborative autoethnography, drawing from Latin American feminisms, we unpack and visibilize the feminist work that was required, as a crucial step to counter hegemonic narratives. Foregrounding the subjugated knowledges of our experiences, we offer a concrete example of a feminist approach to AI development grounded in practice. With this, we aim to critically inspire those who consider building technology in service of social justice causes, or who choose to build AI systems otherwise.}, + articleno = {998}, + numpages = {18}, + keywords = {Global South, NGO, activism, critical HCI, critical computing, duoethnography, feminist AI, feminist research}, + location = {}, } ``` -Proper citation helps us continue developing AymurAI and supporting the community. +For the most up-to-date citation, please use the project-level reference in the organization repository: [github.com/aymurai](https://github.com/aymurai). ## License -AymurAI is open-source software licensed under the [MIT License](LICENSE.md). This license allows for modification, distribution, and private use, provided that appropriate credit is given to the original authors. +AymurAI is open-source software licensed under the [MIT License](LICENSE.md). This license allows modification, distribution, and private use, provided that appropriate credit is given to the original authors. diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 6d7efff6..4c411155 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,66 +1,77 @@ # Contributing to AymurAI -We are happy to accept your contributions to make `AymurAI` better and more awesome! To avoid unnecessary work on either -side, please stick to the following process: +We are happy to accept contributions that help make `AymurAI` more useful, more robust, and easier to maintain. +To avoid unnecessary work on either side, please use the following flow. -1. Check if there is already [an issue](https://github.com/AymurAI/dev/issues) for your concern. -2. If there is not, open a new one to start a discussion. We hate to close finished PRs! -3. If we decide your concern needs code changes, we would be happy to accept a pull request. Please consider the -commit guidelines below. +## Contribution flow +1. Check whether there is already an issue for your topic: +2. If not, open a new issue with context, motivation, and expected outcome. +3. Once the scope is clear, submit a pull request tied to that issue. -In case you just want to help out and don't know where to start, -[issues with "help wanted" label](https://github.com/AymurAI/dev/labels/help%20wanted) are good for -first-time contributors. +If you want to help and do not know where to start, small documentation fixes, test coverage improvements, and cleanup PRs are all welcome. +## Local development +If you want to get deeper into the API, we recommend cloning the repository and running the stack locally. +The codebase is fairly navigable, and most of the important modules are documented or organized by workflow. +### Option A: Docker (recommended) +You can use the provided compose services directly: -## Developing locally +```bash +make api-up +# or make api-full-up +``` -For contributors looking to get deeper into the API we suggest cloning the repository. -Nearly all classes and methods are documented, so finding your way around -the code should hopefully be easy. +Swagger UI: `http://localhost:8899/docs` -### Setup +If you prefer working from VS Code, the repository also includes a `.devcontainer/` setup. -#### Using Docker and devcontainer (recommended) -You can use the provided `devcontainer` load all the tools and packages needed. This can be done directly from Visual Studio Code. -You can check the [devcontainer documentation](https://code.visualstudio.com/docs/remote/containers) for more information. +### Option B: Local Python environment +Repository requires Python `3.10`. -#### Using jupyterlab image -If you want just check the notebooks and tutorials you can use the `jupyterlab` docker image. To run the image in `gpu` mode run: -```bash -make jupyter-run -``` -alternatively you can run in `cpu` mode with: ```bash -make jupyter-run-cpu -``` - +# if using uv +uv sync --all-groups -#### Install direclty on a your python environment -create a python environment of your preference and run: -```bash -pip install src/aymurai +# fallback with pip +pip install -e . ``` -You may need to install redis or run it in a docker container. You can use the following command to run it in a docker container: -```bash -make redis-run -``` +For most contributors, Docker is the easiest way to get a working API with the expected runtime dependencies. + +## Pre-commit hooks +After installing dependencies, enable the hooks: -### Git pre-commit Hooks -After installing the dependencies, install `pre-commit` hooks via: ```bash pre-commit install ``` -This will automatically run code formatters black and isort for each git commit. Also it will clear all outputs from the notebooks. If you want to more information about why we do this, please refer to the [data security](docs/DATA_SECURITY.md) section. +Configured hooks currently include: +- `black` +- `nbstripout` +This helps keep code formatting consistent and prevents notebook output from leaking into commits. -### Code Formatting +## Formatting +If needed, you can run the formatter manually before committing: -To ensure a standardized code style we use the formatter [black](https://github.com/ambv/black) and for standardizing imports we use [isort](https://github.com/PyCQA/isort). -If your code is not formatted properly, the tests will fail. +```bash +black aymurai/ +``` -If you set up pre-commit hooks, every git commit will automatically run these formatters. Otherwise you can also manually run them, or let your IDE run them on every file save. -Running from the command line works via `black src/aymurai/ && isort src/aymurai/` in the repository root folder. +## Documentation policy +When behavior changes in API, pipelines, or DB persistence, update the corresponding docs in the same PR: +- `README.md` +- `docs/api/README.md` +- `docs/pipelines/README.md` +- `docs/pipelines/anonymizer/README.md` +- `docs/pipelines/datapublic/README.md` +- `docs/database/README.md` +- `docs/entities/README.md` +- `docs/models/README.md` + +If the change is user-facing, documentation should land together with the code. + +## Community and security +- Code of conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) +- Security and ethics: [SECURITY.md](SECURITY.md) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..5a05e53e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,28 @@ +# Documentation Index +Language: **English** | [Español](es/README.md) + +This index covers operational documentation for `v1.5.0`. + +## Core docs +- Repository entrypoint: [../README.md](../README.md) +- API reference: [api/README.md](api/README.md) +- Pipelines index: [pipelines/README.md](pipelines/README.md) +- Anonymizer flow: [pipelines/anonymizer/README.md](pipelines/anonymizer/README.md) +- Datapublic flow: [pipelines/datapublic/README.md](pipelines/datapublic/README.md) +- Internal database schema: [database/README.md](database/README.md) + +## Entities +- Entities index: [entities/README.md](entities/README.md) +- Datapublic entities: [entities/datapublic/README.md](entities/datapublic/README.md) +- Anonymizer entities: [entities/anonymizer/README.md](entities/anonymizer/README.md) + +## Models +- Models index: [models/README.md](models/README.md) +- Anonymizer NER model card: [models/anonymizer-model-card.md](models/anonymizer-model-card.md) +- Flair NER model card: [models/flair-model-card.md](models/flair-model-card.md) +- Decision model card: [models/decision-model-card.md](models/decision-model-card.md) + +## Governance +- Contributing: [CONTRIBUTING.md](CONTRIBUTING.md) +- Security and ethics: [SECURITY.md](SECURITY.md) +- Code of conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 7e95a465..72aa9d8a 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -11,4 +11,4 @@ AymurAI is guided by a strong ethical position that considers the complexities o We acknowledge that every line of code that we write may potentially contain security issues. We are trying to deal with it responsibly and provide patches as quickly as possible. ## Reporting a Vulnerability -If you have found a security vulnerability, please open a new [issue](https://github.com/AymurAI/dev/issues/new) or report it to us by sending an [email](aymurai@datagenero.org). We will respond to you as soon as possible. \ No newline at end of file +If you have found a security vulnerability, please open a new [issue](https://github.com/AymurAI/backend/issues/new) or report it to us by sending an [email](mailto:aymurai@datagenero.org). We will respond to you as soon as possible. diff --git a/docs/anonymization/README.md b/docs/anonymization/README.md deleted file mode 100644 index 29deee42..00000000 --- a/docs/anonymization/README.md +++ /dev/null @@ -1,81 +0,0 @@ -## Pipeline actual de anonimización - -1. `/misc/document-extract` recibe el DOCX/PDF y devuelve el payload estructurado con `document_id` y la lista de párrafos. -2. `/anonymizer/predict` procesa cada párrafo y retorna las entidades detectadas (`aymurai_label`, texto y offsets) que el frontend reúne sobre el texto completo. Las predicciones originales se persisten en la base de datos. -3. Se validan manualmente las etiquetas consolidadas directamente en la interfaz gráfica. Al confirmar, se persisten las validaciones en la base de datos. -4. `/anonymizer/anonymize-document` aplica los reemplazos según las entidades confirmadas y genera el documento anonimizado listo para descarga. - -## Anonimización con Desambiguación de Entidades Canónicas - -1. `/misc/document-extract` recibe el DOCX/PDF y devuelve el payload estructurado (`document_id`, lista de párrafos) tal como hoy. -2. Se procesa cada párrafo con `/anonymizer/predict`, obteniendo los resultados de NER (`aymurai_label`, texto, offsets, contexto previo y posterior y otros atributos). -3. Módulo de fuzzy-matching cruza cada mención extraída para sugerir candidatos de `CanonicalEntities` (`canonical_text` y `aliases`). -4. Con esa lista se ejecuta el mapeo de `Entity` a `CanonicalEntity`: cada mención NER queda anotada con un `canonical_entity_id` y un `aymurai_label_instance` (índice entero por orden de aparición) y cualquier atributo inferido, generando la desambiguación de entidades. -5. El frontend consume esos outputs y muestra el texto original con dos niveles de revisión: etiquetas NER y asignación canónica. -6. Tras la validación manual, el cliente invoca `/anonymizer/anonymize-document`, que ahora utiliza políticas de render (`render_policy`) para aplicar reemplazos consistentes (etiqueta o subclase con sufijos opcionales) y generar el documento anonimizado final. -7. El documento anonimizado queda disponible para descarga y se registran en la base de datos las decisiones finales (etiquetas y canónicos). - -## Cambios principales en el modelo de datos - -### Nuevos campos en `EntityAttributes` - -- `canonical_entity_id`: UUID de la entidad canónica asignada a cada mención. -- `aymurai_label_instance`: índice entero por orden de aparición del `canonical_entity_id` dentro de un mismo label (1, 2, 3...). -- `aymurai_label_subclass`: en el caso de fechas donde encuentra el patrón se escribe la fecha en formato DD/MM/YYYY. -- `aymurai_disambiguation`: método aplicado para la desambiguación efectiva del label (`fuzzy`, `none`). -- `aymurai_anonymize`: flag efectivo de anonimización (True/False). - -### Políticas por label (nueva interfaz) - -Se incorpora un esquema de políticas por etiqueta que permite decidir: - -- `anonymize`: `true | false` -- `disambiguation`: `"none" | "fuzzy"` -- `use_subclass_when_available`: `true | false` - -Estas políticas pueden venir de: - -1. Configuración del servidor (variable de entorno `DISAMBIGUATION_LABEL_POLICIES`). -2. Request del usuario (campo `label_policies` en `/anonymizer/disambiguate` y `/anonymizer/anonymize-document`). - -## Render Policy (integración con frontend) - -Para evitar sumar flags adicionales en cada entidad, el comportamiento de render se controla con un objeto `render_policy` (a nivel request/documento), que define: - -- `suffix_mode`: `"auto" | "always" | "never"`. -- `suffix_threshold`: umbral para agregar sufijo en modo `auto`. - -Esto permite generar tokens como: - -- `` si hay un solo juez. -- ``, `` si hay múltiples. -- `` si `use_subclass_when_available` es `false` ó `use_subclass_when_available` es `true` pero no hay subclase disponible para esa entidad. - -El `render_policy` puede definirse por entorno (`RENDER_POLICY`) o por request y se aplica al momento de exportar el documento con `/anonymizer/anonymize-document`. - -## Cambios en la API - -### `/anonymizer/disambiguate` - -- **Nuevo input opcional**: `label_policies`. -- **Nuevo output**: `label_policies` y metadatos efectivos en cada `DocLabel` (`aymurai_disambiguation`, `aymurai_anonymize`). -- La selección de labels para fuzzy se define por políticas, no por un modo global. - -### `/anonymizer/anonymize-document` - -- **Input**: `DocumentAnnotations` incluye `label_policies` y `render_policy`. -- **Render**: los tokens se generan según `render_policy` y respetan `aymurai_anonymize`. - -## Plan de evaluación incremental - -El objetivo general es optimizar la extracción y desambiguación de entidades. Para avanzar con criterio orientado a métricas mediremos cada capa y el sistema end-to-end. - -- **NER**: aunque el modelo actual cubre el caso de uso, debemos planificar un nuevo ciclo de entrenamiento y finetuning. Será importante consolidar un dataset público anotado con las entidades a detectar, para lo cual podemos aprovechar repositorios públicos de documentos legales de Argentina (e idealmente, del resto de latinoamérica). Luego, se deberán realizar algunas revisiones manuales para asegurar calidad. Este dataset nos permitirá definir un split de evaluación estable y automatizar el cálculo de F1 por etiqueta para comparar versiones de forma consistente. -- **Heurística de agrupación**: vamos a contrastar variantes como Levenshtein normalizada, token fuzzy matching o TF-IDF con coseno. Cada método se ejecutará sobre predicciones reales del NER (para medir robustez ante ruido) y sobre etiquetas existentes (para estimar el techo teórico). La métrica utilizada para evaluar será aquella definida en `/notebooks/experiments/entity-disambiguation/Desarrollo metrica.md`, contra un conjunto de `CanonicalEntities` ya anotados. - -Finalmente consolidaremos una evaluación integrada combinando el mejor NER disponible, la heurística con mayor cobertura y baja tasa de falsos positivos y la versión de prompt más precisa. El benchmark se ejecutará sobre un conjunto de documentos de validación con etiquetas canónicas revisadas. - -## Consideraciones de integración con frontend - -- Necesitamos habilitar una lista configurable de entidades a excluir de la anonimización. El frontend deberá permitir que la persona usuaria decida, por ejemplo, mantener visibles o no entidades específicas o menciones a funcionarios públicos según su rol procesal. -- Las exclusiones y la edición manual posterior impactan directamente en el ordenamiento de los `aymurai_label_instance`. Habrá que recalcular los sufijos luego de aplicar exclusiones y validaciones para evitar huecos o inconsistencias entre el texto mostrado y los reemplazos finales. diff --git a/docs/api/README.md b/docs/api/README.md index f5d1b028..dd09f428 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -1,35 +1,321 @@ -# API -The connection between AymurAI's frontend and backend occurs through an Application Programming Interface (API). There are several endpoints that allow communication between the different parts of the software. Calls to these endpoints are made from the frontend to execute different subroutines. +# API Reference +Language: **English** | [Español](../es/api/README.md) -# Endpoints -* `/document-extract`: plain text extraction from .doc or .docx documents -* `/predict`: prediction over a single paragraph -* `/predict-batch`: run prediction over a batch of paragraphs +This document describes the currently mounted public API in `aymurai/api/main.py` + `aymurai/api/core.py`. + +## Base URL and OpenAPI +- Local base URL: `http://localhost:8899` +- Swagger UI: `http://localhost:8899/docs` +- OpenAPI JSON: `http://localhost:8899/openapi.json` + +## Public Endpoints (Mounted) + +| Method | Path | Purpose | +|---|---|---| +| `GET` | `/server/healthcheck` | Service liveness check | +| `GET` | `/server/stats/summary` | Runtime CPU/memory stats | +| `POST` | `/document-extract` | Deprecated alias of `/misc/document-extract` | +| `POST` | `/misc/document-extract` | Extract normalized paragraphs from uploaded document | +| `POST` | `/anonymizer/predict` | NER prediction for a paragraph | +| `POST` | `/anonymizer/disambiguate` | Canonical entity disambiguation + policy merge | +| `POST` | `/anonymizer/validation` | Fetch paragraph-level manual validation | +| `POST` | `/anonymizer/anonymize-document` | Compile and export anonymized document | +| `POST` | `/datapublic/predict/{document_id}` | Predict entities for data-public flow | +| `GET` | `/datapublic/validation/document/{document_id}` | Read document-level validation | +| `POST` | `/datapublic/validation/document/{document_id}` | Save document-level validation | +| `POST` | `/convert/pdf/odt` | Convert PDF to ODT | +| `POST` | `/convert/pdf/docx` | Convert PDF to DOCX | +| `POST` | `/convert/docx/odt` | Convert DOCX to ODT | +| `POST` | `/convert/docx/pdf` | Convert DOCX to PDF | +| `POST` | `/convert/odt/pdf` | Convert ODT to PDF | +| `POST` | `/convert/odt/docx` | Convert ODT to DOCX | + +## Core Data Contracts + +Note: the JSON snippets below are minimal valid examples. Real payloads may include additional fields depending on the endpoint and processing stage. + +### `TextRequest` +```json +{ + "text": "Acusado: Ramiro Marrón DNI 34.555.666." +} +``` + +### `EntityAttributes` (relevant fields) +```json +{ + "aymurai_label": "PER", + "aymurai_label_subclass": [], + "aymurai_method": "flair", + "aymurai_score": 0.97, + "canonical_entity_id": "a3f8b60f-8e7e-4c8b-9de2-ec8dd3f44c12", + "aymurai_label_instance": 1, + "aymurai_disambiguation": "fuzzy", + "aymurai_anonymize": true +} +``` + +### `DocLabel` +```json +{ + "text": "Ramiro Marrón", + "start_char": 9, + "end_char": 22, + "attrs": { + "aymurai_label": "PER" + } +} +``` + +### `DocumentInformation` +```json +{ + "document": "Acusado: Ramiro Marrón DNI 34.555.666.", + "labels": [ + { + "text": "Ramiro Marrón", + "start_char": 9, + "end_char": 22, + "attrs": { + "aymurai_label": "PER" + } + } + ] +} +``` + +### `LabelPolicy` +```json +{ + "anonymize": true, + "disambiguation": "fuzzy", + "use_subclass_when_available": true +} +``` + +### `RenderPolicy` +```json +{ + "suffix_mode": "auto", + "suffix_threshold": 1 +} +``` + +### `DocumentAnnotations` +```json +{ + "data": [ + { + "document": "...", + "labels": [] + } + ], + "label_policies": { + "PER": { + "anonymize": true, + "disambiguation": "fuzzy", + "use_subclass_when_available": false + } + }, + "render_policy": { + "suffix_mode": "auto", + "suffix_threshold": 1 + } +} +``` + +## Endpoint Details and Examples + +### Server + +#### `GET /server/healthcheck` +- Response `200`: + +```json +{"status": "ok"} +``` -# Deployment -This project is deployed using [Docker](https://www.docker.com/) , and the images are available in the following registry: ```bash -registry.gitlab.com/collective.ai/datagenero-public/aymurai-api:prod +curl -s http://localhost:8899/server/healthcheck ``` -You can a production ready instance of the API by running: + +#### `GET /server/stats/summary` +- Response `200` (shape): + +```json +{ + "is_docker": true, + "cpu_core_limit": 4, + "cpu_usage_percent": 0.0, + "memory_limit_mb": 4096.0, + "memory_usage_mb": 823.5 +} +``` + ```bash -docker run -d --rm -p 8899:8899 \ - registry.gitlab.com/collective.ai/datagenero-public/aymurai-api:prod +curl -s http://localhost:8899/server/stats/summary ``` -this will start a container with the API running on port 8899 on your localhost. The API is documented using OpenAPI and can be accessed at `http://localhost:8899/docs` -Once it is deployed, it doesn't requere a internet connection to work. If you need to deployed in a closed network you can port the image using + +### Document Extraction + +#### `POST /misc/document-extract` +#### `POST /document-extract` (deprecated alias) +- Request: `multipart/form-data` with `file` +- Supported MIME types in extraction flow: DOCX, ODT, PDF +- Response `200`: + +```json +{ + "document": ["Paragraph 1", "Paragraph 2"], + "document_id": "f2b25507-cf88-5b11-8f2a-c0b6f940b7f8" +} +``` + ```bash -docker image save registry.gitlab.com/collective.ai/datagenero-public/aymurai-api:prod -o aymurai-api.tar +curl -s -X POST \ + -F "file=@test/api/test_file.docx" \ + http://localhost:8899/misc/document-extract ``` -and then transfer the image to the target machine and load it using + +Common errors: +- `504` extraction timeout +- `500` extractor/internal errors + +### Anonymizer + +#### `POST /anonymizer/predict` +- Request body: `TextRequest` +- Query param: `use_cache=true|false` (default `true`) +- Response `200`: `DocumentInformation` + ```bash -docker load -i aymurai-api.tar +curl -s -X POST "http://localhost:8899/anonymizer/predict?use_cache=true" \ + -H "Content-Type: application/json" \ + -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` -For more information about docker deployment please refer to the [docker documentation](https://docs.docker.com/). -You also can contact us at aymurai@datagenero.org and we will be happy to help you. +#### `POST /anonymizer/disambiguate` +- Request body: + +```json +{ + "paragraphs": [ + { + "document": "Acusado: Ramiro Marrón DNI 34.555.666.", + "labels": [] + } + ], + "label_policies": { + "PER": { + "anonymize": true, + "disambiguation": "fuzzy", + "use_subclass_when_available": false + } + } +} +``` + +- Response `200`: `DocumentAnnotations` (with `data` and effective `label_policies`) + +```bash +curl -s -X POST http://localhost:8899/anonymizer/disambiguate \ + -H "Content-Type: application/json" \ + -d '{"paragraphs":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}}}' +``` + +#### `POST /anonymizer/validation` +- Request body: `TextRequest` +- Response `200`: `list[DocLabel] | null` + +```bash +curl -s -X POST http://localhost:8899/anonymizer/validation \ + -H "Content-Type: application/json" \ + -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' +``` + +#### `POST /anonymizer/anonymize-document` +- Request: `multipart/form-data` + - `file`: original document (`.docx`, `.pdf`, `.odt`) + - `annotations`: JSON string serialized from `DocumentAnnotations` +- Response `200`: binary anonymized `.odt` file + +```bash +curl -X POST http://localhost:8899/anonymizer/anonymize-document \ + -F "file=@test/api/test_file.docx" \ + -F 'annotations={"data":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}},"render_policy":{"suffix_mode":"auto","suffix_threshold":1}}' +``` + +Common errors: +- `400` invalid form payload +- `500` conversion/anonymization failures + +### Data-Public + +#### `POST /datapublic/predict/{document_id}` +- Path param: `document_id` (`UUID5`) +- Request body: `TextRequest` +- Query param: `use_cache=true|false` (default `true`) +- Response `200`: `DocumentInformation` + +```bash +curl -s -X POST "http://localhost:8899/datapublic/predict/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc?use_cache=true" \ + -H "Content-Type: application/json" \ + -d '{"text":"Buenos Aires, 17 de noviembre de 2024"}' +``` + +#### `GET /datapublic/validation/document/{document_id}` +- Response `200`: object or `null` +- Response `404`: document not found + +```bash +curl -s http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc +``` + +#### `POST /datapublic/validation/document/{document_id}` +- Request body: free-form JSON object (stored as document-level validation) +- Response `200`: empty body + +```bash +curl -s -X POST http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc \ + -H "Content-Type: application/json" \ + -d '{"materia":"penal","violencia_de_genero":"si"}' +``` + +### Document Conversion + +All conversion endpoints use `multipart/form-data` with a `file` field. + +| Method | Path | Input | Output | +|---|---|---|---| +| `POST` | `/convert/pdf/odt` | `.pdf` | `.odt` | +| `POST` | `/convert/pdf/docx` | `.pdf` | `.docx` | +| `POST` | `/convert/docx/odt` | `.docx` | `.odt` | +| `POST` | `/convert/docx/pdf` | `.docx` | `.pdf` | +| `POST` | `/convert/odt/pdf` | `.odt` | `.pdf` | +| `POST` | `/convert/odt/docx` | `.odt` | `.docx` | + +For PDF input endpoints, optional query param: +- `backend=libreoffice|pandoc` (default: `libreoffice`) + +Example: + +```bash +curl -X POST "http://localhost:8899/convert/pdf/docx?backend=libreoffice" \ + -F "file=@input.pdf" -o output.docx +``` + +Common errors: +- `400` unsupported input extension +- `500` conversion tool failure + +## Legacy / Not Public (Not Mounted) +The following route modules exist in code but are not included in `core.router` at runtime: -# Source -The api source code is written in top of FastAPI and can be found in [here](../../api/). +- `aymurai/api/endpoints/routers/datapublic/dataset.py` + - includes `/datapublic/dataset/*` CRUD/batch routes, but router is not mounted. +- `aymurai/api/endpoints/routers/anonymizer/database.py` + - `/anonymizer/database/*` routes exist, include is commented out. +- `aymurai/api/endpoints/routers/database/*` + - additional DB admin routes exist, but no mounting in `core.router`. -Please follow the [code of conduct](../CODE_OF_CONDUCT.md) and [contributing guidelines](../CONTRIBUTING.md). \ No newline at end of file +Treat these as legacy/internal code paths until explicitly exposed in the public router. diff --git a/docs/data/en/entities-table.md b/docs/data/en/entities-table.md deleted file mode 100644 index 1037b24d..00000000 --- a/docs/data/en/entities-table.md +++ /dev/null @@ -1,32 +0,0 @@ -# Entities -| Entity | Description | -|-----------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| ART_INFRINGIDO | Article(s) of the infraction(s) in the case. | -| CONDUCTA | Indicates the action relating to the crime, contravention, or misdemeanor described in the article infringed. | -| CONDUCTA_DESCRIPCION | Indicates that the contravention or offence infringed has some particularity, such as being aggravated by some causality. | -| DECISION | Fragment of text denoting a decision taken by the court regarding the case. | -| DETALLE | Specifies OBJETO_DE_LA_RESOLUCION as to what was resolved. | -| EDAD_AL_MOMENTO_DEL_HECHO | Indicates the age of the person at the time of the event. | -| FECHA_DE_NACIMIENTO | Date of birth. | -| FECHA_DEL_HECHO | Date on which the reported event occurred. | -| FECHA_RESOLUCION | Day of resolution. In the case of oral hearings, it is the day of the beginning of the hearing. | -| FRASES_AGRESION | Transcription of the phrases described by the victim as the verbal aggression suffered and that are part of the facts of the case. Applies to cases of verbal violence. | -| GENERO | Gender. | -| HIJOS_HIJAS_EN_COMUN | Indicates whether the accused person and the complainant have children in common. | -| HORA_DE_CIERRE | Time of end of court hearing. | -| HORA_DE_INICIO | Court hearing start time. | -| LUGAR_DEL_HECHO | Indicates the physical place (environment or public road) where the facts occurred or if it was committed by technological means. | -| MODALIDAD_DE_LA_VIOLENCIA | The way in which the different types of violence manifest themselves. For example: domestic, institutional, media, labor, reproductive freedom, obstetric, in public or private spaces, and political and public violence. | -| N_EXPTE_EJE | Case identifier number. | -| NACIONALIDAD | Nationality. | -| NIVEL_INSTRUCCION | Level of formal education attained by the individual. | -| NOMBRE | Name. | -| OBJETO_DE_LA_RESOLUCION | About what was resolved. | -| PERSONA_ACUSADA_NO_DETERMINADA | In case the accused person is not a natural person or is not determined. For example: legal entity, social network user, etc. | -| RELACION_Y_TIPO_ENTRE_ACUSADO/A_Y_DENUNCIANTE | Indicates the type of relationship the accused person has with the complainant. | -| TIPO_DE_RESOLUCION | Interlocutory decisions are those that define a specific issue during the process of the proceeding, or final decisions are those that put an end to the process of the case. | -| VIOLENCIA_DE_GENERO | If the fact under investigation is within a context of gender violence. | -# Subcategories -The majority of the entities described above have subcategories acording their use in the criminal court and the type of information they contain. You can check a more complete description [here](https://docs.google.com/document/d/123B9T2abCEqBaxxOl5c7HBJZRdIMtKDWo6IKHIVil04/edit) (Spanish version) - -A comprehensive list of all entities and their subcategory can be found [here](https://docs.google.com/spreadsheets/d/1FTRtltYJrGJ6huQd0ih-QBZfqo5LGamVFXvXKcmX9-k/edit#gid=0) \ No newline at end of file diff --git a/docs/data/es/entities-table.md b/docs/data/es/entities-table.md deleted file mode 100644 index 1f4b9301..00000000 --- a/docs/data/es/entities-table.md +++ /dev/null @@ -1,27 +0,0 @@ -| Entidad | Descripcion | -|-----------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| ART_INFRINGIDO | Artículo/s de la/s infracción/es en el caso | -| CONDUCTA | Indica la acción relativa al delito, la contravención, o la falta que aparece descripta en el artículo infringido; | -| CONDUCTA_DESCRIPCION | Indica la contravención o la falta infringida tiene alguna particularidad, como puede ser que se encuentra agravada por alguna causal | -| DECISION | Fragmento de texto que denota una decision tomada por el juzgado respecto al caso. | -| DETALLE | Especifica OBJETO_DE_LA_RESOLUCIÓN respecto a qué se resolvió | -| EDAD_AL_MOMENTO_DEL_HECHO | Indica la edad de la persona al momento del hecho | -| FECHA_DE_NACIMIENTO | Fecha de nacimiento | -| FECHA_DEL_HECHO | Fecha en que sucedio el hecho denunciado | -| FECHA_RESOLUCION | Día de la resolución. En caso de las audiencias orales es el día de su inicio | -| FRASES_AGRESION | Transcripción de las frases descriptas por la víctima como la agresión verbal sufrida y que son parte de los hechos del caso. Aplica para los casos de violencia verbal; | -| GENERO | Genero | -| HIJOS_HIJAS_EN_COMUN | indica si la persona acusada y la denunciante tienen hijos/as en común | -| HORA_DE_CIERRE | Hora de finalización de la audiencia | -| HORA_DE_INICIO | Hora de inicio de la audiencia | -| LUGAR_DEL_HECHO | Indica lugar físico (ambiente o vía pública) donde ocurrieron los hechos o si fue cometido mediante medios tecnológicos | -| MODALIDAD_DE_LA_VIOLENCIA | Forma en que se manifiestan los distintos tipos de violencia | -| N_EXPTE_EJE | Numeroo identificador del caso | -| NACIONALIDAD | Nacioalidad | -| NIVEL_INSTRUCCION | Nivel de estudios formales alcanzados por la persona | -| NOMBRE | Nombre | -| OBJETO_DE_LA_RESOLUCION | Sobre qué se resolvió | -| PERSONA_ACUSADA_NO_DETERMINADA | En el caso de que la persona acusada no sea una persona física o no esté determinada. Por ejemplo: persona jurídica, usuario de red social, etc. | -| RELACION_Y_TIPO_ENTRE_ACUSADO/A_Y_DENUNCIANTE | Indica el tipo de vínculo que tiene la persona acusada con la denunciante | -| TIPO_DE_RESOLUCION | Interlocutorias son aquellas que definen una cuestión concreta durante la tramitación del proceso, o definitivas son aquellas resoluciones que ponen fin al proceso de la causa | -| VIOLENCIA_DE_GENERO | Si el hecho objeto de investigación se encuentra dentro de un contexto de violencia de género. | diff --git a/docs/database/README.md b/docs/database/README.md index 387ea6ed..64cf5212 100644 --- a/docs/database/README.md +++ b/docs/database/README.md @@ -1,66 +1,113 @@ -# Descripción del nuevo flujo de integración en AymurAI - -En este documento, describimos brevemente el nuevo flujo de integración entre el _front-end_ y el _back-end_ de AymurAI. - -## Actualización principal del back-end - -Se implementó un motor de base de datos que permite persistir en disco tanto las predicciones generadas por los modelos como las validaciones manuales realizadas desde la interfaz gráfica. Esta base de datos no sólo funciona como un caché para las predicciones, sino que además permite a les usuaries recuperar la última validación manual en caso de necesitar reprocesar un documento específico. - -A continuación, se detalla el nuevo flujo para cada _pipeline_ de AymurAI: +# Internal Database +Language: **English** | [Español](../es/database/README.md) + +This document describes the internal persistence used by the API runtime. + +## Engine and Migrations +- ORM: `SQLModel` (`sqlalchemy` backend) +- Migration tool: Alembic +- Runtime setting: `SQLALCHEMY_DATABASE_URI` +- Default DB URI: `sqlite:////resources/cache/sqlite/database.db` +- Startup behavior: + 1. API checks DB connectivity. + 2. If SQLite file does not exist, it creates parent directories. + 3. API runs `alembic upgrade head` on startup. + +Related code: +- `aymurai/settings.py` +- `aymurai/api/startup/database.py` +- `aymurai/api/main.py` +- `aymurai/database/versions/13f78d08e925_create_database.py` + +## ER Diagram +![Database ER diagram](schema.png) + +Editable source: [`schema.mmd`](schema.mmd) + +## Tables + +### `anonymization_document` +| Column | Type | Nullable | Notes | +|---|---|---|---| +| `id` | `UUID` | no | Primary key | +| `created_at` | `DATETIME` | no | Server default `CURRENT_TIMESTAMP` | +| `updated_at` | `DATETIME` | yes | Updated on row changes | +| `name` | `TEXT` | no | Original filename | + +### `anonymization_paragraph` +| Column | Type | Nullable | Notes | +|---|---|---|---| +| `id` | `UUID` | no | Primary key, derived from paragraph text hash | +| `text` | `TEXT` | no | Normalized paragraph text | +| `prediction` | `JSON` | yes | Model predictions (`list[DocLabel]`) | +| `validation` | `JSON` | yes | Manual labels (`list[DocLabel]`) | +| `created_at` | `DATETIME` | no | Server default `CURRENT_TIMESTAMP` | +| `updated_at` | `DATETIME` | yes | Updated on row changes | + +### `anonymization_document_paragraph` +| Column | Type | Nullable | Notes | +|---|---|---|---| +| `id` | `UUID` | no | Link row identifier | +| `document_id` | `UUID` | no | FK -> `anonymization_document.id` | +| `paragraph_id` | `UUID` | no | FK -> `anonymization_paragraph.id` | +| `order` | `INTEGER` | yes | Paragraph order in source document | + +Primary key is composite over `id`, `document_id`, `paragraph_id`. + +### `datapublic_document` +| Column | Type | Nullable | Notes | +|---|---|---|---| +| `id` | `UUID` | no | Primary key (document identifier) | +| `prediction` | `JSON` | yes | Reserved document-level prediction payload; not written by the current public router | +| `validation` | `JSON` | yes | Document-level validation payload | +| `created_at` | `DATETIME` | no | Server default `CURRENT_TIMESTAMP` | +| `updated_at` | `DATETIME` | yes | Updated on row changes | + +### `datapublic_paragraph` +| Column | Type | Nullable | Notes | +|---|---|---|---| +| `id` | `UUID` | no | Primary key, derived from paragraph text hash | +| `text` | `TEXT` | no | Normalized paragraph text | +| `prediction` | `JSON` | yes | Model predictions (`list[DocLabel]`) | +| `validation` | `JSON` | yes | Reserved for paragraph-level validation; public route is currently commented legacy logic | +| `created_at` | `DATETIME` | no | Server default `CURRENT_TIMESTAMP` | +| `updated_at` | `DATETIME` | yes | Updated on row changes | + +### `datapublic_document_paragraph` +| Column | Type | Nullable | Notes | +|---|---|---|---| +| `id` | `UUID` | no | Link row identifier | +| `document_id` | `UUID` | no | FK -> `datapublic_document.id` | +| `paragraph_id` | `UUID` | no | FK -> `datapublic_paragraph.id` | +| `order` | `INTEGER` | yes | Paragraph order in source document | + +Primary key is composite over `id`, `document_id`, `paragraph_id`. + +## Endpoint to Persistence Mapping ### Anonymizer - -1. **Consulta inicial en la base de datos (_endpoint_ `/anonymizer/validation`):** - - Tras la extracción del texto del documento, se verifica si existe una validación guardada para cada uno de sus párrafos. El identificador utilizado es un _hash_ único generado a partir del contenido textual del párrafo. - - - **Si existe una validación previa en la tabla `anonymization_paragraph`:** se retorna dicha validación. - - **Si no existe una validación previa:** debe dispararse el flujo de predicciones consumiendo el _endpoint_ correspondiente. - -2. **Consulta de predicciones (_endpoint_ `/anonymizer/predict`):** - - - **Si la predicción para el párrafo ya existe en la tabla `anonymization_paragraph`:** se retorna. - - **Si no existe:** se ejecuta el modelo de predicción, y los resultados se retornan y se persisten en la tabla `anonymization_paragraph`. - - > **Formato de etiquetas:** tanto las validaciones manuales como las predicciones se estructuran utilizando el formato actual de las etiquetas de AymurAI. - -3. **Interfaz gráfica y validación manual:** - - Las etiquetas retornadas se muestran en la interfaz gráfica, donde pueden ser validadas manualmente. Una vez finalizada la validación, se procede con la anonimización del documento (_endpoint_ `/anonymizer/anonymize-document`). - -4. **Persistencia de validaciones:** - - Al finalizar el proceso, las validaciones se escriben en la tabla `anonymization_paragraph`, ya sea creando nuevos registros para párrafos nuevos o actualizando registros existentes para párrafos previamente procesados. Esta escritura es realizada al inicio del flujo de `anonymize-document`, luego de que se indique desde la UI que el documento está listo para su anonimización. Además, en la tabla `anonymization_document` se escribe la referencia al ID del documento y el nombre del archivo correspondiente. Asimismo, el ID del documento permite recuperar los párrafos y su orden en el documento a través de la tabla `anonymization_document_paragraph`. - -### Data Public - -El flujo para el _pipeline_ de Data Public es similar al del Anonymizer, pero presenta diferencias importantes en cuanto a las validaciones, ya que estas no comparten el mismo formato que las predicciones originales del modelo. En este caso, las validaciones se realizan a nivel general del documento (no por párrafo) y se llevan a cabo manualmente en la sección lateral derecha de la UI, donde se definen los campos que serán volcados al dataset público. A diferencia del _pipeline_ de anonimización, las predicciones siempre son necesarias para resaltar los campos detectados en el texto, incluso cuando ya existen validaciones realizadas, ya que estas no son modificaciones directas sobre las entidades reconocidas por el modelo. - -1. **Consulta inicial en la base de datos (_endpoint_ `/datapublic/dataset/{document_id}`):** - - Tras la extracción del texto del documento, se verifica si existe una validación general para el documento. - - - **Si existe una validación previa para el documento en la tabla `datapublic_dataset`:** se retorna dicha validación. - -2. **Flujo de predicciones (_endpoint_ `/datapublic/predict`):** - - A su vez, se consulta si existen predicciones guardadas para cada uno de los párrafos: - - - **Si existe una predicción previa para cada párrafo en la tabla `datapublic_paragraph`:** se retorna dicha predicción. - - - **Si no existe:** se ejecuta el modelo de predicción, y los resultados se retornan y se persisten en la tabla `datapublic_paragraph`. - - > **Formato de etiquetas:** las predicciones se estructuran utilizando el formato actual de las etiquetas de AymurAI. Las validaciones, sin embargo, tienen un formato distinto, **equivalente al de las filas del dataset público**. Es necesario tener presente esto para poder integrar correctamente con el _front-end_ los campos validados persistidos en la base de datos. - -3. **Interfaz gráfica y validación manual:** - - Una vez finalizadas las consultas a la base de datos y el flujo de predicciones, las etiquetas retornadas se muestran en la interfaz gráfica, donde pueden ser revisadas y validadas manualmente. Posteriormente, las nuevas validaciones se persisten en la tabla `datapublic_dataset` haciendo un _post_ contra el _endpoint_ `/datapublic/dataset`, ya sea creando nuevos registros para documentos nuevos o actualizando registros existentes para documentos previamente procesados. Esta escritura debe realizarse una vez que desde la UI se confirma que los datos extraídos del documento son correctos. - - -#### Requerimientos a la UI - -Para la correcta persistencia de los datos (por ejemplo, para hacer evaluaciones o futuros entrenamientos de los modelos), se necesita que la UI envíe los datos corregidos a la API. Esto puede ser resumido en un _endpoint_ de "compilación" al final del proceso de validación. Este _endpoint_ sería equivalente al `anonymization/anonymize-document` - -## Esquema de la base de datos - -![schema](schema.jpg) +- `POST /anonymizer/predict` + - Reads `anonymization_paragraph` by paragraph UUID. + - Writes `anonymization_paragraph.prediction` when cache is enabled. +- `POST /anonymizer/disambiguate` + - Writes disambiguated predictions to `anonymization_paragraph.prediction`. +- `POST /anonymizer/validation` + - Reads `anonymization_paragraph.validation`. +- `POST /anonymizer/anonymize-document` + - Writes `anonymization_paragraph.validation`. + - Creates `anonymization_document` keyed by uploaded file content hash. + - Creates link rows in `anonymization_document_paragraph`. + +### Data-public +- `POST /datapublic/predict/{document_id}` + - Uses caller-provided `document_id` as the document primary key. + - Ensures `datapublic_document` exists when `use_cache=true`. + - Writes `datapublic_paragraph.prediction` when `use_cache=true`. + - Writes link row in `datapublic_document_paragraph` when `use_cache=true`. +- `GET /datapublic/validation/document/{document_id}` + - Reads `datapublic_document.validation`. +- `POST /datapublic/validation/document/{document_id}` + - Upserts `datapublic_document.validation`. + +## Legacy Note +Route modules for dataset CRUD (`/datapublic/dataset/*`) exist in code but are not mounted in the public router. Do not treat them as active public API until exposed in `core.router`. diff --git a/docs/database/schema.excalidraw b/docs/database/schema.excalidraw new file mode 100644 index 00000000..111dd9fe --- /dev/null +++ b/docs/database/schema.excalidraw @@ -0,0 +1,56 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "id": "UnZYOKsPO14ownJjIhB0K", + "type": "image", + "x": 216.9140625, + "y": 240.5078125, + "width": 968.171875, + "height": 397.984375, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "a2", + "roundness": null, + "seed": 810215012, + "version": 5, + "versionNonce": 845707748, + "isDeleted": false, + "boundElements": [], + "updated": 1772457952595, + "link": null, + "locked": false, + "status": "saved", + "fileId": "X7nK5-PoRG7EVUWSedgsz", + "scale": [ + 1, + 1 + ], + "crop": null + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "X7nK5-PoRG7EVUWSedgsz": { + "id": "X7nK5-PoRG7EVUWSedgsz", + "mimeType": "image/svg+xml", + "dataURL": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGFyaWEtcm9sZWRlc2NyaXB0aW9uPSJlciIgcm9sZT0iZ3JhcGhpY3MtZG9jdW1lbnQgZG9jdW1lbnQiIHZpZXdCb3g9IjAgMCA5NjguMTgxNzAxNjYwMTU2MiAzOTgiIHN0eWxlPSJtYXgtd2lkdGg6IDk2OC4xODE3MDE2NjAxNTYycHg7IiB3aWR0aD0iOTY4LjE3MTg3NSIgaWQ9Im1lcm1haWQtdG8tZXhjYWxpZHJhdyIgaGVpZ2h0PSIzOTcuOTg0Mzc1Ij48c3R5bGU+I21lcm1haWQtdG8tZXhjYWxpZHJhd3tmb250LWZhbWlseToidHJlYnVjaGV0IG1zIix2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWY7Zm9udC1zaXplOjI1cHg7ZmlsbDojMzMzO30jbWVybWFpZC10by1leGNhbGlkcmF3IC5lcnJvci1pY29ue2ZpbGw6IzU1MjIyMjt9I21lcm1haWQtdG8tZXhjYWxpZHJhdyAuZXJyb3ItdGV4dHtmaWxsOiM1NTIyMjI7c3Ryb2tlOiM1NTIyMjI7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLmVkZ2UtdGhpY2tuZXNzLW5vcm1hbHtzdHJva2Utd2lkdGg6MnB4O30jbWVybWFpZC10by1leGNhbGlkcmF3IC5lZGdlLXRoaWNrbmVzcy10aGlja3tzdHJva2Utd2lkdGg6My41cHg7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLmVkZ2UtcGF0dGVybi1zb2xpZHtzdHJva2UtZGFzaGFycmF5OjA7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLmVkZ2UtcGF0dGVybi1kYXNoZWR7c3Ryb2tlLWRhc2hhcnJheTozO30jbWVybWFpZC10by1leGNhbGlkcmF3IC5lZGdlLXBhdHRlcm4tZG90dGVke3N0cm9rZS1kYXNoYXJyYXk6Mjt9I21lcm1haWQtdG8tZXhjYWxpZHJhdyAubWFya2Vye2ZpbGw6IzMzMzMzMztzdHJva2U6IzMzMzMzMzt9I21lcm1haWQtdG8tZXhjYWxpZHJhdyAubWFya2VyLmNyb3Nze3N0cm9rZTojMzMzMzMzO30jbWVybWFpZC10by1leGNhbGlkcmF3IHN2Z3tmb250LWZhbWlseToidHJlYnVjaGV0IG1zIix2ZXJkYW5hLGFyaWFsLHNhbnMtc2VyaWY7Zm9udC1zaXplOjI1cHg7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLmVudGl0eUJveHtmaWxsOiNFQ0VDRkY7c3Ryb2tlOiM5MzcwREI7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLmF0dHJpYnV0ZUJveE9kZHtmaWxsOiNmZmZmZmY7c3Ryb2tlOiM5MzcwREI7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLmF0dHJpYnV0ZUJveEV2ZW57ZmlsbDojZjJmMmYyO3N0cm9rZTojOTM3MERCO30jbWVybWFpZC10by1leGNhbGlkcmF3IC5yZWxhdGlvbnNoaXBMYWJlbEJveHtmaWxsOmhzbCg4MCwgMTAwJSwgOTYuMjc0NTA5ODAzOSUpO29wYWNpdHk6MC43O2JhY2tncm91bmQtY29sb3I6aHNsKDgwLCAxMDAlLCA5Ni4yNzQ1MDk4MDM5JSk7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLnJlbGF0aW9uc2hpcExhYmVsQm94IHJlY3R7b3BhY2l0eTowLjU7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLnJlbGF0aW9uc2hpcExpbmV7c3Ryb2tlOiMzMzMzMzM7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgLmVudGl0eVRpdGxlVGV4dHt0ZXh0LWFuY2hvcjptaWRkbGU7Zm9udC1zaXplOjE4cHg7ZmlsbDojMzMzO30jbWVybWFpZC10by1leGNhbGlkcmF3ICNNRF9QQVJFTlRfU1RBUlR7ZmlsbDojZjVmNWY1IWltcG9ydGFudDtzdHJva2U6IzMzMzMzMyFpbXBvcnRhbnQ7c3Ryb2tlLXdpZHRoOjE7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgI01EX1BBUkVOVF9FTkR7ZmlsbDojZjVmNWY1IWltcG9ydGFudDtzdHJva2U6IzMzMzMzMyFpbXBvcnRhbnQ7c3Ryb2tlLXdpZHRoOjE7fSNtZXJtYWlkLXRvLWV4Y2FsaWRyYXcgOnJvb3R7LS1tZXJtYWlkLWZvbnQtZmFtaWx5OiJ0cmVidWNoZXQgbXMiLHZlcmRhbmEsYXJpYWwsc2Fucy1zZXJpZjt9PC9zdHlsZT48Zy8+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG1hcmtlckhlaWdodD0iMjQwIiBtYXJrZXJXaWR0aD0iMTkwIiByZWZZPSI3IiByZWZYPSIwIiBpZD0iTURfUEFSRU5UX1NUQVJUIj48cGF0aCBkPSJNIDE4LDcgTDksMTMgTDEsNyBMOSwxIFoiLz48L21hcmtlcj48L2RlZnM+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG1hcmtlckhlaWdodD0iMjgiIG1hcmtlcldpZHRoPSIyMCIgcmVmWT0iNyIgcmVmWD0iMTkiIGlkPSJNRF9QQVJFTlRfRU5EIj48cGF0aCBkPSJNIDE4LDcgTDksMTMgTDEsNyBMOSwxIFoiLz48L21hcmtlcj48L2RlZnM+PGRlZnM+PG1hcmtlciBvcmllbnQ9ImF1dG8iIG1hcmtlckhlaWdodD0iMTgiIG1hcmtlcldpZHRoPSIxOCIgcmVmWT0iOSIgcmVmWD0iMCIgaWQ9Ik9OTFlfT05FX1NUQVJUIj48cGF0aCBkPSJNOSwwIEw5LDE4IE0xNSwwIEwxNSwxOCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJncmF5Ii8+PC9tYXJrZXI+PC9kZWZzPjxkZWZzPjxtYXJrZXIgb3JpZW50PSJhdXRvIiBtYXJrZXJIZWlnaHQ9IjE4IiBtYXJrZXJXaWR0aD0iMTgiIHJlZlk9IjkiIHJlZlg9IjE4IiBpZD0iT05MWV9PTkVfRU5EIj48cGF0aCBkPSJNMywwIEwzLDE4IE05LDAgTDksMTgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iZ3JheSIvPjwvbWFya2VyPjwvZGVmcz48ZGVmcz48bWFya2VyIG9yaWVudD0iYXV0byIgbWFya2VySGVpZ2h0PSIxOCIgbWFya2VyV2lkdGg9IjMwIiByZWZZPSI5IiByZWZYPSIwIiBpZD0iWkVST19PUl9PTkVfU1RBUlQiPjxjaXJjbGUgcj0iNiIgY3k9IjkiIGN4PSIyMSIgZmlsbD0id2hpdGUiIHN0cm9rZT0iZ3JheSIvPjxwYXRoIGQ9Ik05LDAgTDksMTgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iZ3JheSIvPjwvbWFya2VyPjwvZGVmcz48ZGVmcz48bWFya2VyIG9yaWVudD0iYXV0byIgbWFya2VySGVpZ2h0PSIxOCIgbWFya2VyV2lkdGg9IjMwIiByZWZZPSI5IiByZWZYPSIzMCIgaWQ9IlpFUk9fT1JfT05FX0VORCI+PGNpcmNsZSByPSI2IiBjeT0iOSIgY3g9IjkiIGZpbGw9IndoaXRlIiBzdHJva2U9ImdyYXkiLz48cGF0aCBkPSJNMjEsMCBMMjEsMTgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iZ3JheSIvPjwvbWFya2VyPjwvZGVmcz48ZGVmcz48bWFya2VyIG9yaWVudD0iYXV0byIgbWFya2VySGVpZ2h0PSIzNiIgbWFya2VyV2lkdGg9IjQ1IiByZWZZPSIxOCIgcmVmWD0iMTgiIGlkPSJPTkVfT1JfTU9SRV9TVEFSVCI+PHBhdGggZD0iTTAsMTggUSAxOCwwIDM2LDE4IFEgMTgsMzYgMCwxOCBNNDIsOSBMNDIsMjciIGZpbGw9Im5vbmUiIHN0cm9rZT0iZ3JheSIvPjwvbWFya2VyPjwvZGVmcz48ZGVmcz48bWFya2VyIG9yaWVudD0iYXV0byIgbWFya2VySGVpZ2h0PSIzNiIgbWFya2VyV2lkdGg9IjQ1IiByZWZZPSIxOCIgcmVmWD0iMjciIGlkPSJPTkVfT1JfTU9SRV9FTkQiPjxwYXRoIGQ9Ik0zLDkgTDMsMjcgTTksMTggUTI3LDAgNDUsMTggUTI3LDM2IDksMTgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iZ3JheSIvPjwvbWFya2VyPjwvZGVmcz48ZGVmcz48bWFya2VyIG9yaWVudD0iYXV0byIgbWFya2VySGVpZ2h0PSIzNiIgbWFya2VyV2lkdGg9IjU3IiByZWZZPSIxOCIgcmVmWD0iMTgiIGlkPSJaRVJPX09SX01PUkVfU1RBUlQiPjxjaXJjbGUgcj0iNiIgY3k9IjE4IiBjeD0iNDgiIGZpbGw9IndoaXRlIiBzdHJva2U9ImdyYXkiLz48cGF0aCBkPSJNMCwxOCBRMTgsMCAzNiwxOCBRMTgsMzYgMCwxOCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSJncmF5Ii8+PC9tYXJrZXI+PC9kZWZzPjxkZWZzPjxtYXJrZXIgb3JpZW50PSJhdXRvIiBtYXJrZXJIZWlnaHQ9IjM2IiBtYXJrZXJXaWR0aD0iNTciIHJlZlk9IjE4IiByZWZYPSIzOSIgaWQ9IlpFUk9fT1JfTU9SRV9FTkQiPjxjaXJjbGUgcj0iNiIgY3k9IjE4IiBjeD0iOSIgZmlsbD0id2hpdGUiIHN0cm9rZT0iZ3JheSIvPjxwYXRoIGQ9Ik0yMSwxOCBRMzksMCA1NywxOCBRMzksMzYgMjEsMTgiIGZpbGw9Im5vbmUiIHN0cm9rZT0iZ3JheSIvPjwvbWFya2VyPjwvZGVmcz48cGF0aCBzdHlsZT0ic3Ryb2tlOiBncmF5OyBmaWxsOiBub25lOyIgbWFya2VyLXN0YXJ0PSJ1cmwoI09OTFlfT05FX1NUQVJUKSIgbWFya2VyLWVuZD0idXJsKCNaRVJPX09SX01PUkVfRU5EKSIgZD0iTTEwMy43MDksMTQ5TDEwMy43MDksMTYwLjgzM0MxMDMuNzA5LDE3Mi42NjcsMTAzLjcwOSwxOTYuMzMzLDExNC40NSwyMTYuNUMxMjUuMTkxLDIzNi42NjcsMTQ2LjY3MiwyNTMuMzMzLDE1Ny40MTMsMjYxLjY2N0wxNjguMTU0LDI3MCIgY2xhc3M9ImVyIHJlbGF0aW9uc2hpcExpbmUiLz48cGF0aCBzdHlsZT0ic3Ryb2tlOiBncmF5OyBmaWxsOiBub25lOyIgbWFya2VyLXN0YXJ0PSJ1cmwoI09OTFlfT05FX1NUQVJUKSIgbWFya2VyLWVuZD0idXJsKCNaRVJPX09SX01PUkVfRU5EKSIgZD0iTTM3MS44MDEsMTcwTDM3MS44MDEsMTc4LjMzM0MzNzEuODAxLDE4Ni42NjcsMzcxLjgwMSwyMDMuMzMzLDM2MS4wNiwyMjBDMzUwLjMxOSwyMzYuNjY3LDMyOC44MzcsMjUzLjMzMywzMTguMDk2LDI2MS42NjdMMzA3LjM1NiwyNzAiIGNsYXNzPSJlciByZWxhdGlvbnNoaXBMaW5lIi8+PHBhdGggc3R5bGU9InN0cm9rZTogZ3JheTsgZmlsbDogbm9uZTsiIG1hcmtlci1zdGFydD0idXJsKCNPTkxZX09ORV9TVEFSVCkiIG1hcmtlci1lbmQ9InVybCgjWkVST19PUl9NT1JFX0VORCkiIGQ9Ik02MjkuMTM2LDE1OS41TDYyOS4xMzYsMTY5LjU4M0M2MjkuMTM2LDE3OS42NjcsNjI5LjEzNiwxOTkuODMzLDYzOC45OTIsMjE4LjI1QzY0OC44NDcsMjM2LjY2Nyw2NjguNTU5LDI1My4zMzMsNjc4LjQxNCwyNjEuNjY3TDY4OC4yNywyNzAiIGNsYXNzPSJlciByZWxhdGlvbnNoaXBMaW5lIi8+PHBhdGggc3R5bGU9InN0cm9rZTogZ3JheTsgZmlsbDogbm9uZTsiIG1hcmtlci1zdGFydD0idXJsKCNPTkxZX09ORV9TVEFSVCkiIG1hcmtlci1lbmQ9InVybCgjWkVST19PUl9NT1JFX0VORCkiIGQ9Ik04NzUuMTM1LDE3MEw4NzUuMTM1LDE3OC4zMzNDODc1LjEzNSwxODYuNjY3LDg3NS4xMzUsMjAzLjMzMyw4NjUuMjc5LDIyMEM4NTUuNDIzLDIzNi42NjcsODM1LjcxMiwyNTMuMzMzLDgyNS44NTYsMjYxLjY2N0w4MTYsMjcwIiBjbGFzcz0iZXIgcmVsYXRpb25zaGlwTGluZSIvPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDIwLDQxICkiIGlkPSJlbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50LThkYWFkMTFmLTBmYTUtNThiZi1iZWE4LWJiNjg3ZmViNTA4YSI+PHJlY3QgaGVpZ2h0PSIxMDgiIHdpZHRoPSIxNjcuNDE3OTY4NzUiIHk9IjAiIHg9IjAiIGNsYXNzPSJlciBlbnRpdHlCb3giLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgZm9udC1zaXplOiAxMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoODMuNzA4OTg0Mzc1LDEyKSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudC04ZGFhZDExZi0wZmE1LTU4YmYtYmVhOC1iYjY4N2ZlYjUwOGEiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+YW5vbnltaXphdGlvbl9kb2N1bWVudDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguMTIzNzU4OTUxODIyOTIiIHk9IjI0IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSwzNC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudC04ZGFhZDExZi0wZmE1LTU4YmYtYmVhOC1iYjY4N2ZlYjUwOGEtYXR0ci0xLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VVVJRDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguMzI4MDI4MzYxMDAyNjEiIHk9IjI0IiB4PSI2OC4xMjM3NTg5NTE4MjI5MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDczLjEyMzc1ODk1MTgyMjkyLDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50LThkYWFkMTFmLTBmYTUtNThiZi1iZWE4LWJiNjg3ZmViNTA4YS1hdHRyLTEtbmFtZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5pZDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMzAuOTY2MTgxNDM3MTc0NDgiIHk9IjI0IiB4PSIxMzYuNDUxNzg3MzEyODI1NTMiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDEuNDUxNzg3MzEyODI1NTMsMzQuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9uZG9jdW1lbnQtOGRhYWQxMWYtMGZhNS01OGJmLWJlYTgtYmI2ODdmZWI1MDhhLWF0dHItMS1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+UEs8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjY4LjEyMzc1ODk1MTgyMjkyIiB5PSI0NSIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1LDU1LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50LThkYWFkMTFmLTBmYTUtNThiZi1iZWE4LWJiNjg3ZmViNTA4YS1hdHRyLTItdHlwZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5EQVRFVElNRTwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguMzI4MDI4MzYxMDAyNjEiIHk9IjQ1IiB4PSI2OC4xMjM3NTg5NTE4MjI5MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3My4xMjM3NTg5NTE4MjI5Miw1NS41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudC04ZGFhZDExZi0wZmE1LTU4YmYtYmVhOC1iYjY4N2ZlYjUwOGEtYXR0ci0yLW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+Y3JlYXRlZF9hdDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMzAuOTY2MTgxNDM3MTc0NDgiIHk9IjQ1IiB4PSIxMzYuNDUxNzg3MzEyODI1NTMiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTQxLjQ1MTc4NzMxMjgyNTUzLDU1LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50LThkYWFkMTFmLTBmYTUtNThiZi1iZWE4LWJiNjg3ZmViNTA4YS1hdHRyLTIta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguMTIzNzU4OTUxODIyOTIiIHk9IjY2IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudC04ZGFhZDExZi0wZmE1LTU4YmYtYmVhOC1iYjY4N2ZlYjUwOGEtYXR0ci0zLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+REFURVRJTUU8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjY4LjMyODAyODM2MTAwMjYxIiB5PSI2NiIgeD0iNjguMTIzNzU4OTUxODIyOTIiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3My4xMjM3NTg5NTE4MjI5Miw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudC04ZGFhZDExZi0wZmE1LTU4YmYtYmVhOC1iYjY4N2ZlYjUwOGEtYXR0ci0zLW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+dXBkYXRlZF9hdDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMzAuOTY2MTgxNDM3MTc0NDgiIHk9IjY2IiB4PSIxMzYuNDUxNzg3MzEyODI1NTMiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDEuNDUxNzg3MzEyODI1NTMsNzYuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9uZG9jdW1lbnQtOGRhYWQxMWYtMGZhNS01OGJmLWJlYTgtYmI2ODdmZWI1MDhhLWF0dHItMy1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCIvPjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2OC4xMjM3NTg5NTE4MjI5MiIgeT0iODciIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw5Ny41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudC04ZGFhZDExZi0wZmE1LTU4YmYtYmVhOC1iYjY4N2ZlYjUwOGEtYXR0ci00LXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VEVYVDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguMzI4MDI4MzYxMDAyNjEiIHk9Ijg3IiB4PSI2OC4xMjM3NTg5NTE4MjI5MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg3My4xMjM3NTg5NTE4MjI5Miw5Ny41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudC04ZGFhZDExZi0wZmE1LTU4YmYtYmVhOC1iYjY4N2ZlYjUwOGEtYXR0ci00LW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+bmFtZTwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMzAuOTY2MTgxNDM3MTc0NDgiIHk9Ijg3IiB4PSIxMzYuNDUxNzg3MzEyODI1NTMiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTQxLjQ1MTc4NzMxMjgyNTUzLDk3LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50LThkYWFkMTFmLTBmYTUtNThiZi1iZWE4LWJiNjg3ZmViNTA4YS1hdHRyLTQta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48L2c+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjg3LjQxNzk2ODc1LDIwICkiIGlkPSJlbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMiPjxyZWN0IGhlaWdodD0iMTUwIiB3aWR0aD0iMTY4Ljc2NTYyNSIgeT0iMCIgeD0iMCIgY2xhc3M9ImVyIGVudGl0eUJveCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyB0ZXh0LWFuY2hvcjogbWlkZGxlOyBmb250LXNpemU6IDEycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg4NC4zODI4MTI1LDEyKSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25wYXJhZ3JhcGgtZjVjNjUzOTMtNTA2MC01NDMyLWIzNTctOGY5MzVhNThhMWUzIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmFub255bWl6YXRpb25fcGFyYWdyYXBoPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2OC41NzI5Nzc3MDE4MjI5MiIgeT0iMjQiIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1LDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci0xLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VVVJRDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguNzc3MjQ3MTExMDAyNjEiIHk9IjI0IiB4PSI2OC41NzI5Nzc3MDE4MjI5MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDczLjU3Mjk3NzcwMTgyMjkyLDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci0xLW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+aWQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjMxLjQxNTQwMDE4NzE3NDQ4IiB5PSIyNCIgeD0iMTM3LjM1MDIyNDgxMjgyNTUzIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTQyLjM1MDIyNDgxMjgyNTUzLDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci0xLWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5QSzwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguNTcyOTc3NzAxODIyOTIiIHk9IjQ1IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsNTUuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9ucGFyYWdyYXBoLWY1YzY1MzkzLTUwNjAtNTQzMi1iMzU3LThmOTM1YTU4YTFlMy1hdHRyLTItdHlwZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5URVhUPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2OC43NzcyNDcxMTEwMDI2MSIgeT0iNDUiIHg9IjY4LjU3Mjk3NzcwMTgyMjkyIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDczLjU3Mjk3NzcwMTgyMjkyLDU1LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci0yLW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+dGV4dDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMzEuNDE1NDAwMTg3MTc0NDgiIHk9IjQ1IiB4PSIxMzcuMzUwMjI0ODEyODI1NTMiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTQyLjM1MDIyNDgxMjgyNTUzLDU1LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci0yLWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIi8+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjY4LjU3Mjk3NzcwMTgyMjkyIiB5PSI2NiIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsNzYuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9ucGFyYWdyYXBoLWY1YzY1MzkzLTUwNjAtNTQzMi1iMzU3LThmOTM1YTU4YTFlMy1hdHRyLTMtdHlwZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5KU09OPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2OC43NzcyNDcxMTEwMDI2MSIgeT0iNjYiIHg9IjY4LjU3Mjk3NzcwMTgyMjkyIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuNTcyOTc3NzAxODIyOTIsNzYuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9ucGFyYWdyYXBoLWY1YzY1MzkzLTUwNjAtNTQzMi1iMzU3LThmOTM1YTU4YTFlMy1hdHRyLTMtbmFtZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5wcmVkaWN0aW9uPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSIzMS40MTU0MDAxODcxNzQ0OCIgeT0iNjYiIHg9IjEzNy4zNTAyMjQ4MTI4MjU1MyIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE0Mi4zNTAyMjQ4MTI4MjU1Myw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25wYXJhZ3JhcGgtZjVjNjUzOTMtNTA2MC01NDMyLWIzNTctOGY5MzVhNThhMWUzLWF0dHItMy1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCIvPjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2OC41NzI5Nzc3MDE4MjI5MiIgeT0iODciIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw5Ny41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25wYXJhZ3JhcGgtZjVjNjUzOTMtNTA2MC01NDMyLWIzNTctOGY5MzVhNThhMWUzLWF0dHItNC10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPkpTT048L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjY4Ljc3NzI0NzExMTAwMjYxIiB5PSI4NyIgeD0iNjguNTcyOTc3NzAxODIyOTIiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuNTcyOTc3NzAxODIyOTIsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9ucGFyYWdyYXBoLWY1YzY1MzkzLTUwNjAtNTQzMi1iMzU3LThmOTM1YTU4YTFlMy1hdHRyLTQtbmFtZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj52YWxpZGF0aW9uPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSIzMS40MTU0MDAxODcxNzQ0OCIgeT0iODciIHg9IjEzNy4zNTAyMjQ4MTI4MjU1MyIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDIuMzUwMjI0ODEyODI1NTMsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9ucGFyYWdyYXBoLWY1YzY1MzkzLTUwNjAtNTQzMi1iMzU3LThmOTM1YTU4YTFlMy1hdHRyLTQta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguNTcyOTc3NzAxODIyOTIiIHk9IjEwOCIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsMTE4LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci01LXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+REFURVRJTUU8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjY4Ljc3NzI0NzExMTAwMjYxIiB5PSIxMDgiIHg9IjY4LjU3Mjk3NzcwMTgyMjkyIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuNTcyOTc3NzAxODIyOTIsMTE4LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci01LW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+Y3JlYXRlZF9hdDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMzEuNDE1NDAwMTg3MTc0NDgiIHk9IjEwOCIgeD0iMTM3LjM1MDIyNDgxMjgyNTUzIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTQyLjM1MDIyNDgxMjgyNTUzLDExOC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25wYXJhZ3JhcGgtZjVjNjUzOTMtNTA2MC01NDMyLWIzNTctOGY5MzVhNThhMWUzLWF0dHItNS1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCIvPjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2OC41NzI5Nzc3MDE4MjI5MiIgeT0iMTI5IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsMTM5LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci02LXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+REFURVRJTUU8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjY4Ljc3NzI0NzExMTAwMjYxIiB5PSIxMjkiIHg9IjY4LjU3Mjk3NzcwMTgyMjkyIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDczLjU3Mjk3NzcwMTgyMjkyLDEzOS41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25wYXJhZ3JhcGgtZjVjNjUzOTMtNTA2MC01NDMyLWIzNTctOGY5MzVhNThhMWUzLWF0dHItNi1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPnVwZGF0ZWRfYXQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjMxLjQxNTQwMDE4NzE3NDQ4IiB5PSIxMjkiIHg9IjEzNy4zNTAyMjQ4MTI4MjU1MyIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNDIuMzUwMjI0ODEyODI1NTMsMTM5LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbnBhcmFncmFwaC1mNWM2NTM5My01MDYwLTU0MzItYjM1Ny04ZjkzNWE1OGExZTMtYXR0ci02LWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIi8+PC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyMy42ODQ1NzAzMTI1LDI3MCApIiBpZD0iZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudHBhcmFncmFwaC05MGMwMzBmMC1mNzYzLTU3NWUtOGU3Ni0yNmU1M2Y4YjRmYzkiPjxyZWN0IGhlaWdodD0iMTA4IiB3aWR0aD0iMjI4LjE0MDYyNSIgeT0iMCIgeD0iMCIgY2xhc3M9ImVyIGVudGl0eUJveCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyB0ZXh0LWFuY2hvcjogbWlkZGxlOyBmb250LXNpemU6IDEycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMTQuMDcwMzEyNSwxMikiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9uZG9jdW1lbnRwYXJhZ3JhcGgtOTBjMDMwZjAtZjc2My01NzVlLThlNzYtMjZlNTNmOGI0ZmM5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmFub255bWl6YXRpb25fZG9jdW1lbnRfcGFyYWdyYXBoPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI3Ni4yMzg3NTkzNTg3MjM5NSIgeT0iMjQiIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1LDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50cGFyYWdyYXBoLTkwYzAzMGYwLWY3NjMtNTc1ZS04ZTc2LTI2ZTUzZjhiNGZjOS1hdHRyLTEtdHlwZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5VVUlEPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI5MS4zMTY2NzA3MzU2NzcwOCIgeT0iMjQiIHg9Ijc2LjIzODc1OTM1ODcyMzk1IiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoODEuMjM4NzU5MzU4NzIzOTUsMzQuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9uZG9jdW1lbnRwYXJhZ3JhcGgtOTBjMDMwZjAtZjc2My01NzVlLThlNzYtMjZlNTNmOGI0ZmM5LWF0dHItMS1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmlkPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2MC41ODUxOTQ5MDU1OTg5NTQiIHk9IjI0IiB4PSIxNjcuNTU1NDMwMDk0NDAxMDMiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNzIuNTU1NDMwMDk0NDAxMDMsMzQuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9uZG9jdW1lbnRwYXJhZ3JhcGgtOTBjMDMwZjAtZjc2My01NzVlLThlNzYtMjZlNTNmOGI0ZmM5LWF0dHItMS1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+UEs8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9Ijc2LjIzODc1OTM1ODcyMzk1IiB5PSI0NSIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1LDU1LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50cGFyYWdyYXBoLTkwYzAzMGYwLWY3NjMtNTc1ZS04ZTc2LTI2ZTUzZjhiNGZjOS1hdHRyLTItdHlwZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5VVUlEPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI5MS4zMTY2NzA3MzU2NzcwOCIgeT0iNDUiIHg9Ijc2LjIzODc1OTM1ODcyMzk1IiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDgxLjIzODc1OTM1ODcyMzk1LDU1LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50cGFyYWdyYXBoLTkwYzAzMGYwLWY3NjMtNTc1ZS04ZTc2LTI2ZTUzZjhiNGZjOS1hdHRyLTItbmFtZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5kb2N1bWVudF9pZDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjAuNTg1MTk0OTA1NTk4OTU0IiB5PSI0NSIgeD0iMTY3LjU1NTQzMDA5NDQwMTAzIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE3Mi41NTU0MzAwOTQ0MDEwMyw1NS41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudHBhcmFncmFwaC05MGMwMzBmMC1mNzYzLTU3NWUtOGU3Ni0yNmU1M2Y4YjRmYzktYXR0ci0yLWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5QSyxGSzwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNzYuMjM4NzU5MzU4NzIzOTUiIHk9IjY2IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudHBhcmFncmFwaC05MGMwMzBmMC1mNzYzLTU3NWUtOGU3Ni0yNmU1M2Y4YjRmYzktYXR0ci0zLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VVVJRDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iOTEuMzE2NjcwNzM1Njc3MDgiIHk9IjY2IiB4PSI3Ni4yMzg3NTkzNTg3MjM5NSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDgxLjIzODc1OTM1ODcyMzk1LDc2LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50cGFyYWdyYXBoLTkwYzAzMGYwLWY3NjMtNTc1ZS04ZTc2LTI2ZTUzZjhiNGZjOS1hdHRyLTMtbmFtZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5wYXJhZ3JhcGhfaWQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYwLjU4NTE5NDkwNTU5ODk1NCIgeT0iNjYiIHg9IjE2Ny41NTU0MzAwOTQ0MDEwMyIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE3Mi41NTU0MzAwOTQ0MDEwMyw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWFub255bWl6YXRpb25kb2N1bWVudHBhcmFncmFwaC05MGMwMzBmMC1mNzYzLTU3NWUtOGU3Ni0yNmU1M2Y4YjRmYzktYXR0ci0zLWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5QSyxGSzwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNzYuMjM4NzU5MzU4NzIzOTUiIHk9Ijg3IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9uZG9jdW1lbnRwYXJhZ3JhcGgtOTBjMDMwZjAtZjc2My01NzVlLThlNzYtMjZlNTNmOGI0ZmM5LWF0dHItNC10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPklOVEVHRVI8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjkxLjMxNjY3MDczNTY3NzA4IiB5PSI4NyIgeD0iNzYuMjM4NzU5MzU4NzIzOTUiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoODEuMjM4NzU5MzU4NzIzOTUsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1hbm9ueW1pemF0aW9uZG9jdW1lbnRwYXJhZ3JhcGgtOTBjMDMwZjAtZjc2My01NzVlLThlNzYtMjZlNTNmOGI0ZmM5LWF0dHItNC1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPm9yZGVyPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2MC41ODUxOTQ5MDU1OTg5NTQiIHk9Ijg3IiB4PSIxNjcuNTU1NDMwMDk0NDAxMDMiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTcyLjU1NTQzMDA5NDQwMTAzLDk3LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktYW5vbnltaXphdGlvbmRvY3VtZW50cGFyYWdyYXBoLTkwYzAzMGYwLWY3NjMtNTc1ZS04ZTc2LTI2ZTUzZjhiNGZjOS1hdHRyLTQta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48L2c+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNTU2LjE4MzU5Mzc1LDMwLjUgKSIgaWQ9ImVudGl0eS1kYXRhcHVibGljZG9jdW1lbnQtYTBiZTViOTQtOTNkNi01MTZiLTg1YWEtNTliNmM2ZTRjODY1Ij48cmVjdCBoZWlnaHQ9IjEyOSIgd2lkdGg9IjE0NS45MDQzNzMxNjg5NDUzIiB5PSIwIiB4PSIwIiBjbGFzcz0iZXIgZW50aXR5Qm94Ii8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IHRleHQtYW5jaG9yOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDcyLjk1MjE4NjU4NDQ3MjY2LDEyKSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudC1hMGJlNWI5NC05M2Q2LTUxNmItODVhYS01OWI2YzZlNGM4NjUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+ZGF0YXB1YmxpY19kb2N1bWVudDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjAuOTUyNTYwNDI0ODA0NjkiIHk9IjI0IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSwzNC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudC1hMGJlNWI5NC05M2Q2LTUxNmItODVhYS01OWI2YzZlNGM4NjUtYXR0ci0xLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VVVJRDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjEuMTU2ODI5ODMzOTg0Mzc1IiB5PSIyNCIgeD0iNjAuOTUyNTYwNDI0ODA0NjkiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg2NS45NTI1NjA0MjQ4MDQ2OSwzNC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudC1hMGJlNWI5NC05M2Q2LTUxNmItODVhYS01OWI2YzZlNGM4NjUtYXR0ci0xLW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+aWQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjIzLjc5NDk4MjkxMDE1NjI1IiB5PSIyNCIgeD0iMTIyLjEwOTM5MDI1ODc4OTA2IiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI3LjEwOTM5MDI1ODc4OTA2LDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY2RvY3VtZW50LWEwYmU1Yjk0LTkzZDYtNTE2Yi04NWFhLTU5YjZjNmU0Yzg2NS1hdHRyLTEta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPlBLPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2MC45NTI1NjA0MjQ4MDQ2OSIgeT0iNDUiIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1NS41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudC1hMGJlNWI5NC05M2Q2LTUxNmItODVhYS01OWI2YzZlNGM4NjUtYXR0ci0yLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+SlNPTjwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjEuMTU2ODI5ODMzOTg0Mzc1IiB5PSI0NSIgeD0iNjAuOTUyNTYwNDI0ODA0NjkiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNjUuOTUyNTYwNDI0ODA0NjksNTUuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnQtYTBiZTViOTQtOTNkNi01MTZiLTg1YWEtNTliNmM2ZTRjODY1LWF0dHItMi1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPnByZWRpY3Rpb248L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjIzLjc5NDk4MjkxMDE1NjI1IiB5PSI0NSIgeD0iMTIyLjEwOTM5MDI1ODc4OTA2IiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyNy4xMDkzOTAyNTg3ODkwNiw1NS41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudC1hMGJlNWI5NC05M2Q2LTUxNmItODVhYS01OWI2YzZlNGM4NjUtYXR0ci0yLWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIi8+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYwLjk1MjU2MDQyNDgwNDY5IiB5PSI2NiIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsNzYuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnQtYTBiZTViOTQtOTNkNi01MTZiLTg1YWEtNTliNmM2ZTRjODY1LWF0dHItMy10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPkpTT048L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYxLjE1NjgyOTgzMzk4NDM3NSIgeT0iNjYiIHg9IjYwLjk1MjU2MDQyNDgwNDY5IiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNjUuOTUyNTYwNDI0ODA0NjksNzYuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnQtYTBiZTViOTQtOTNkNi01MTZiLTg1YWEtNTliNmM2ZTRjODY1LWF0dHItMy1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPnZhbGlkYXRpb248L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjIzLjc5NDk4MjkxMDE1NjI1IiB5PSI2NiIgeD0iMTIyLjEwOTM5MDI1ODc4OTA2IiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI3LjEwOTM5MDI1ODc4OTA2LDc2LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY2RvY3VtZW50LWEwYmU1Yjk0LTkzZDYtNTE2Yi04NWFhLTU5YjZjNmU0Yzg2NS1hdHRyLTMta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjAuOTUyNTYwNDI0ODA0NjkiIHk9Ijg3IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnQtYTBiZTViOTQtOTNkNi01MTZiLTg1YWEtNTliNmM2ZTRjODY1LWF0dHItNC10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPkRBVEVUSU1FPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2MS4xNTY4Mjk4MzM5ODQzNzUiIHk9Ijg3IiB4PSI2MC45NTI1NjA0MjQ4MDQ2OSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg2NS45NTI1NjA0MjQ4MDQ2OSw5Ny41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudC1hMGJlNWI5NC05M2Q2LTUxNmItODVhYS01OWI2YzZlNGM4NjUtYXR0ci00LW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+Y3JlYXRlZF9hdDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMjMuNzk0OTgyOTEwMTU2MjUiIHk9Ijg3IiB4PSIxMjIuMTA5MzkwMjU4Nzg5MDYiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI3LjEwOTM5MDI1ODc4OTA2LDk3LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY2RvY3VtZW50LWEwYmU1Yjk0LTkzZDYtNTE2Yi04NWFhLTU5YjZjNmU0Yzg2NS1hdHRyLTQta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjAuOTUyNTYwNDI0ODA0NjkiIHk9IjEwOCIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsMTE4LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY2RvY3VtZW50LWEwYmU1Yjk0LTkzZDYtNTE2Yi04NWFhLTU5YjZjNmU0Yzg2NS1hdHRyLTUtdHlwZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5EQVRFVElNRTwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjEuMTU2ODI5ODMzOTg0Mzc1IiB5PSIxMDgiIHg9IjYwLjk1MjU2MDQyNDgwNDY5IiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNjUuOTUyNTYwNDI0ODA0NjksMTE4LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY2RvY3VtZW50LWEwYmU1Yjk0LTkzZDYtNTE2Yi04NWFhLTU5YjZjNmU0Yzg2NS1hdHRyLTUtbmFtZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj51cGRhdGVkX2F0PC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSIyMy43OTQ5ODI5MTAxNTYyNSIgeT0iMTA4IiB4PSIxMjIuMTA5MzkwMjU4Nzg5MDYiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMjcuMTA5MzkwMjU4Nzg5MDYsMTE4LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY2RvY3VtZW50LWEwYmU1Yjk0LTkzZDYtNTE2Yi04NWFhLTU5YjZjNmU0Yzg2NS1hdHRyLTUta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48L2c+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoODAyLjA4Nzk2NjkxODk0NTMsMjAgKSIgaWQ9ImVudGl0eS1kYXRhcHVibGljcGFyYWdyYXBoLWE3YTE2NDVlLWEzZTctNTIzNy04M2NlLTMxYTVkNzUwNjg4YiI+PHJlY3QgaGVpZ2h0PSIxNTAiIHdpZHRoPSIxNDYuMDkzNzUiIHk9IjAiIHg9IjAiIGNsYXNzPSJlciBlbnRpdHlCb3giLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgZm9udC1zaXplOiAxMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuMDQ2ODc1LDEyKSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmRhdGFwdWJsaWNfcGFyYWdyYXBoPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2MS4wMTU2ODYwMzUxNTYyNSIgeT0iMjQiIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1LDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY3BhcmFncmFwaC1hN2ExNjQ1ZS1hM2U3LTUyMzctODNjZS0zMWE1ZDc1MDY4OGItYXR0ci0xLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VVVJRDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjEuMjE5OTU1NDQ0MzM1OTQiIHk9IjI0IiB4PSI2MS4wMTU2ODYwMzUxNTYyNSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDY2LjAxNTY4NjAzNTE1NjI1LDM0LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY3BhcmFncmFwaC1hN2ExNjQ1ZS1hM2U3LTUyMzctODNjZS0zMWE1ZDc1MDY4OGItYXR0ci0xLW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+aWQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjIzLjg1ODEwODUyMDUwNzgxMiIgeT0iMjQiIHg9IjEyMi4yMzU2NDE0Nzk0OTIxOSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyNy4yMzU2NDE0Nzk0OTIxOSwzNC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItMS1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+UEs8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYxLjAxNTY4NjAzNTE1NjI1IiB5PSI0NSIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1LDU1LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY3BhcmFncmFwaC1hN2ExNjQ1ZS1hM2U3LTUyMzctODNjZS0zMWE1ZDc1MDY4OGItYXR0ci0yLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VEVYVDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjEuMjE5OTU1NDQ0MzM1OTQiIHk9IjQ1IiB4PSI2MS4wMTU2ODYwMzUxNTYyNSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg2Ni4wMTU2ODYwMzUxNTYyNSw1NS41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItMi1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPnRleHQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjIzLjg1ODEwODUyMDUwNzgxMiIgeT0iNDUiIHg9IjEyMi4yMzU2NDE0Nzk0OTIxOSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMjcuMjM1NjQxNDc5NDkyMTksNTUuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljcGFyYWdyYXBoLWE3YTE2NDVlLWEzZTctNTIzNy04M2NlLTMxYTVkNzUwNjg4Yi1hdHRyLTIta2V5IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiLz48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjEuMDE1Njg2MDM1MTU2MjUiIHk9IjY2IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItMy10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPkpTT048L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYxLjIxOTk1NTQ0NDMzNTk0IiB5PSI2NiIgeD0iNjEuMDE1Njg2MDM1MTU2MjUiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg2Ni4wMTU2ODYwMzUxNTYyNSw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItMy1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPnByZWRpY3Rpb248L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjIzLjg1ODEwODUyMDUwNzgxMiIgeT0iNjYiIHg9IjEyMi4yMzU2NDE0Nzk0OTIxOSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEyNy4yMzU2NDE0Nzk0OTIxOSw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItMy1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCIvPjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2MS4wMTU2ODYwMzUxNTYyNSIgeT0iODciIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw5Ny41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItNC10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPkpTT048L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYxLjIxOTk1NTQ0NDMzNTk0IiB5PSI4NyIgeD0iNjEuMDE1Njg2MDM1MTU2MjUiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNjYuMDE1Njg2MDM1MTU2MjUsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljcGFyYWdyYXBoLWE3YTE2NDVlLWEzZTctNTIzNy04M2NlLTMxYTVkNzUwNjg4Yi1hdHRyLTQtbmFtZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj52YWxpZGF0aW9uPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSIyMy44NTgxMDg1MjA1MDc4MTIiIHk9Ijg3IiB4PSIxMjIuMjM1NjQxNDc5NDkyMTkiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTI3LjIzNTY0MTQ3OTQ5MjE5LDk3LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY3BhcmFncmFwaC1hN2ExNjQ1ZS1hM2U3LTUyMzctODNjZS0zMWE1ZDc1MDY4OGItYXR0ci00LWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIi8+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYxLjAxNTY4NjAzNTE1NjI1IiB5PSIxMDgiIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1LDExOC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItNS10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPkRBVEVUSU1FPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2MS4yMTk5NTU0NDQzMzU5NCIgeT0iMTA4IiB4PSI2MS4wMTU2ODYwMzUxNTYyNSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDY2LjAxNTY4NjAzNTE1NjI1LDExOC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNwYXJhZ3JhcGgtYTdhMTY0NWUtYTNlNy01MjM3LTgzY2UtMzFhNWQ3NTA2ODhiLWF0dHItNS1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmNyZWF0ZWRfYXQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjIzLjg1ODEwODUyMDUwNzgxMiIgeT0iMTA4IiB4PSIxMjIuMjM1NjQxNDc5NDkyMTkiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hPZGQiLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMjcuMjM1NjQxNDc5NDkyMTksMTE4LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY3BhcmFncmFwaC1hN2ExNjQ1ZS1hM2U3LTUyMzctODNjZS0zMWE1ZDc1MDY4OGItYXR0ci01LWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIi8+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjYxLjAxNTY4NjAzNTE1NjI1IiB5PSIxMjkiIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSwxMzkuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljcGFyYWdyYXBoLWE3YTE2NDVlLWEzZTctNTIzNy04M2NlLTMxYTVkNzUwNjg4Yi1hdHRyLTYtdHlwZSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5EQVRFVElNRTwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjEuMjE5OTU1NDQ0MzM1OTQiIHk9IjEyOSIgeD0iNjEuMDE1Njg2MDM1MTU2MjUiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNjYuMDE1Njg2MDM1MTU2MjUsMTM5LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY3BhcmFncmFwaC1hN2ExNjQ1ZS1hM2U3LTUyMzctODNjZS0zMWE1ZDc1MDY4OGItYXR0ci02LW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+dXBkYXRlZF9hdDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iMjMuODU4MTA4NTIwNTA3ODEyIiB5PSIxMjkiIHg9IjEyMi4yMzU2NDE0Nzk0OTIxOSIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMjcuMjM1NjQxNDc5NDkyMTksMTM5LjUpIiB5PSIwIiB4PSIwIiBpZD0idGV4dC1lbnRpdHktZGF0YXB1YmxpY3BhcmFncmFwaC1hN2ExNjQ1ZS1hM2U3LTUyMzctODNjZS0zMWE1ZDc1MDY4OGItYXR0ci02LWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIi8+PC9nPjxnIHRyYW5zZm9ybT0idHJhbnNsYXRlKDY0OS40MDA5MzYxMjY3MDksMjcwICkiIGlkPSJlbnRpdHktZGF0YXB1YmxpY2RvY3VtZW50cGFyYWdyYXBoLWVmMGYzODg3LTJkYmEtNTc2ZS04NjM0LTg1NjI3OGI2OGI0NiI+PHJlY3QgaGVpZ2h0PSIxMDgiIHdpZHRoPSIyMDUuNDY4NzUiIHk9IjAiIHg9IjAiIGNsYXNzPSJlciBlbnRpdHlCb3giLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgdGV4dC1hbmNob3I6IG1pZGRsZTsgZm9udC1zaXplOiAxMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAyLjczNDM3NSwxMikiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnRwYXJhZ3JhcGgtZWYwZjM4ODctMmRiYS01NzZlLTg2MzQtODU2Mjc4YjY4YjQ2IiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmRhdGFwdWJsaWNfZG9jdW1lbnRfcGFyYWdyYXBoPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI2OC42ODE0Njc2OTIwNTczIiB5PSIyNCIgeD0iMCIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDUsMzQuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnRwYXJhZ3JhcGgtZWYwZjM4ODctMmRiYS01NzZlLTg2MzQtODU2Mjc4YjY4YjQ2LWF0dHItMS10eXBlIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPlVVSUQ8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjgzLjc1OTM3OTA2OTAxMDQyIiB5PSIyNCIgeD0iNjguNjgxNDY3NjkyMDU3MyIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDczLjY4MTQ2NzY5MjA1NzMsMzQuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnRwYXJhZ3JhcGgtZWYwZjM4ODctMmRiYS01NzZlLTg2MzQtODU2Mjc4YjY4YjQ2LWF0dHItMS1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmlkPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI1My4wMjc5MDMyMzg5MzIyOSIgeT0iMjQiIHg9IjE1Mi40NDA4NDY3NjEwNjc3MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE1Ny40NDA4NDY3NjEwNjc3MiwzNC41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudHBhcmFncmFwaC1lZjBmMzg4Ny0yZGJhLTU3NmUtODYzNC04NTYyNzhiNjhiNDYtYXR0ci0xLWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5QSzwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguNjgxNDY3NjkyMDU3MyIgeT0iNDUiIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw1NS41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudHBhcmFncmFwaC1lZjBmMzg4Ny0yZGJhLTU3NmUtODYzNC04NTYyNzhiNjhiNDYtYXR0ci0yLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VVVJRDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iODMuNzU5Mzc5MDY5MDEwNDIiIHk9IjQ1IiB4PSI2OC42ODE0Njc2OTIwNTczIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDczLjY4MTQ2NzY5MjA1NzMsNTUuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnRwYXJhZ3JhcGgtZWYwZjM4ODctMmRiYS01NzZlLTg2MzQtODU2Mjc4YjY4YjQ2LWF0dHItMi1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPmRvY3VtZW50X2lkPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI1My4wMjc5MDMyMzg5MzIyOSIgeT0iNDUiIHg9IjE1Mi40NDA4NDY3NjEwNjc3MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNTcuNDQwODQ2NzYxMDY3NzIsNTUuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnRwYXJhZ3JhcGgtZWYwZjM4ODctMmRiYS01NzZlLTg2MzQtODU2Mjc4YjY4YjQ2LWF0dHItMi1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+UEssRks8L3RleHQ+PHJlY3QgaGVpZ2h0PSIyMSIgd2lkdGg9IjY4LjY4MTQ2NzY5MjA1NzMiIHk9IjY2IiB4PSIwIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudHBhcmFncmFwaC1lZjBmMzg4Ny0yZGJhLTU3NmUtODYzNC04NTYyNzhiNjhiNDYtYXR0ci0zLXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+VVVJRDwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iODMuNzU5Mzc5MDY5MDEwNDIiIHk9IjY2IiB4PSI2OC42ODE0Njc2OTIwNTczIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94T2RkIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuNjgxNDY3NjkyMDU3Myw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudHBhcmFncmFwaC1lZjBmMzg4Ny0yZGJhLTU3NmUtODYzNC04NTYyNzhiNjhiNDYtYXR0ci0zLW5hbWUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+cGFyYWdyYXBoX2lkPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI1My4wMjc5MDMyMzg5MzIyOSIgeT0iNjYiIHg9IjE1Mi40NDA4NDY3NjEwNjc3MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveE9kZCIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE1Ny40NDA4NDY3NjEwNjc3Miw3Ni41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudHBhcmFncmFwaC1lZjBmMzg4Ny0yZGJhLTU3NmUtODYzNC04NTYyNzhiNjhiNDYtYXR0ci0zLWtleSIgY2xhc3M9ImVyIGVudGl0eUxhYmVsIj5QSyxGSzwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iNjguNjgxNDY3NjkyMDU3MyIgeT0iODciIHg9IjAiIGNsYXNzPSJlciBhdHRyaWJ1dGVCb3hFdmVuIi8+PHRleHQgc3R5bGU9ImRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTAuMnB4OyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNSw5Ny41KSIgeT0iMCIgeD0iMCIgaWQ9InRleHQtZW50aXR5LWRhdGFwdWJsaWNkb2N1bWVudHBhcmFncmFwaC1lZjBmMzg4Ny0yZGJhLTU3NmUtODYzNC04NTYyNzhiNjhiNDYtYXR0ci00LXR5cGUiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCI+SU5URUdFUjwvdGV4dD48cmVjdCBoZWlnaHQ9IjIxIiB3aWR0aD0iODMuNzU5Mzc5MDY5MDEwNDIiIHk9Ijg3IiB4PSI2OC42ODE0Njc2OTIwNTczIiBjbGFzcz0iZXIgYXR0cmlidXRlQm94RXZlbiIvPjx0ZXh0IHN0eWxlPSJkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEwLjJweDsiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDczLjY4MTQ2NzY5MjA1NzMsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnRwYXJhZ3JhcGgtZWYwZjM4ODctMmRiYS01NzZlLTg2MzQtODU2Mjc4YjY4YjQ2LWF0dHItNC1uYW1lIiBjbGFzcz0iZXIgZW50aXR5TGFiZWwiPm9yZGVyPC90ZXh0PjxyZWN0IGhlaWdodD0iMjEiIHdpZHRoPSI1My4wMjc5MDMyMzg5MzIyOSIgeT0iODciIHg9IjE1Mi40NDA4NDY3NjEwNjc3MiIgY2xhc3M9ImVyIGF0dHJpYnV0ZUJveEV2ZW4iLz48dGV4dCBzdHlsZT0iZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMC4ycHg7IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxNTcuNDQwODQ2NzYxMDY3NzIsOTcuNSkiIHk9IjAiIHg9IjAiIGlkPSJ0ZXh0LWVudGl0eS1kYXRhcHVibGljZG9jdW1lbnRwYXJhZ3JhcGgtZWYwZjM4ODctMmRiYS01NzZlLTg2MzQtODU2Mjc4YjY4YjQ2LWF0dHItNC1rZXkiIGNsYXNzPSJlciBlbnRpdHlMYWJlbCIvPjwvZz48cmVjdCBoZWlnaHQ9IjE0IiB3aWR0aD0iMjQuMDE1NjI1IiB5PSIyMTIuNjYzMDQwMTYxMTMyOCIgeD0iMTA0LjIyOTUwNzQ0NjI4OTA2IiBjbGFzcz0iZXIgcmVsYXRpb25zaGlwTGFiZWxCb3giLz48dGV4dCBzdHlsZT0idGV4dC1hbmNob3I6IG1pZGRsZTsgZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMnB4OyIgeT0iMjE5LjY2MzA0MDE2MTEzMjgiIHg9IjExNi4yMzczMTk5NDYyODkwNiIgaWQ9InJlbDI1IiBjbGFzcz0iZXIgcmVsYXRpb25zaGlwTGFiZWwiPmxpbmtzPC90ZXh0PjxyZWN0IGhlaWdodD0iMTQiIHdpZHRoPSIyNC4wMTU2MjUiIHk9IjIyMS42NzgwNzAwNjgzNTkzOCIgeD0iMzQyLjU2NDE3ODQ2Njc5NjkiIGNsYXNzPSJlciByZWxhdGlvbnNoaXBMYWJlbEJveCIvPjx0ZXh0IHN0eWxlPSJ0ZXh0LWFuY2hvcjogbWlkZGxlOyBkb21pbmFudC1iYXNlbGluZTogbWlkZGxlOyBmb250LXNpemU6IDEycHg7IiB5PSIyMjguNjc4MDcwMDY4MzU5MzgiIHg9IjM1NC41NzE5OTA5NjY3OTY5IiBpZD0icmVsMjYiIGNsYXNzPSJlciByZWxhdGlvbnNoaXBMYWJlbCI+bGlua3M8L3RleHQ+PHJlY3QgaGVpZ2h0PSIxNCIgd2lkdGg9IjI0LjAxNTYyNSIgeT0iMjE2LjI1NzAxOTA0Mjk2ODc1IiB4PSI2MjkuOTIyNjA3NDIxODc1IiBjbGFzcz0iZXIgcmVsYXRpb25zaGlwTGFiZWxCb3giLz48dGV4dCBzdHlsZT0idGV4dC1hbmNob3I6IG1pZGRsZTsgZG9taW5hbnQtYmFzZWxpbmU6IG1pZGRsZTsgZm9udC1zaXplOiAxMnB4OyIgeT0iMjIzLjI1NzAxOTA0Mjk2ODc1IiB4PSI2NDEuOTMwNDE5OTIxODc1IiBpZD0icmVsMjciIGNsYXNzPSJlciByZWxhdGlvbnNoaXBMYWJlbCI+bGlua3M8L3RleHQ+PHJlY3QgaGVpZ2h0PSIxNCIgd2lkdGg9IjI0LjAxNTYyNSIgeT0iMjIwLjc4MTM1NjgxMTUyMzQ0IiB4PSI4NDguMDA0MDg5MzU1NDY4OCIgY2xhc3M9ImVyIHJlbGF0aW9uc2hpcExhYmVsQm94Ii8+PHRleHQgc3R5bGU9InRleHQtYW5jaG9yOiBtaWRkbGU7IGRvbWluYW50LWJhc2VsaW5lOiBtaWRkbGU7IGZvbnQtc2l6ZTogMTJweDsiIHk9IjIyNy43ODEzNTY4MTE1MjM0NCIgeD0iODYwLjAxMTkwMTg1NTQ2ODgiIGlkPSJyZWwyOCIgY2xhc3M9ImVyIHJlbGF0aW9uc2hpcExhYmVsIj5saW5rczwvdGV4dD48L3N2Zz4=", + "version": 2 + } + } +} \ No newline at end of file diff --git a/docs/database/schema.jpg b/docs/database/schema.jpg deleted file mode 100644 index 0c37c647e1a48146973499c9b044b51155c43b66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 142043 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%0A6m`Yu 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

m{af)fzwnaALZzhq`;?y5F;IEiq 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 M?la7^>hF>N0>^@i$N&HU diff --git a/docs/database/schema.mmd b/docs/database/schema.mmd new file mode 100644 index 00000000..c45aa17a --- /dev/null +++ b/docs/database/schema.mmd @@ -0,0 +1,53 @@ +erDiagram + anonymization_document { + UUID id PK + DATETIME created_at + DATETIME updated_at + TEXT name + } + + anonymization_paragraph { + UUID id PK + TEXT text + JSON prediction + JSON validation + DATETIME created_at + DATETIME updated_at + } + + anonymization_document_paragraph { + UUID id PK + UUID document_id PK, FK + UUID paragraph_id PK, FK + INTEGER order + } + + datapublic_document { + UUID id PK + JSON prediction + JSON validation + DATETIME created_at + DATETIME updated_at + } + + datapublic_paragraph { + UUID id PK + TEXT text + JSON prediction + JSON validation + DATETIME created_at + DATETIME updated_at + } + + datapublic_document_paragraph { + UUID id PK + UUID document_id PK, FK + UUID paragraph_id PK, FK + INTEGER order + } + + anonymization_document ||--o{ anonymization_document_paragraph : links + anonymization_paragraph ||--o{ anonymization_document_paragraph : links + + datapublic_document ||--o{ datapublic_document_paragraph : links + datapublic_paragraph ||--o{ datapublic_document_paragraph : links diff --git a/docs/database/schema.png b/docs/database/schema.png new file mode 100644 index 0000000000000000000000000000000000000000..522c5e5796995de65d8bef3e98500120b6d80162 GIT binary patch literal 67305 zcmZsDbzD?izqcSMA|)j$C@3Hy-6$oXgmi&A^6_;N3#Uf;NJbN0p!v@9Gf@RJzl zde$2^2ye(qJyY{Q+fKuNcbAvEbAFDdA@DT@+Qy?>C+w4TZ(1Qn!Wz3?N9IDy`yiSUG3&?YEJDb^^TaCISK9Qf63JKpy_d!f`P%X)3FkU zl*Iq}WVYdc)7C?&n*V>U(F@|dSm=j~ZKmRUc=x|QcVpgR?7n#)Ce5R-`hV_9?+CuB znCeYxFR1SKfA4&7pFTjCPCzK`1xBnU5h2=teLirY6IU;9`90$AdM>g0zb?M;1Q%5= zi3s1R(PuvW^xv(D6+^?F{XU?lc{f0fIrAXw-&ZB%2|qWd5m#vk-$f((@KVC!zgk5v zgz>;ZHZ=b=DQHW;5|J|7znT>A?Yg;d?Y`e)Kxd#wf2bt!_}>q{n*lmvsZ90dpRWWA zKg`Vk_@5_BJSPH=RjyJ&%>Cw%JtB>#gXIvf#qs9F*z;B*|yS^;m`ud;$`%^*UA^D#M zydb^qz*WWk)c;&$AdGx>@z*21%7AZ<4zd{k`}MyPD|=l3`vnvDYRraR9^3zX6?BK3 z#M|rlZFU21+Ms`WSNp$agM8RK2qQYfXG`!d%+oZge$xM*gY>jGj|jlsFo{1m>(et} z{;$#g;Evv%fz!qahIQXVGnV;Zt-2m3DW=T&uy>5~0W-#fQUBAafAz@&RKQv~mlPO#0uS{GW@TOEEs(cgSI5 zCDp@_%8bP|g>+Ruwr4LX64PR0#&Sg7e(7l<_qd6&_Rp&Mb|+xI(SW9E-oHYLINz7= ztfHOE(~;P4ArhBQUk%)V2PgJPhPhg~cFo)Pq_<9Q2;B!HDiJpQ$dNj(@B7c!?_GEH z=l2*aYKm27W#gStgyGJYHmihHjA7exC2NxdEV%`C<866Ga4%C_o7vAMPZ0Tbws-O$ zgT^3kkLKz^OzAwnGyQpwV*CL7q$x)PO0(`k$+TGomHOmb4a*Y(uxzA-_$G$b|7&#q zjMN(`FeSp9bJon%t^T|J!Hl4}o=h-<{BKzpE^Pn1r&Jz*W%J1)t{mrX@Vj6CUNT^W z9*~1U?Q#`Yzen`wF}gf67KWnev9fNxhe`=V#Q#zcxse0co7FU=u|u6hw@!}BcmurQ z4O1Nv-pRE3V;YdV>3qh&wA>+_XD(8z|?V4jwjEAE&u%isA}xEpX4Pmr0DHHUsn&EpX``eWcY^bd#+BMoNsZg zt{#VTM;1>QP#IUvO^+S(G+i8gu6LgIMa1bl_XUq<%aYfv#^>)0i2FOkc57fvR8LnZ z$zcaQ1Ett>+h*F@+I*JE{@$BEL-i>9#tU_=nbSQo3w0`ntNVL6nk@O}Jd*SsT0ZhQ zE+NNr1|noG<{G@U%-4jzCeFv8w#$5XCQT4i-DVaRb)4Uv+ey<3RCBVSkN76cO;eo0 zsSxoI_m1CVMmg9|7PruPZ_{eV=NE|$gxsMqs;LoVe{vvQ@388Q_UmHS6Lx&k%N;ej zQ)OtKVBi&!a00CyGI=>z<80x%THB&1T-d<8XJ}>Udn`D2vX+v)z26D1u!Hs^1Vnc) ze#Hfn_@jIh2iQANR3!cMl~<3}UD2hgL7D&kJ!=R&RW@O>R)@0!~xOiM$U!|bgB$Sdh!cTNr#^BH|xsi z<TlX{dBViBZeE0rrVI#CKsLAL9=BovVw@_83K>-|x%CEf*%evZQ|Cu zPla)a*(xNkyRE)b!1I8OPe~Hs7t7Lm_N)8g<=g=?` z9E{XGUw8v*XUam>8`(5-v|%{47)oay!{lozD3}sF#nG5(>8OsUA(bkI$ucR|V;@A-big5CBCwwdoeeY!s{;6D8pHuVhKwfN}B1+LRHHCbXm zndUBLH6Y4AZQgr2C5Ad;v>q{65?*-Mx_!DVJnae7-(+5{lnfEsX@6CglR>+vf909b z*%iZF?Yv?Qt+nleE6SW^1xT2zTp}|{(Qe92**Bp~GkgvL@bG6e3a34uUkPjtE^1K; z>~X;|;^Xb+eGY?}kLEXdJs?q9chCu_Ppfwtkp}6?S6?)LNJe}TBb=P&lvhwFTkT1h zW-anDC1p`_K|CEkZba@{7pX2h<4B9HY`s%q+x8*g0em+0F-d)h6h{%)aS3X_(|!(x zoIcxP-p4J_j*dGGR>lR}nSAVxv|a*npU{a7zrYDJ@!wYCvn{z>H8?aKN@8d4CMf-a zHI?dNo79?Vm*IJF~OCVl0wCIda&A4 zUytCL#ty`4u+oD=-3@W6#u2?7hS6JFJV;o^*?8^o?nxVoq+Y0(fS6wPx6Q4l%kvRM zfkmF8h^LcVIN}5NOrOQrwXaLk>?^@PbH<^A5+;mB+EOJQrZ2jf->;FKhD|d%7uVpn zQ>*dwH7WBT*VCCFuY|1!GqZ%4%e)dn^ZUqa zKR2DH_H*-C*KpS^mYMfT}EZPdRxn~_S#8BI*&g_oA_Rz4YYe`{0Ug_Q=6+k;=#U_PE z%ce_k3NL+FrZIFcUd0v{;t=SCdw~TOdbW5+{6ZjwcZ=Ywfb97b-Q6`;sc&^h32bK* ze@2xpxo!??PN*ln@lr{UYZ78%bd>GSe2JGuEP#Hv*5`VRnDeGvh>Q}yJ6&oq*Pr-_|=}YdT{_?#szPS$?2dcsg9rPpgdB;vyMSUvXonSl|?5CQl zrPz^;@1DVhIVVRdcC?pW6Typ;e^Nh@mSF1nkl*CaM_j%XVA8KW8x zCjUg8+npQ+A+L5;O-QnPqt)1^VjmQNqv?00_wC8sQy7bSo{itl#Tomia_gdo---gp z{&jo5VjAjE6RL(oBqu0=v$#O{cpg-7xYQ}qCU9WYT~tU5$KD)5Bwc&yxK|^w&;%y_ z1fL_WT3)ho#b!d8Gu#s3pmsm3$lclIr`=e@2x;a1Du(7!h`d2)EnJS~WloL%#k4hJ zfkMJaxYuz>=kCcg&efQ{A4TO^aF`kgF~^sDYBm0m0Hwxph&~CQhh-f`-;*YNBEDZ_ z124|Hi!KY)ejdb6rtn91ziPNgU0HqX8pkrmMmTxVXl5Ggn6?TA(v7@Gry_agfCT4( zo$r%?6yZnA07jK#BsM`CQCuO5(fi9yC0@t(?rM#1j#=wCd=K5EeEuflUd2I#!oYU< zTh-Y|2uNL}>wAMnq60xe2P5$r*9oX-7V1O2GDnk08*Yh7htK+GUzF&{XuWf^o0W&? zqV>29q#CEpYV4N1i^!D|A-gzvZ-}o);l5XP5`phwA7T;-S1L;|xJSkH@uFL0%K9BA zW^+`yS5p&R{gZXCl^%ko4pwo`qbQTwvG#05BUEx9qozvJXLitTKGRJ~`5!4^gOzSO z{>Sugs(iN7>z_`Wu3kBlwP4?-*w`FPv8$aq3%$I1m%X~*c)rMacx2@8OLzCQ>80!b z?S2xPJvGOS45jz7v1_!$H)GNAM|&K@b1Bw z0dzjYe|-WL}u17ekSP`fD>HnX==PW%%jFU^nuTu?9`V7$4T z-kpjv>b!u1W!&ef(xsU6bm(LXM(?gSoAFqcsoGQDMJltjaSP%-`BfS(Em`#T3-|5G zi3XMT)J1{xp{<2_eyb8Y{=?t)*)KE=eeIlK{Z7a%aZG(UEF%Z@vz)tg)*tKnh}^MB zoZ&S&`I07qI>*;1BBGr-TL`S0jb%82^(JlnAXCp(9>Q&<;FVrq)^lh`HWc_3l25*$ z^NQ1cj@m6k=!w=1*%*9bw$yLw(`E^4b}k9a%CZfpts?PSuZRmSVx<%&9=&zPY9CTH zf2^G7Kh=T#R_H?g!{J7ZU8!2#?tGjN64AJ+-n$RoW^AF`Ybiyg@TRMd#3NZ79YhC#XFdxhP1t#C$o7!v&fJY~eUUTD#*Uio4zy66$e zTyJOu%kclol@TUr)nfdqwrSokR0}=_Ewr9+E>zElra6`|y-L;&BP+yLSTDAlbRf5$ zt^QdOX>NHAs=`y_kH^CbO8jd@Nax+>BagrYb{x#?Y!FGeC>Gu-2zwqg=y*Y-9C^(w zuT_Tc->0O>_07NzmX<%lZ`=J;#*0f?CQa0&qsVPJB4JA39cq-5?p4{BdRC{q!&q(5 z$3ac`qaU}Bd>=l!uUCZc6p>#wQJ`&`>j7I?@k$$-O3!QxyDw$vIwp8BuAAN9)`3s9 zK{sv14;}5?tuG5r^H@SNfHgC56v3o!rNijh4Kc?uJfj=ZF1n#p)`787zWOe0u5hq`Qy zL%U|UB`1BCK4#fvWb8t{r#5mjIw7jw%wnE2f(O3dM?=p%BhPfgOQY`b_MbUIv!lei z3_Q)=bDxx6U4~Al*ekkWjT5q?T&pSLWc!dw76wimh;_%%Ix_JU*4Jl(bY0P%p>%%Z z%cmg|FKR}%s2?py)aFpiXcea`UUJ!;%sO*;<0m#6WG~p%9giaqzVsAPJA@#?TP^aw zrY&v{yK?PV|3IBOFF}8BjFXa{zR3HM)-`^V&Sx*F{3q=ov|!t<#87?OZKj3dCR zKeJ&d3Vx4C*_BG0`#BZ*O3LsOr)2F?$^k_cWbf@>yIRKwI0})RG?X2{>kF5Fh#k zL1Bhu6mHBTMRfPCvyWGSOhvzo%lSpfX42X17j90cufZ~JU~4Er`6UYOyty7m&QW@H z2=mHbw_W0`>rTLlrA5=1yDk_@AKqM?OGAx~Fp0)LY&ZMn zqb3QLJE)@(_cP4LCpF?%7f>p+O$xqCs5`<%CPP3w(T5nq32}$hdTxZ^(G~eEcQ%m} zX{$C$WlG_4@{8!{N6^Wl@H7$>Do-pu^_C4rYi^F*FaMslib&Rda*S{>l#Ic=SgRXj8%XQPG z9G~(a9G~{$Tl6mPgq~&i8cF1q`0;3<;tbYuoF&m>l<;ymBQ;#terHqWQrn8~N|v@} zMC+W;B%zSAsnj&gO-pm98fH@x`p?wsa!JS2;bGX#ql3~>HU+#`fTQnH8nNH%k(0MotaKZV{H!p zy`wzcrMN|P~6n|nsjJU52hE4_~Mid7oV%=3VB(E*C1xCPPKS_&L$ zPq+j6?s6{d`iG&;xXSAzGaZt7VyC#0=c1 zJ}saPuisZsO=s^}jlwwyGChn0Lfp@G1I*NJp0i{zCFx-qhCb`0hl_Yw> zi=MttmBKK>Iv#^?VKJPLWp0D3$gVeA?rSzW{i@HpJok!9GVI zGE7l)Hf{=M&p_+k-BOKFbKXU(5e_5*9vjj!^<`ycd+{Uze`MkhLIH`mvnm`(?ANO0 z9>&uN)0EX@)al04nkTo#{N6Ucq7X9_soYDv+<%RVrp|--ozIMY7Mt82NTy69$2?elw?E?UG zq49KUoXCk)0RbhTp;h|%{-A1D)62bvx+s;abYTR?73X%Pe4G`4&(rnJfDJhy$MPo* zF0PgXV0r4S_0|)mn+A;&Sh%Q5*WnRvoOqa)Cp|p#v+y@j%bw&`if?WD-aCcC;e|$B zQbu!hNtJeHZZ8}6zt3Mz&dwzrOg~3j{;rQ@Idmt9pTrKliquKEIyL`ptCv9%qbd0x zH9q*ha-~mlT;XSPUaRlg?Vp%nT#pR7jD-0)ILK)6(m%4O-;5{Yv>yNQ=4Ilj{p)^) z2#4g$hYteIkEv>X7B=*greRq;{U{W|#(LyO znslvVn$WRL`=`}P^FH%uzUN0pFY;bMe398Z5&SZ14Td+dPs*msEY?!65cJHS`uhWJ3=LH* z>+oSg^S;uJinTEI+V0}75w6>>Qc7oEu+y;iGNyAaYu4>|^lU@w?21*DL}$$VFQ5j# zuGJ|MsB5HbVty7J*zAX-dDGzSUIoz~sL&{MtGand;I91^fTMLgmDaaeXK?a!?XJ-% zx@jfzI(#X}k}bCBc-*pXGmlCy)j=FU#iQYM6Zg5PRz;Eh8#Co^V-hBue_{3=3d2&_ z)87eq7c+^O_i_sFHQ(|4wF|cWGRNgPhxj({qw2Q0lZbSBkv&8apT_4^}Jf|n??Hvl=6ZO)P z%KmkZ%V@oP4cl!XW^ymh`XK|;KO^7K_#Vlzd!z{oPccT_=3)ETgqTxfwBHRvkZcI$ z&HzD2`ahM3Rj_j(Km|N?T^8yam|_`h}NX$;&?*5lIfL>!?o!mf$>#3b8zDasn9ocvasfG$|fyXKTQ~E z!iz)LKt+b%d8GbC;9SvsgPr)ac!M{>;c)b;Z`zla;{5!~iwAmNRyB350p-6w`_h>% z7`vw|&Og^e3^uYP=UGm8n=YI_F*_)^?+*xVG1M)F%-I==&k!d9nL1^na))MR=TNO%OU8rF(nCg?u23C5dHE2bi64q-rd9KPh58Qfec84I?uHJ^yxFsTX^^Fts-IAO^p{>A+u@tBCzbHZ6 zvGE&tf9QAE$8X>I_|)eqJc^RL15^tscYltP-7E2bw1C=m2BpFE&0S%$wb>XYu`Y=7 zO|09+b?`g(j?Df|el z352&F;n~#m<1(kNu>kSU?Fe%C9_ndf2#g(RZ{&_717_QHglFI@e6yY2-dGEz@%NDxhSw{|F$@6MUrx^77q?u} zneOhHD&qMbvvP%1@9dBvbSf**s0upm_5MKl8k=te)b5%EoToR}7S9BcW79EQylvU5 zTJ&g;W_Om{(8nsnmv6|iaXB&+=rk>JH^o}h!j1r}wrP3qnZ5v>Klg};1XQH!9>3k@ zT5yG3L)}Ep-j6WAT+7lI%6t2uwO5xpBJ5F9;#a*@56jT&vwig0@GR9AW0x^fpruZZl#LK)5-0_4!aq3OshTjr z)=GM6hM%7pagTR@>B+u9?Q#Rr!N8Lds%L$DeZ0f#3%H9xMQT4k)$x(NO5wLR!wFyQ zj^hrpj~~=(^m*J;=_rokfifvlTT^H(nwFUtinLsbW+NyiS^H9|Dy73N7uBR>#T11$ zUb;8FX_t3f&yt-48r@1{kIbVcVaml&mF+t;k-Xex=6yP~t1>v}W11PdDSSKi^}H*C zk;0Jd5^5X~ilI=8){r`idd?ri)sEcc>`fV!wg|374MXY=hjY3CsDs{t z63a^uWUtH^J%W&+2D)a~;C!9;ze4#3eDNWmMBizn15Wxex7Gim$vEf1S~8Q+JZ1jqZ4e2S_CADz?s4#IYvmu6C3J1|n>cPeLS=Wq@@lmxE20Bkp^09wiO#5h*XIomTi1qB4g*}^hU zPybvhT|d%pxg#QE(>aQ^iYg8Bw8${yEebgg!%dW}EA=^DtedN-icrv+e`46!%c`J$ zHK>s9WuVRCg!XA*&b5lo z=Y6vM3nQY3^XlR-%6G2?`(#*wV+w_sxA(t1v(Q^BE9b6wJHiCQ3W)m1q4C{ewf^GT z%kwRK^@;^}23{uJpAbbr?8A41CliML?XG8Z-rHQ>OCOn2b<50O>A@-DHYz zVLJgRt^wxtheZ_0&J3M(hVRKo-~Dz|$+TGnN59)bvtQ*Fq>hSZ-p^-E0ASbYL@qj^ zxI>euC#S|gf#FpmlatW_DA6r-GI5{vYtBTQQsFtrs%b|{ns3nX19nBny%st0Ou2RI z1CA)a_sL61Oi}QMgT{>l-$M7U>@;vkmpmN&9YF=NR{8QlUh84<1;)DCR}(fB1tIHk zHtVsxIF(3XJ$cZC)IGFPk$*6s`(@;#)9?GClYn7cy3cu97}WMoh%bk8hu6&dSs2dA z?L2r8;F`}rBVD4$fqcBg2RRg4Z)j3uIsAcd5YW(+8#m?cbCfWR0obvL%V-BHrj4kX zx%qUzFx=+0)=mv9eLs1OxJMJQ3ynCxI9-l%cdo2++4z#c#|B2;F8mzk*)gQ}>(*@V zh)gh5{K$`2`xp)F9j%>?58U@!Xl#B3A#P_y&wbusp08{`h;hE&6Y&q)2I5Eu)#{}~ z9fsX#r8siiWNX}Z%QHUqyIBwPx@vuScr^{s&tgQRMa|ZTrOeJW4F-zyDn-Sxe!M{2 zEZ3-vjH$ETG1nQ{v3PlL$e+S(@k7CU-j|>hAcOwFN6jWcP_Y3P(^EBAS1WUd&jRf^ z5Ev-2#(w)lYmaR&F9flcXJ=FE&lcJ^3V>5>>Af5g&5pk`sKPZvvOX2HVnjMX*ZJaX z?#@+g3|DRoB-jhj3B0BpCK9DI))yZ`74X=>Ir0D z=@7v;MbDb5B2l594iO%1E5zvt*VSa+!xZ9k{TFe)nz_ox`8DIYddPbU<(Lc=B)66h zLAIsMRhOPWfwujF1y10<)T@7HRkVBN+upi?}*k zM0Q^oFG1-f?*nd?g6LoMn*R`S0;GdZ?|73h;`dku*!{K&tEK_uf1BZdDH!U6`!dt# zyUR@0Gwr&yee=i5(;3<`_jrmvKV4m&OZV56ROl(rjXMk9#b^6W_F{qmzH4dZCIZ|L zek7H5KJSV>y2d1ulnTXf3rX2NqwIo8akv`%a6+o;rZ|S61 zdZT^&g7ZMV=3vcpu)$k=sUb6GwH;4%&at!B?R2qoHH{fc#5mU{EF)2WG`w{X*@f59 zspEmZKA4p+@NpMb_jt~2}D$A*K6QbwqG23yPOajKY9FWC3^%;XE1FYM0jI;3i!=$W^h~5|lk;C2>-U|Uag}`D^yh&d!0$x6qO7#3DmB=Y?LWtj& zlpA@?Ak|R}@=#rUQ(5n~M{=TAd7i_}67<(xvGk4D=mL&60ETZXw%S0)KxMx7Z70>7 z6ojRkKx<(jmop#C>vy9Ul$S$s@k;+gISmB??&YuGev~Y!sPMLwwWI28vq}OnVdz0-`MEj7~rAAZhOnOB>ipG*M)y zH}%O7JNQjKO6#ghx zN7(Nw!^VYPKqgDEGL()`DfW$1Q!5L!SuDN2rd{;it}D^9_d+TrJ16g|Mino&l>ABm zNri#NTSlwb{;iTIqhrKM`49MpvXTTCLc{fA#7mEJTAW3f9~*v;P5^}^o`EJ(VeRK-P>%K86%C?c0w!<2%$cFrMB^RU|ZsVSh?#xK+Aol zQUHPC9YjPyfnK2`jvA%tlO_boC-^dB;P=mX;pQ}8=JJ_z+;*>!pf_T>Kbo(}VbPWB z4O3i~{Y!8GsoA@WEN?-?Yv%zWG|sS++xZhaFb=)ZO9s%M&j1O46dAq}69|;L-gJ*8 zTo^zEF-pHzgev|9e+ANEWDp~q83(N@yR?$<*d%d8**{vq;pm^dvs9AAON?Dl|AI1q znE7;6OhT9EZKkG+s8mF7|Od;5{x|{vo_6!w7Muw>cDK}GBD_yAA$-lYt!VVh!e1;K%nDGNH`%hP3O>JGbp?TY>lvYrGEei_uE zNCn9RMttwQ5!KT&lY@wy$dAED$IV;1Welv}yD#PzFypsSQDpGP_D@PuQzu6!xQMF3 zrq64qKg6Q`R50qYOOcOM*|u*y z>%bjD%sNLo!XNw76Bf_d)%Afaur-0$X(kE@Z}RAA7YvZlY0ev!SNQ2wWH3@%DH%9w zg&eh4>FADA3e!m`dKNZ0cKxEBMa~VhA-++CZ=HAxecE|+;Snnz+t*;m2+2He(Immj zPUA5J)Y;^5bDl`LljHNu=c_I=)nc7Gbjm~1Zn+O&TsR(vJ2v)G>LQokw0x#(I;&P2 zT%KZ9<2}VZMH%dh29#!ubm+N$z+OIN$B54>8STS)MC-j%k#J34LROt3!Pc*PEmSQI zI0}T)3!8P{m0S=zTRGJiiY4;EP%Lm#jRb%+`W2gAZ&8;hBMCkgUpdeZ=e$m~-%d?U zd33dN1?U`i>#QZG0*%>3eL~}Bv|UpE>-^p)CoFVhe1>Tg$q|{asjy z?|-g%%xCrH;TO+`uURncYB!i9Crx+Rdwh0^TkrHckdfO11p`=xW^OH*@VzUtjv4hNv+r1LjqwHVT|&TN0+1#k%$luB;eZ`(P?Z zMY!exyy?pvPV{cILcpBP7)aJ7>@*i4KrsOnc1>+o@Br1#T2$>*VLv~Ib%)v#2qWA= zBmSOK#87`$BXI@N}VU6m36%9VKpkyc5;FYNGQV%lJ9O(9xYx`}qplSn0Dibn=DguGr`MoC!}epKLOIN0_?z6_{1KbP9PghOn|9NoAYcA7f9B_aV`~UL_w@L09FR2qtq`-p1ej}*E?<-b5X?$I zP&0{r7i@%y#sL$OO<%$%3n#A+v6Kb|7zwO$l@R`ja7Z2lqNJ*DB}P~ zFGWum(Friv_#>w*@V&_$@-rrBPgSKqeZd<$md;W?Fpkk!I8iBCdyxG#d;!?s0|>>~}`k2hO7fb1@g}4Zq8L)Yfgoj|p+gJ1366oeE460Fwh%$iMRTDbbECkYY={2D( zp&v!3<4^IyG$Q~5i(G9&lF^NQ1JiEsjcB=kog2il%Ms*KC$%(*tH6|#Vtf7(=D9On zVJB4t_C0pnAlp+;-y5vu{i@;&gwGesM-&{Q`g^=%NLWk@1^0ULNuz%2l2Rbka!no-_m{Vhs z;?Z$e-ltT~(%B}@*e2ZUkSr52-KS0Hh+sk6~v#J=k#eD_1atyOw#iB=N0jTc* zoFf!g1B?M4g0`ls%dIsBF7cF4kKj_oJJ*|xjFNj4t?2Ai2{8MMG4aSK6z+57y$WsB zwn&SUdZ?iyWyBqDyyY~j7+EDp3cIz9`X=xBIL8w)!CG2Ehp*ZAT&Sz(p#Yi&1CAXY z(8xkPA0~_W*50?oo^kCGPNEl%-t-zz65ngSxdRrdE8{%w>r_iKZua2_)_^+sIF^oF zGfql1F&2%2_4;3FhBZ##Q@j_^R}KT^1rNmzafz#PC~6{RdfVwu!r%As3jSC$2Bkh=rjnA1nw8!k*u>Sn;>0|;j>K%uKLq<~FbeV)#bh>uLtNu z+ba};zwswXpfTrSb~@7n(HDbBIonM;zeY7g-$yAe))6~ZZ)}tIamqEhcB{9;hR=|G z&`FAFs{ipl0r$aPN@f8})@Y$QV7$acHeWqI-Z=Q;XHL2kR{UWYi4yFh()L^JC7{#A zV8YErIE-va%#8$2<52g+u?Lh7H|Skz0%OGvx9FPuS>EPmCJK8G4jVZU4G1jX2Ima| zjN?8F)`HYb$@QM)oF!f_68>hWI91fUGE0N_9#eE=Np0V-%=Lb|7#{fW^`(Mv(b1bX z#>qns!;O^?a&L4tk`F?z#k$oFS)yRQDz+z6o12-eqv%{{Zzsek76Jhjmu3VpyCT}4RQdR zS*Wgzpq{=Gvo|1K+nf1CZckOW#tU}1MKEYQ1GH4P)#`S!>Ok+C(Xn4fFycr~Q+i87fhy zdMP$Xx3krRA?`z>I^a-NvBT3b;+d|`rGbLZKNK8oc?`XzC5SR8`eU`a`d}g6g z-1=N_J{W{`V8QKQM0gJxLa03;ZpQwUT0wA)}sXJ_Ok3jAJJazV#0m z9#F5F+CC8VGokOV0B8F8Lm!P3ln;Oc(#~XB%RzV{Qh1m1M*@Q$qw1+y z{dQ^3EOFK)S0EqG#-(Gu?c4eDp5);1<5)b&pSP92!0n*5l!39oHS@Oa6H}49qr2O1 zKA2XIGyE^4a!nKiJeUDXoP#SftSEVc6SjYo$AA7Z83Gub?dRW&L%5Hw{;tD>kvCNP zit$^mFjKG2U>RwJH@CBmwpPIw-#jB24tctY;mw&UD}4+ERA-o$#%IqA3T7wTIRY8V zr1RAsCMcb%>!Z7T43C(Ri>dyQOozp#?mq`$zr=xOnKqQMXx0-di~ZFLOF=h&9fF5s zBv5UC)pPFS?I5#m1hB3F1%9|IqJUMx^Y}RrOi6I{F317u_8M|wm?)r-2zO)ERctCE z8X*@P-P!L73AGOs1(FN}`g^VkqXf(K*Tj@PrJYDpEf z7FPi@d)f`W1{=n!@CC&BQ0v7iIwiD|lZ56j1#3GYN&BHJL^~vA=qevl+s!E@E##s+ zXdJL8Cr(Wkli|5W$w*VcWb!-SWskA9kAL2V!tDZ_A_Fn4>#_QF&FCN7=igG-L)V>F zZ;ya@NIz6oK3#`gydE5L1&IOrE?k%0*(u!gYd!;vw(d(5!ccSRdRx-C02|bLB#Mp= z)t@FjfxC#4h7+yzyuZ8qAh4~Ej}V7K;VN2IDp(h8~(4Up2 zUBp%0x84iCKl$-0g}RB?dYqz%%)p@qlbygbx*QxZ2C{_=$PXgAzo*!=^uF|7-Z*oj z4NMY;RJ0%ReF*M+Z?RMeTl0=9X%Fh0Bq!7HO6tp|lskbin>s$7FxQolX%_Qv)c#p5 zRo%Z-lVa1)LDj~%o-~=5WHRqx%Ea`t+Rp8wO9%I?v6Eqh?dlL&@7`+$4vRve_wS*#Jg+>QJ&+WLe|Q@MUE{kvX(0K; zGS9u6z)`oNfAvmLK7Qe-=vMCOTX9GNcXOI(W#s6idm%eqA=P@I#ZhGkXlcxnQ&v*cn&K^w~ zwf$l@mEvR*IPs3-xJrfmwgP?j%jAmL{A9q*ACBow9*o=S&FR2(dADoS%+!24pN?1h z_9b$@or5HQ{~qk?vPvn7Fy>nU}#1Fi_COqFA{ zY!u(TM6$3py0{*{0Oi%BrYeD0jxQ08Ed6J);$+vJ_7y6+e6NZwNL=AA`%m>XvYkAg znp+zx)`u0dWwqMPZw@$^`hxO!d$jB#wP)_ct%zW)vV5atW{ug-n^=Jinx%)$bS%|Pvi%-^R4sM>Yf(m~mu|U+ z{ngA|zA7&J=(wEj6t3pzPe1kGz(IB2`H^DRP0~ixouttF$Of#ia3ZZBWeh2dG52}j ziNtK5&7V16UZ$G_ofMSyf9g@OyIr3pZ#UNjY8KR$%%jfJ--VWQGa{Kk{aU@;60n@D zE;%EcwCGJV4nK9Ca|gTlQvoLti+<{yr|IeGw0zWQcY^{sSdbvhz#Zzuplpd=u^Ct4 znqLa!m?-s`Z25?%mFCh`aW%)6V_&D&@+ZE%$3!oQt~OzCAV0@fmH4}&gKllJAL*dj z_!zt*8M-gG0Fnd_lyx8vfZqb2G>LL$=?A7}LrPBX7b6;Bw{mb|as~u47Ji+8_(9^b z&vFF+beyKaTR>DJpui*5$a;?HE_Mn7@?$ZeQ<&cE?S6m;UT?;H-I{=vn?$-gbSNJ- zu6$A028rArRw_SGjX8xLTx$>DfNu0yp)S8bvT8OnHP#3xBt%{;jRI$$Lh|q?oy*`e zjRr5*s-t@v3*JZT#+Kx#u!=w7Yc+aM07-XCyC40bGlc5s@*<76rlzI>Sp+vNwAxRC z8-ZUwQyd$?c?#56a8`CMiJ34S5oBLrUG{)NrnA^+F7w$|)aOf}HLhVe z!#N?B#cGOYgy~?(-^buCg#d5P3m4}bWoG@c zbYgRrF-)&mT;dmCMP1tKFASQ2Fr-2zD|+WVObl(#xnTKgf7e(%yS`O!KU#BFHiib7+`V0)da^2Iq>Fy=5fe?VkTh&;CkiUL=`mUDQvo%cZ(^VBOLn03-! zwb0ggzsT=Kayl*Iw#7BSBBSE9GR-C1cgX(YG9Zeez!DY+H9;wi+nM73j-cY#>4|@$ z@3FKEG%7nKO{8kV5i?7#;&EaYu5+^#tP~pk>+!{apRJ$_N_a@w6W?b|AG9(#>ey z$?#2e>h&3Mrqx(phrdMOi?{1=?Z-&531t{K8Z0s( zt|NRcC7wNJiI?BtWi%YBHL$GheQd%LDQF(vI5O4T`Cdgts{r`Su1`6Mqg3t+J$Mm# zra|#M%Oc85Y|k4g5NW~cUiFOaDMGG!C2hD9hg2hN_^|bGiJ2Q&!9%~Usmmpz>1t}F zD<*qh6*83~B4haDOoKT^Gs33EwnX|A>Xz$-~KcqrEO{)%@brZg0*+ndQ`bE6U*z z!mZP+HwZBE3`j#;I{f;&4?^-UGYl*J8X6Cxiy^sAnjy>lFDiA9U2>6{{C3y7;6n-gbcOA8N@HGMAz4n8P z8O;rQ_Yzb@?l$3y5bOPJ-;QabU79Vc6||c1y_Gx>LPvlow#*K_x@uPU_sqUThSWmF!+Cyq5~aBzO+J)NI+5?#(--UXA|ZwCB0X6^^lns3x0<`Mu`(Bb7B3@X!2x(nhgny z%{yZZjZ+i8iMy|f$#P`^bbPwnc8vQhYgwJ6RfCzBKlS$_UF%&Ldbm-ErT}q7t4b8D z^cCi9LJtffT5IVzHb0J9xcvv)9{TRy@f%|%n-NU(iB?(9LT14ogLUi_EMpc5WU z1Xv<5fB56@hck%rw7@!_X>0&P5i%#@mkGqDP>{bSqCQhV5XGC0Z;-sP#TyYZOU?_C zn6G2;^npX?0V-i-gAmL~PVj9v^*`u@{$O1EX-!;GMg-Kjo!}VRus~o3`^dz;TIytt-deiJ$8os{Li~SqSN}5mLCf&MJqyhnE_>~D*Iv@}vB?7pVjNC2af&lz!` z{dpW+Pi7d{-nooW_`*zJLE8;sGYpOTIm~aJARX@=o;++H9)CxJB$^eS`!=B04b@e` z)H%oVP}3fNkQ${lGVnK=vs8t#Vzl%(8?_}zs3-UmtdF~_r9ANMqrYZcgVy(3-tP!FN;l-C3PC%~x497#Qw~5x^E%qi z)RVk(SdGsPnGwg>)#F@RLHp{xQXpsMZXGgz>OAo|W8_pmAh#i{fe{(J2#%*kX!D;U z^pYc6J}jzN60={nX*QKN2xa#6$auAlHRxEuW1w(n7{bF?}Y~BHB7ceYr`DyPq6_`@=oArTcDqwLqh5BRp-^ia}0{_rV&azaQu!(xO z^Ua0BJuBG z^8YZ}pZ@UFibC^lu7u20>VPmpyBF?; zs))~vq{O5)gkQuWUf+?P6KghLmwwpQ!ZF!?j`Xl{;pPN`;Bvonjy|I-d$tSiCp5nY zls`FkE`3JHYNt&hDm=)`Ss)+&Zd7 zvAY$+@7-H>KO8$sd^&llR5RE0wRHfFcSHg|%jF80z1W z_(m6*jika;fgDL)cpeTT&vv|nj26jZS-IyUBh8l;l=H}Sl@H^GA{va2?H*ham|5uG zFdkL&!@Fhn2EcS-aqbpA1E`RiBU#9EpAEtym?-XZXOYTGX~`GHQ0$~ZE`{&hrNd_5 z{P{tVTWlWu;5W5AnV-HSgb&;ahw~+?;F5~|oJ&r3BC#D@t9BPvP zUJ3@(ZSvK87+UNoZSP0L{~MesR5cP!`uQ?>OIG#k3t9?#_>GNd;b?!gpm5#3@?B** zGIV;L@4!<-m+6wNnEt^cSK_rFq3rzAFD5_J*#^*3_o(;`XXFA6a~gh3njak@GcdVAzJ0z2?1XAi>A>8F*k6?IY@WUAFP#J-+phjtBz_9#nns~xF1D}007CGxLI%F)Fzw@vmIizQozuNKmgy)>agg9e8 z&IX5V<%jB-61woYmfsJNQ~$zb2)g!le8@b5CD@AvI_=LkrW|FX^VKZKiL%4Um&;tw zMg~-?mGdUQocK^m;oWP9P;DGnkw#Wa*WVS1*;pwu4o;e7FNIOc2C=%b%>* z?C)zG`{LqwGxFmD+RTn(nHO|hkElYV$7Lsw9v^h5EU4?jLF)wCqFggM!`stnEqHeF z|Iq@L?UI>ftHU;5=a&^9Wp5U@9SlR{=HvrgySW!fLM;fzcG+b=Z~5gZE!KjmA{+6$ z!w@^+u9up(9Ck?rii`i3n{zDCQ%+sasJv@nLqt@m@D^4i5J39%qdPLshzfS0`63+^Us4NGyqi z7QdGj)ks&X%fUFo6v!otq#HjHP(#EZipW@D6t12RxkZ&^KdX=-B>lsvAbYz{( zBx6W_Or>z76)xB39nMU|+^wzRPkN=5pxASK8-S`RedvPbF)`JfE7;fk+S_G|OHnWm zxg7JRhRTBah2dw6|AxiMp-B=NH+aA%#j%{%xXpiroWK5T)Jj{E-C=_F$<^#K{AlW7 zD|S0T8xXd&7#NwRznC8f#z^{Mi>5l>3X>gr8}Rq@dL)Ixo@W7O#Y4LP%Wk}bhR#ha z^l{rdMav|0Tz=TE*y6?tGFaZkT^iin(+NzdbvSx0J;TTpmb(d`~gS`4Es z_xEiA(5#I{Gur+)>?;3JW7*4%F}z2$wc4~(TT{KB_NL1I!p)`g7S~4QKE8=YQ^8#P z)p(?C@f0JKw#Wy#%0#&-qj>4MpU`uEp@CrGhg5bf$J;-W)^7v$mk!@};ABnAnu<R1*8g5C5HxL+@N&o7nktgDR_0!#haw zugyr=N0i5x=l93wTdJAAOginQvK+hnUHO^<%{7>L5TE5g;eYxmW;|$7uJ{Mve)dDQ zz7O}6^}8nn9`+T^4(U7NtOzMz)>FP1x7U2=;mW4v7B4bSJf{WU7`FrlNUpqA#9y|B z%OnD&!0QxiAVbLd`NjqxbV8GT2v}g~shYrC2frWyKuo}f1^OB1BjMg zAkaO~Z8zYfQgnf|FADCY@f;h$mM;$!#tsrmmj3Y1#K_5GVc4R7(iVEHeFBJo%g=iM zuuBGAy{SY>r2~`smOES9>5y5JlXN!Q=*RE$OrW+OQj9qu8nQPk_sibiZS#t_;$U}stI33C2`aKT`W~7+EEm!smw>mW{LP-^3{s_BjqMzrAlKu=B%1` zF>vpoL`U|=%=S7C;~h^b@t@rH!{YaXZlQW?ma829!yfg4jG|_Jt{uSFxN}WHGJrFS zOMVw6;Q{Qh4OlbnitVmf(@bfx+Z5J4$dLcocg;rfLvGxws-% zPp03 z;b4eHUO&QR)r{q#{m&rr6;8fFAh5O2cC{0~r)evy>t~0;!K>vYz_j2dTgy{C>rxPP z&ry!2wbbYTt!zWXf`n7sE<6eX#6;x6plhR;ZmsOu0;b~ATq$7t8T6!;y4@T#D9JOjQ^jpMIGp}HAr~jZ_GG1Vj!oz=$ zcA&o65T^p`DZXy>$a>1kFkfDkUWN^kc* z&b%ITFG@TSpfe|@Z}x}?feb6Ct9A*Z3f0iHZjRSYoZLr`^c#IDgql}&Y3FVAEBJs{ z{;#dLNX-nWFkT0pRNso$>qICIfuihX4LO)Fbbjzbav>4Hi@xi>(!=32oK?l=NL zX{Qr_fG}?qgTz9RO@1f6_EWBbr#sVKVPRWTN3Xp=A3>EX1~@h^KDtW~qDR^m?`ueZ znNY-!8?(&nbZ*e#QDVsTqOU+Loxcs}ovTcld8V=fHPjqEc*Mn$`aG*)u-G{VGag$A9!Qt-;jHb3O#vNrwkouE5LxX^YQsu$#Z6)JgJPd5s*UpaRV0 z^z?_bAs0>}w{`gQd#ijgh07%NogIsY@gsM^3GmOvJRcNqNrBhr>+8m;5{zNd4ooNp ze9&Bz@BaNhoJC-B&mUnK^1z)rRt;QWH?2#s8D#%h7$5{FGgfORr$FPO<4i&Z z3373Qhf}J|zp#D{OwU~X0IZp4Z4~s_ib*KWKij1pCz9p$=!PvUFm2upX$C25Tte*v|u2N{Mb!zs#H%FGg;fFn#a%%6`g3&uj$6)99H zBTAzn$;pOH|C?7S%y+7VaELGT!O$5>#{wp}S~=zg^&wx4Fs3>u);vU(enyEpe(6%k zb4xdjeV*K}>wN8uZPuUdSKTt9#dxrD@C`!&%Q0xPsM&Bpc7#APMc~ZLzvZ9YW3tv@ z7KWX`2AgV__aXqv`LWkuvt7A==9e?xv=0Cgc;f`0M`TVB9b=~%*0}6( zUYi;d;ca;@X(n2Xg-D3|Ebs^i+8FO8x{L|PGs1t^(hU_!}U!sR@p3jJ}lHy8QvPx6~E9GoSH^5q@31 zL?|Am1V5Uh;w9h+YHR2G`ow-sRTQEIn~??Nv@*hO5X<&O@>7}q-J&P~ZK?BExyPgn8EY9utTYlH@N=$ZJWB3zz`%AY zl;YLej&-dK=4@BWvA4fG0AqdXl(Zw&e5Mbzs(>Y2O~*~i-2ktT+TENya}Og$xV;XK z{1|apcI(`u@<0vNi(gEVknu4rgkAR-22yLDiaw1RlrDQLMxXM4GLGiK#%z7n_BcWo z=wZ)gJ;+6z=Vmv~T223E9DrNnoqVuFw7S(yl`4e=E&F6aX|J2-&LuA~Bz>L|0tC+e zc;;98-O+VSye2i{-+)8ReHvz#AO&3i`I?^6NyMp(?cG7;pNVJm7N~viSCG7GDu9kwVrf*X1&Tu|d z6UK|rXR!~NPGz2nmK(6DM; zBnT<6m}WiflXkM z>b&8FRZMw$y+$8miGE49{Bmn3Wm#Vx>q%zog{L@g554o-CkYD0+P>~hmvjSyX`f!J zAG+Z@2@YYx4u;>hJsNE;GB%v5K|6WP*3093-`xy=oRO~$#~X4F z+3qt_4bQ=dNBEd6dEupU`dg}$(qrfs2Qx#{5|TXSL7n&c_zHGTFMNTs3|PV{w2W^S#F}{JP||MqU-uMb5_>Y z>+CcQ8Zt*9nP?cYR)`p7f{+U5hpDgcvZnJlMBGoHC1|pYmxkR=@sM%x#j#h$dM6h= zV$*`mv}Te|>bn98BlK45%U<%^_;8Tw{SCU>4(FjDSoBB!z9s+GVieZbXaxK>em+G6T zd-ze~dXfXCQU?H8!wU0=KG|K284QP!Q6*v}z5MG!vRrwg84T3{50aWIP3Ln*bRdu_ z1j-qbc{(I4cLHa%MZ^8)wUF8FyAh?^e<~wVi^>oF_!MlOAwz6d7m7wlhXX4oRLv=$2@+i_T{r?(-wU0_Y1z9Z2AY z)i#Uc9R@<=-!-rP9HG1y69ksYxm3M-5l;Yw*klo2WMqR^o=B{i$k?^8(Ye%MLya|b z#B2m#4pWwa$od|xG>*;IHe&8Z%i)kLh$}m0_onuedAh#&;GOD>d8yj~@Vz}0~&);Y7 zA$XgM)qCqO)ywQoGLzLZ4&9t3O=`o6if_NuTU+M)V!LT6614YjKb@b$9TE~6`un~hhxy|^-YQqImJarIc4S1_cyyV%?v zJB3JBb|e1XNUWmSi#evPu}1#DK|=8rV(UB6UA22u4VJm0o43Bb`zSoBzusxl>~3=r z7#KG8`@4i9g7PFiZK-ZKL5O-5Xk>$|5(MU>2j49-(q6GcuhJC<9z8HTRMj7sw2>2H zick*|8WckiOK6^VY>WViV>wm#T}YhPowXPFWkl9xYSy=HS(D!~PU5VW6ZRN6Lq{rz zi7=rM61Q{}GTwwMrTjXqtM#|y&!;>W{;=`n22^YD4|X=P#f8FD>{1V7NubAgwKosZ%2Tz1^U~*EG(99wW`Vb#IGXSj2$zvjs8%C5s|X z$qZ)(@SmIj8V;fig&;-7N35Xs+$d$Vx<>#lYC+8e*Km?7l_Y4(H;(=CewiVAFh-Q__6l)`S*>}0V zbL(!sA~CX#YDj2LWav&{cHz6#jI}?ldFtGL9^z4m4JyO=k&$q8{u?opn&V$W1Cfk2 zhkchrzwx0S4O%0IKl9%vICE_s`BOpqXg@Trb5}tvRU_u$T5O1GOqGu;{zuYcyVYaa zAsMI{D;Rz|PX*;4uKtKkaodqAf9RR$QLlXcr$DF-WZV1ny^_1e`e%U&E_3SwStt|s zApA0*EwPQGdcmgU9ga%Cue?IF;9#`?Wy9cvms?MGA2RrXYQ18cezWCt#@?y(&N>OF zY`5%6tQWBX>kXi`w|sh)IkCKqAh8_uo)Td%Y%uaAnC{77)S6DRB@R0+%v7^PYZ%6g z$Zmcti&A(&^$f#%#bHZTidgP#u=q?tLYKc3z)=5HLqlwcH8cNdgiz*1(z;j`-pB(K zJ_LvfkCOG^BxmTfBE#0lqFfqd08adE0<_--Klx|%$7?y%=91w7ZN2|Ckul0>n6Kc^ zmdZujtKVw=xTDH;z;kF}lyr|uY|TxOAvB=ftR>=soj9SFzVd0J;A-&!_5W8GB~L>W!Qsyg=OJ^5=O-G~z(ddau37#&n8IX@OK^xR%8_z@5WR*t zIxHS@@RsCS)CF=8g{Mr3m>DqLP_sQU`XOtj68PtM%AA|>M!ycQtur8Bfb>MA%74rY zB=`*#pc4F;F&={TD&K4x$)EpM2yVkM19JXji>|ny`#60Tm5l^lN&+(J-mFg~sUrv| z&1j_OfRRGw*p52RT$l+{`?FZ9;3I0y7Z1?&c+JKc*tDp1BapN8?mtfqv=82>@CwAS z!IYAceDHZHlHWP|5ygFG^c>gf z8dZR_WFus0LESo~F1h;xRYRsSDCGEGU!8Xe!r47Rp`hpA_6wIX0`$KY7REn;wmilY z70#1BQm9P#sft-u$ZaTfn~X{xM5E@3e3q<=TLSSC_Mcrs?fw9kVfLai99c2TY=2n! z5%-{+Fy2Muc@jO_8n=Lw5w~j9JDg8h<-Hgfk~0`dOT8^qSmavZ^Toz8XLb4VyrE}p zsJ~h?Hr6A-VsFb&96$N!S6dQ-?}xj1t94%3w&|M2;bI@dxLrOFO=l?~?O z06?gpr!D|d@GG#DNe$%y4dXnL$eWbHb&xShuX2Jdn_!w7oEi6pj5 zKV1+6AW#hV68vX8LPBHuq{N>7sg%cvs2}ev(Jq0~)tj!t%z^h?@ARegvYOJ zEHEc#-vEu|XMkCr{pI8$=%Vbt-?s<8BIF9)-lR}bQ>k`gT&Y3Qb4#bDps(y)}iRlAfH|;=$94&DH3U=P>1Eor)sPZhP@c-VVCyAq_u`~*vLxNC>pEcCI~(a@=%I-UNx!Y&^2 z9i*6G0Hff@HsNsFa2sfT*wgtQvaMx(uHv}n-ix9%6T9*T@Dh!SJHYG=rQQBDZgMRc zF?qU=LWS~y!s#=OnhH~EA@YvP^?#{{pSRgC^yQK;F1`dhW@M&>QF%Dy;}mIC?L$(q zVM83_)l)N^*;k$|$%g+9XTeoJqQ-#iqKtkK4dM5K1^+JjxQ?~*gO-*EsriG=P_!S8 zda$Jh^)8H%WABPBQEF+84x0+^(>H4Q_C(*v@J`q{6`S-98Mb{hD*Dfreg`~Cnb?f4 z&Nu`VI%MYQxwkHC$?}qTg38z?5d{r1AV9#2N37+2h=md|CvGecn9|_G;)VX;yJTE| zxJ1v8+}^WCC9eBpY1%69N{zFdK7RU6pV-V2y_yHEGXj^3y)&){jM7GC06Z%0V+>*K zO8Ji#P;(0sD+x?(_`9U1^Dp4dD}Ks^2{!>_l7$GgA$kz?o*QeWy&?y~@5BE3YE zG{y`SNFB+PBpl?M>;$%jo}Ae48d|_l7d;U9Zp{;gC+x<(>rzSGFXC}o?;{AI{eEvv zuR<655^(wYCiJ?A`$r5geXnzRb%R%N%E?M$H;TU0x z_9+UO1sIqnK=Z2gIjli?f?>qLkqWIC*Gwr!#|S!ha%dk}>1WrycPTZa|194F33jSv z1?rv6XrV_NBZWt}(!gJXP{&l+gJHRX3CM%?rF4am?6&L2oH;8?!z@D;d#|N&?PTks z4Fg}xa%ki>u6AeVV9c=iGR`IBncmP=^GNNbU!~|750TU3%nH{cy9q_#q0WvfL?5v`l&_rt4MAF zf4>tDi)oyW8rkw|Dy(;nm+0i=1u8L*;Aqku_FG(8&o%m%iBa<@K%j_-^UOh^7+JL} zkq1y8lH+>(ra6z(3RBty#sFHvGArd@2dw>akadSC;1GWX_3PF#~u}Koogv}s|7U*i|R~u%nd~YmpIG{At zYH~-AWflLzI_tn<<@a@m|Lhec4haQBLAgerjEH$hbYuQ_fK4GPc1w?zt%sTu|JP@$ zJgvP({FGM0zJ0CQu`cVU5yK5K+Bs_9@)~me(nZkN4%$4W4J=NuxBOn<>Jhaj@_2F9 zF=A4mt*#H_n&rQhS6>P|`Th)LqX&8VFC9R=cK%Rp#@+QnyRlL4F}mz(3ZgKS#^)J>0LWWx?+{bflexXu_?aH-rL>H?{^6z zq;n`nfnk{DBMX+8oZIbHb7A|gsMB=bqGHxo-%f;cU`$IM8GGLn8q9@4l%;1vfM zWj%N3*ey5CSh;ZfPa6hcSo6B#VGtG{+%XZ zgN#H=ShX0xVC#I_@;3<`028TbGj{lb0-0*`&_*q?VnU^Df)<;4aAl~lAK=xhBXpdZ z#m4}uWnBmFD}FWU#OISiKao-PR#Z@`w-8e>3 zwk>tQVf9*9sTTOI6eDt_hR@}ZQlDtcNii{l!SpkcS~NrBPI9YS*dCa)h|aSFUx-H4 zzlBHo18A}NnYP2dF_h@qtBn$wZ_qs{prbx4#P1CHMsMv05{os)SI{f}sBxTr;CH3J z{MPq=qpFAM@V=!|OkyY=`I@o`YF#8;4*tRwo_H{@(6p$SD3@vK8+ftFSzAruUg6p~ zlHB%AAe49S4%?uSg$@l4RVM~i}WQZ*Q?I=f?_FovWM0Dz-0(GvkA*V#(+sz zRF)uQlIl$fnpRd}Xi-&yGp1|6Z*bhwrbtT9fiSM%3L~PN5R`Q$NSulKauMOEHKe?~ z02nplW<`EnD)m6ta%o^^>T?}&Z&c$F$IW@NI&kvKS-8)rMnU00qC5+gQod2W8>+^( znB#Y}3O5Uvn;C@U$jjGGKTJQ_wyB~1^MgYZow55~+=s&FgXA^C3;hh7j`KXvtM3Xw z>R3kEdkD(3elJlMaFm-)Rxyd#k_BN239!*$P%kK4O>K5yvWX#yD`dkPLU?L`xDbG&;W~CM zcBd6`pP~Qzr)Q$$JpyH_lEL>(AU|yKR?{4Hzn0_$tkWs=@g)Q$c%fY?Gl2OlFvvp< z!vn5D8FB^#FB}Zq_|E)YPs6tTmZB!6SK`%!c8mnrQ));T6&SeI$B)Dg6W1JU(ytOo zHb~aA?jt##1;TVTjTCTZ7oG6!-szL9b?JT9AK`7>S14TPFq(RCP*@vH6`Xck{$2U1 zIaW*pPCFu=7v~?^}Dfx9|}IK=oTO ziK@XWqwndzNCxa9J`7wA+?BqLlM#B;-@Kex{Zo*qI*tkVvE-{#i>_`A_^& zxboMyfbpTtM`la|ti8(C3?f2jgl#D!?t{v19>M&F>OOvd{r1RGmGKmIUui7M>V6xfPEh46?JskE-Q#?bl zVoY6XdJc{ei{x;r6P<1q6F+f!HWe_VJpV5XCJ_ zch!~xH_JJ33?Y>q0ovdsabdGeQD>)PZK1s^#vm-aQ4X0*Ox+oPy=Lne7jx#|%2bd3 z{?eD4>$K)46f@Z9H)Wnoa8eCyv}8)^ST$L4(2U?xgjh~jJ!r-vNKfU8LC8*z;H|u<`B|4L1bSik)?hDQ2kD|dxe9| zz{?lE{VwL$Dx-ky&`$y=Jp_beNd6APUMxHR;X7G}ar{<2snU?zSRg;Q0eY`fB( zK9Xx*oYw_Gzn3@Km%k?uTHxl~19lI_Hl+Po#M7j1hyy6-eumLvIv ziR7*=Mo|)DCXYu$!D&Y}Tb%o_j*4YC7gdUiiwr*{^kFa)mw6k8Evl&$esq6I3r5Nq zbs;LF4ngiZ%oo~(S3?dTmN$74RQ#8LPkTm@hABkZJBcz$P>}4$B z_E2h#*dxyg61IbA1P-f5lWSc6t348f+a5m7qZoDPMYc^dqR5ITsUaa@#6~u z&P2le=LoK2VHn}ZGsTj80fS?P{UEZbIzMWB6*T9&UY|dn=<&im7|nkz!@6?&v*%l& zJd5wCQy#9PM0x1;h=^h|Vd*y8_i25C^_lT=k0<=dOhTNNvh_oF)>{!bEJ5tRZiexn zXF7o|aIO&I&|`r)Ri7EPZh_BM7*sPH*Bjn-bv-*&X&Byun9rs`dHy6Pm{+KO7B%QV04z(Ow9L3 zkcsGbMwJH0S{AO}Fgk(sq3oCjwxC-ydX^6&+pXU7Z$_xtgXTpq`@Cv#^i3YBlIn;7 zsFQxuq~|~SZVd}F5lJ)$`WmI6Hz{T$;GJ^g8Koum+#pj^l&yidlvf#hkM-%hQi&&~ zk=N)+>7Tk?%MlB&gXnn)5B#6iIvL~DObzv-1A%pD0zg3=N7@I8U%_JI3W|pdyiS1` z8X$0`?wA~86)>9sSvMg~vcMm_4Ad*3Lto{5jAJ&^@}DxAv~o$g5E_rK@(0Ax^&KTn z5bC`Qi_kl*5Hr%A1irIZFnG5{VhICCJc$*W2^TO}Gsy*I(pnUvU8j)A$mrwTmrV0=2#)DMaX(hq?p|#l_!>FzG~{ zcChyQ`&EDVuICUuy#P5XLVO0{Kf&+kUL7b~G>ZZy=>0KpE7lQ) zKiVYW9Ip^2p~a>)riuU9`X4PI6WAv6 zcRwi+Y!USddD&ao`Lfqgg`1O8(}bd3SfQR`1PCbB2)SL?};Slwd6SCS(V=R z@;@Zj_?4GopjV^Nz>|??yk+@Z?EVj+OcDVduSZu3+8CG&!aMs&nf%iZ1(3JP?t$vBs1z|;b==*Sdbci7N`^0fa3 zxo<~mm7wR1e7zwF4LXV^_81kN0E^<3r@^pnqiiTpleji^f3tWfH3e<@WPIq9c`%Qr{Pml zTq2j#gksW7QwPhtCfR{%nA`r=78Z1|jXAEyn4k37r7gKCeRypmdN*ra0}{T@w7lCL zX?~N9WL^mPS|zd?6M<|G;y@+(6@f%Qn0BF4WYMNO$xvQWxv#|_Ki5$IGeVTK3Z}>2 z>o~*kWHyh>tu+`~&wQ1pHHlz_Ndk;tcNUMLG(z}ay|2caMh*al;N=KJopKasyL$s<`%{pa zLu7|zFt%1oZKUIup%i?T4&}*?}Jgt zpC8A$+>fODl)nxv>wefMQmT-ov+f z;RI%BFhsNPj9UyD)_74O*Q1 zsAW#zkC%&;ZQlk2Tu)gQhdQd(bDPWIULj&TDB zkPOc*@u;V6Sgzq)0QZ|PAX5H%1!4eQ+2&BV%*oF5*j=j4LIF7`(_LvJKOpUQG zj^4dLiPWd1y-jTyhElrBc?@gtUlk~#WY(^MC&#eDe4~d>3 z9s#JI17|DF?8y61sC?RYP_ze%x-14&DM{3+m9YBE1w5dywgL=er7``>BYk={33y7S z2DPptu&*nLhKA+s*)YH1MRJEBy2&o#>SZQP5`2zJAcuWXB;dlso98C#tCN9Z>M}U~ zv7M&MVc9YDAQD}aTlVSq&R8nCuD7^ZTD@RjvMjlXkBJx*|A-J39z#rlp-k@@{?o0G zN9(af%E{M32v@VQmovB{ zmh@ACZ7FsNpUN9YpW+~!EuJd{?%uApOed6|>9D4~J#i)81=|ij?F6deKmls*Yi&3j z1K~Btxq97lwdKd#_7TScZyEQkNu5VINk~An%lez|8W`S{a|S6YSlYp8DK;R#GKcm~ z3a!fMS?7mPrHE?(^TVzy)wn%k%BUGm4B<;4n|o@3rC=}UZ%fif>#m#$AYY5;>_pKe z!NhYGVqz>EQCV7PH8;!aX~HfmZL(BDKTwvrM;P9&eW6=6uFG8iZXOhdbOdE`8!E4h zjWG~sn*w)#qpAhD3)rC-X^a+!B`6(oK~;+&l%&>Co>D&JAZ5@72(S84=nPTEkuiwy zi~oM>YMHP3tlcK+4C&AV5)ce$D9?~HFx58{bnkMAKJ0_4N5rz|Z#^l6dqmt8>&9D-ra8cW@qH^=+A#6~$tZ_q0Ee}%4}iXf z&w{V3)ixj(VYAU>!jN>Ln3laL*{1V;PRsFE{M5CA$0~0qe{)hr0lg=XGa4)?6 za5cVr9W8MphAi;>1MSf&Ogl2a?(9M%of`@T$)?;_}Nl)g*W!M!r}jhB?g4G^td4&d`~Pr+$}y9i))1acdL=vtr` z>N>&eEbhFzGJ6C(GzC$Nf_^s#g{-oufdS@Y-2_ww9(IyulqA?xO0bQ9oapZB_EVcF zXhKgIL-MKxGFRp?NAcI;-SwwnF0`9UWF7$1y#XWAHExQiST@;zhcb7gfnGWO``XPd z&S#8JY%Sd)o25N;iR#4PIsIYv@HrCj1=eq)=3%$G+_L|L%olrb#G56KAN$<_QN7>D0!hp2Z9kYS@!ixv^&r0 z3e{7YNY?HO5&iInzh0-3nXL!SD|M(yVS6^1`wC`BDf3l;ueQXkLv^TY6mIeg$|hT= z@PXuYMusgANkzGA{jSA_Hd;a44?)2NSi>aPLZ6MWw6^}X>P!3)l}MwT+i#i&!t`KY zX|9uLQl#6J-E0`m7O6jVtZ*JnBrWxrV&SSVi%xQjay~H1aLdYa17lsm5gzyRn9YcQ zadKWlobn|!Pa5|Ktpg}T2825j@CZxzAN2vXq{U%;s98~wyJdfI5Ey?O9iZbG?Ub~U zglGV$|7^-c`#}teGBSfI(-7>Ok59M_Ekb-hc^_XMi%nlR4OuJ5v_-WQWHTk(2K6X@ zl(J-3&Tr8Ogx3%_D(W%it5KrH^l!d9A5q;mP)WmD1)-x*HW}GxAatitKF2g2@Y#3J z2`J>T4mpFL2!=9k&H7JifN}XV*TaGv5UqO@KilAG&&kckzpPo?E2=R3SXj#?u3V>$ z>}FVzhyb_3H*Ms_;CTY$?*Z#4*HnvB8V@}38ZXvEYawlrR&Mr=X!m{bpuBpUesKf~ zzfjA7?6Y*9$q&ou2m$JE7Si+W9Xiw`cez8p-mlutpu4WNc2Xq}-ThNkW4FnnQY6@N zyg=VK*c<;m14(d>#E1x3Am=TEEy2PNKBf2o+ z5Rb_};etTVe84EiTFaL+HqK zLJ+)gXZ+-EB)}sfVbwq+h`e$Sy+K7GEzT&NcdFI6gD>N5!bd6A*P&P&ISdc%l1D1W zLCBC|9h80MOFwm~Wq4N7p3M^2^wZVoxTc=swW?j95Fz#5WvycD({5S{_U%jEN{>hU zq-s7b&vJ4d2FD(^`JQHcVSqR|xs6)nrlhR;4bo63-{r*bGD|N5dxID}{?8-%oi8Xm*(m&yzTIUym1%}~| zmTpU~QKH88>Ar*Tiph^p?X&V%M8yK|-#C!L(-}d?Ycb0XFtdySyeR;cym+K-UPehd zn=#o57v$WSwqiU1W*sM+o&{vIr1T;6;{w(X^l^S;Ng)?!AQfOIlFo@=cUb=d@2SA} zc*R=6h0MXDw=tQ=?c!WJsF^=c8*~bEy~8%dBbo|dbNnM>Ib})i;)gtWDuheMUDBTX z>9rNbr}wG29?*<|oRE>mq?Av^b5-POxg)AsN&0KJLKJZqxR*R0m6s=PgB)kj`@ft@ zW(C|V@GzXVod{n-;B7G6DvkA*?;BoUy(!y+W8%H#fPt8|X7+d#Wf*$v!dMDD>#44o z@=xH57Z;6DGo~||ETo9lOmNk$MpFly?ySERJ$}pKG($7iOTAgl6ETnqxCL6SbE7;7 z31MjPK8z$Gy~>bG_^$aEJkZD$dq$dI;t;;j9B@fXsTwvpb4LSskObp$htU@OfHA0C z@&l5IQD4Avkm~3=MA>(fIbSFY8y{PrIC-=57XVMR7`aURJ_0|&;9WZ3eAb6PU9#Dz zXtSRIVDH?^_(&4UK_Erg1~huy#-}FcjkyAP25{K-Q8%XC2}Nj{V%IVaTPdcWEVI3+)X3?!qu*g`6pW7v zkZoz(bkB8<@Qho~c{cV-e&a)_yb(54H;=5me$))R@Jyl7 zI1$3lu^JY&JcGL9y8pw~S3pI*b@9SDDo99*fOIzkg7koNcSuV~OLt3%bV`GCN_R_0 zBOTJ+B@ObnCcW2qz%p2np~C!cC6Ooi(!LfVD|k^UIKGk%9fcHfuv z?{#A^zJ;vUVN#GeoUP3lNL zA+wGW7YC@n6;;*Idp(L(htfl5k_qv>Er}hA6q|S$r+7}mts-owhNSbi!1QmQ{_R<% zNH`0zXljOiI!c^@)RaaH~E1!td_XVi4Se^;vPKFdBZ3?R$?T;$7W(U#i;Y4*X{ET{xI~ zURX26iBnkRBsM{@a*T}oAMZ7OvRJEO{n6W7UFCos!NlkF$D?Gm+|AWV<_lv|Go7L? z)jGQ<(jGuDbf0)cz39h<9naD;N-Q6u+anccC~7%QFqM>wtA=H zPq5wd8@?Gxa{yR^H{VczoEsDqsWG{pdd~b%yFLCchM_i~J!##<-g{oflDPH$=-Xgw zdEwvU0^==1k6p!}$z2&4wej0q=kSSQE#|#b2Km3Sm+wAJ85w&|U+iFTFPDItem-BhOEbG42v8>*Jxmfj2(TQX>o&BqT6f0E+MB z>igqoIe<6>@OvRH{qZLhkU80mS#;y#)d}9NwywihEPE3p%m?%N(=z6@sa96uy^Kz` zE=?qJ&T4No)&C_XE+fCNGcWn#xoD`mnd%;+KDDTL+3?3_Y^>zn zSUPsn7{0E~Y`wD~Z?o22e%xxPg`u*Z^b-2Lb-y}%-K_-q*eQ|vvKgzU;vz{R{%`a_ z+4?PQPPjH6T!+@TlRD$q|Ag^CkrgK#%&89BkX?o6vRd_a#@d^TiGNj5X)zTlK;|k0 zHOk>b3Uq?cUs7~<)K0D&we@wSRxRfl^S-W{c z@&mRi6qA+=0stc z_Bth^O)c7{|0ib$F~|~r#z|)ZMAk34fIPU(3F|drn**OsbW9ykf(AZ3Vv}U)tRRb+ z8`7q203x^@*b4BjUkPjjaN1a#=J^^ctvAnpe6!vJH{t6mxiST@n84q_uGX~|;HY~C zRbKvYplZl79>C|PgbKWJa5hA@_aHSO5b zJC^tF#0Fms4`R;V*`G>V;6asKw(mZ zF$)ySn=A}Y00r8R%N%zjwh4TMQZT#~1(D^#3*b-XtpWu_QGE-DL&Hzl;;gzj=!6_t zhDHMI4=L`Vh^3RFIc^$;^{$TA`6$W{He4N-5KOh_lql9=++#ZT%v%+yZ64nrp2ba$%o#|A0 zFeQi}4jIR~G#;N~st~|L*y=v{3g*FA!osir^iMDh2PwZ9<6*uOs9}+ABgLxt0+A4$ z-q#XA^@JLFb)6$k-Oiecb=bmA~vyS{llTn%Uk))C=`2X@D!$UM+wVaz3+^TpkdeJ&wJoZJrq zE!{P8U4Dn;Sjh;v|U zrt61S%JD7F0-Rfv=!p2Lk}2*vDIu^be)Rd-aD3Fx~kx}u;i(%WUg zr^`9smzb9*e-5rUL`X%EkF1t>qrP^jmxJl#hcu!)!cj#^I*aQIrGm{5-K1p9$bYf~ zDkc?kGKNWMrJZ!~b^v;)kOaLHi`_VLU;ccx(3PBb(H@MU6JeDcK z2WtIPnC%V>R&JwN?r1Pf67vht{s%nk((Gtu9`N5KVHrTLEs)0?3rAEG1DH>?@eVYm zR3KnwEP<7`M2$=J89*m$chXkZ8Kn3EaD9a_6e6M28N^4>7T3N8BoT0T`Och01i3UC z*H?+$C-;ffy;4I8vob1}W1kV37P9goVHdpFw{fV5IZ8MXj>3rtx;XEiFhF|ceQY49 zw!L~vaSG7r7@w*stko8&CArWWm27P#UvpyTs7SgpBuhcx*YZOAOSWGAvHY09h=^ic zmzi9Q1;4M#qQa_BI=JixAxZ9@y7bl@npEri7!Z4^q7D?lNk+GcnAGiY1?Jld;h?mH;r}KJ%twqvS>_2+?ie}7 zH)!lPB~qBX(AbC+VihwPgi6GxfoT5~PrnqcBo($O7{V+hu1U#LtZNpd;?u9Y;JAzx zKpY>uM9ldU6$RQal%|Q7Vk0i{L!$*Ma1iQqg_!fVE5FnM@YeoYNQyGO0>NB< z3J!M#IT$cXK18wNGFZydLq+)E(1A@$rZy1HCvk!93|M8;3+UHIOBrmzuqNybod~ffsYb_X z>gzV_U}7Y5Q|_~{P=p6Mk3Lg+2sVM~K!n4lkNZ|-Ki+^P3qhQHlJfQCFeh?K2v`Y{ zu${F}&RSF-XcqVx?7}B3bc~F^?~&zwqUce{s62#J5WpH$BJ*h*=Sg zm}?6e)tBOEEMEvREo>R-$olIirMi(PxGaFZ)YG3jec%Dz`|@4B92gu|>v>vYFjJzeUpZa|fFZRK z1k>ISIdj)uh!-}N0;e)7m0HGRV@=i6f}2^9Oah&9H_&b{2FKBCpWb7zPD1x%{aon>@XqW1^v%5{vMdXmD0~#MOtXq%-UOgZ;0U`wgO!m$e&=mylT1M+Rb2Iy7?Qd zMFlMA7Q!2QGfB*eXPLg{*Ci&MNYrvWu)TdVejMpPo~7>{^$#f0%@#fMMpgF7)%iIocpWrZIoqd+yMuL4eO>h>wpyS!ZUbwGpPlp1=!O zPJUPS)7TMD%X-p1egG2UW`JZZxICR9{MKxkxXV`Z9W!Va9|)+JqT}d*sW}VH55=r` z)j(u53IvLyBigR;QmvZZ7OPa-o$^)3fFN#FTsk`FV5xM3)a_8qRjK=(hIg3AAJLe7 zc^Tu^PKq_k-|70YjgF!{Fjx6nUtfRz!~ZVKYMnk#=gZEk!nxBoY2|_@w`QiPPMMC4 zCy$a}ow7K~34&>IEQ#HE)*R8mM{M6&z-iaX;M5OH z`F0vjPtf2Dj<_1l{tpT`rAQ@$?Fd#`E7Di|>Y?zA)$JCRj$_$nnIS zCWbiV_p@D{V}yGCnnwOr&f?y;0VhPsZHbMvtk>*XeQTbZ9g{~LSS^>15i8BRDJf^s zs@#w*zBhbuGGqosWk~-ZDd59(U5^u9g5eV(T}H}&2&n<8TJCmjS?2@xcb1nUKWj_| zXG{8yRqjnoyzWx>noxLV*5q@izlwg|FF^F%Kh7g|TK2j=#;cu(K+5Lv{V~Q|f%1xf zwdh-G6=&n2c^JXr3$iAjTC8P!Y3YwL@nXcv`ve+{7mw;ny3t?lH4v-Mbt1>?-E0HY zs!@c6wbN?_p`I1joWA?8$VTjIOhEU*gmBmN)=V`E9uUoyJE2)j*Li)Z;*6INhzkZQ z+Z^+C@m+gq+Zo}WQQY*#*ZTiz0rct>aQG?2*Tv<>FXCfl_sdGv9ZC zt4n3B3eT&!RI7*@t6$uA!LUN?A2kE-2uZY4>!;~e`^&zEPYb>yC>Y{W>|^oe6*yEG zx9?&z(49B?jCW^|A9K;LO1(RFgJ?18fM?U$m^$xz<0+Twu@?N&$+5QoYZ{3T2#w#F@SLni6dTjY3*F5ZnW=UjG>xk@?%>YDF(n$D3r9#V>@VqRepuK%mY+Xr zqWD8Jzifo()jMijb2@}Z9ys=?lMD#M+a9R;a^D@rI0JIZYps)Cgl)r@opl}~L_a4msbpEFpmAhiX>0a8+VVUWp^GeLD$6DXTcsIMI;G1bL zmW%7SMfZt&wp(W=O`TNyorJahrFg3C_tyI~QvihdgroBJzDa=`%GzD$u&qR6^px<` zk3U~tj)lFy`9$F$IC?1HZZ?2YV|1+KzP`?Ns|?pju_VJ7dc7R4JZA|!te0=;RU+dH z9z-n(njxoo8+-F2kC!O->h}-z68GBV)T}J8tBOHkS6#~ePPhf0t-FO3jbVPgI`B*dYUAoWcrqPD`5+2X zg5F|Ui$yT=96qTHL5TNZ5xAF1zMe^NO=zcQeGClf9r=!5+#Cm`TkUL)?d1|$*IImQ z`RO+QtH zW99Q^?||A+e>`*L@*6SDRvMBjnl#tW5&A2a4oW;-!DD%lx!x{j39qy2BT84Yb=mPw z7Fs0ka?Y{{-V>8~1tzY$$$2BgV45-zh?yDUjm4zp?uX9I^Sz8ePUrP`b0c_qc2sj! zwlT^y-_&bM=j{w_8V|0EtSEFzlCbE!Z!gfe?!nvW!&q ze&(01r~OA>+~S?<_Rd<%&A|IX!m|kH`I2fhl2<=8)M6z(+=&m|BPt)*OMfE_rL*wY z^_aaDybCTTcw(>y<^?(S^r4SuvCIrxVAM*tEJ1xZLzP^4d6nh1o%_l$;`wFFQ%#WP zH?eM)9(b=-J2!E<=UR}Y{46kB>vW_pMau3{wT?}Ehb>Y2q=vs#@ot0DtV89-_WICZ zv|#Jgsc}dum#B;}gx=j2IhH|v@_f$Q2Cv!mvq_E1v6A{ssYZPVJ)rkR@SkK8xr}%@ zbt>-bJP##l`Li>(ur=CR6Enr`HAlq7<9!FuQ9 zz%`a3k>2E~4nSC$0lXcC?Yej5^~G87Rl%C1YV(b_ z{PZal-4eG~jinayyLQW}=Rbo;HdDvIHUNTZ97O1WtfuDBA8E;)0tXS&3FNi4jcMSK zQF8F?O@8e!r{?`?XD#>ZPrk12osPxY-OpNj7YJ@DURf-3UJG)P9;P_0B!k%VvPCc_ ziTC3HNKWR;43fjrV|Th7Ut&rKK}6~7oaAbLjxZ_LguXH#AJKhroPy?J9(h-(e=4C2 z=os@@UWN|BKjX;2cO+3#AFFr( zDtI2K0LV1^;~8l>Q>*65uMMI-1@FXfwtMu7dtPxh;wTE4ihh-fV`wnE>l6fQ`Pe%` z>QxY^5>)~lpILx<&?%gn==wXIG^*Z5xt@KilnQSSOx>BP3`8TG?$R0Jnj8kMY(P25 z#8j){1=M` z!>D_v6k<hlBgTd4snPNq>Rx&fioH$XI=br#~vWAtW!_52ryKdx>O3)$hLz&%) z#yp0~R&?hv6WP7g3%%Z=;HNy7FlU*J!DX9wQyBT>1i!XZ#`eq5gX%)QtP6{^@^sFU zcm<)XAHAUHe~5NaGSw#bf+QY@7%BVp$C z9}h-XOBp`-$ir~U<%Q=yKmpe27}jRP-~o_NI~fr{gkSk6Q4x18!8w;;O37rvRvP*Y zZsz>XKsro9B^x+kJD=7ozLXDBDvE_$Bdc@*KE9IZiyN)X7obopoWlx|w_-ct$IY`( z=x#~#w=j_`c|8qR0~v1)yahGpd3ZIuo~U-n^wQosJoOII{P?+_R}NmYjUmMRHUrZ^ z%_Qt!FO*n4W2V#lBuzRsT0Ed;y?*jaSM)Y(qPQhXwNSyT$Uf5mg@^MF+c%anLpXuc z7m#X`XP@NA>P!I^Gd@{2@>KD(k$*a&LD)`h+1m-H5PgTTqeo~D;;pao?&0axJ%5NR zI%Y$;cK8U<=>Y8m@<`i^9h9TYvw6dqp}F$u2Rz@h#nK{cy$=3?gzN?{Ip8+Ymj(t!wJ zBfT*+gkeg9GtBt8e=}<@q!BgPkH`@s!3!gI`>&Ux6h39mKyF}_pZ2XxfE*`C=)f&| zypn6a1papXh>ld7V`4Trj7o;03IOe>4R{NzOP;_B6e6H89gh}ydGP(^%+#SZ2{7%R zytITeqN&<^6?PimMipBcaPceQnW;6|AG5nq$nle+O`DnC;N$+5jwl`c#sTI5Vh++w zUV(!EJ4{)~ea`;WDc{BYl{rfsGLZ9FZ`6Yr=aGwUSy{epi73~PQ!5f9w1ek^W<3^D1>+b7$~RP z@Ap$1`v9>R_JVt~1&E_JMR&^brzcSCcRqk`%pdTu_@1g{gCwg=A=4djNjaVNGzfw4 zBph97Exj&9mAoXXb}p*V0LhnDLIf=G)yY~LJwhNxCksU8IIVweb-es4OEu6aoHgbO z-}~V8Y=lKYOEpr52;dag4dgOa3sr2L7)t^5pZ97l27rz2x@%7WG)R_=jozFb;}YO1 zt$;!%KuERD5WDXgjIRTY=W@8^5*(v8)lJ0lK9b?dCUDw1LCU@khaRYSL!`=X+l9IO z&VVngxk{O7nrkiyoCk-1QDxEF>cS!;cuTRGDnJEf8bhPSqaF>PtrN}|R7cbUfOaQ9 z9i4-_<9^0tsmV+Cn#Jf&?4JONH&bPyvT}~9@Y{r7e#BX5wfRH^T;J8H9pIqM0Z^zC ztYp{RbW)K;hF{7H_v#*Kw?l)ImFWs zS146K1gf>ix~O-+4_s+j_icfmBA$#n1nyx)KL+P$_WcHw&l-Rcg75q#fDZ2jcLa{3 z+oX|8`7+L^QnyA8^N&(Yif7WA1tNoo^!oIRK*&-PD8{6G@Lc&sGYiz948c#Og#`=bPo4q19EB>NUOJxasPLc&Ox!-e@fDls_o3RSUL`9kJ8Xd$| z&IdgU82Hxf?n`KjJ{J!-0j@xyI3j=ZnMgJ$+_|UT#>CCdt;IMu<`3YtacuN&5Gv4! zlJ-HtciP}!ey%{jr381)`}t^cyw^`6XW{B2R-N+UIi>EW0+|9zltLNI?km;;HrXck z;up!rCMFGmOMs!TONy>C0<@nEK?jTb8sPrDGLB9}p!fyoJIpGWiW525tqQ)l5@5Gm zf-|k(S_H@vqt({iZ$9I!>&QU@>!GXlX9#{ELL5b$(HG@87tHXZxs=Etq)u)``X#vP z;?`?=88v_kGcWW(c_Rf+l%nGh#3=3U?Ln&aB!Hg$v^kMiE58kh`YMu_fxOAoJHM>g zu;@LAeFD%*KhS|YYUj~kThn-yKs*!xqKpO%m}IQK9QFl;KB;3}#ubCE1R%uGO**0^ zlhEs@opl7Nzy5nC#tCsy7?t}mG{mg(bFxHB{rz&20y2Fh5{^H@80k-Q21}I=u?l&G zX$~CbE4VsPi#tIjma&nM1`w8L!cii#6Ef}#V#GkgA+PcahTUQ;)#oTNS%$kzqVN_f zPjle@ohMjfFhKY(DdS{P5HyK4$NH}p(6eOpHBRwLmKmb)lO-gOz@WS?T^mOwX`hPJ z*WDeN{*M|oUj~I&Jx(g&NQ(+1=K&Q1P&CfS$35DcsRVV8YpTSDIiUCr>Z;-h(nA0h z&Y;qQJOzS5;Q&=q%;0B;A5A&9^5oNXm#6?r+PQX(Xza%m)M5lWQP5vf^9Nga@qNF+ zQl}pe5CBvP>7RX73LZGLUdXJqW#A5y6KH-z*gusue^?ftbDYvaK`lZ64o0~n5NGS!g+S`C4|<}JHRQG zcQhCw_Hz#KT8lHUfQk2J@-4u}?b45d9d;djfV96)siF#m@y7RMI@keb;4UmLuYrzx zsOjAo!*JU%Ch|w)$bZKU69TrFhGVN2+;-Vo)^v5#?|%Sf{lJ&a!6#4mHfh$NJrgZR zBK~b);q9j>r_I4-wt)K5yYc%!)n(f!Gp6Y?fZ_5Uj!CY5|Fc6drvzyY9u5Qv^HPcW zL|{Go3f$*g29+d$*Y{uL5D-L%RyV+96IKn?l%~{pBw?gOpMA>iI=EgB4Ak>m<5VH=r z|CL}O%mDb0wLJe>EZiU+E`2g*Kg@3!qp0)h033qhH(IeS_(o_4V0XfA9?Sm)uvK>l z-yHyiAK!e)x11BCecccpZ`i)QF$-d`_gsq} zmF`X~&A*izfoGCVk3uSshl{PsW{W%P2`@_fK|=!z@mxIj3JKKx`(zlZ(fX?ml?xCTKi zl^{iGLMsv!4pxwPbE8P60C-oc-#cmbvr#UExkyAllA)dTgi>3ug zC@s{GUUQ;UCFjHDXuznT`*Ocmw(i<-?6K@J`C$+HS!Rmo?d$l@hLFA_5V?(F!6G+! z2jZ{O4&6Q&a0g|jF4baQc8{6$)u!|KgpVz~o|PAX@ZnWG#E;Ch3SJ6T7-V0bI$M?+ zY(pDH8b;l8jh_bM5t5*opo4`IC-w>BNYL8jMS(&A>D7mggx9wD+E=g@Bxyc@n!WxU zPQ)~lw8t;PnCW%swbPRQejK4*#jy-i2s;beI_N_Ekl*WpOOrLEBead=A+D5gr7y8>^@ z3-b_cT!_co2bBz!$lqd0FUc=)HvBrNh;bPT-*hs`@C8W9LA<)8DLzZZnr5+5tzWIq zEaQ_Chw+_D=CK~b535+83M%+z*&%ztlDlp!CuIKtlx6m@M?WT@VM@p|A0v;biG0`~ zKK1x8j6#n)jBv)Uwd39~=Cq_~0A`33oNO6QUf>}05rITPz=<+2<9iTx9H~I|C2n`r zBiwTOiH;GeAyz(?c3c|+P$rRH@2~t`x!JRtxaRsh0&d?qtqTcZ0lIXsdEyuTHf)RA zU#l=B9vBRekZsNpr{tbv$AD)JBMP$*iyBA?dCK#pA*W?^bSeTUFf;tbr^<6tB=gDm z{{Cya%TZ7nE&phza?XyjObJtmlOlsI(o65prlCUwX+*ak;#~vm>m+|wcZ{GaDRneU z-u_p_H;G+O4L;cjEP5@rW-u+ftdM;;-e;k08tP#|TK8}J!OrTh_L?sbhE{6a#KPCntju!3P zSCyv7r7QhE&(K)Ygg{FSWp<1O(BMWK;P$Z;GYw%MvE{Vg^muhHj6_)FJt5@&!%##| zZEKlrM-D~nH0IHq|DQV+8M*wig40jfrPiBQPplr}Q0oL>`rd+YVJISeD2@k_9`=Hy zY2-77!>O-G#))7>ra=eMsgS6~<^#fmrrT(L1T<%*&2zjj&Kos^H5(8xNM|L! zG9rhhzDN;zDzo$?Ik)2z%mB258I>x4P8Fi!<$>{CCpLnVWD3-q-zvIQU^W!^Tulc` zt9yNt_j!aJR{kOGech;{<|%3>Pd7U*Gpd(L8=v6bUn6e7oDD~?@&Q)^&le9r)FVA> zK+#&fS#)kWTON(o^T5hT{h~Kdl(Y+sxbTU#qTs8-bv6UM7ievRRT0e*r}ha0rZ4=u zJ3u<}30`|h1Ubow#IoNiRuHkQTQ`O3c>8j7x(4(%5I3x(V=d(fX-j4Dsw)$5gRA>V zOlb$$#o!xR1cD>Cqqo=D>qUo_eI$90U6ejFvr&OBe6AI^x%}m_ZYMyA>yKwnv&KkQ zeO?uA{V*TiRY2Yli%im0PNqFM1{|68K}BiW=8Z|XteaK2=hdIlFZGMLCR$;??)JYY zn2HZPFzEX>H~)4*U`E&NT~ZhcKf^nXR>sZ(_0nd~>&Xtt_iNj#uz7n0obyGGx;_F` z?goVmN0)n+{RlI}xz?+PHAe~bSKU{8`=Z_UY50J!$d^ka}eq!GFPC6VS_I7VTuvK`*m+;H@}w=-ieWAFr6%wi)11 zf6t_KsF+_S>RKbgOJKd-Iuox*9f_Kb7bgVDaLC9b)|dNp6Y-Y_fTM{4CB$PMQ ziZcH9>wo`J#)Nn!0>C{7Tji>K|NlS2l{q6-G69TXVqXQGm;8S(sqnV*97i!vvin$}4PExpMgX{tp)uW8P)|_WAl&abdozequCG|MAC~1b`oZqB zTcWdn(m!1Bm}JlR-t>@hDZ6l%_0IxRyoLr8Ij2!1n^HzW3JQ(8McQUI^L_aFz&bk$ z0~)KQAR=TY1dYYWHtf}Lx;n653a{)>oxyid{J53vT!Gs=Z(JvT>Q@{5+(<_S_0P zmK~U)UTtN`6{6GHcZb^2FQOCuq1nn5!^(2L-WViQs<-QXZatJD8B7j>_sFs`>yshg zZ&J0^gFrRXE0)*Ux_>0|Zv98p8{o;(tkRUEM)B);0H`kcR@p2{U;x{3272_JfQB#C zdZMh{BI4rxKcf6`S+aTUH?pZFo82!|p3jb}u{?F`{=rM`vl&EE6aBVY7qja0SG_m% zzEGWoM!i(KBgd|;)$6X%hkb|VgFe^Q;{8H=izn}ojlo@q1*>uXQdP)ZncJBXkkU%C z19FMavShUOzn?bRt|tB7`YDAsfcN{wzRKf=; z(e}s}Bo|0)s+&WyRE))qrFbH5-=(odwIhWxsatkc(x@MyEt*f*hTmAtagw{QJMCS{ zC3sK75tln`cJMzbrn(Mg{@96%*UCbYWCZ@9;RjkSjMB6Qiwosq+M4CGZQUNGXAs`3% zz!9{yWj5nJa&EWZkRn$!^|J4H0_*|pB?t=E_Z$8tblT6a9n)gkY z+dF)(X=VGutkXc6w2|jM;w&{)dT0Eru0HzZYURm(ZBe$vcEZ}py7Z1=2r9E)3vHhK zJrkh$V9Smls*P3Pe zsUJUP$Aj7ZCSW+}mCzF$T5=RTFN$x?YMQxnM0C9|c_V@wgO2wd4T^#)UF_(9PpJw> z-p$rcgR#ii8%I0v@nH^weU)5}k(-)a{YwvUgpOyDOQo{?u>|6Z&8UuwwcOW)N z+4AW^U9WgAudYyXjn#|J!>v1qMtHdi^3e%9t1on~uC96yTMx%}+2#A*H&>Vp+MQVn+!iLnm_E6>cmtZ!Ni) zmS;HxOr?|UyjA1T>;TZmLN8-$fL!;^mD#m>m74jKbw;}B*2S$ngc1g!)c=eS+R_n_ zu71+0n5EW`ax;O2yLdRw_T0C8J*33N>$-M6URy}u9Qd;nPa2QNG_&hx45ae*9>l&g zH9kmW&vUrq6WxCGCQt?|OZml_ZM7vxTR*}|g>`eJFRDt12gV(%FxgB77&WWS3-lEb zQi)lecpZ1L9CA$42Xl9cvJ{AtE1FFP8%}EZ&Sc#fj}~qC#>s>D1o@qO|!eRWBs3U=Eg=^{-urp`$E~I-0g~a z`M3x3Hha@Eh4#O6U2BXQx9-mm?^Rh$bN>vqjGToW+Z`_O&nMhVl3GJJ>Q+rUpUYwW zh{^M@)-R1>)U4=Nmd{COaz*I_hZkc#4vVfB2OY{2@*lwl-{?mE9(P^ z>L+WxEErBlK4r4W=XBaq2ftj;IPfOKf3GJn^u;qR(t7{ah-bNP=))r(7SvPf5}Lia zpm2Q9%-7^dQ6GGbQA8N?z)i?vJijO*Mm``gAZ*l~T~I;HDUpq(AKaX&{;5G{tph5z z)a~uPagl{81%cL)L=_@j7OhlAFC6iCtQbeEYV&pD4yR~HtQ(Ec z!>iQ@|3Y;<;ViWhHz}7_??<`wL|C~)R>{@ZteDTGYat}cNf{M>ZmMGBhOF^AFu&8FU zUtNOhguQU{9H`Vu9k1j}xPP)+aQ{{wV)MdobLbn7(FYQB*RGH_VGhZ7#>A!O@3auU z+q*l*uFM>_KcFBxCjQ&NhvMVEJ98+430rfn^Lq-^3KAZK(&ZO%?dL1Y?l#owk*)lX zuL5)4MY3F-;>Bar{NV@-k5U1Xu*I_x>LxW?wH=#MqH)Y5y%1SY8oN)Y9EfB@hB^&~ zk(T@M%)?beyVISC{tEXC^!e7{(HVs(AOpde|G0E{g<&qL2ZbfJTQbd+x@c`!Ph#^b z2>S40?@AY;!_4j1QuU9t)SJWid8WSnJHa0vcfRyHb@uF4L{s(C#SbPsN9X6$QYxae zKP=j9h|az0(oAET2@hTHyzp)ih!RpDVSUJTITi)ehQ9yMBO1Ichh67>5gv+v`YFjT zz-*R~(}U@98XrGLBC4YfM|SLY8SOkmOR@KRWvyG=C?3cB=VOU}{v~6VngZFtpYEr) z0~cun2p@EGJYa`(SfNCiZ0+$f4%;fek2NnX2_qgR*RSq1wLa zt2kPoYhS8?J;+$4K^cKTW~P~HT6eSNO&DvXz00Me@gAYU(mU-eaRRYA+XzJga zzs%X)z23;m)(-b`-88=3iM^_t@7*Srmv^q=;C-k_dLpp#J-8 zn8Qq%X)3%=-~HIK7gw5$lUXT8$_iPsfUu<2dcNwHmL81xZBM|9VCfBEHLd=Xkr4&y z_|o|OK!J~t+uPeS^ksc*`pvuuK5E`%sHyWb+zic z13bB-yO#%bNaf&LjYucb5Ek%itFaaljHHt0%%_`;W0(qM z|2#6{V7II066(Tbt&RQrw)-g5@${E{*F+G$MKJ67bN;gOudh8m6ORH*3W;=q^x#$j zsZSrdY!)KP-dsx#r}-PtH>4Z?xvf5`*#+8HMYZdKnI8MIs-7aRQs+6&A(^zWEqvRy zt~$A*i0j4iFo{)S19|>9Ibp}u*(93Kp6@{yMeoJtKKMs@%eeMbXECcB!rm{o!w>Rk;r)v+l)6rcYoS9#H=W}?x0w^I}cC7j6&2g2`)ikZ;)dV6u5RUfmB z*U9yDeU)lWAJ8^Tu0|sMiMj+3f7EN$T5FO6D@$3OMF)jPJ-Ea1+Q+A->g&%RGm5g6 z+P0Wc=|w$WBe^x?^|;5hzICe zniOd8u@uiib(fIu&~}$-WZ!1|4k6}$G{e{xZ}}7%`BSE|FGHHIrkHJLls zR!z^XO+v69Z@TT}#?{`HDEzq%5FO*Fci8q55WZDTY4%BE7c9!%vIJ%+1fizIJI2Lghiz@mx)0Bo9~Os&O?h3di%W0%J#kp_ z(S%;oJwxIU>2Y&23==pQ)K*Z49AcDm{%O+w^0q9k|A)=)q|HNRl%LA`1MUHJ8s7p! zfqiu&xSUngZ(42sRk>+85#zl%WL1rau=0g_&G$0NF3K7vbn7+RJcxet6O65a%zBO8(I_?{2B zR=F}BSk-4_7-8XWPfL8mm*=x!WC7HNfHe7!v&Fb4v&DSlgEBRSA#N(;o~fJ6I^yo6 zBd+h9bDv*zsS+DE3Wb=eV`a4OOC=3RW4dgnKB~}fcW4hEkD-Z(%$1#^%fe_5q4x{> zo*|UAmTaSzzdfhZ;6Z9N>k#qsZc2>Jb-!B5T=`}3W(_V4^ZkRz=d?nV7E|(t3;8!4 z0qj)jrF_vWdP3E64uDWbsa2B_O(AZ5b-9|RRHm<3EvfbS*BC1 zidnT#i$?RQQWA=AcCO1Awqop#q1kEfCgFfWsSMJHrvh8~gq|1Ko;PBnWy@Mh#Tsv&c5?mph7oTfMWJbxEYcYqQgQ@kIcasE5Nf?g+?Ud#?Ar z%GRoVW}aYOoY})uCElK!2dtt{CjEhK6TkIVJNA>;n+ zL;~bt8g}s^S3k}6tp*!%Bm%O_BVV_(q}~u*l!vX>6-K?YewR5ME(n*g^Kic7^}2o9{;hdS^4)DM)!fVH zKWp}b{N_iss`9haltDyinElFng+8KUp0uly0eNJ}iAr`O2MLGitu~45omk-0bn3gC zr!icM#ibXV)=Gr$mRigwoK^T<6d$sic!&j}B^MHk>1{o_MlVp=wi3bg@NmEQBcij4 zaYNjwYe=tx%&>}l)j=!b@meP0$*8!dZCKb$M~B#oQkfPH>f3RA+p;mP9kigZZjM3u zGE5XFEfP-4khbYmHsf+;95E!$k6Kk*T8S?W6Z=rc5)4L`H|{Qy^XH4oSGk?Ug5Du` zkN2zHU|Mgm?psb4> z-J3F$-IH~#-*TZr$v??j62HG?a~KUJc%@7&r=3B#)1}J6N3n+!;g|HV9r?mFag+T|MaXie+2bJ>xsP|<#hYK3zJf6AJtJy1p)SC@rUq5sSf5H7m z;KtH#!SycW-3bsEAYqtFvkYQ>?1{>Te@$Xi9uSy|TebL>d5+;}99PW#(fvvPpkL~o zEgIepv6llpV?(pnGTJ)CgdPc{a$1El<5+O>znY~W_#xF0i!j;#%2Gr2u7)S~$iU6( z=T|E2w~yFQQ6a@t@I@NwbAi#8&&Rnf`q}B=7q#mNj)FAAR$d$;DeLpdSxFEv{=O5+ ztjotzZQe|tpr7zt|G!!Qb7}%u-u$)#2a#p&7xCA$mJgJJUUeKOh^tQ+^u;RX?psck z`o7?GnpW-lvf;mddRa2O{QY~j)!ZYHZ0Qu}EmkfPjRgX=b)>QuFnYQYJ{5PFy7o(L zHpqV*$mYsBOFVA^PX@X4Bx|kj0`4W+bdbQxOQ30Ydo7DF=EaKkLOG&*CU6YDP7xww zoX%mEnKb$ACbYoVT4lmTJx4a#I(J{Bv3$~PDCOIVPGB=?p;}2!?uKC^?3*r$;JLlS z`6z*bMzqhiMK}L2<&q9`ngHvF81jWVb;Pdg8B^bRkQluAG#jM0As93Lp(7ce$Yy)tzBx!ARrg?ktD2|2gSXV!k7~N&HGGY(ej*_hn_*@FA8)aC@UrM!n7c@N&F%CXEk87LSz7?3QHJ zfCcTl_UUAM5Tsvo&c&GaD&O>%5Go!FeK*{}yIWcY zieB}30d(`n29++q5kUm*xkM%?iJf&Ic-_D+`7W32zmfPm9zn>!)YpXt4Aa65u%G|G z9>c|XG=UkiJ_RH0mS_-A z+0&S{nJ-S`ckcr~#mz4J5Xj`ADnJ|foNe|`;U1E?hwMZTf= zI@>pJBu39pvr%t!&+noh@}H|O!4t)RUTY4(-&7d(pyNK3=?NpuE4BT?VHS-_z=4$D za7@$oB83v>KPRaldO!fdrjd&Ub>Lp0*l7&Z<0{_&B%d1nDcYCqb z8`XQk1qJcKCMf+zJ?hnO69~Y4N0pVaCUV)NO})Z?l>V|KV(8&-bLX9L$x@xh4M!`- z+DGm1I%gFC^N4WBDx*`-Zz15b83lt<-okw0z%_hBML>QHBlZ4sI|}ryK-JRsLHRsG z$QjZF06b*_b5%c01R%NyXtHkat=LS57-uR?6UOr78S1~8B_;WCJ0ED{^Sf1DUj5uV z9ueQwoZu{ATI9o~{Vk;p*-8x!35gC44(?=n9VG=uH^l?E0Qo6S$qU}8$VNzKe+Bl~ ztUX&!zL1CGb^!pyDhX_C)`2;2EKmr%V#MQ2fp1GqzOdeCs&#;ZJKxIHFCa3}YM*a% z9m|?qL67Sh6&Y}Q?Rt`JG?=8?>$L>|^AneGT{@91hgT)W@kkLOY4+iU){b*76b3@N zHGoDl5h6YeG80fYHl3 z$Miu6Bq91|movrk;X7NCy9Vy%MV=!1&)or(4Ln|cR1I>ejOZIsD#qGl_~?ta z^){bi^4d@yuXw$?4gGdYf|L%N2sH|uqT0|S#755>r_lErH2%78K6Y__!Hfs{_4DIF zYcO7vml%P8fk_X?BA_p*eFl}B4i`#HaGn$9m?cpMJi%2WJjlo+9P2x7;ZC8W_-A|N z!$f4CU%EcqeYb^H;}BB!#6KzyB-eFc>#bgk8P3<(5v!Gh2OzBpyx?3G?cq(zFiQfq z25+pklELLmwKK{sNbup!lY6og9=jcA8-mADikb)@`h~N1z~xSnCwZK4&t zJ@S9T>;0!mKfz9BS(TU*9q6w^!lwkxA@%`wmIt_YV>thaZ)MYX;Si zonNaof*OZ#I|`NqeCLTgg0k8*0t{Te`$Z`|DsRkp(hj6o4v!gY*~aKpj0hj^$%KWe zm50xX;nZHB|DUq1JD#fl{~OoJ9_8AEkm$-5+1I*AC}dobGBU~*T_cj4S!P65HldW% zMMjbxCCMyQvPY=j>(Xa^e}8lz9^HG+J@SAXo{?Jt$C^n? zqc-0x@Orc%h&Ci=3Tg(wl;EKeQi5eKI(9^wR;$cjVd9IzLNzV;Y|ZOc&b56R8^hKr zQk0J~oqiD#3=d8;_ONVUt1r0t*)dyX<|WAx9Gk(0%X$3f(1-(T92A{>U}#H8hs+*! zr6#R#&ZClrhvvjXxM?|KtJzVl#W3#vLZp~4ZxV%L%qnbcTn0;vo;TRr+ZRi$dGFib zIETx(+z{)9#e!yqst&R>En60zy@tlnG~Q%)VZkdIz^C>b1cfuCv3$x03s$?s)J+IR)9(a=U=^X^$XMZ+y71C1UR%8E5!!>%~5Ecdp9*cJ$m+phAfa4Dak8z?&FG9W68>xFjl#x6I{4($ICS$p+y zIUD7*h1aM^zER<4$6*0NJ@Y>lswD^!LGQ_G{vX1GUoXm33tz7i&Z-B9g{I3YCl z9$^vmKO5O&epsj_c*(`p$wm!u68{P~;DdI;@aCC&${!5Lp6lVt4*h$B{O3!FXS`vE zTmSbiIEukhK9*Otd31}o?%Wk1)cyNiN#c3)6;xEKgZ%CbAD#>SX6}aq^B2y3wc35+SCY8?sjO@JgBJ$99#V7 z=pymQmkjDgdR}~lh;A`R{&rSvbNxzbzmA8&#+|MC-&9?kPa|L|q+nOFFp0wJtaTTb zDRe)Nc*ml2mup^3i7{hrqZgh#iZh9d^=)jieI1xx?Oq`te~~9b;Dk|3W$KY(R=sBU zkey+r$fH_iXDn?bbjkblQe|6vTBS@+_06D^tUF>lxL0yB)^!5jqKNg1n1&-a~MfV<=$UJL4NyVbL@cM(Niiz1Gfx zDjN|L@6u1&z5hZdNRxGULrqvAu=;Q}#0~`REpYI2{11~3X8Z|MN3O%T_yw?(Qtd9w za5PSy1)D*P8E}ZJ#3&XD>vqWnH-=FxwXoa0)LjDu`fDiNCKAQKlL+N-+o-p|Wa|je zMu$gJ1P$m?oIW5605Z#-zvdA z3=NcxdQ8~3xw!@D`t&mNAM5=~7y9yP}!3uD%9Xd)n$Z$n2!RPWJc#_(_#pT_^b(!xAWTkVe z&naJ?(hY$2bi}B^Y+X4XR}JgNaRdCKjXuB6+(2KwpNA#%8ZcP)iRy$KAwpcA+xGL& zhJ-Nw9zmVj?$zO=LEF^NfZ|`y@c#r#HV4W9+;KRIi8uk^<%xow;f1b8!?G3}p7 z866KpChSgn;NJt5Ki?@Z%;*3k!6bf5h?zy{4RoW;x2$&3N87y!vDr_x=~%!HL&w*b zqe(RjZsyK=s&*~1{j_wOv9Z+nL8E&oY&f!dq#;SUuunY&w;g3mk~t22+B*0G8)33h zJf-qJfc%hE%nnb62|N_VPUwrnn(uFMq(WD!L}&tlp;N)gD#wNwI3K25kz8nzHsw{0 zC$KX4UnEsl*El3VdWKo;hoiT5jTRdH^svF>cB=j=GIH{_7sU&jZ5jg2-_rKaVCjs~ zW%R`8p)Ue6wZ_$f-k{&mj~3*{vu4)SU~!`5t!#lP4@CT^gTVb5ky0UNk=Ml$D`vS1NaTo! zhzG97RTC4FFk3I`Wteg8Ab^(9U2?o5ph@|5E5@}`vhMQqK1m+mi>$+82rxf4zbdny z?zl4zZ3t4}`JlzSdb?$ZS$r{n=%`m4N5aOtk*4S!$loyT8Rs8cpkuxF#D_)*lPJzc zXRgHO#J_)V4K!dOfE)X6r`eKN#>Or}WK^VpoQgcp=0uw0Foj_uU9?P}7d{Qp-p@b(G|IyPNkR>=UHYP~(9+FRiZ8 zv0x?S{hPWw?O*Z*AQ=KVCIo(fPo%xnvf9%?hs+o@`E}OZ<%Wn29LPN)=;kUT;E|@n zP?#rG3|gszDmPP~M~t4iI#bpkv@9EF1WIykWlv3%X=Z#>!H(apAO%cOtCElcMxt3p zdc$>i(rf&O1j807Rz+zIaj_>m)FrvVS$~nhrnNHX;DnPk*gxA#nz2b7mI~+C!fUtb zjrYO|B?#F`q@QMU@pmR0<%ra7@lhsJSKs;OG(#C$K0pf^v*FnY+0Gu?F#z0`qH~>j zi@9bbL@g?_k;k|UCW$=|Kb{#l^|08yWMA@2do^)>mUCkj}uLb7%u>zUzAM4MQC55U6VvhpqNDT>>nYq&MkbLf+$ASIBeMChznLe`2%vnPde8Q`$gwxM z&9Z%dqOx-Rh*sfYB@@1%{$0#VRMNxzrj-LUJX8-FU~;|3TRKCzJZ-kn#vA9c#`oFz z$?+OoOY;*gF=0iY7v!&qe&}B%Lq%$Cp^7~&$v9Z@BH>0z_nrGJAm`9rQ0kRmb%%XN z4@W8gi8P8v?IgCE!R^~Bba#E=LqICFTr4hd4s-pc9E&OyY?|R8Bv0FqvptR3YALWw z_1$UZ@<`QQzNm_EZj~u#RNX#Vsp(XJNiz#VE#2(eS1R7r>M({Avs-AB@my)WA9cE4 zCICv#B1~VPTDbdPnn8wSW#hiUzyt=N{bb+|&fj&gc~qtlsXABZ+*CG*i}EN{8|*m>-2b^c23jSv$D{Xe`L6^ zC!#lkzA;->&FEZaxevE-U2Dw`U~sJDWUe#g12rGD4$_V>281)5>+E{!H5rNZoYY$- zQzpkGwBG&-y>)aUo6aPnXj!g-fJ(0lmB2fF^9!$?E4U@U__99I&x3#?4T}w2#9u4T z=VAs<5Y5=kT6_w!bl(E8aAc;oHSz+wp;t4;P?0Gzs~-{qIn-TJ4D+s2HDObY?<$y} z_SqI1@%RU2HgmcnpS`2!M#~1S_3D0vp-SzvQp~_9 zqq}pL0^tPp91t1#0^AzRuF0M}oScU@HYKecih0nl5*WfbxytP4UYJn5RDb`@pE8WP z{@%GSUK<&TQ!(2D-V4W*FS06~UNGfwT1;wU{IP$SrQQwI)G8IJI+5KlGoYqJRVPTN zN;(KUiFK>zT3_3ZcCOu!CKQR_58|)rc|x}t&T(lbPyV3#QNm-cKuxzyve!BMR~G1P zp|K8@Q^vR77P33ld^rOAhdH=X?o0GA^1oPQHG8x|R=U`VrF29pampC7N;i-!ef%l^ z=GKl5fim+)ypN|v2|lwUfgRn=9Gh@ulCztf>jCHGzK^S9&$zJRzAt^N&MOg-74RxG z*ca^I9KvOKlCl}chKF0$qHKwk{2OOp_$b>R*C#xl>>XSC{-t{`33nYQwS?=Xa)r%A z$$;CVo^V^rA)@iaaO>J17^ZfW8XJ&Zdje~nJ1KNx^N^3#wp&S+36zt#J}tr=swJ6B z>35L)f|t-(IRe!{mpfEt11YE@wH=G)DFx0;P{_UQIG@w*BMcAnD4Im@Q3u8#!WP( zkhZ&{$n|zZ|2+Wk=aoPSjDQ@$|GxZJ%>O&{*aS22;v4s8L$B8Y1KJjwY+<=naCYRlG zI^;vCd4l&-&>45zWuT*LR0O*8yNAEq1P(r7Wo8MP4*8}kG8!ZX7i9Yrd#}clNJ)F@ zUwgH#;qq$7`Ud-x2-nx9X<>O6H%~s)k60J}K`W4WSf;1YqVU=wi>bzNk)0%`-ThSe zBw6|)7N%^y##7E$=RUX@>vWi)@*TT4Fuam|w0!|NS$A?z79)1*9Y4=&6S^CUn}_Sj zL)+_362){XZ~F^MWRla}mdF$5Hd?&QZ})k9V=Dzn>5;e_YenlzA&xcKALkb?VR?u{ z$S)U~ja6+F^-EaV`zo}E@%N*T-L(>;V!ShFbb`CqQiH6J-fi)PWaoY>E{+-y+2cMc zu1`+dAFr+W#CV`Fpz>Jg?M427zYY*n5UJ^ZFx}o=dlm+Wq{1KXhJfL1 zV#apuZ32H@7aWPa0EhfN3}6U1&=Ar1N5Bc4gye2f05&NAy;`Wxf{U4sN6Bmx63I`2 z)3&Hw{B)@(FwwVx(a?ihu;*v{@|Q?rEX_n2qxG<0?tKW5F6!pU!}BrI0aj2Dy}A&R zLEDDK^~%dWl|V}uV(?(50>;xrP=CyPNCEsyrqBRW6oRzIvK9%;hgze7UnN#;Cq71m z-^-nq;1FJ+SO&?0pOjIc2a*@trkaUyDKv!IAEZQ)J_N<_6@BJzk8y2xh*v!DxB|g7 z0{Ujz+|WoNK>#*51ew=Wnu<_XWRJ|A(C}>?Wao>SB4hmOmkThU5Awg?S2;v=aQGmh z2l~@idoax$yV%1IOH+?Mlz}K5J=z|uFe9_@8_xQHN z3R)7UL0xG)pQ9Kbi&tYRuM;N zP;(5@@Abf9i${%^m0Mdjr1;B^1H`5Eh=~zz5Wdf7Q&~j3YwDMY zTWfb9P!;j6>QrSQD>5xS9e&75%b*84`7u@TN&yjt5|PvR__$O@M9#Cn$?r)@9?kg8 z$e{7-?09}3Vo$Pst!S20Wmd92-Q+Y1288bS2)r>_xlsHeLrxl6+9VjIC&$h{Zg&OZ zpR6U@w9x2Oz3(N3Oh=FIixu7rm-9 z75QLl6-iEn?WKW9NQ`&tO&VZqg_tED;wM3XEtiod>QRm0c@hf#xxz4H{0HIn?nk5o zlYvWNZNI1bqQ?EB)qx`xV_p&sAv;g8Q@lKs3JyXX(%WvYuD;}e_6l=CXonnA2!yp> zx#6{%e?Sd6uMV;+;?C@dzg9i_?6cV%!gZF3?+L8_E@CufrlI^#DEqAN-K_4vH z=_f$?KD@eld2xL`C08d-|K5pUGsa@eyHG4e)Zr?ixg{WGN=AbX`^~JVQ=ldWt%U|j zEQd6Dnh%K-P1PuKPItD^`t7$qZi2H|zF^k=v~M`V)($iK@ZP~i zO%olwJGO@4yF zAJy4LR{>QbMKxJxC;G%>-aLcBHr?!Pj6DXtDtUzhPcp-~HRK4e7nArObJX!~Q&(~7 zcvwXazh|@|A?HBe)&-5iRQsT+w-fgC_4j7pg~uEm?}-4#_{ENNoh1H<<*~QnGrYB4 zHWCn;70^wviJj5~>3twjW`&?ZICqH|o!gs)XSo+RC-y2{fLyZW2m{?&WW2h%I$7i5 z_HuVgox&8*ykul#o<)IvRg%1D8M+X`Yt>KrN!i#}e%{BdJZ$dHY8HKJ5*HuOBxYS# z*)S8$39F@|deFaAko^iF+jY0aOwr#3Nl58brK7Uk^5nVanY(*eZUCBcH^A)|Bt0rX zqBv8OxdK#+$wS+InNaSitD)OKJ1o@gJ8eFWdPE>-_E4bPL6-J?jJmOX%rpSkhVnm+! zHfY$U#DTm<-F!Raowu>wk-xYA`wi^btu&k5p#ywPV6&{o#;s}A<0-QrvoYlMqn=Cg zYysSr52M%@;pK3E%2}WtuP}H)P+~&O^BHtj2ow8~8hGKQbO~)!4{L0-yn;7Y&AE~K zS(Qn8f%B;cCk1N9X#$^0m5rod_oPg#M0F%kdzbK?&qDC%gWQ=QMD-2G&a#k%hZM`#J#Yz z8T0TSn;d42@>O6tDlmbi#0gY4QuF)})#;ZhGRcih54lIouc^5j(c+7|Bfmu8Py+U* zufUM2_S+&P`?ENZ*S>QOFeZy-f^C^vxYYy!;*TWCu`5fZWFBabGqUGsuTkFw25eu! zCw`{>yh;Pbf`y6Ei;417IS)>M-O|yHY+z%}?yMJe*@*0l{wggd> zXB8V=G_}xnL$a%ir!Re$$H^x;b1)(3h+XrjSkDgAZ$c=!f^bpzNTjB4;QD-7@(>4F zdPQoIgMXw`K!STC7Ad7cZ1VW}igb*zDodpfq1%?fS(lJbLMO4!O(i$fRABw?JM-}q zR8&+YvYK^~nn<}}LMv}-pj&2?*R3}ysPAAZvN~0B(WD5f!7xvmUqJe$jz;u4Z97sF zbmd;)47s$D)el>`xByd7ICHf^>b_gdUZNa;`OMs@6v$h%Jy)FYF}LV{F*J z9?N{vIx5pc<4NRttTex4en#MFKT@NYp)b~*UOIOuqLA6FJz?Vt^@Y^z)N~qlNibeO zlRMN1<5*?_!|jc+$#wdw3^_zW0!x1&s`wV_WvC~rsnY%}6qLzz@0E_Rk?HNHAE%wP zrtlvp)u7^Gedmw3NtF&|^|WhaW`Oj3%Q*=|H|?NJFo;*wr@M|ARh?@Qa%jbeeM;0a z77r}#{cy|B>|~_=13uWx3zwoi)paNb13}=`@0<%08}w*cP0rFskWs9f$seKu5iEQn zyzbp1S4ORxJxVX}fvtZ9znKI3&DHON8PEBpdnmu=uz zf8tuePg)_o5JBIJ7ys7Y001BIP3{bLvSzNJeL+ve<25D6x$r!d0#_=lL>vzdzUK_^ zpWxu3Ol>7{*hQqY(rJuOZrXWn~O9Y$xa$eF&(=X&#+yFm@GzkSD5omB+31)L(>1se&pQBe(6uB zuwQl$T+2}kEN4XsDoQ5SrWzBU!|Zsa50EIr(GzjEJP55(5;?Gb+{Wxtp3-LU)dg| z&%f|}K~m-GO790EM7{s3tknkTAjAgWN~1lfxons`Vw@;EH1&R)G*OW;Q;@Dt`TNlT zeMHikgU^my(o*W*90)nlqT~~}BfX=xvFnl_NyHUIZ%|xJZ1BuB4$k;KOVvF^bGxuQ zF-is96_LNFp(1V?OY(R-$hSm4z~sEQVONY*b3t8%n&V6I040NX<@L+@N>oVYo?8N< z+*5ZJei)>${JLy+O*J^$$1G2G7_Tn5`N8QBaVW=J_7q2ve<_ZA|56e;jA{U-_7YKQ!V{JP9S(4bnFEM1lVh z54bJXg^=(MJNHOk|CTEMrYpv-L(Czvq`5jZ0ZwE|;6006nqULT2jn+5tRUk$h=GvV z@!Pv9kZ{hX5KSB>Q;~4C7_#j z;_H;7C6!PuKo^Wb4tbi^2&*W8A0V7`fTF`Z6xI9K6 z%{K)HmdPvwT-lxWcHR9>WnBF9cXQ;`qMS#cJ?UUqqJq@AUqyXSK9Kr+d~xkXy?G4r z5%46!coA%X{eZvhEPNmVUA)4u(OU+T*HFJJ|A@hIe0`)?>O#5B;&63YJfLe%S2sa)$iPxTW&X9Uk*j04CE6?LQ) zA=)6!pp_If<<&S9TpMygxjAe%!_{-Psi`S`FRjbk2$=KN2|tY@K{rhXkn)<`trpqs zL}b??IYo0``{StotcnW=vYCi-@ad#;_yNN5KeGu04aC|7uuj$qkrSr+)v>tEhvhyd5aifl(Fs9v7BF$W%Hk_M9g>8c|Pf$Gqdb{fiHos#_t z_;VW6cd}p-26A4%AEV~ZjXA*b9Oh+&3HJA|FJ=xr&3?p!e`Dsj)gtWVuL175d!-(r z6aZ8&OpABt@-oU&F4|^4YU`#Kj>5B)knCW2B5Nn%RCh3G$7Tie*7-DQAozgKvrIs~ z(E-g@YC04yYXCwG0B3rN&3IB%Q=c3HC9qyi)Ni&=yX?FwfG>VX>ZpP2Qsc?Qy&OZZ z>E0w!x@(U-r!~}jGnbs_*e6em^2nMVF3(6!oqA^X2KJk^?l@1^2GZ)bF)E@W6zUc8 zjHNH9pLn*R2F+P5H{? zinSF={HP=s9Ih)`xw9T5Hi?>6(AG-r{-))>#8yq(EzXxu8b7E+Qu;Q%47nwD%W&&w>68 zP6YE!rq9S%kk(!DRGvZc@)VQ9g#jQpif7MJH(!+Z1;yRhqYW)xS5U2u`?a@BWocvs z^92sdyZ+{n!7SiH<*nIuP}+MYx1VPyRtbMh^D{`W1HD4V+>C-l$Z0wB7ZbnRmof!b z$XS0 zN1Dozz27NEgH4yg8)q<=l4Y~2g;*Wm*3bvcFwj~&^FRk#Q0(x%dbP$&XO(iBO)LaW z$1{0ayMCKRNgXyfM18)dyr{|ji1QtFCP-gwg+>G3>vblJfR*oiGd#2>} zW={*gNFU4A;8S;{T6kZ4kNzYH3oI+O!2r3c51Cw@5iuuNUar?^WrNFf8g=RuI8JI! z6_rF$-+6hs&507%EB)9;1m{&z`&|2&99F<_kN4pn&6nf52PxGP9__xBcTs|~xv z85JYB$UpB|>);gsKK08u68ia#MF*F^V%*S|0)$h4&P|wv6R*|jKs}K?D4y^w;!3%(`#<^3H5F|o9=ZP6w3Ix_*}rAiHcmJZ zDnv(5H~8W;SCKUG*u0T{4FWNXVNsXlJRi8sQSs>UtYvR6W6u#KJ^^6dba-o|-&{TH z5O1x(AuKPck_`z0Q#J`nQ3u=i41ML9afuIf-xONtjJ_2*^`pn@vq!2IQE=j~q8?$0 zOYBrkR9&-){jolp)Ni*VuRkB5%FoI^OOeo19TK;2IBTd&mFbOY)h~TZqf?-LWDXb; z=wDa#i^U9F+@Z@1r{i3GBkAdwyzrxQ>*K?Y-#^cBqQlP&4Z3U{Q586$0krEV@lx6|c7k+inZH!Jn>)iEQ|8vU;CS-UW5bog6$0{a|qW*KJE@79m zewhKc)?d((^6#ne=MSL$Q(uS>(OR_eEua6mFad^z<_QrV@*IT07r@}P{=Ya^ju@%6 zm8tu<`l{0Qf6uH&mZeKLb%Ar_0NWqa>YjD=uh$`FPsZ>MKHu$){{N9eV+UX(%TT5a z{Cjf#6Wyy_g>i^I+8ANn&GOGE{528b`GJ+@>P5Y?=aY^8{}mIVTI|Vl-0Q-G^#46K zE`vA@1&onzmoQ|dvj2gP@byTzBrYNUL!>_h2?ze?SRny8uO9V1?IfHBGuHJ#DktGF z@yRLs@@5b`l1K!c;IHS4IKl|xgA+IsOA^FcwQqYCz5}u9R_0Yoc zBMBs5|GvRv&xv8gk81ljf5w;aC!1>TPMwB#&o++jWqQG4fRks&p8fMlerMt&wfc1= z^RH=0I73~Txp&|RVvyRca#`*#-~$I~weQ_I{&AXZJ`$4Ozh$OBYm< `anonymization_document.id` | +| `paragraph_id` | `UUID` | no | FK -> `anonymization_paragraph.id` | +| `order` | `INTEGER` | sí | Orden del párrafo en documento origen | + +La clave primaria es compuesta por `id`, `document_id`, `paragraph_id`. + +### `datapublic_document` +| Columna | Tipo | Nulo | Notas | +|---|---|---|---| +| `id` | `UUID` | no | Primary key (identificador del documento) | +| `prediction` | `JSON` | sí | Payload reservado de predicción a nivel documento; el router público actual no lo escribe | +| `validation` | `JSON` | sí | Payload de validación a nivel documento | +| `created_at` | `DATETIME` | no | Default server `CURRENT_TIMESTAMP` | +| `updated_at` | `DATETIME` | sí | Se actualiza ante cambios | + +### `datapublic_paragraph` +| Columna | Tipo | Nulo | Notas | +|---|---|---|---| +| `id` | `UUID` | no | Primary key, derivada del hash del texto | +| `text` | `TEXT` | no | Texto normalizado del párrafo | +| `prediction` | `JSON` | sí | Predicciones del modelo (`list[DocLabel]`) | +| `validation` | `JSON` | sí | Reservado para validación por párrafo; la ruta pública hoy existe solo como lógica legacy comentada | +| `created_at` | `DATETIME` | no | Default server `CURRENT_TIMESTAMP` | +| `updated_at` | `DATETIME` | sí | Se actualiza ante cambios | + +### `datapublic_document_paragraph` +| Columna | Tipo | Nulo | Notas | +|---|---|---|---| +| `id` | `UUID` | no | Identificador del vínculo | +| `document_id` | `UUID` | no | FK -> `datapublic_document.id` | +| `paragraph_id` | `UUID` | no | FK -> `datapublic_paragraph.id` | +| `order` | `INTEGER` | sí | Orden del párrafo en documento origen | + +La clave primaria es compuesta por `id`, `document_id`, `paragraph_id`. + +## Mapeo endpoint -> persistencia + +### Anonymizer +- `POST /anonymizer/predict` + - Lee `anonymization_paragraph` por UUID de párrafo. + - Escribe `anonymization_paragraph.prediction` cuando el cache está activo. +- `POST /anonymizer/disambiguate` + - Escribe predicciones desambiguadas en `anonymization_paragraph.prediction`. +- `POST /anonymizer/validation` + - Lee `anonymization_paragraph.validation`. +- `POST /anonymizer/anonymize-document` + - Escribe `anonymization_paragraph.validation`. + - Crea `anonymization_document` con clave derivada del hash del contenido binario subido. + - Crea vínculos en `anonymization_document_paragraph`. + +### Data-public +- `POST /datapublic/predict/{document_id}` + - Usa el `document_id` provisto por el cliente como primary key del documento. + - Asegura existencia de `datapublic_document` cuando `use_cache=true`. + - Escribe `datapublic_paragraph.prediction` cuando `use_cache=true`. + - Escribe vínculo en `datapublic_document_paragraph` cuando `use_cache=true`. +- `GET /datapublic/validation/document/{document_id}` + - Lee `datapublic_document.validation`. +- `POST /datapublic/validation/document/{document_id}` + - Hace upsert de `datapublic_document.validation`. + +## Nota legacy +Los módulos de rutas para CRUD de dataset (`/datapublic/dataset/*`) existen en código pero no están montados en el router público. No deben tratarse como API pública activa hasta su exposición en `core.router`. diff --git a/docs/es/entities/README.md b/docs/es/entities/README.md new file mode 100644 index 00000000..5152c66a --- /dev/null +++ b/docs/es/entities/README.md @@ -0,0 +1,17 @@ +# Entidades +Idioma: [English](../../entities/README.md) | **Español** + +Esta sección documenta los catálogos de entidades utilizados por los distintos flujos de AymurAI. + +## Catálogos de entidades por flujo +- Datapublic: [datapublic/README.md](datapublic/README.md) +- Anonymizer: [anonymizer/README.md](anonymizer/README.md) + +## Notas +- Las entidades de `datapublic` describen la taxonomía de extracción de datos públicos usada por el pipeline de producción `full-paragraph`. +- Las entidades de `anonymizer` describen las labels usadas actualmente por el flujo de anonimización para desambiguación y reemplazo. + +## Documentación relacionada +- Índice de documentación: [../README.md](../README.md) +- Índice de pipelines: [../pipelines/README.md](../pipelines/README.md) +- Índice de modelos: [../models/README.md](../models/README.md) diff --git a/docs/es/entities/anonymizer/README.md b/docs/es/entities/anonymizer/README.md new file mode 100644 index 00000000..b4fee224 --- /dev/null +++ b/docs/es/entities/anonymizer/README.md @@ -0,0 +1,45 @@ +# Entidades de Anonymizer +Idioma: [English](../../../entities/anonymizer/README.md) | **Español** + +Catálogo de labels usadas actualmente por el flujo de anonimización. + +## Alcance +Estas labels representan los tipos de entidad reconocidos y transformados por el pipeline de producción `flair-anonymizer`. Son las labels sobre las que operan la desambiguación, las políticas de anonimización y las políticas de renderizado. + +## Labels +| Label | Descripción | +|---|---| +| `PER` | Nombre de persona o mención de persona. | +| `EDAD` | Edad. | +| `DNI` | Número de documento nacional de identidad argentino. | +| `NACIONALIDAD` | Nacionalidad. | +| `ESTUDIOS` | Estudios o nivel educativo. | +| `DIRECCION` | Dirección postal o calle. | +| `LOC` | Ubicación geográfica o referencia de lugar. | +| `TELEFONO` | Número de teléfono. | +| `CORREO_ELECTRONICO` | Dirección de correo electrónico. | +| `FECHA` | Fecha calendario. | +| `NUM_EXPEDIENTE` | Número de expediente o causa. | +| `CUIJ` | Identificador judicial único de causa. | +| `NUM_ACTUACION` | Número de actuación. | +| `NUM_MATRICULA` | Número de matrícula o licencia profesional. | +| `NOMBRE_ARCHIVO` | Nombre de archivo. | +| `TEXTO_ANONIMIZAR` | Fragmento de texto libre marcado explícitamente para anonimización cuando no encaja en una label estructurada más específica. | +| `USUARIX` | Nombre de usuario, handle o identificador de cuenta. | +| `LINK` | URL o enlace web. | +| `IP` | Dirección IP. | +| `CUIT_CUIL` | Identificador tributario o laboral argentino. | +| `BANCO` | Nombre de entidad bancaria. | +| `CBU` | Clave Bancaria Uniforme argentina. | +| `NUM_CAJA_AHORRO` | Número de caja de ahorro. | +| `MARCA_AUTOMOVIL` | Referencia a marca o modelo de vehículo. | +| `PATENTE_DOMINIO` | Patente o dominio vehicular. | + +## Notas +- Este catálogo refleja el conjunto actual de tokens de anonimización usado por las utilidades de reemplazo del backend. +- Cada label puede configurarse con políticas específicas de anonimización o desambiguación mediante `LabelPolicy`. + +## Documentación relacionada +- Índice de entidades: [../README.md](../README.md) +- Pipeline anonymizer: [../../pipelines/anonymizer/README.md](../../pipelines/anonymizer/README.md) +- Referencia API: [../../api/README.md](../../api/README.md) diff --git a/docs/es/entities/datapublic/README.md b/docs/es/entities/datapublic/README.md new file mode 100644 index 00000000..9b9c1c91 --- /dev/null +++ b/docs/es/entities/datapublic/README.md @@ -0,0 +1,47 @@ +# Entidades de Datapublic +Idioma: [English](../../../entities/datapublic/README.md) | **Español** + +Catálogo de entidades utilizadas por el flujo de extracción de datapublic. + +## Alcance +Estas entidades corresponden a la taxonomía extraída de resoluciones judiciales por el pipeline de producción `full-paragraph`. Se usan a lo largo del modelo Flair NER, el postprocesamiento de decisiones, la UI de validación y el tooling relacionado con el dataset. + +## Entidades +| Entidad | Descripción | +|---|---| +| `ART_INFRINGIDO` | Artículo(s) o norma(s) legal(es) infringida(s) en el caso. | +| `CONDUCTA` | Acción asociada al delito, contravención o falta descripta en el artículo infringido. | +| `CONDUCTA_DESCRIPCION` | Caracterización adicional de la conducta, como agravantes o detalles de modalidad. | +| `DECISION` | Fragmento de texto que denota una decisión judicial. En producción es una label sintética emitida por el clasificador de decisiones. | +| `DETALLE` | Detalle que especifica qué se resolvió dentro de `OBJETO_DE_LA_RESOLUCION`. | +| `EDAD_AL_MOMENTO_DEL_HECHO` | Edad de la persona al momento del hecho. | +| `FECHA_DE_NACIMIENTO` | Fecha de nacimiento. | +| `FECHA_DEL_HECHO` | Fecha en que ocurrió el hecho denunciado. | +| `FECHA_RESOLUCION` | Fecha de la resolución; en audiencias orales, la fecha de inicio de la audiencia. | +| `FRASES_AGRESION` | Frases citadas o parafraseadas como agresión verbal dentro de los hechos del caso. | +| `GENERO` | Género. | +| `HIJOS_HIJAS_EN_COMUN` | Si la persona acusada y la denunciante tienen hijos/as en común. | +| `HORA_DE_CIERRE` | Hora de finalización de la audiencia. | +| `HORA_DE_INICIO` | Hora de inicio de la audiencia. | +| `LUGAR_DEL_HECHO` | Lugar físico o mediado donde ocurrieron los hechos. | +| `MODALIDAD_DE_LA_VIOLENCIA` | Modalidad en la que se manifiesta la violencia, como violencia doméstica, institucional, laboral, mediática o en espacio público. | +| `N_EXPTE_EJE` | Identificador del expediente o caso. | +| `NACIONALIDAD` | Nacionalidad. | +| `NIVEL_INSTRUCCION` | Nivel de estudios formales alcanzado por la persona. | +| `NOMBRE` | Nombre de persona. | +| `OBJETO_DE_LA_RESOLUCION` | Sobre qué resolvió el juzgado. | +| `PERSONA_ACUSADA_NO_DETERMINADA` | Parte acusada no determinada o no humana, como una persona jurídica o una cuenta en línea. | +| `RELACION_Y_TIPO_ENTRE_ACUSADO/A_Y_DENUNCIANTE` | Tipo de vínculo entre la persona acusada y la denunciante. | +| `TIPO_DE_RESOLUCION` | Tipo de resolución, como interlocutoria o definitiva. | +| `VIOLENCIA_DE_GENERO` | Si los hechos investigados ocurren en un contexto de violencia de género. | + +## Subcategorías y campos de validación +- Muchas de estas entidades tienen subclasificaciones o vocabularios controlados específicos para validación. +- Las opciones históricas de validación están capturadas en el template de Label Studio: [../../../../resources/annotations/label-studio/datapublic/label-studio-config.xml](../../../../resources/annotations/label-studio/datapublic/label-studio-config.xml) +- Un glosario explicativo más amplio está disponible aquí: https://docs.google.com/document/d/123B9T2abCEqBaxxOl5c7HBJZRdIMtKDWo6IKHIVil04/edit + +## Documentación relacionada +- Índice de entidades: [../README.md](../README.md) +- Pipeline datapublic: [../../pipelines/datapublic/README.md](../../pipelines/datapublic/README.md) +- Model card de Decision: [../../models/decision-model-card.md](../../models/decision-model-card.md) +- Model card de Flair: [../../models/flair-model-card.md](../../models/flair-model-card.md) diff --git a/docs/es/models/README.md b/docs/es/models/README.md new file mode 100644 index 00000000..3067c6a6 --- /dev/null +++ b/docs/es/models/README.md @@ -0,0 +1,19 @@ +# Modelos +Idioma: [English](../../models/README.md) | **Español** + +Esta sección documenta los modelos individuales utilizados por el backend. + +## Documentación disponible +- Model card del NER de anonymizer: [anonymizer-model-card.md](anonymizer-model-card.md) +- Flair NER: [flair-model-card.md](flair-model-card.md) +- Clasificador de decisiones: [decision-model-card.md](decision-model-card.md) + +## Uso actual en producción +- `flair-anonymizer` usa la model card del NER de anonymizer documentada aquí. +- `full-paragraph` usa el modelo Flair NER y el clasificador de decisiones. + +## Documentación relacionada +- Índice de documentación: [../README.md](../README.md) +- Índice de pipelines: [../pipelines/README.md](../pipelines/README.md) +- Flujo anonymizer: [../pipelines/anonymizer/README.md](../pipelines/anonymizer/README.md) +- Flujo datapublic: [../pipelines/datapublic/README.md](../pipelines/datapublic/README.md) diff --git a/docs/es/models/anonymizer-model-card.md b/docs/es/models/anonymizer-model-card.md new file mode 100644 index 00000000..8ab878d8 --- /dev/null +++ b/docs/es/models/anonymizer-model-card.md @@ -0,0 +1,172 @@ +--- +license: mit +language: +- es +tags: +- flair +- token-classification +- sequence-tagger-model +- anonymization +- judicial-text +datasets: +- ArJuzPCyF10 +metrics: +- precision +- recall +- f1-score +widget: +- text: 1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas. +library_name: flair +pipeline_tag: token-classification +--- + +Idioma: [English](../../models/anonymizer-model-card.md) | **Español** + +# Descripción del modelo + +Este modelo es el componente NER usado por el pipeline de producción `flair-anonymizer`. +Detecta spans que deben anonimizarse en documentos judiciales antes de la desambiguación, la validación manual y el render final del documento. + +Siguiendo las guías de Flair para entrenamiento de NER, el modelo se entrenó sobre [embeddings BETO](https://huggingface.co/dccuchile/bert-base-spanish-wwm-uncased), una versión en español de BERT, con una arquitectura BiLSTM-CRF. + +Este modelo fue desarrollado por [{ collective.ai }](https://collectiveai.io) como parte del proyecto [AymurAI](https://aymurai.info) de [DataGenero](https://datagenero.org). + +## Usos previstos y limitaciones + +AymurAI busca ayudar a abordar la falta de datos disponibles sobre resoluciones de violencia de género (VG) en América Latina. En el flujo de anonimización, el objetivo inmediato de este modelo es identificar spans sensibles en documentos legales para que puedan ser revisados y reemplazados antes de su uso posterior. + +AymurAI sigue siendo un sistema específico de dominio. Sus capacidades se limitan a la anonimización, recolección y análisis semiautomatizados de datos judiciales, y la salida puede verse afectada por la calidad de la anotación, la heterogeneidad documental, errores de OCR o extracción y la disponibilidad de datos de entrenamiento representativos. + +Este modelo fue entrenado con un dataset cerrado de un juzgado penal argentino. Esa especificidad de dominio mejora el desempeño en el contexto objetivo, pero también implica que el modelo puede no transferir bien a otras jurisdicciones, estilos documentales o culturas jurídicas. + +## Comportamiento en producción + +En producción, este modelo se carga a través de `aymurai.models.flair.core.FlairModel` desde: + +- `resources/pipelines/production/flair-anonymizer/pipeline.json` +- model path: `aymurai/anonymizer-beto-cased-flair` + +Sus predicciones de spans se postprocesan luego con: + +- `aymurai.transforms.anonymization_postprocess.core.AnonymizationEntityCleaner` +- `aymurai.transforms.datetime_formatter.core.DatetimeFormatter` + +Esas predicciones alimentan el resto del flujo de anonimización: + +1. `POST /anonymizer/predict` ejecuta la extracción de spans. +2. `POST /anonymizer/disambiguate` asigna IDs canónicos y metadatos efectivos por label. +3. La revisión manual puede editar labels, `label_policies` y `render_policy`. +4. `POST /anonymizer/anonymize-document` aplica los reemplazos sobre el documento de salida. + +# Uso + +## Cómo usar el modelo en Flair + +Requiere **[Flair](https://github.com/flairNLP/flair/)**. +Instalación: `pip install flair`. + +```python +from flair.data import Sentence +from flair.models import SequenceTagger + +tagger = SequenceTagger.load("aymurai/anonymizer-beto-cased-flair") + +sentence = Sentence( + "1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento " + "de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO " + "MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves " + "agravadas, amenazas simples y agravadas por el uso de armas." +) + +tagger.predict(sentence) + +for entity in sentence.get_spans("ner"): + print(entity) +``` + +Esto produce una salida similar a: + +```text +Span[22:25]: "EZEQUIEL CAMILO MARCONNI" -> PER (0.9541) +Span[27:28]: "11.222.333" -> DNI (1.0) +``` + +## Uso del modelo en un pipeline de AymurAI + +```python +from aymurai.pipeline import AymurAIPipeline + +pipeline = AymurAIPipeline.load("/resources/pipelines/production/flair-anonymizer") + +item = { + "path": "dummy", + "data": { + "doc.text": ( + "Acusado: Ramiro Marrón DNI 34.555.666. " + "Fecha: 17 de noviembre de 2024." + ) + }, +} + +processed = pipeline.preprocess([item]) +processed = pipeline.predict_single(processed[0]) +processed = pipeline.postprocess([processed]) + +print(processed[0]["predictions"]["entities"]) +``` + +# Entidades y métricas + +## Descripción + +Consultá el catálogo de entidades de anonymizer ([en](../../entities/anonymizer/README.md)|[es](../entities/anonymizer/README.md)). + +## Datos + +El modelo fue entrenado con un dataset de 535 resoluciones judiciales de un juzgado penal argentino. + +Dada la naturaleza de los datos (datos personales, características de la denuncia y protección de víctimas), los documentos se mantienen privados. + +## Métricas + +Las siguientes métricas por label provienen de la model card publicada en Hugging Face para esta familia de modelos de anonymizer y deben interpretarse como métricas NER a nivel modelo, no como calidad end-to-end de la anonimización. + +| label | precision | recall | f1-score | +|---|---:|---:|---:| +| `BANCO` | 1.00 | 0.90 | 0.95 | +| `CBU` | 0.92 | 0.92 | 0.92 | +| `CORREO_ELECTRONICO` | 1.00 | 1.00 | 1.00 | +| `CUIJ` | 1.00 | 1.00 | 1.00 | +| `CUIT_CUIL` | 1.00 | 1.00 | 1.00 | +| `DIRECCION` | 0.97 | 0.85 | 0.91 | +| `DNI` | 0.96 | 1.00 | 0.98 | +| `EDAD` | 1.00 | 0.95 | 0.97 | +| `ESTUDIOS` | 1.00 | 1.00 | 1.00 | +| `FECHA` | 1.00 | 0.99 | 1.00 | +| `LINK` | 1.00 | 0.94 | 0.97 | +| `LOC` | 0.99 | 0.72 | 0.83 | +| `MARCA_AUTOMOVIL` | 0.95 | 1.00 | 0.97 | +| `NACIONALIDAD` | 1.00 | 0.94 | 0.97 | +| `NUM_ACTUACION` | 0.84 | 0.96 | 0.90 | +| `NUM_CAJA_AHORRO` | 0.00 | 0.00 | 0.00 | +| `NUM_EXPEDIENTE` | 0.98 | 0.92 | 0.95 | +| `NUM_MATRICULA` | 0.33 | 0.50 | 0.40 | +| `PATENTE_DOMINIO` | 1.00 | 1.00 | 1.00 | +| `PER` | 0.98 | 0.97 | 0.98 | +| `TELEFONO` | 0.97 | 1.00 | 0.99 | +| `TEXTO_ANONIMIZAR` | 0.98 | 0.61 | 0.75 | +| `macro avg` | 0.91 | 0.88 | 0.89 | + +# Cita + +Por favor citá [el siguiente paper](https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view) al utilizar AymurAI: + +```bibtex +@techreport{feldfeber2022, + author = {Feldfeber, Ivana and Quiroga, Yasm{\'i}n Bel{\'e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} +} +``` diff --git a/docs/es/models/decision-model-card.md b/docs/es/models/decision-model-card.md new file mode 100644 index 00000000..22350451 --- /dev/null +++ b/docs/es/models/decision-model-card.md @@ -0,0 +1,217 @@ +--- +license: mit +language: +- es +tags: +- text-classification +- embeddingbag +- binary-classification +- judicial-text +datasets: +- ArJuzPCyF10 +metrics: +- f1 +widget: +- text: 1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas. +library_name: torch +pipeline_tag: text-classification +--- + +Idioma: [English](../../models/decision-model-card.md) | **Español** + +# Descripción del modelo + +Este modelo es el clasificador actual de decisiones a nivel párrafo utilizado en el pipeline de producción `full-paragraph`. +Estima si un párrafo contiene una decisión judicial y, cuando se usa dentro del pipeline de AymurAI, emite una entidad sintética `DECISION` con una subcategoría basada en reglas. + +Este modelo fue desarrollado por [{ collective.ai }](https://collectiveai.io) como parte del proyecto [AymurAI](https://aymurai.info) de [DataGenero](https://datagenero.org). + +## Arquitectura + +El clasificador actual de producción es un modelo compacto de bolsa de palabras con hashing, implementado con `torch.nn.EmbeddingBag`. +Su camino de inferencia está definido en `aymurai/models/decision/binregex.py` y `aymurai/models/decision/embeddingbag.py`. + +A alto nivel, el modelo funciona así: + +1. El texto de entrada se normaliza quitando tildes, pasando a minúsculas y colapsando espacios. +2. El texto se tokeniza por espacios en blanco. +3. Los tokens se hashean con BLAKE2b sobre un vocabulario fijo. +4. Los IDs de tokens se agrupan mediante embeddings promedio con `EmbeddingBag`. +5. Una capa de dropout y una cabeza lineal producen logits binarios (`not decision`, `decision`). +6. Si el score positivo supera el umbral configurado, el pipeline agrega una etiqueta `DECISION` al párrafo. + +Configuración actual del checkpoint cargado por el modelo de producción: + +| parámetro | valor | +|---|---| +| `vocab_size` | `20000` | +| `embed_dim` | `64` | +| `max_tokens` | `128` | +| `dropout` | `0.1` | +| `num_classes` | `2` | +| `batch_size` | `512` | +| `lr` | `0.005` | +| `weight_decay` | `0.001` | +| `epochs` | `50` | + +## Usos previstos y limitaciones + +AymurAI está pensado como una herramienta para abordar la falta de transparencia en el sistema judicial en relación con casos de violencia de género (VG) en América Latina. El objetivo es aumentar los niveles de reporte, construir confianza en el sistema de justicia y mejorar el acceso a la justicia para mujeres y personas LGBTIQ+. AymurAI genera y mantiene datasets anonimizados a partir de sentencias judiciales para comprender la violencia de género y apoyar el diseño de políticas públicas, además de contribuir a campañas de colectivos feministas. + +Las capacidades de AymurAI se limitan a la recolección y análisis semiautomatizados de datos, y sus resultados pueden estar sujetos a limitaciones como la calidad y consistencia de los datos, posibles sesgos del modelo de IA y la disponibilidad de la información. Además, la efectividad de AymurAI para abordar la falta de transparencia del sistema judicial y mejorar el acceso a la justicia también puede depender de otros factores, como el nivel de cooperación de funcionarios judiciales y el contexto cultural y político más amplio. + +Este modelo fue entrenado con un dataset cerrado proveniente de un juzgado penal argentino. Está diseñado para identificar si un párrafo contiene una decisión judicial. El uso de un dataset específico de dominio, proveniente de un juzgado penal argentino, hace que el modelo esté ajustado al contexto jurídico y cultural concreto, lo que permite resultados más precisos. Sin embargo, esto también implica que el modelo puede no ser aplicable o efectivo en otros países o regiones con sistemas jurídicos o normas culturales diferentes. + +## Comportamiento en producción + +Cuando este clasificador se utiliza a través de `DecisionEmbeddingBagBinRegex`, el comportamiento en producción incluye dos reglas adicionales además de la predicción binaria cruda: + +- La clase positiva se emite solo cuando el score de decisión supera el umbral configurado (`0.5` en el pipeline de producción). +- Con `return_only_with_detalle=true`, el clasificador solo agrega una entidad `DECISION` si el párrafo ya contiene una entidad `DETALLE` proveniente de la etapa NER. + +Si un párrafo es clasificado como decisión, el modelo emite una entidad `DECISION` que cubre el texto completo del párrafo. La etiqueta emitida incluye una subcategoría basada en reglas: + +- `hace_lugar` +- `no_hace_lugar` + +Esa subcategoría se asigna mediante postprocesamiento con expresiones regulares sobre el texto del párrafo. + +# Uso + +## Cómo usar el modelo en torch + +```python +import torch + +from aymurai.models.decision.binregex import DecisionEmbeddingBagBinRegex + +model = DecisionEmbeddingBagBinRegex( + model_checkpoint="https://github.com/AymurAI/backend/releases/download/v2.0.0-alpha.1/tiny-embeddingbag.safetensors", + device="cpu", + threshold=0.5, + return_only_with_detalle=False, +) + +text = "1. DECLARAR EXTINGUIDA LA ACCION PENAL en este caso por cumplimiento de la suspension del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas." + +flat_tokens, offsets = model.model_input_from_text(text) +with torch.no_grad(): + logits = model.model(flat_tokens, offsets) + probabilities = logits.softmax(dim=1).cpu().numpy() + +print(probabilities) +print(model.get_subcategory(text)) +``` + +Esto produce una salida similar a: + +```text +[[0.0010057, 0.9989943]] +['hace_lugar'] +``` + +La primera columna es la probabilidad de que el texto no sea una decisión, y la segunda columna es la probabilidad de que el texto sí sea una decisión. + +## Uso del modelo en un pipeline de AymurAI + +El pipeline actual de producción `full-paragraph` incluye este clasificador después de la etapa NER con Flair. + +```python +from aymurai.pipeline import AymurAIPipeline + +pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") + +item = { + "path": "dummy", + "data": { + "doc.text": "1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas." + }, +} + +processed = pipeline.preprocess([item]) +processed = pipeline.predict_single(processed[0]) +processed = pipeline.postprocess([processed]) + +print(processed[0]["predictions"]["entities"]) +``` + +En producción, el clasificador se configura así: + +```json +{ + "aymurai.models.decision.binregex.DecisionEmbeddingBagBinRegex": { + "model_checkpoint": "https://github.com/AymurAI/backend/releases/download/v2.0.0-alpha.1/tiny-embeddingbag.safetensors", + "device": "cpu", + "threshold": 0.5, + "return_only_with_detalle": true + } +} +``` + +# Entidades y métricas + +## Descripción + +Este modelo solo considera la clasificación de párrafos como decisiones o no decisiones. +Cuando la predicción es positiva, el pipeline emite una entidad sintética `DECISION` que cubre todo el párrafo. + +Para la lista completa de entidades usadas por el flujo datapublic, consultá el catálogo de entidades de datapublic ([en](../../entities/datapublic/README.md)|[es](../entities/datapublic/README.md)). + +Para una descripción completa de las entidades consideradas por AymurAI, ver el [Glosario para el dataset con perspectiva de género](https://docs.google.com/document/d/123B9T2abCEqBaxxOl5c7HBJZRdIMtKDWo6IKHIVil04/edit), elaborado por [DataGenero](https://datagenero.org) (solo en español). + +## Datos + +El modelo fue entrenado con un dataset de 1200 resoluciones judiciales de un juzgado penal argentino. + +Dada la naturaleza de los datos (datos personales, características de la denuncia y protección de víctimas), los documentos se mantienen privados. + +### Lista de personas colaboradoras en la anotación + +El dataset fue anotado manualmente por: + +* Diego Scopetta +* Franny Rodriguez Gerzovich ([email](mailto:fraanyrodriguez@gmail.com)|[linkedin](https://www.linkedin.com/in/francescarg)) +* Laura Barreiro +* Matías Sosa +* Maximiliano Sosa +* Patricia Sandoval +* Santiago Bezchinsky ([email](mailto:santibezchinsky@gmail.com)|[linkedin](https://www.linkedin.com/in/santiago-bezchinsky)) +* Zoe Rodriguez Gerzovich + +## Métricas + +Las siguientes métricas provienen de la notebook actual de entrenamiento/evaluación de EmbeddingBag y corresponden a la tarea binaria de clasificación de decisiones (`0 = no decisión`, `1 = decisión`). + +### Split de validación + +| métrica | clase 1 (decisión) | general | +|---|---:|---:| +| precision | 0.774 | - | +| recall | 0.896 | - | +| f1-score | 0.830 | - | +| accuracy | - | 0.962 | +| support | 336 | 3211 | + +### Split de test + +| métrica | clase 1 (decisión) | general | +|---|---:|---:| +| precision | 0.754 | - | +| recall | 0.905 | - | +| f1-score | 0.823 | - | +| accuracy | - | 0.959 | +| support | 336 | 3211 | + +# Cita + +Por favor citá [el siguiente paper](https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view) al utilizar AymurAI: + +```bibtex +@techreport{feldfeber2022, + author = {Feldfeber, Ivana and Quiroga, Yasm{'i}n Bel{'e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} +} +``` diff --git a/docs/es/models/flair-model-card.md b/docs/es/models/flair-model-card.md new file mode 100644 index 00000000..68e2763f --- /dev/null +++ b/docs/es/models/flair-model-card.md @@ -0,0 +1,166 @@ +--- +license: mit +language: +- es +tags: +- flair +- token-classification +- sequence-tagger-model +datasets: +- ArJuzPCyF10 +metrics: +- f1 +widget: +- text: 1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas. +library_name: flair +pipeline_tag: token-classification +--- + +Idioma: [English](../../models/flair-model-card.md) | **Español** + +# Descripción del modelo +

+schema +

+ +Siguiendo las guías de Flair para entrenar un modelo de NER, este modelo se entrenó sobre [embeddings BETO](https://huggingface.co/dccuchile/bert-base-spanish-wwm-uncased), una versión en español de BERT entrenada sobre un corpus en español, con una arquitectura BiLSTM-CRF. + +Este modelo fue desarrollado por [{ collective.ai }](https://collectiveai.io) como parte del proyecto [AymurAI](https://aymurai.info) de [DataGenero](https://datagenero.org). +Actualmente se usa como componente NER del pipeline de producción `full-paragraph`. + +# Usos previstos y limitaciones +AymurAI está pensado como una herramienta para abordar la falta de transparencia en el sistema judicial en relación con casos de violencia de género (VG) en América Latina. El objetivo es aumentar los niveles de reporte, construir confianza en el sistema de justicia y mejorar el acceso a la justicia para mujeres y personas LGBTIQ+. AymurAI genera y mantiene datasets anonimizados a partir de sentencias judiciales para comprender la violencia de género y apoyar el diseño de políticas públicas, además de contribuir a campañas de colectivos feministas. + +Las capacidades de AymurAI se limitan a la recolección y análisis semiautomatizados de datos, y sus resultados pueden estar sujetos a limitaciones como la calidad y consistencia de los datos, posibles sesgos del modelo de IA y la disponibilidad de la información. Además, la efectividad de AymurAI para abordar la falta de transparencia del sistema judicial y mejorar el acceso a la justicia también puede depender de otros factores, como el nivel de cooperación de funcionarios judiciales y el contexto cultural y político más amplio. + +Este modelo fue entrenado con un dataset cerrado proveniente de un juzgado penal argentino. Está diseñado para identificar y extraer información relevante de sentencias vinculadas con casos de violencia de género. El uso de un dataset específico de dominio, proveniente de un juzgado penal argentino, hace que el modelo esté ajustado al contexto jurídico y cultural concreto, lo que permite resultados más precisos. Sin embargo, esto también implica que el modelo puede no ser aplicable o efectivo en otros países o regiones con sistemas jurídicos o normas culturales diferentes. + +# Uso +## Cómo usar el modelo en Flair + +Requiere **[Flair](https://github.com/flairNLP/flair/)**. +Instalación: `pip install flair` + +```python +from flair.data import Sentence +from flair.models import SequenceTagger + +# load tagger +tagger = SequenceTagger.load("aymurai/flair-ner-spanish-judicial") + +# make example sentence +sentence = Sentence("1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas.") + +# predict NER tags +tagger.predict(sentence) + +# print sentence +print(sentence) + +# print predicted NER spans +print('The following NER tags are found:') +# iterate over entities and print +for entity in sentence.get_spans('ner'): + print(entity) +``` + +Esto produce una salida como la siguiente: + +```text +Span[2:11]: "EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento" → DETALLE (0.5498) +Span[13:18]: "suspensión del proceso a prueba" → OBJETO_DE_LA_RESOLUCION (0.5647) +Span[20:21]: "SOBRESEER" → DETALLE (0.7766) +Span[22:25]: "EZEQUIEL CAMILO MARCONNI" → NOMBRE (0.6454) +Span[35:36]: "lesiones" → CONDUCTA (0.9457) +Span[36:38]: "leves agravadas" → CONDUCTA_DESCRIPCION (0.8818) +Span[39:40]: "amenazas" → CONDUCTA (0.956) +Span[40:48]: "simples y agravadas por el uso de armas" → CONDUCTA_DESCRIPCION (0.6866) +``` + +## Uso del modelo en un pipeline de AymurAI +También podés ejecutar el modelo a través de un pipeline de AymurAI. + +```python +from aymurai.pipeline import AymurAIPipeline + +pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") + +item = { + 'path': 'dummy', + 'data': { + 'doc.text': "1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas." + } +} + +processed = pipeline.preprocess([item]) +processed = pipeline.predict_single(processed[0]) +processed = pipeline.postprocess([processed]) + +print(processed[0]["predictions"]["entities"]) +``` + +# Entidades y métricas +## Descripción +Consultá el catálogo de entidades de datapublic ([en](../../entities/datapublic/README.md)|[es](../entities/datapublic/README.md)). + +Para una descripción completa de las entidades consideradas por AymurAI, ver el [Glosario para el dataset con perspectiva de género](https://docs.google.com/document/d/123B9T2abCEqBaxxOl5c7HBJZRdIMtKDWo6IKHIVil04/edit), elaborado por [DataGenero](https://datagenero.org) (solo en español). + +## Datos +El modelo fue entrenado con un dataset de 1200 resoluciones judiciales de un juzgado penal argentino. + +Dada la naturaleza de los datos (datos personales, características de la denuncia y protección de víctimas), los documentos se mantienen privados. + +### Lista de personas colaboradoras en la anotación +El dataset fue anotado manualmente por: +* Diego Scopetta +* Franny Rodriguez Gerzovich ([email](mailto:fraanyrodriguez@gmail.com)|[linkedin](https://www.linkedin.com/in/francescarg)) +* Laura Barreiro +* Matías Sosa +* Maximiliano Sosa +* Patricia Sandoval +* Santiago Bezchinsky ([email](mailto:santibezchinsky@gmail.com)|[linkedin](https://www.linkedin.com/in/santiago-bezchinsky)) +* Zoe Rodriguez Gerzovich + +## Métricas + +| label | precision | recall | f1-score | +|-----------------------------------------------------|-----------|--------|----------| +| FECHA_DE_NACIMIENTO | 0.98 | 0.99 | 0.99 | +| FECHA_RESOLUCION | 0.95 | 0.98 | 0.96 | +| NACIONALIDAD | 0.94 | 0.98 | 0.96 | +| GENERO | 1.00 | 0.50 | 0.67 | +| HORA_DE_INICIO | 0.98 | 0.92 | 0.95 | +| NOMBRE | 0.94 | 0.95 | 0.95 | +| FRASES_AGRESION | 0.90 | 0.98 | 0.94 | +| HORA_DE_CIERRE | 0.90 | 0.92 | 0.91 | +| NIVEL_INSTRUCCION | 0.85 | 0.94 | 0.90 | +| N_EXPTE_EJE | 0.85 | 0.93 | 0.89 | +| TIPO_DE_RESOLUCION | 0.63 | 0.93 | 0.75 | +| VIOLENCIA_DE_GENERO | 0.49 | 0.59 | 0.54 | +| RELACION_Y_TIPO_ENTRE_ACUSADO/A_Y_DENUNCIANTE | 0.93 | 0.76 | 0.84 | +| HIJOS_HIJAS_EN_COMUN | 0.47 | 0.57 | 0.52 | +| MODALIDAD_DE_LA_VIOLENCIA | 0.57 | 0.56 | 0.57 | +| FECHA_DEL_HECHO | 0.83 | 0.83 | 0.83 | +| CONDUCTA | 0.79 | 0.67 | 0.73 | +| ART_INFRINGIDO | 0.76 | 0.74 | 0.75 | +| DETALLE | 0.53 | 0.37 | 0.43 | +| OBJETO_DE_LA_RESOLUCION | 0.60 | 0.78 | 0.68 | +| CONDUCTA_DESCRIPCION | 0.54 | 0.43 | 0.48 | +| LUGAR_DEL_HECHO | 0.75 | 0.47 | 0.58 | +| EDAD_AL_MOMENTO_DEL_HECHO | 0.50 | 0.20 | 0.29 | +| PERSONA_ACUSADA_NO_DETERMINADA | 0.71 | 0.19 | 0.30 | +| | | | | +| macro avg | 0.77 | 0.72 | 0.73 | + +# Cita +Por favor citá [el siguiente paper](https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view) al utilizar AymurAI: + +```bibtex +@techreport{feldfeber2022, + author = {Feldfeber, Ivana and Quiroga, Yasm'{\i}n Bel'{e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} +} +``` diff --git a/docs/es/pipelines/README.md b/docs/es/pipelines/README.md new file mode 100644 index 00000000..f94559f8 --- /dev/null +++ b/docs/es/pipelines/README.md @@ -0,0 +1,25 @@ +# Pipelines +Idioma: [English](../../pipelines/README.md) | **Español** + +Esta sección documenta los pipelines de producción del backend por flujo. + +## Documentación por flujo +- Anonymizer: [anonymizer/README.md](anonymizer/README.md) +- Datapublic: [datapublic/README.md](datapublic/README.md) + +## Modelos relacionados +- Índice de modelos: [../models/README.md](../models/README.md) +- Model card de Flair NER: [../models/flair-model-card.md](../models/flair-model-card.md) +- Model card de Decision: [../models/decision-model-card.md](../models/decision-model-card.md) + +## Fuentes de configuración en producción +- Config anonymizer: `resources/pipelines/production/flair-anonymizer/pipeline.json` +- Config datapublic: `resources/pipelines/production/full-paragraph/pipeline.json` + +## Mapeo con API +- `POST /anonymizer/predict` -> `flair-anonymizer` +- `POST /datapublic/predict/{document_id}` -> `full-paragraph` + +## Documentación relacionada +- Referencia API: [../api/README.md](../api/README.md) +- Base de datos interna: [../database/README.md](../database/README.md) diff --git a/docs/es/pipelines/anonymizer/README.md b/docs/es/pipelines/anonymizer/README.md new file mode 100644 index 00000000..2d241616 --- /dev/null +++ b/docs/es/pipelines/anonymizer/README.md @@ -0,0 +1,68 @@ +# Pipeline de Anonymizer +Idioma: [English](../../../pipelines/anonymizer/README.md) | **Español** + +Referencia técnica orientada al flujo de anonimización. + +## Alcance +Este flujo extrae entidades del texto judicial y compila documentos anonimizados. + +## Diagrama +![Diagrama del pipeline de anonymizer](../../../pipelines/anonymizer/pipeline.png) + +Fuente editable: [../../../pipelines/anonymizer/pipeline.excalidraw](../../../pipelines/anonymizer/pipeline.excalidraw) + +## Entrypoints de runtime +- `POST /misc/document-extract` +- `POST /anonymizer/predict` +- `POST /anonymizer/disambiguate` +- `POST /anonymizer/validation` +- `POST /anonymizer/anonymize-document` + +## Flujo paso a paso +1. Extracción de texto (`/misc/document-extract`) divide el documento fuente en párrafos normalizados. +2. Predicción (`/anonymizer/predict`) ejecuta NER por párrafo. +3. Desambiguación (`/anonymizer/disambiguate`) asigna IDs canónicos y metadatos efectivos para la desambiguación/anonimización. +4. Revisión manual en UI para editar etiquetas/políticas. +5. Compilación (`/anonymizer/anonymize-document`) aplica reemplazos y exporta `.odt` anonimizado. + +## Componentes técnicos + +### Configuración del pipeline +- Fuente: `resources/pipelines/production/flair-anonymizer/pipeline.json` +- Preprocesamiento: + - `aymurai.models.flair.utils.FlairTextNormalize` +- Modelo: + - `aymurai.models.flair.core.FlairModel` + - base model path: `aymurai/anonymizer-beto-cased-flair` +- Postprocesamiento: + - `aymurai.transforms.anonymization_postprocess.core.AnonymizationEntityCleaner` + - `aymurai.transforms.datetime_formatter.core.DatetimeFormatter` + +### Contratos de API usados por este flujo +- `DocumentInformation` +- `DocumentAnnotations` +- `LabelPolicy` +- `RenderPolicy` +- `EntityAttributes` (en particular: `canonical_entity_id`, `aymurai_label_instance`, `aymurai_disambiguation`, `aymurai_anonymize`) + +### Módulos backend relevantes +- Router: `aymurai/api/endpoints/routers/anonymizer/anonymizer.py` +- Render/anonymize: `aymurai/text/anonymization/doc_anonymizer.py` +- Desambiguación canónica: `aymurai/utils/entity_disambiguation/` + +## Persistencia (DB) +Tablas usadas por este flujo: +- `anonymization_paragraph` +- `anonymization_document` +- `anonymization_document_paragraph` + +## Notas +- Las políticas por label se mergean desde entorno y request. +- `render_policy` controla el comportamiento de sufijos (`auto`, `always`, `never`). + +## Documentación relacionada +- Índice de pipelines: [../README.md](../README.md) +- Entidades de anonymizer: [../../entities/anonymizer/README.md](../../entities/anonymizer/README.md) +- Model card de anonymizer: [../../models/anonymizer-model-card.md](../../models/anonymizer-model-card.md) +- Referencia API: [../../api/README.md](../../api/README.md) +- Base interna: [../../database/README.md](../../database/README.md) diff --git a/docs/es/pipelines/datapublic/README.md b/docs/es/pipelines/datapublic/README.md new file mode 100644 index 00000000..70bc7b36 --- /dev/null +++ b/docs/es/pipelines/datapublic/README.md @@ -0,0 +1,76 @@ +# Pipeline de Datapublic +Idioma: [English](../../../pipelines/datapublic/README.md) | **Español** + +Referencia técnica orientada al flujo de extracción de información del datapublic. + +## Alcance +Este flujo extrae información estructurada a partir de párrafos y soporta persistencia de validación a nivel documento para curación de dataset público. + +## Diagrama +![Diagrama del pipeline de datapublic](../../../pipelines/datapublic/pipeline.png) + +## Entrypoints de runtime +- `POST /misc/document-extract` +- `POST /datapublic/predict/{document_id}` +- `GET /datapublic/validation/document/{document_id}` +- `POST /datapublic/validation/document/{document_id}` + +## Flujo paso a paso +1. Extracción de texto (`/misc/document-extract`) divide el documento fuente en párrafos normalizados. +2. Predicción (`/datapublic/predict/{document_id}`) procesa cada párrafo y devuelve predicciones; la persistencia en caché ocurre solo cuando `use_cache=true` (default). +3. Revisión en UI agrega la salida validada a nivel documento. +4. Los endpoints de validación leen/escriben payload de validación de documento. + +## Componentes técnicos + +### Configuración del pipeline +- Fuente: `resources/pipelines/production/full-paragraph/pipeline.json` +- Preprocesamiento: + - `aymurai.models.flair.utils.FlairTextNormalize` +- Modelos: + - `aymurai.models.flair.core.FlairModel` (`aymurai/flair-ner-spanish-judicial`) + - `aymurai.models.decision.binregex.DecisionEmbeddingBagBinRegex` (`return_only_with_detalle=true` en producción) +- Postprocesamiento: + - `aymurai.transforms.entity_subcategories.regex.RegexSubcategorizer` + - `aymurai.transforms.datetime_formatter.core.DatetimeFormatter` + - `aymurai.transforms.entity_subcategories.sentence_transformer.SentenceTransformerSubcategorizer` (4 instancias configuradas en producción para `CONDUCTA`, `CONDUCTA_DESCRIPCION`, `DETALLE` y `OBJETO_DE_LA_RESOLUCION`) + - `aymurai.transforms.entity_subcategories.article.ArticleSubcategorizer` + +### Algoritmos y procesamiento +- Extracción NER sobre párrafos judiciales. +- Clasificación/filtro de decisiones para relevancia, con gating en producción para que `DECISION` solo se emita cuando ya existe una entidad `DETALLE`. +- Subcategorización rule-based + embeddings. +- Normalización de fecha/hora y mapeo por artículo. + +### Contratos de API usados por este flujo +- `TextRequest` +- `DocumentInformation` +- `DataPublicDocumentAnnotations` (payload libre de validación a nivel documento) + +### Módulos backend relevantes +- Router: `aymurai/api/endpoints/routers/datapublic/datapublic.py` +- Carga de pipeline e inferencia: endpoint de predicción en `aymurai/api/endpoints/routers/datapublic/datapublic.py`. + +## Persistencia (DB) +Tablas usadas por este flujo: +- `datapublic_paragraph` +- `datapublic_document` +- `datapublic_document_paragraph` + +## Notas +- El directorio de pipeline en producción sigue llamándose `full-paragraph`. +- `document_id` es la clave de agrupamiento a nivel documento para asociar predicciones por párrafo y el payload de validación. +- La persistencia de validación es a nivel documento y acepta intencionalmente un objeto JSON libre. +- `GET /datapublic/validation/document/{document_id}` devuelve `404` cuando el documento no existe; `POST` crea o actualiza el payload de validación. +- El router público no monta actualmente `/datapublic/dataset/*`. +- La validación a nivel párrafo aparece en código como lógica legacy comentada y no forma parte del flujo público. + +## Modelos usados por este flujo +- Flair NER: [../../models/flair-model-card.md](../../models/flair-model-card.md) +- Clasificador de decisiones: [../../models/decision-model-card.md](../../models/decision-model-card.md) + +## Documentación relacionada +- Índice de pipelines: [../README.md](../README.md) +- Entidades de datapublic: [../../entities/datapublic/README.md](../../entities/datapublic/README.md) +- Referencia API: [../../api/README.md](../../api/README.md) +- Base interna: [../../database/README.md](../../database/README.md) diff --git a/docs/models/README.md b/docs/models/README.md new file mode 100644 index 00000000..7f2aeafb --- /dev/null +++ b/docs/models/README.md @@ -0,0 +1,19 @@ +# Models +Language: **English** | [Español](../es/models/README.md) + +This section documents the individual models used by the backend. + +## Available model docs +- Anonymizer NER model card: [anonymizer-model-card.md](anonymizer-model-card.md) +- Flair NER: [flair-model-card.md](flair-model-card.md) +- Decision classifier: [decision-model-card.md](decision-model-card.md) + +## Current production usage +- `flair-anonymizer` uses the anonymizer NER model card documented here. +- `full-paragraph` uses the Flair NER model and the decision classifier. + +## Related docs +- Documentation index: [../README.md](../README.md) +- Pipelines index: [../pipelines/README.md](../pipelines/README.md) +- Anonymizer flow: [../pipelines/anonymizer/README.md](../pipelines/anonymizer/README.md) +- Datapublic flow: [../pipelines/datapublic/README.md](../pipelines/datapublic/README.md) diff --git a/docs/models/anonymizer-model-card.md b/docs/models/anonymizer-model-card.md new file mode 100644 index 00000000..53a46813 --- /dev/null +++ b/docs/models/anonymizer-model-card.md @@ -0,0 +1,172 @@ +--- +license: mit +language: +- es +tags: +- flair +- token-classification +- sequence-tagger-model +- anonymization +- judicial-text +datasets: +- ArJuzPCyF10 +metrics: +- precision +- recall +- f1-score +widget: +- text: 1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas. +library_name: flair +pipeline_tag: token-classification +--- + +Language: **English** | [Español](../es/models/anonymizer-model-card.md) + +# Model Description + +This model is the NER component used by the production `flair-anonymizer` pipeline. +It detects spans that should be anonymized in judicial documents before disambiguation, validation, and document rendering. + +Following the Flair guidelines for NER training, the model was trained on top of [BETO embeddings](https://huggingface.co/dccuchile/bert-base-spanish-wwm-uncased), a Spanish BERT model, with a BiLSTM-CRF architecture. + +This model was developed by [{ collective.ai }](https://collectiveai.io) as part of the [AymurAI](https://aymurai.info) project by [DataGenero](https://datagenero.org). + +## Intended uses & limitations + +AymurAI is intended to help address the lack of available data on gender-based violence (GBV) rulings in Latin America. In the anonymization workflow, the immediate purpose of this model is to identify sensitive spans in legal documents so they can be reviewed and replaced before downstream use. + +AymurAI remains a domain-specific system. Its capabilities are limited to semi-automated anonymization, collection, and analysis of judicial data, and the output may be affected by annotation quality, document heterogeneity, OCR or extraction errors, and the availability of representative training data. + +This model was trained on a closed dataset from an Argentine criminal court. That domain specificity improves performance on the target setting, but it also means the model may not transfer well to other jurisdictions, document styles, or legal cultures. + +## Production behavior + +In production, this model is loaded through `aymurai.models.flair.core.FlairModel` from: + +- `resources/pipelines/production/flair-anonymizer/pipeline.json` +- model path: `aymurai/anonymizer-beto-cased-flair` + +Its raw span predictions are then post-processed by: + +- `aymurai.transforms.anonymization_postprocess.core.AnonymizationEntityCleaner` +- `aymurai.transforms.datetime_formatter.core.DatetimeFormatter` + +Those predictions feed the rest of the anonymization flow: + +1. `POST /anonymizer/predict` runs span extraction. +2. `POST /anonymizer/disambiguate` assigns canonical entity IDs and effective per-label metadata. +3. Manual review may edit labels, `label_policies`, and `render_policy`. +4. `POST /anonymizer/anonymize-document` applies replacements in the output document. + +# Usage + +## How to use the model in Flair + +Requires **[Flair](https://github.com/flairNLP/flair/)**. +Install it with `pip install flair`. + +```python +from flair.data import Sentence +from flair.models import SequenceTagger + +tagger = SequenceTagger.load("aymurai/anonymizer-beto-cased-flair") + +sentence = Sentence( + "1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento " + "de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO " + "MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves " + "agravadas, amenazas simples y agravadas por el uso de armas." +) + +tagger.predict(sentence) + +for entity in sentence.get_spans("ner"): + print(entity) +``` + +This yields output similar to: + +```text +Span[22:25]: "EZEQUIEL CAMILO MARCONNI" -> PER (0.9541) +Span[27:28]: "11.222.333" -> DNI (1.0) +``` + +## Using the model in an AymurAI pipeline + +```python +from aymurai.pipeline import AymurAIPipeline + +pipeline = AymurAIPipeline.load("/resources/pipelines/production/flair-anonymizer") + +item = { + "path": "dummy", + "data": { + "doc.text": ( + "Acusado: Ramiro Marrón DNI 34.555.666. " + "Fecha: 17 de noviembre de 2024." + ) + }, +} + +processed = pipeline.preprocess([item]) +processed = pipeline.predict_single(processed[0]) +processed = pipeline.postprocess([processed]) + +print(processed[0]["predictions"]["entities"]) +``` + +# Entities and metrics + +## Description + +Please refer to the anonymizer entities catalog ([en](../entities/anonymizer/README.md)|[es](../es/entities/anonymizer/README.md)). + +## Data + +The model was trained with a dataset of 535 legal rulings from an Argentine criminal court. + +Due to the nature of the data (personal data, complaint characteristics, and victim protection), the documents are kept private. + +## Metrics + +The following per-label metrics come from the published Hugging Face card for this anonymizer model family and should be interpreted as model-level NER metrics, not end-to-end anonymization quality. + +| label | precision | recall | f1-score | +|---|---:|---:|---:| +| `BANCO` | 1.00 | 0.90 | 0.95 | +| `CBU` | 0.92 | 0.92 | 0.92 | +| `CORREO_ELECTRONICO` | 1.00 | 1.00 | 1.00 | +| `CUIJ` | 1.00 | 1.00 | 1.00 | +| `CUIT_CUIL` | 1.00 | 1.00 | 1.00 | +| `DIRECCION` | 0.97 | 0.85 | 0.91 | +| `DNI` | 0.96 | 1.00 | 0.98 | +| `EDAD` | 1.00 | 0.95 | 0.97 | +| `ESTUDIOS` | 1.00 | 1.00 | 1.00 | +| `FECHA` | 1.00 | 0.99 | 1.00 | +| `LINK` | 1.00 | 0.94 | 0.97 | +| `LOC` | 0.99 | 0.72 | 0.83 | +| `MARCA_AUTOMOVIL` | 0.95 | 1.00 | 0.97 | +| `NACIONALIDAD` | 1.00 | 0.94 | 0.97 | +| `NUM_ACTUACION` | 0.84 | 0.96 | 0.90 | +| `NUM_CAJA_AHORRO` | 0.00 | 0.00 | 0.00 | +| `NUM_EXPEDIENTE` | 0.98 | 0.92 | 0.95 | +| `NUM_MATRICULA` | 0.33 | 0.50 | 0.40 | +| `PATENTE_DOMINIO` | 1.00 | 1.00 | 1.00 | +| `PER` | 0.98 | 0.97 | 0.98 | +| `TELEFONO` | 0.97 | 1.00 | 0.99 | +| `TEXTO_ANONIMIZAR` | 0.98 | 0.61 | 0.75 | +| `macro avg` | 0.91 | 0.88 | 0.89 | + +# Citation + +Please cite [the following paper](https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view) when using AymurAI: + +```bibtex +@techreport{feldfeber2022, + author = {Feldfeber, Ivana and Quiroga, Yasm{\'i}n Bel{\'e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} +} +``` diff --git a/docs/pipeline/assets/ner-schema.png b/docs/models/assets/ner-schema.png similarity index 100% rename from docs/pipeline/assets/ner-schema.png rename to docs/models/assets/ner-schema.png diff --git a/docs/models/decision-model-card.md b/docs/models/decision-model-card.md new file mode 100644 index 00000000..066c2395 --- /dev/null +++ b/docs/models/decision-model-card.md @@ -0,0 +1,217 @@ +--- +license: mit +language: +- es +tags: +- text-classification +- embeddingbag +- binary-classification +- judicial-text +datasets: +- ArJuzPCyF10 +metrics: +- f1 +widget: +- text: 1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas. +library_name: torch +pipeline_tag: text-classification +--- + +Language: **English** | [Español](../es/models/decision-model-card.md) + +# Model Description + +This model is the current paragraph-level decision classifier used in the production `full-paragraph` pipeline. +It estimates whether a paragraph contains a judicial decision and, when used inside the AymurAI pipeline, emits a synthetic `DECISION` entity with a rule-based subclass. + +This model was developed by [{ collective.ai }](https://collectiveai.io) as part of the [AymurAI](https://aymurai.info) project by [DataGenero](https://datagenero.org). + +## Architecture + +The current production classifier is a compact hashed bag-of-words model implemented with `torch.nn.EmbeddingBag`. +Its inference path is defined in `aymurai/models/decision/binregex.py` and `aymurai/models/decision/embeddingbag.py`. + +At a high level, the model works as follows: + +1. Input text is normalized with accent stripping, lowercasing, and whitespace collapsing. +2. Text is tokenized by whitespace. +3. Tokens are hashed with BLAKE2b into a fixed vocabulary. +4. Token IDs are pooled with mean `EmbeddingBag` embeddings. +5. A dropout layer and a linear head produce binary logits (`not decision`, `decision`). +6. If the positive score exceeds the configured threshold, the pipeline appends a `DECISION` label to the paragraph. + +Current checkpoint configuration loaded with the production model: + +| parameter | value | +|---|---| +| `vocab_size` | `20000` | +| `embed_dim` | `64` | +| `max_tokens` | `128` | +| `dropout` | `0.1` | +| `num_classes` | `2` | +| `batch_size` | `512` | +| `lr` | `0.005` | +| `weight_decay` | `0.001` | +| `epochs` | `50` | + +## Intended uses & limitations + +AymurAI is intended to be used as a tool to address the lack of transparency in the judicial system regarding gender-based violence (GBV) cases in Latin America. The goal is to increase report levels, build trust in the justice system, and improve access to justice for women and LGBTIQ+ people. AymurAI will generate and maintain anonymized datasets from legal rulings to understand GBV and support policy making, and also contribute to feminist collectives' campaigns. + +AymurAI capabilities are limited to semi-automated data collection and analysis, and the results may be subject to limitations such as the quality and consistency of the data, potential biases in the AI model, and the availability of the data. Additionally, the effectiveness of AymurAI in addressing the lack of transparency in the judicial system and improving access to justice may also depend on other factors such as the level of cooperation from court officials and the broader cultural and political context. + +This model was trained on a closed dataset from an Argentine criminal court. It is designed to identify whether a paragraph contains a judicial decision. The use of a domain-specific dataset from an Argentine criminal court ensures that the model is tailored to the specific legal and cultural context, allowing for more accurate results. However, it also means that the model may not be applicable or effective in other countries or regions with different legal systems or cultural norms. + +## Production behavior + +When this classifier is used through `DecisionEmbeddingBagBinRegex`, the production behavior includes two additional rules beyond the raw binary prediction: + +- The positive class is emitted only when the decision score is above the configured threshold (`0.5` in the production pipeline). +- With `return_only_with_detalle=true`, the classifier only appends a `DECISION` entity if the paragraph already contains a `DETALLE` entity from the NER stage. + +If a paragraph is classified as a decision, the model emits a `DECISION` entity covering the full paragraph text. The emitted label includes a rule-based subclass: + +- `hace_lugar` +- `no_hace_lugar` + +That subclass is assigned with regex-based post-processing over the paragraph text. + +# Usage + +## How to use the model in torch + +```python +import torch + +from aymurai.models.decision.binregex import DecisionEmbeddingBagBinRegex + +model = DecisionEmbeddingBagBinRegex( + model_checkpoint="https://github.com/AymurAI/backend/releases/download/v2.0.0-alpha.1/tiny-embeddingbag.safetensors", + device="cpu", + threshold=0.5, + return_only_with_detalle=False, +) + +text = "1. DECLARAR EXTINGUIDA LA ACCION PENAL en este caso por cumplimiento de la suspension del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas." + +flat_tokens, offsets = model.model_input_from_text(text) +with torch.no_grad(): + logits = model.model(flat_tokens, offsets) + probabilities = logits.softmax(dim=1).cpu().numpy() + +print(probabilities) +print(model.get_subcategory(text)) +``` + +This yields output similar to: + +```text +[[0.0010057, 0.9989943]] +['hace_lugar'] +``` + +The first column is the probability of the text not being a decision, and the second column is the probability of the text being a decision. + +## Using the model in an AymurAI pipeline + +The current production `full-paragraph` pipeline includes this classifier after the Flair NER stage. + +```python +from aymurai.pipeline import AymurAIPipeline + +pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") + +item = { + "path": "dummy", + "data": { + "doc.text": "1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas." + }, +} + +processed = pipeline.preprocess([item]) +processed = pipeline.predict_single(processed[0]) +processed = pipeline.postprocess([processed]) + +print(processed[0]["predictions"]["entities"]) +``` + +In production, the classifier is configured as: + +```json +{ + "aymurai.models.decision.binregex.DecisionEmbeddingBagBinRegex": { + "model_checkpoint": "https://github.com/AymurAI/backend/releases/download/v2.0.0-alpha.1/tiny-embeddingbag.safetensors", + "device": "cpu", + "threshold": 0.5, + "return_only_with_detalle": true + } +} +``` + +# Entities and metrics + +## Description + +This model only considers the classification of paragraphs as decisions or non-decisions. +When the prediction is positive, the pipeline emits a synthetic `DECISION` entity that spans the full paragraph. + +For the complete list of entities used by the datapublic flow, please refer to the datapublic entities catalog ([en](../entities/datapublic/README.md)|[es](../es/entities/datapublic/README.md)). + +For a complete description of the entities considered by AymurAI, refer to the [Glossary for the Dataset with gender perspective](https://docs.google.com/document/d/123B9T2abCEqBaxxOl5c7HBJZRdIMtKDWo6IKHIVil04/edit) written by [DataGenero](https://datagenero.org) (Spanish only). + +## Data + +The model was trained with a dataset of 1200 legal rulings from an Argentine criminal court. + +Due to the nature of the data (personal data, complaint characteristics, and victim protection), the documents are kept private. + +### List of annotation contributors + +The dataset was manually annotated by: + +* Diego Scopetta +* Franny Rodriguez Gerzovich ([email](mailto:fraanyrodriguez@gmail.com)|[linkedin](https://www.linkedin.com/in/francescarg)) +* Laura Barreiro +* Matías Sosa +* Maximiliano Sosa +* Patricia Sandoval +* Santiago Bezchinsky ([email](mailto:santibezchinsky@gmail.com)|[linkedin](https://www.linkedin.com/in/santiago-bezchinsky)) +* Zoe Rodriguez Gerzovich + +## Metrics + +The following metrics were obtained from the current EmbeddingBag training/evaluation notebook and correspond to the binary decision classification task (`0 = not decision`, `1 = decision`). + +### Validation split + +| metric | class 1 (decision) | overall | +|---|---:|---:| +| precision | 0.774 | - | +| recall | 0.896 | - | +| f1-score | 0.830 | - | +| accuracy | - | 0.962 | +| support | 336 | 3211 | + +### Test split + +| metric | class 1 (decision) | overall | +|---|---:|---:| +| precision | 0.754 | - | +| recall | 0.905 | - | +| f1-score | 0.823 | - | +| accuracy | - | 0.959 | +| support | 336 | 3211 | + +# Citation + +Please cite [the following paper](https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view) when using AymurAI: + +```bibtex +@techreport{feldfeber2022, + author = {Feldfeber, Ivana and Quiroga, Yasm{\'i}n Bel{\'e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} +} +``` diff --git a/docs/pipeline/flair-model-card.md b/docs/models/flair-model-card.md similarity index 69% rename from docs/pipeline/flair-model-card.md rename to docs/models/flair-model-card.md index 15fd493d..8b9ceddc 100644 --- a/docs/pipeline/flair-model-card.md +++ b/docs/models/flair-model-card.md @@ -16,23 +16,24 @@ library_name: flair pipeline_tag: token-classification --- +Language: **English** | [Español](../es/models/flair-model-card.md) + # Model Description

schema

-Following the FLAIR guidelines for training a NER model, we trained a model on top of [BETO embeddings](https://huggingface.co/dccuchile/bert-base-spanish-wwm-uncased) (a spanish version of BERT trained in a spanish corpus) and a BiLSTM-CRF architecture. +Following the Flair guidelines for training a NER model, we trained this model on top of [BETO embeddings](https://huggingface.co/dccuchile/bert-base-spanish-wwm-uncased), a Spanish version of BERT trained on a Spanish corpus, with a BiLSTM-CRF architecture. This model was developed by [{ collective.ai }](https://collectiveai.io) as part of the [AymurAI](https://aymurai.info) project by [DataGenero](https://datagenero.org). - - +It is currently used as the NER component of the production `full-paragraph` pipeline. # Intended uses & limitations AymurAI is intended to be used as a tool to address the lack of transparency in the judicial system regarding gender-based violence (GBV) cases in Latin America. The goal is to increase report levels, build trust in the justice system, and improve access to justice for women and LGBTIQ+ people. AymurAI will generate and maintain anonymized datasets from legal rulings to understand GBV and support policy making, and also contribute to feminist collectives' campaigns. -AymurAI is still a prototype and is only being implemented in Argentina and Mexico. Its capabilities are limited to semi-automated data collection and analysis, and the results may be subject to limitations such as the quality and consistency of the data, potential biases in the AI model, and the availability of the data. Additionally, the effectiveness of AymurAI in addressing the lack of transparency in the judicial system and improving access to justice may also depend on other factors such as the level of cooperation from court officials and the broader cultural and political context. +AymurAI capabilities are limited to semi-automated data collection and analysis, and the results may be subject to limitations such as the quality and consistency of the data, potential biases in the AI model, and the availability of the data. Additionally, the effectiveness of AymurAI in addressing the lack of transparency in the judicial system and improving access to justice may also depend on other factors such as the level of cooperation from court officials and the broader cultural and political context. -This model was trained with a closed dataset from an Argentine criminal court. It's is designed to identify and extract relevant information from court sentences related to GBV cases. The use of a domain specific dataset from an Argentine criminal court ensures that the model is tailored to the specific legal and cultural context, allowing for more accurate results. However, it also means that the model may not be applicable or effective in other countries or regions with different legal systems or cultural norms. +This model was trained on a closed dataset from an Argentine criminal court. It is designed to identify and extract relevant information from court sentences related to GBV cases. The use of a domain-specific dataset from an Argentine criminal court ensures that the model is tailored to the specific legal and cultural context, allowing for more accurate results. However, it also means that the model may not be applicable or effective in other countries or regions with different legal systems or cultural norms. # Usage ## How to use the model in Flair @@ -76,36 +77,11 @@ Span[39:40]: "amenazas" → CONDUCTA (0.956) Span[40:48]: "simples y agravadas por el uso de armas" → CONDUCTA_DESCRIPCION (0.6866) ``` -## Using the model in aymurai pipeline -You also can run the model directly in the aymurai pipeline. +## Using the model in an AymurAI pipeline +You can also run the model through an AymurAI pipeline. ```python from aymurai.pipeline import AymurAIPipeline -from aymurai.models.flair.utils import FlairTextNormalize -from aymurai.models.flair.core import FlairModel - -config = { - "preprocess": [ - [ - "aymurai.models.flair.utils.FlairTextNormalize", - {} - ] - ], - "models": [ - [ - "aymurai.models.flair.core.FlairModel", - { - "basepath": "https://drive.google.com/uc?id=1QJYkegv_P3d27FyRLabIUiw9154ur9-I&confirm=true", - "split_doc": false, - "device": "cpu" - } - ] - ], - "postprocess": [], - "use_cache": false -} -} - pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") @@ -116,7 +92,11 @@ item = { } } -pipeline.predict([item]) +processed = pipeline.preprocess([item]) +processed = pipeline.predict_single(processed[0]) +processed = pipeline.postprocess([processed]) + +print(processed[0]["predictions"]["entities"]) ``` @@ -124,24 +104,26 @@ pipeline.predict([item]) # Entities and metrics ## Description -Please refer to the entities' description table ([en](../data/en/entities-table.md)|[es](../data/es/entities-table.md)). +Please refer to the datapublic entities catalog ([en](../entities/datapublic/README.md)|[es](../es/entities/datapublic/README.md)). For a complete description about entities considered by AymurAI, refer to the [Glossary for the Dataset with gender perspective](https://docs.google.com/document/d/123B9T2abCEqBaxxOl5c7HBJZRdIMtKDWo6IKHIVil04/edit) written by [DataGenero](https://datagenero.org) (spanish only) ## Data The model was trained with a dataset of 1200 legal rulings from an Argentine criminal court. -Due to the nature of the data (personal data, complaint characteristics and victim protection) the documents are kept private. +Due to the nature of the data (personal data, complaint characteristics, and victim protection), the documents are kept private. + ### List of annotation contributors The dataset was manually annotated by: * Diego Scopetta -* Franny Rodriguez Gerzovich ([email](fraanyrodriguez@gmail.com)|[linkedin](https://www.linkedin.com/in/francescarg)) +* Franny Rodriguez Gerzovich ([email](mailto:fraanyrodriguez@gmail.com)|[linkedin](https://www.linkedin.com/in/francescarg)) * Laura Barreiro * Matías Sosa * Maximiliano Sosa * Patricia Sandoval -* Santiago Bezchinsky ([email](santibezchinsky@gmail.com)|[linkedin](https://www.linkedin.com/in/santiago-bezchinsky)) +* Santiago Bezchinsky ([email](mailto:santibezchinsky@gmail.com)|[linkedin](https://www.linkedin.com/in/santiago-bezchinsky)) * Zoe Rodriguez Gerzovich + ## Metrics | label | precision | recall | f1-score | @@ -179,10 +161,10 @@ Please cite [the following paper](https://drive.google.com/file/d/1P-hW0JKXWZ44F ```bibtex @techreport{feldfeber2022, - author = "Feldfeber, Ivana and Quiroga, Yasmín Belén and Guevara, Clarissa and Ciolfi Felice, Marianela", - title = "Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico", - institution = "DataGenero", - year = "2022", - url = "https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view" + author = {Feldfeber, Ivana and Quiroga, Yasm\'{\i}n Bel\'{e}n and Guevara, Clarissa and Ciolfi Felice, Marianela}, + title = {Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico}, + institution = {DataGenero}, + year = {2022}, + url = {https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view} } ``` diff --git a/docs/pipeline/README.md b/docs/pipeline/README.md deleted file mode 100644 index 22514bf3..00000000 --- a/docs/pipeline/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Pipeline -

-schema -

- -The AymurAI pipeline is written in a modular way, each step is independent and can be replaced by another one. This allows us to easily change the models or the way in which the information is processed. -It's made up of three main steps: preprocessing, inference and postprocessing. -The preprocessing step is in charge of dividing the court rulings into paragraphs and normalizing their text. The inference step is in charge of extracting the information from the paragraphs. Finally, the postprocessing step is in charge of filtering out irrelevant decisions and formatting the text. -# Preprocessing -The flow of information in the system starts with a pre-processing step for the court rulings, where the documents are divided into paragraphs and their text is normalized. This normalization process involves the unification of multiple spaces and the removal of accents and/or special characters . -In this way, the paragraphs become the minimum unit of analysis, and predictions are generated in parallel and independently from one another. - - -# Inference -

-schema -

- -The fundamental piece of the AymurAI backend is the AI models. They are in charge of extracting information from court rulings. -For their development, we use the following work frameworks: -The NER model was developed using [Flair](https://github.com/flairNLP/flair), a Python library created by Humboldt - University of Berlin focused on natural language processing models. Flair is based on PyTorch, one of the main artificial intelligence frameworks, and allows integration with Transformers, another of the main libraries of natural language processing models. -For the decision model we use PyTorch natively. - -Each paragraph is processed by these models, and the results are combined. - -Check out the [model cards](#model-cards) for more information about the models, and the [model training](#model-training-notebooks) section for more information about how the models were trained. - -# Postprocessing -Once the inference is made, the predictions are postprocessed in order to obtain the final results. -This process involves: -* Subcategorization extraction or classification -* Filtering out irrelevant decisions -* Text formatting - -## Subcategorization -* Regex -Regular expressions allow us to identify some subcategories whose texts tend to be repeated following very marked patterns. - -* Sentence Similarity -Entities with many subcategories, and less well represented, are identified using sentence similarity. The Universal Sentence Encoder Multilingual QA model, published by Google, allows us to encode the text identified as belonging to certain categories in order to then calculate a semantic similarity score with respect to each possible subcategory and thus generate a ranking of candidates, ordered from highest to lowest similarity. - - -## Text Formating -The NER model extract non-structured information from the text. Dates and times are reformatted to a standard format. - -## Filters -Many of the decisions that are extracted by the models are not relevant to the user. Relevant decisions are those that contain a specific type of information, such as presence of other relevant entities (e.i DETALLE) - -# Models -## Model cards -* [Flair NER Spanish Judicial](./flair-model-card.md) -* [Decision Text Classification](./decision-model-card.md) - -# Model Training Notebooks -* [Flair NER Spanish Judicial](../../notebooks/experiments/ner/flair/) -* [Decision Text Classification](../../notebooks/experiments/decision/) diff --git a/docs/pipeline/assets/decision-confusion-matrix.png b/docs/pipeline/assets/decision-confusion-matrix.png deleted file mode 100644 index a88291fe5890ed66542e08275fcdc043dbd39414..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15037 zcmbt*1yogQ*X}mZBZ?js4AKB80qF)65jRM83rI_YbQr*q)GeVj(wmlU6afK28l(|6 z-QC=|h;zR0|Ne3B|Brjd@T{eK#k<~^^O?`{yly9h(htupnvkRN z2|xaI@ncfH8SPQgYk$&R3+t!wTeUuyfFa@YG}ZWNujW55Fv>H!Q%6Z?jJV!3~>$5HunqDELvC5ZZvDf%#1iznP+4f4e!^lVdY`uD7=e0r4LWgB6 zF{f#YMv24tw>KBP-n?mom!>b^>Uh%%c6T<}%?IxC?`|!MN=Q5>?Juy>f47x_a{FEL z);)jZR-7=Hn*)o6pVG7Bo|!;OGrZr*<6{Mc00yqy`+iaSdU zyt8BBwtdpL+Q2sG82qnf4t{a$q|re6i*-LH<2ijGHN{%4%xhc%CK ztB2?P4-Y*HxO=}Y`*o`yMI}C~PkRnwqPCt}-}aOQ{`;0y=cjRzyz|wD*z>zjyk!c$F8TN#U3FnwtTk*8`5BP~|Kq=yCD;SDgK~v(5|W;mVAw z^hgsk&Z^!Bfx(0uc(T)xVMWgP#tglr&ce@i8C0LR?<4O_sSquoeXfZt@@G|htw<5t z^rAiZE$FZReAPLJ!w07Xglex6!JXxLDgWhFEFNEG==Bbo$^UnQr|JLmd1gy&l|g^O zQ{3v6Xivhy#z2!<80HI{*)_Hh?stGzT+e@;UH|9(uPxyLN>z6()yeVZYw6PsV19^7 zN-E08U<7uztk{iOzZ*8JOn2*E@o4!V=vvwm)|F#yyuGnp`{RckTof-EnI;n_%3VL+ zo*JsHqho`sB_iW@kQ4GaLpwL?zSn7!!?*$g{3uv6_~*_kR{N0=UAXXxMYq;qaipG3 zF)gg681M8Ynrqj}nIHO-Pjiiqk0%k3aD1<;6AS0DX@*e7W<4e)9>&$goB(mCD?{s5 zu33Ltd#bAO%G58FY=d_WD^to*4*Zl?@d|%SUfcX?Q6z>!1*ZOLo4J6xTfjX!#rUNr z&g8UuX|CF8HT>VG4O?hF`10keSIhOB{f`QBWp*mg368m6*0@tLQo1?QvaviVpQR@r zF6gR(VblKhhj=K5cpFw;RzkurULqXZSK^qgTNmUvDX=kiQ$9sWy2N3*aB$;b6!0@; zW^gzvO-;>&K^)FTNON*@lo~CHMqBU*7&Kl}&o{rfxiZ}nKr1Vk`%JmIAS&wGba&p* z^WUjxSy*ITTwIL$iVJiaf*4f8X0BenniLfkb#zMr=ulm5OvolA} z&&S8+xbkeeGgIi~SyFRS%}j0g6X(cNie^hyqoboYy8CzHadpAG4JVHur=g{-8Q16# zgww4VQb9q%UduWL&Mjjtu?H{>wrF2_co?;(C`(j-{``4ou5fP7JjbBvzIvgx1y8B@ zpsT9k%4~o7>(|Fkx^u+|h}jz7T%`7jA0v6NKk4u@CGDR-&;6X0b=tbVr@*QWA}!v@ zlk@@tJGP@$-@ZM<96ff-=J&T#RJU$noi|q`thTndsnBoUyz$#DbD8R}YHn_}hHy!e z_I?Ff9ZCs*PSfMD+s>$MJl9HB(M}jnwM? z{rdqyLGk(dT-9OZ{0>~b)RdGDnwpyMuz~y2P$`>A+s-Z@=^Th`bT@Ab?df5+-c2uA3F*oR#qB9&Mbr!*_Nd*DIUS6 zJUBS$N3?0%@2rUQMz&!~YrcgJ|N8KI;yX{=zJC3RFUO>M<7m0~S6HWBue9^1es8>V zZ_}jjsCJsX&+4H?ZsB>B4Ext#f57Ats|#jQ^uEL}JTw%;s^2gMdA4J?=6&G1cY_}^ z6C}v$BLy{Wdu@VQSXqhApO045uoo^U*meFWooCuhcZ(c!yR{yu{@>ao{uROrEb8)Xl#`)|)mwGW>1XRUbVCVo%z z*Ess+#(oj(HvcwJ&!(2IlkO*p2!Tm9>h)2=5|()en@L_N+m*3|lb-xBt|t9j4rNnQ z&$i31OC}4CYVcSO=eKY}djI0}vvqT@+PYfZxo!K!7YC-_F`+A2N6eYbigzT{>-}tr zH&>mfxn`%QQ}afPlVV?Q7k;pO5SgMDHPM#brNk`t$YXHBTqh-116UFy&la_@Z>g{fNnadG-I4Ez4V!V?YL(m=UL@FX`c;J0%nPDSQmA(eU5`0pE~J<~LPtA(zjTO*Zp~;d!;^ij zNk4l#*^CP9>biwT)_FPZ>~uGc-s-ACFg_tUWI+SXdvE5%MySvjO+3x&%yx#5iMmv2 zQL&#=8X6HCrt6}=e*H4)A9-FKHXI=58_6LOon98JYFa?m?_9RS@i52e#MopwbKz>b zP}|}zK@&-ImNM;0scU(7?H!T{+BU5V!Cn*)HO6Tx(b&`s(UIt{U?{k zvnDz-Q`K=t-QVly3-o+QrN_x*<(lROD~JdQW8K`0lf5CBbro181l?BtG(7y2x9(La z-euR-)um-%=p7GP9A%=p78N2+bj$sB4g|2e=@agK08q`iQC252kPt#wlE{-}<5!qJLqEE)afSOY+_34>eTP$@xNtEU2 zFG1?v^vZQQxlS>yQ|YSt`}}pUykuxHfbO=0NEa-1gx%MrEy#1p1y-Y2*#wC)$4F+K zDub=Hd5LOErZ~D;86)XHFTqSs{nD6p+ZlxiYpVE(JN@!;kqr?oUh$Mb^=*5$j?C;@6^;t|`^wF}En>$l2g~J%>IO2(*Fv&R zx>wSLiG3Zr2r&{bC@3iHridiXos5XwXX_99`uY|YlLxX@0I#r9-5Qy_cXH><8HZZ& zU+uDeSb2JPclYg)bpYHsro9{IW-k&GWATaTxCoANpQ&gJW$kZjPYie1olaUOFD=Fd zQlS^-mdtr(#>Z)g1b3B9ek@8F$Un#zP_;BEUTlAWZuU8)!)E#IPjoXGL+H4XX_^a< zV}pgitYD=W#^{7x8Mh!QDsN;+R)T<}RsQ~0`%0JH7)a7>C61S?*B|;4V@-Qix^gC0 zcg0xT1TS|h)Ly)Jv8~kEkxam;bIA#?N?<@hndhpjuD(7!FK@@;fXw4*3hF1#39eq%F)*=PfJ}U}Cj?7Ef6_ zEp)nKHD~_}q*Yg0)PF43xpi)7X>7jGY5lWN2R4aQ(^2|Mcvt`2s-1&_QD63a$OR5f zp$OvC&$?#P9e&en6Thmxmqw2al$xf>3)Ka?CyNG(7Mfod?w{#NZBXB&<6iI5{_4%- zs|fK*K)K*9OqH%J=*S;gIwonvG{?!8*l^cta$VK00))`88^p^o=~jpn4a895Mn>p3 zI25w<>YHKqPc%DcF_G>Lp;6}V{{`yq*kRmVKHh1>8Q1x%O1};yWXd&tvsObLIrd&s zKzh76PCjQMNAUzTH8pQZ%^AqRrms)(ixYWsI>1zwhv@Y@7;?H>sBeU&Y;n^?xFAD0 za}U_wJ@w^P#9edU|xUwCI)uN!w!0(L&SS zLR$E0#Wc01rWg_Sr{CWm-Q5Sn=DfXyHnITdpzKY2`xZt__F*WenL>djj?@akS8JY` zCc+0yKxG1`HmNOHk+;DSMy+%0btt5& z$X{kulQK8YC|w^Rkx!Jm2Y+oWe{l@3DIHp7sLI!7tns?dRHrmEGjri=>1H;3Yg>x4 z?C8(PU`pRB%=cU3#bx2*fcNiXl4KLGwzGXkzdpwe75(=`MpNnU|F+0@M~O@rByWAz z_10;Cirr>o$q)|@4~=>G@@2MJzktZK;MniqAFZ#iC)qEK_;Ht&RxfjR%v!|kLqMN* z`uTiSK38LwmaG$)^?rO1+>!v&sXl^VmG}8nBOqr=^pPV+YHMp{R8&G*dSYWK@s1zo z8lj}3!tuIp_srJMFD|w)rqlwIB{klk$XGdD#I3=#pN;;e7e(@&mDKMj>2fZf(O zvCF|_n|e3*%V77;1U_C~RmkCZg?ckR1rsd^{!pb6QBcfsMSS=`V`gRs&E`%G+T7fv zXJ&?i5Gf;87XibE747VH_-{K%K%>&s3M?yZn)gudB%uCJ)(mfV|0yA86Ra{bGiw_f z6#U8gNvnZZi3QA02ekx-kc=!93NI`$C4Su3uU{7x6O&a_3)5*xpS5sqSa$58*<&6C zo`0>V*yFzD%8%84|8Ab5r>XfxLQ=BhccnMGar^DK*jO51=8#O)5Y9_<@#0N%SFwH8 z@87?(pZ#L-CFfUxE)3zb{|wI|qhEpPkQQM-auumFXUld=3vFl9jvPCY2y*}r8w@ae z;1*J%Ro=7czQFAKt%Olib+F_+Nrds0k@L1=jnQ6z{q@#*8g~!shSr<@d^ezG`Y&VE+)}>z=t^K%4vEIK+TMP6S~| z_OBY+IL+Tnyhlm|MJM!-?$Z-MMf}6I{5vVavJ?<{FfaaQVpxDWIruj?+rN|LMD!uW zfe;&erR*WG!UA_5T>tv8n(+v0=kj2K8b0pJmoHs;W|6?cM(u2G zCOfS!U}7OE7=C?yN?7F@T-xLLZgg0oM0KPKSmpaIS&j;nQ5DCfytm8Zy6o z0o~;02%Jrr7(Wj1SStjOMKVFxonm;m%Gf7(%s>PJBnq-+T;_iZw@s79hE+9@ix$C82Ugv+Dh5Y>pH2E_?`=<)7+O{82zy3v^7f zkmuR)A0JuiG)s$Nh7uAH#f9_Q8Z8Xh2&>;j8h#w8tHrlZ^BpWwRdQNC>xu<3X=*sG zOf_ZdRC{Hxb?9nxnc4y~`I)__3urqU&e5=5DlYEc+@iXUcHdqFBn`Pc*f#?8Yy*_d zCoCR3)wH2ku~;1^vstSj=^PKSeUw+gsFlWfp@w?@LuTHr5Lq#n@fkquT=z5U%0@#M z|NV_dnzYc|7O_`pbu~58?)XIb>V!yJ-w!Ud_{`MD1uj5n7?1WOueIG8^rTQwQ&Wrf zhO*bq@so39m>50o{VnlkD8hxvfExyO<9&+-1ly|~(amwE z1DBChe4#RKsrYHl1$D^J&Kpb8zW&%(UQ>>-B3vN>Q-tM=&^f+2x0dyD0&90Yw77gB;&9g|$t7Wem^9O} zv)SU}u#&~~NmSM{+BqdZqDEe)UP-}9)^dY35fb#|o7njoMOSjF#R+pFCM(RV6 z?1W^jn1{a2Yx6_PYeW8*r-E->?pD-rS=SYh6j0Zx_5(D!33+kITHxl*iokAUZ0ePB zHfuo=Nn$G7TCg2`3Kb5JTT5y%tgXq4OgY9K5)kAuu`sz5NH|Sf#h6NBfw=;n<`E=E zVgaXo5C#Y@Urqo}I2pOSm2insO)1JjU4^zE5+?#Fpvxw<))z&^#pR8Ru#6hTiLI@2 zil(QKF)6>pr$#P3omMm>10?8KGM-r5K6{Zsdd25qr}6P+;QE_y#X4Bb0pvkI82E6J zhzOT`mkijvTjC*!+Lc~-*h-k9P`h*o*1ixLlOCi`d-U*$}uJ!fx(SBo~-24P*`^z*1ch+Jg z!nmS~W(vi+b4{#D9$hYIExmyT045Tf(Nix-&KeVw7#Py%!sxdKaFp#OMA);2eJ>kD?)H^NA8 zGBoh^vKu#V+N>|=<`}kA%}1W!+S+1!KBaWf-%)q?aexYtR7;$eo%W$%xm{I0PLzm> zlJXJeQ%sC}k_;7cBXfe|>I~>ba*rST=tuw0kx_{pqa^%sRv`35{3mqDc;*xyx zuXpDCUAfqET{oxmB-|nDqRRC4=P{7Ofsp>G&{)l~QaFhNGN7)yS_A;8BCvIGd8X<% zvwiBu9cgV4{s^yLrA5OKzvVFLigiDIc>-h~IRse(!gb!7ul5@#)vm;c%E=f815oJ4 z6KAeOjYc?1Kn9_ko2`tCSOEDgbR{q$E{+G~h&Zj8DY!f6(P$U4Qvd=REZZ;JR?he705 zgd{^mPM+4;sRWSQ`1iLrcztK3EtvzTZ{4E1b4Lnvv*$d0fWyMMEWQS+!rDR!k4&bQ z1$kDR?Vc`oUhQ4=Tzw=i-Ud>Vi){m}L_$(hwSkSDV6kYY!LRNitonW)=O`E}?#KaU z4nWfoz$37bGSS|2wwUNS~0HNCQm8-u;|r8qytqKwCJq@}8EqsHy-AzD9Gp%dx>o!LJ*@_Qu}nm8a6)}3 zXR={SJOI2Fn9XJn5!u#U2tb9Eq1dzEgvUmGW7y22p|zYq8i6B+cEVJhMxEXTXLd4m~LyDM2=7 z{QMiaQe$EG073x9pa;1im`PIsq5?284Cn>G-JO{_-r0BI()@EmI{JgAc;o`KzCw!dAU<{k@ff| zsFDZ^X^>}A?_&q3a1yz#MiL>@LSljDB5;KrItjSyvV*J`g=AaR8-PLopCdguGuS0h zjxjaJ`wke~2;^1?v$@-{@jf6M$d@|V0|8IV%DSl6rhHAe*fgi;I7%wV(ghI+d2E>* zW-f%Kr0-w_o6A zZ;Arr2H~zP*F?4cBdZ8xu)2CIGS^K1>IGDmP4yc%MJjb;S;NkZ=ue+MA*#p?2Bch{ zq5k=5g@~1rKUEn*p2@Gz!Xkd8O%Oul;WN?ANco{t<#U5!zg0Bf_TVPqE_!Ne5x{^= zabm%w)lf_)ZO#;>AHdB)--r=4BhB$&SqXb|Uv)JvnV`c`A{5T5lIh@@Ze+rFu1Lfc5X`8q z0_z}mV`VxS>U-U%PZMFetCTq8K-CoZ;e#FP1OmKBV2Y`|5L$=&-UgyMJv+O+Z2aSb ztL#Vv#S1nW>C!Bd65vkU#%BMnMr#f<2}OkgfDN6|4jsLRk0s`Y6^pTg3Pe5K?o=$@&g-aqJIC_xT z5MT<~_R?*o0j}A}$z+JGK$o`|b?2r6!5B9`R6Plpl<7$h#`CnGPNrhjqynPR%F~a6 zu#cpLAw;9i=6R)7x`K-oupZ~BxYL@hDVVBW)NU~aT4D&dRlHt97%dtr75x(EBt#NU zRV$DY4`FM9_}vES5@>2s3^IXDdh(@#NI?`rq}e6wBcb?z{2>M6EhQ}*n;eMOvcR>R zmb9FMiS6cKWJa&nRlj`(Uqa0RlQV0Bem+=en97#nw*|+ z>*{0y5Rh8I0wsN+hCvo|Eczno!I^j2_eb#K*X(qktE>;l$HygfetclYOS^vU+FeXQ zK)|pyAHY=$M))fbK(;)Q`!FtnTW@u3*|vvfuZnilUBGYRCIfa@IZKb5tgg0}?isrB z=-yDd;v;ydp@DJ9`NGAERA`Vg{RB04w*YN(jmV{I^o|#TE}sM*89!sV05>~3%Qm_( zs@cE#a9{qbQ_7+GJ_gRiC)C~kBI`OGtbQbrwV3}}Q) z({P+-U!Lw(WKhXQs!*Gm9`01-tcMuDX4l~@Xb6?9NPLD&Vc1t}zX63n;M=#?&?=y3 z10c?^o7YBYieo3vG+O=S4^FQfIs6bpoY(5CVMkgx;-0A<1wI4ajG+=^1M3b_KR|7w zlJVpPB(_8{-sfXbzFSR5Q?MDlg}Ivm37d|INfI#wf%HK(+S1a3h`a8dp7anAYHDgi zxGX*)rNMy1uLM$*>4g=Li-7%euGLKE1(uaMTw{-A-S=^@xc_pl3~!P}!bhi1;GVa_ z!{(4~sKTD)-+gwl^7(OxG2q={tcZ55B>gv8^dFui=sMVT1)GFwrhWfXp!CHYQHLj_LMhRsV^NfpO0+4 z;a~i!)0JTpcXl^h)zSZf;rv2g+ntO)vj)wT@ggrt{wT-U*%>Z{Bur$G>qdn3Q10Y| z-{jklyO+cxcCfXZ8%lE*QSSPL+WD+qic;D(6FsUxTU$Dr_7!KA_AF&8q;^Gxuy4s{ zd6a3m=wi;2^I>^xOy$>#ld#Gan&$*rzE)w6Y<;wuvQD^h$vKu{Wl9$4>gC$WpN5qa z?uE%iyWH)ZKNT=!DViAwaz|C!<%;BN_FxfBZFPmFjufIJ;!_uMpn=w9~ z+pkw<Du>qkN_|9)tQy()c=^Je}dxhtX`idCyCVC(70B?d%NhkJWXROoD)8_rt>J zYe4XF?+kxevEk;d21V%@1DW@(L_furXxY=JkkL3zpV!=d_njV~LM2ZCKm%p)?yUE6 zLzTP-a^ZMM{tsJb>&^-J-9qnEzwe9%bys1EK<7HA%}gYKG;mJ0AR1c%(q_>p zkZg0FtBA9u%AaD^`dM?VatPbUxz{AJ2@RFuf(|D!Bjq! zZ(F{%qsWtdidRnG#mkn5(`@BNs?y5GmP`}g4x_D3!;Ow$&Fv9>e*W}rtAJe@AHid` zW&wn>tG@593HJ+}$4WhA|5^fLJ=P?0(qMhz zXBhdw(lSH3FNs2;TES;xo@cRia&tC(Z*2y@{;aJVN+(3&aq3o0PONrpvO5iAZQz2% zunOBNu`V1p^I#t)3fv& zls6VpY2PmUw&yalHZS%^)swWjXnd1Q$nd@MZ;&P3MvFRAOBBQ=xNw^yOsK>RgK=;B-7vQSW}zXL*f_wHT%XdM)dU~HrX67KFQ!;p=! zbihfJyG&|WWG@xUtwG%BFG6FYsL1wVgwGcee(?j~ z1|r_UbH->n51;t2Hy=D^@SddAvo}bY`**fD$$yCc{&@%zPxgG289rK982w*f;WSk% zojga*H@4?50TqXqn_C&YVjELgKjlgsY!Vz>)6`WbJJJ>P^x_e;kR*&??LzDE8)(FW>p?&g0OcU$ z=On;%h&>7zw55sU^h@@sdwhC+9MDyu-O={XgPJ`y>$+QX;w)(*)B$1`xH%rsLK6G| z6R|XK5}>s7eeT!kZde5ne z;OO9!|Alc|toH?Xb7QoS&Dxw6@ajT9JGXH5JH-J02Xo?GWo2a`3#|=axC3i5OZGnrH?2B2wMYngeDQaLaW=6 zW2P(qV;2r!J#_`{{DB9+x3RI2WTOwLSnzT@0RBw$@nZyT10NQKkY*rzNn>CfXk1-) zokr6m>5cZajQBgzh;#;%K%yeWrqajX-=CP{St3xLfQ#wi7tp-T!^~O}-$7ZI4CoFm zV{M(SlKU(P2rurD*RNmGFffQ)SXc;eik;t^Z015{CCfoz**+aE;H-jF_peV~3;>+! zFR<|l5UonFT_&)BaZpglB_tSwT!%Pcw6(P<(TEHSvKdtI2(eEOz4xA4Qo+t{jbPXN z?mbYJV6lCCS$h1tJmB+@Xnx{Pcs!q9gta|l0(_i3Z7$J zz5w7gs5hE`nVB_ zM$%Vo+y8jJ-sMXDfJlp~^7O&7rQh@oK5)EMVOIhLNe;%O`cS#L4H_0Vz&==|2ddU> zu($2IfNxjK9M*D=$^W+N{tFxfVAko3#ECp({PM^O7Gdi9MN`u&?vudcCF`#^1*i%K|XiI8N$VVj_n_j?{3 zga4)FO4OXA*IhX83IG-%28?iDNC;#z6I*VS=(Qd4qoSAYb3ggo(V+;F5-AT^SXibQ zPu@NCtzYPF&3#EE#6Q`WD*xs1ZMM~h$9{<7DHP!O7t!4$1nmv0tBgG@Nf;hI61|5$_?)iTzUGLD|hZ9 zrVUsSP{11K5x`G@* z@_&{Byiq>yeeO95021(SAHU4j6)tKr|8kWo=19Tjsj{PWY-5+bHn`(WcGM0 z=salHim-DNXe5wTCYoYAhduz$0|`GGVhIU7Fz7RB*^m({Yf_Z62*IEVnzjV6Bkka0 zWul;n zVHOWX=)1SWhNc+e5UA^2>L*a;!cYyG(*v;`!eJ8Pva_xa#Gye?z6B;0c1TQmGnJZ$ zs1{lqQc+PEuFVZ%(sIgvg!3vQW&!ve02>}+b{`M%BBDpcdPt~Xwr>TF4_HMSG-78# z?1k`a?VU4MJqFiY(1?p3s)H1;Y#_1PUvMYCrNp=m8wZLM9q?g-yIWb{>qe~2JPo#! z?c%^_00Ptu2noSLO^oDp%tBuJR-YQ`?)+0^?+&jIq-~PROd4!`c0&X=@7!rz10%WK z@W=@9YLAuwc|yXc!^6W@Ud>N5YP!8Wo2c9z*pq2!f^OP zDi{LogAKBoK`{`eRlxK40sy&+@c|lv1U&C|AVWXRHfZ{4&>Z_F6X3xR>~?zikww=B z7?7(;Nl8^eMfsi}Aie@@5i_~-l5`A!Mh{9I7?LVrh|i#1xq`pImZeI|P7M_7JtC|@ zro?&B?5uC!x>W_z7CYrt*yO?quf=iYJ)c$?+FtFqE!+XRTcX3$!-K~U7&l~x)4hB5 z{1&0pIl!gu3rt)(yyg4b>ko~Lj7qyCBKQn%s~5J8E5S}AX4qCBgkgpa0Z3~lMnNFf zd8(&J45pKZP&c2cxZ^W0@T4VjyCZtbe}v`AnG-Q<1YL@#{6Nt5o5sQI{t~O0&WJ|# zKLEJ8g~n=>z`C7?TkUu4H{5{$5+)!bA~KoVZTdbTApvG0HY|*^^4mAAh6Gq~Kzka2 z+5LsF*yG36t?jT5;S0bLU%?E5rga@dUZPfo2S}f7Cn=nw07D_d1}I8$ckjB5uM$3G zL`B)bHY9U;Zf7YM>+p)_K zWaLM%>+CHh0fm4X^cMme$Q{P6BXEa|$NJ88+RGn!s7`;Wvr*q3q0voHiXlu6V$-4k zWLnC-OQOaL5FtjyA7O5gooq1FVIy)-x%!fDBDjN+7Vr*qBAvNOzw2&^Y0)$XvXuiA z09#_1pMLg&TXV0FjU3?3F$S4|n9F>?tS{@D)e+PRcuHub5#JZ0vw=Va)|&6OrLaH{ z1`@Ff0qd!RgyoSRA8(?O9aqT00_6`;rjWe>2tKW>t~Q3yjEMzPY7Hc&-XdE?z~8Xn z;};2b5)s5LEkC!XsV74*lL*E;WKF~KVpPpaTyfKIG@<(bAme+otQ z5>V*xp&@n{Kj)qGQHfDx;|_((+C8S?xtHQ?M^K`4V7CeQgPfckELT_!r+H!ZVms-{ z_SCE*N)(C|xH8e#JT?1MeVkAB6P~y@I8^XT@KhxBcK^4}gLlHz zfPFDy!uh{r6d~)Z_PGV$^6g8J@z=f%$Pj9%WS%;clqCNz!d!JGf+2cL9XxdK9wzx$ z8UpZwR9IVv3B2HOFOC48qg(E%6M`EEh9>e@9`8)blhT3xH$?c?|HcZ#{{J+$G=&Xet+q)RC|Sg$9%N#E-UFTOP?}?kWeLm>Uq0bGR}@pkzWY}5{lmL*TQf$2s)3(NyB~%j%~XBqdKRRCg?p_Y|KzDq};hm z3M5XT8?>l#78LP1{56=!sH?60y|>rQ)~=~kws`_fL}tK(MJ_&xp`o-`sh zJ?EqLO9n>9^?g(<8aYO78ChZ`I)euLzwg?g2{>vGZ1SW<5yPhbJ)!?-sUL=$VtIRW zvo(@d>%RM=Kq>VzxzHvvodUj$MgkoHavhuXOu`4agyBuw`gFsyQ-ORUKcC>kH*TW_Oe|w3CQ#p%)j-Al5E0{3U(Kyiy7bV6K-t)M zDpIMEJ_hKIgLuA|XY@Pg-=>dn6URzq( zapP{HVeX#2%6@w`rPe8b^V-u6GoBkUD3gW;F3fCy<$fg?t#SWnwfV0m7uROL^FK3b zX=(NK_1xUt33OSSlIr5>A~bkk=k`QhH$IGSCk|Q!Q`Obgd5chFZ!@Z-pN;U28+y)L ziaX~si?e|MAdg4Ge3|fpNj380wfC4x?A)}~ipO?+bu}3$Zdes&zB-dhS?P;?cM5|x zZ%Oy4t<{(LlY$3Btb+=kBGixny7$fxfjRRvmW-JgP+#=3%XVAu>&;XgF?d-n>)BZO zZyWAz_XIp~11uaI0Zzl=;`+WOXWvQSVP+N&`0*cdA!^u&UN_ml+^vWEqlejmj*I#^ zV>dxEOG``i&^1guR<3<#;ViJ%Gcz-UgoLk3!E9%C-Lq@%s?GZw?B|2uYG&f(dmSf) zd>z<98m)+3-%`uGyJi=7sOX@+J#77~M~Z-GF(O(}V7_^hetSerud&windwa(x3?n# zV-HyJKL9-i=;@K@VcR}oW;DIX50v!On(w>w6uuk}=B(!sMTX+yQ&Lu5If_Ul6J^WV z%A{syV?%Lx^IM}CPFGWHpU|oUYIXZ~5K-l!5DvYE(F6&+@}?~TfrG%xi`}B^Y`(WY zK)fsl#!WrDxwyEPDb)pVnK5d0N5{`kQ}w!gXDA zXq=gy%{JAy;L-Q;YE&)KD$#b^9uqY}V)CAB;+7nlG55jgXR%B`^oLpjJW(aCi-9BPk-Vk>b!2Tr&j>zxmy#c%%xEI*2X_6X!puH@{(M|oQBe^V7B)LO3sS=M z>2~MezGs3@78e&=!DPUbqRC%)0&f+6xE@CdXU6PVwWw4qpn(<7{MpX-ttc#HAV4qC z{@Qxf;d^to%WFMGx1z(7y=@Y3y$M_e{h@8QFe4!`(W&V-^3(Xt6t3d{V{Q$4q?d(B z^$+%c#g8}FL|x#lxV+~kRa#< zj-TyEgLqU!r|^v5o{5#!oWyFm%_s2wG^eE4P`)@K%GjBj(+o9))g1~Dvm9cTi}}S9 zaJMLatCTnRYr0sl^Ez0l_dHm5xXyWaDHYV;eQq>Wq{axdu(V80POfGHd4Ak+spULL ztb{3IIE8(9Xs89u^O2r_%>bU(3C5V8pVyXAMdtiqaD@3n+q^Ie36lI&nzAx+Vq9K1 z<@1l#Ei@N0!=qDYkZw+AD-RTPUK$oKaCwNB8i;V3ypEQ)wzeD=8zw`|h%trZpT9H9 zHIeg-p*E1 zR-WEn8{^`6N?#3_vh6+#Tr#;Cx`$k5R1X4lR8f47e;0!QqMih-f9zCL+EVL|IX z@%;8FHxDx1$9Qf{Jur z+|14MXKbUtFloq(U9E;#XZ!RWc=BRC!9;%C=7oiYN0@VL%oyDQnCi7XmL;4Oqd0&R z5>uyv-or&=3ZrLcV0dS4-EXH7&U@Hq?kM?fSp2>^dHueznp;>{5z+K!(`o`o4Sst> zxBRt^u5Qt*QURysJAf9dS;B;Kr&oR*ML7XCL#&l-tgIOVPR53YhJXz?IaMk%_+Bn~ zp;0&K5R-B}(a_L<#lc{(va+)0cC!Frx10iR7teO5R^IKgm%ob4E>mW(b8>pPI~_-( zUTkzSsj(Pz8y6LD+ZvIes(RClF4_27STvXlR}z($R)U0-78!B%cglI>np1PxVTqwh zqf+~+_qH{PlYXboS}?1io#~Gx1s4~WZExqy&w?+%RgY)h!AsvgyhlK>;F*`B^d}%E zkA7F{{QKL@%}uKDyFpW~U;dX%y2d`1bhy=v2Xe6#S-jTRg=)H$#{N4Kc>uV?@2}P; zCnw3t$&o`|=Bb+!e>Nlmp)KqzANiRH9#^t2=HqqQ=GENNlI11)or0fV(0UVB=XnE? z3ddZliVC>ZOyTUS+3P;Qifw2+l%Jbxq9=$HvOn^|pVeOZ4u?1Ml6a zaN~wIL2won6u35vkYOjjhraEd<4e*hXtE?%ww)*{DJcOecXxgIXx8pjQ6~WJ_Yy(4 zH39$LLGmgp?EpQ0OieY~&wo~D0!%#`OfA%r!xwqORfvT@q!_+4XRYF{Y?omZ1qT**+NL`Jo~7CcGs zY!s+-g)@RiH32O+$Uw2uu=&UK>A&s3`y#~xo{Uku*|IcYkFUm+IikLv%E}`~UQ08R zlYa*pbCk11(hl?8x^n^R{2)R}L7Vy{bS*k09Q!BvEzvSDXDUjMS*Wrss{H4;z;RJ5 z?EbOC!=J@AR2D-UgMa`2-QcsUBS1$QuF1;Eia+PQf}sRNX4@+$d>ph8_C8+i!4c2Q z$$9vO!MU-y2{H#E>nk#0chuBPTuHr@gTuo<+P(9e^z?K9+8p{dUqFg#YPwqXJu+&4 zcb-76M5pkztSl-v_R#?w92Q5cYG0Qh9v*^4j{Q4`U@NVP?BuVkj2XgO_4mR|INnmw z!1?4`spI`!hrujoREJ;GDi$xB)EFPLX9ZKTVwf4%7|DKU?o{sFo|^ny76SAzvx?@e z^iQ8Y0X*yI5ZgCx^*s1yN${#P8CO$NbIrARw!+Bwc(uFpZj%#$_U(CPU{-Q+s3W4v zTVt-BP>N)T&9JFz>L{?jWDpnguzB5+-V8oifST zFN2s^b|xRsBonO1OoO1crRA79XrK{nEOgkk9utZ|?6}-^eKO3M1436-b&T@isvl5q z_Sbbbqv_9=mX<({{{j*qZ2Y2i$+h`zAfDDDt`F+^qL8@k zvrQh-%?08o)g-{@_qWh-k<$@S))XnHC8VeSxxD3Oeo9E_F>jgbf832SI5-G$x6jq@ zaPFkM+bScj9r7Z$wLh^%R9?26z!g5X7Qte5WnNP(`gry{u zPqb=mCW{Un9*#`cKNl!*OL=^ooWKz*? zGqZlHC;M>CXQuo6%g&W%x9w^kz2A zzf}Ev&_=DugpeVUR}5j&3UMT)yrv(z*FEzgOt^gtmSja-#OaSuW_R%=E1K5OU*f8M zdft8B>ePNd`&FkjxO;UwCotgZ_%{HEf|?rO3!RwZJtWhL31|1WN9*RYcp%u8HvUR} zn=s@5+9lUBVs(15IZVuH?AKOiuk7ShmKjago_0UVi7NF0;(Apgf{#jed>e^@vHi>M zl(eDa%2+zaZRoryWPHuD72pwIYi|2LxittX0cL@T{{!-dL7fdA^~S%;6_aLHdTI+$ z-_IGkVL{qDI-ttHlQafwZ(Qs)>d-)pq^;_qe&1}|O>yRmiFzdQCC(nMqy+poOmt%D zxLBQwcK;@^l6Qu8g7fNGW2RhJAfa?#twmxGv61-o|9v<(I4FHpegld*wd|gLc&plZ zdw!F^f9LT+ZXw;c#KgqUp56X5kF~V0_~p`14x&NaYCKy7mHTNl@Muul@n@757w`O< zLsAdJ)QQ(Xj2V;)$8HB3#R>jrrZ5}-NTcz zAHUz-TRHc4Rq$LX=;VxFu0?W!!Y~9k7$ex_A{4jAe!d29K)GyK!5z@HNZD6^4v&ud zuSW|sIIRQ>vp1p!Q(4d73#@0ug;De9dwO1=Q2NECrV>+922zJxN(azX52FRXvE+M- zWo1;TmZRz=Aw&*Iki6kfdvLp!I=0#W`HTU`M4wGjsj1{O^`iFs2C8`CsERMsy*!=X zZI||nn_&L%8P#34ZP&WU90<#>F1|pk-DH$s0F>(TaA|R7Mh3O{=1(c5_v-r$rw*Tm zy0=ml?3=zXbu8+F5IA{xPYW{~Tei~eXr3)+4PzWRV+uTf4x)&?X607q+u+tN%s+*R z(Y$tE?0O@yr7-Mj@Gtd83`BSu#t(3CwP~0=T#EYkXP;WPSI(!k)Qo%&>U)ej`&emtw}M^mdoB&pJLQx@X=f2B)1h5sK?r8w2u$2vS5|37j6(>eQS zl1`Btr$`Q8t8>Wya%_B6O3z0_Itg^jOiso&PM9P$Y}Jli9Fzeo5BHa_uLB>#umgrB zUQSK?_)+6|@LG}`$r5)*&%)Yzduwaqz|*g@%UL(#Bt$|7#^cTvU+;6e<+bb+9vA8V z;5>wc&=}(gWKTy&P(0&zM8*}0%CUfXNrhYL7fm($-(E;ifpH~m1i@o5-9yR^8ke1W zuwun-YFwa;#bfaA*QsMU!rl3FsndtoXA9lDofXcH1Spqr&^tXKJ2?_Y+uWrM|@462> zR{+a7V{f3ve;TPCCTU^pKb9#3qNdhrG@Z*V_;q<9e{gWI_E*5XC?LtaiRlt8r?$Vc zlGbCgOph~x8|_vLI7tL157^c#Ce*z<|5Kt>gzeSNM2r#dmAC$fEqgn>RW^wd{VPpU zUP!4B(o3M3nUN$bKL7Rnv!Qfu>3e;)r=d}%KtT?}7S6zX_HtX5IY|Rm2XAQNqhJP} z5b5Dl4W=XvtpDElfKu47^G+Pyl0fpm1;0`+(FQYz_0bRv6~n%wTJGf9H!U50e8Pwi zB=G<9mMM)=`75<-5g#B)=c$LG0836~aABW5kw}{3p<8N$p-!Bj?U~(u;Z2KTC+;<% zjtiL-d#f|$lRjQce=<#dF3ij*l@*1D1I)O_pXdH4DfC{Q38utV9L^p5-}Om~1%@1q z(|cbsVJk^hk%pP=)JoG*ybEELqN|DJ^rs4P6^4R5|F>eeLfyg> z-vvT>gddlRQ`P$dgkuyx7+?(JCV~asG6@*yY7C<9=7$HmCEtI40lBZ`Eo&%G`hWL; z1nMzoB=^{8$R~W@Y>>mS|IDXy(y#DVQCObWY1Vc7qF@Zz4d6nS9 z_wq1BshR(l2lr#!S{ypsru)Pp_tV_}CT)Hq5=+Yd$5j(KWQ|$@|A2&+0z88{cosxR zEt`^!ZRCkjmG9NR0AUCIwLF1OJkk@&pmT!ugaH@CO^1@Sj7>ku-^WlTk69-POB3^d zwBnkBkBC%s;+Zn3@Mk7jV=KA5Ol2m5Z&PL%kp96d;NJ_uZy{XwPwzwBRAv=1j+Hk^fz~W3P$uQivWjM%Z-X|C`x_OY0I@ z|KR4y?+Vn-H;9l052+{4)2f*Nq6_{hQqdH11dUO?j1YY>jeGR$e_P8WtxZQw{gNS3 zLoLyj=hNgjJ(yM9e-0`|eX@Gf70pCU3t9_~alHS>P+jf+?f_Gyf1Egy zJNqtecoHv{p3MKIcN*ML8sUmeL&`pc8U`GdNg7{YTb!u~0h#15LOnq5(S6|4k;8kq ze-Y*xwoNq0X~2VcQI{Z`+&c%QZ;ui2kPLdXq%7KFMD!ncGSboE{_)UMMe5;V8~)Mp zU!0Pn?^q#+bhB2rxjr_WDY^1#T7gpBlA;H z2vSI(iCu`ca%MG29Q=NIr=x2m<8@JxnV``Wfph6XqO+GFw!G7(%~UsqRG=XdviW^p9~*#q=wK+?X>@>(W6 z`~x~_NXr@r2;y?ig zB)vA^7MQ-U>&{`^c6Ai^a7!C2;yP#Km8Q%PW`^7ui;**WpU0xoY|$MK=h(7as8J)1 z`#jQ`=0vu0V2>{hB!;7KI)zVW5^gIC3+eIkW{r#EcdQx&q+trm%KHZgS)#rdiE3i{ zMn?YQqL-gWtJgBq=RV6s0v+NBKEAXD z0U`*yH046T=O?F$ET<)PHugT59#Owy?mJEL6>Ul#4__lTz2j z-{Xri-MI6RHKPk-H?vk@t_W)I@jB&0Q*N#)P*6dB?gK?QDs@07CG=-+ul}`zxjF6l zDH<9YC>~mX3~I_=U|1J*CH)E!cofYK99gySrs;0BS28la>#^dhsLgv7t;T@bJ?h7I zSAQ+k6X5FMvO?rrGznx3J3LV1G-}kZUkoO7#kZK8L6Q9>=vZb zSa)7;WjqSbyu|~|sTk`C6s|YBH}Z-b8-#DRYnG#U*rKkGI`E1kGST)?+_iov#avx^ z|B4T`oS(0?&WB;n;_wXQwk|n_nXRp@(fpuMNSNA1400AEV;<*69o#sE1M|* z7y=kllbs87ZepJ`%^NS-yStws;8ZT!d`^J^WIdW*@3hhZdRgxPivol0*BATq zr$BXI&j%#yV$n&>279*Qf9i`)=?o0_B`zv8+wg*YgHGwICD&p0M-60<>C?CN4O5c7 z^}lhGaf8s%Za3lpP{Cu#gz&EuT}!%Leu1vf_DEWY(Z8(>r?KH-1W1G6!1FeOkaZ$e zOTz^F|p02Uh?7P(ocZ{VFwR8&TR$RY>fBAPYXo%Mh? zQ8sk~HogVj`ib}Nc7v?QA2<~>&CGs-YVv*G4N#g9gFx)8=K#GST(zht0SO6d&e*qH zvqZae28h{%3G@IbL3f%}x1#N!VezrXzk8If5MSaV{stIK4clLCe+D_5abvnClvcFZ z_C^o}bb_WrHtq@7gv*PI7*by3*dW!9-KJgh_n-xAQ~w%tSp3g*BnLnP@po%szhmPg zxrW7o(5Npgd~9yO;*cGj9w64WYziZd0k%keOxHKEv z+a>@kU~%c`PeZz?QirWaKK*uWuA*DE`*r#NWO;<3%ayIPjHg5y@@O#jfZs*MmfI^_;0tg}r>)wIeesFVjrRluc zRSRTE9S%Ipr}SxG9)PR92Xd{zlKT_VPwyXqv_ZQP<4x-^h^G-yD4X73p-}@j1r3E&DI8H)A|=qSN=i$g zAm)Kq29O5WhSzGNuMU8O&b5sUftXzeAs2M>Qedmu2CxL;tLQ5qyoHA`?BqBlB)%rl z3IdK{SZ6Z{Ake_XWCiHZ^YcDuJCl#{3s78$5r0>-9)b+6SWxrj%XfQzIXSuYOg{~c zNss_}-v0Q~`S9-uvj;p+mLc){{2a(oe26?!Co0&PVl zoo^SU$H9@2?}R;U!|&RcL0>_bp577^af$`5ps}v6uiwP@v&zVBXg=tDy&LUH5T+Wc z`^TWX9W6Cc8Q#~a=m~U4@b9g2{4bK)jTjRBZ+46HPJk73FljltN0kkr&d$bQA{sR) zAzyeOQxQ$F6>uawocEei5qQh@6e=z)?NNJGVYurqtfi#| z@Q(6{q%jC5g#>hTbbNe#RBB$Uk*e3_#9LoAJBV!rZ0+mGPQPVYX#Zf`kF~hliJ! zo97c~&j1-ah0{dLb6?MI!5p*{fONJ$lEyozpn&FwyO9n~i~y1_G(1eqrUzgVbm{3shVNPJJYU15g7% zD zNg)z?oU@5W?JP7u3lQR#z@WqZ`C2(YClc<=->O;XmRj51snvQwoXEL9V+@u23tCQM zCj+#M`-u1cFECU3pROUqvJG<>HaUYMK>#ZH$9IQoI0B9-K-1h2jMx)~b@gG#S@#bL zD5u0 zWVeI;(zoy{OT&l-k|o-2u4`&|cy@Xt1w#=+3ay!l86jsNFk^YKb07l3CT&qXg}ae} za0wH4OY5dsW5&oCX2lx}vce2_m@%Cf{5=p7`;k!4=Sh;5V-n95YMqqvi1guD60_C- zlU}|Ipi9!m-a>1>2%ERTMr+}RBz5aX5ui#lvYHxK;KddMP1%pElA$Ks z|6(2-Yg=A6ZmCKD!w`l_#>dA`f_6MOtR}eY0nx_dEw`PbKn%*Cj=`C!e>ZcTswyhI z<=M;x=$lD;<+I>K+!}}~z@xXBe4gX^8w1m`G4&c9v&Of#GrU>K^v*Yx!JZe;U|I`=YS_n#3^Z*A{%#M@Xu}tB7== z^1eN@9-CN-KD=)t-LsmsTZ=eX31d@(yrI0bVDo1K~ zsIxqJ|ByMjbJRN4Dqk;5hl#+dll`TTYM%O)WPmDqtX2$oOE$-+OypHB3%x>(>&2kP zlTFuV){XcNe5%~9I8vYaZ~cuBL@LFlAH?%ijY#jRDdXKp;Z`nt6P1~qaX0HNL&jK`rk&B2B4}x^tc@u}!fKuKC7mj9 z@Xk*H;!cUyDABgcd9KQxVhO675enBgQ}DlYQQz=A1BZ$%&*%HACV6E0YRVGb`UlNH zpDFhAiKI4&;*$#P6nMeo>Nn zRVbO0_DP0)H9SP)!(7VhsG-u1Z9I=Q!KVoNlt~uG)w)V`xu@CU_izPJoK!0o z{Mg}*)#@80O-Zg!iSz%=1FB0TSS}S>^$9mi^3b2!*!cdcC}ob+#gG`62*DJ~5I?3L zd>P{uw6Q68Y^!8NB#|lzK}@egRU#8(ElH43y^#VlMP8L?3&V4y#LEn712y0$->be8 z{3Fy>hEj$aw!O7qllBBkU{B1@7M>6QiNb7E>J5{s7}#$E_y#>6On#Lk0hN#G-?@|} zP+joDRcevUwL{Z!dyqUlaB6lxddK-5jhFnCqu(!nip9 zB6yAR%TmzN0+%$y5nLlM2Tmovp9+1p_zIN6{C*KtF``;o?6K#@c;O-N8ARmds6RZYau1ixBT`x% zyWqaZ|AFvwQje`t2-O+Pd?h zr1$7D!!RXjjI4I*+o@mHp}Lt<^YFpRwI8!lbH8$Vx2gL2#KGYJ-wSrK{)4G$f{Wx< zQOCyq_I&ouPbJTBQQa4B8|n}0o65-g3D0#l&QqF29b@Ne+eHhOeh^|JzbIdNv7lwo z@vPsaS(M)Lk8N!K`rmgAjRo%dzJf7(HRt=g169rTpP63S*nX{loXPq*otM?+!ZcaG z$NW3DcM;@{D3CUZEsjBKXpfmwS84$Vk54%?ak#@WqjMbsr;wm{uETzD;Vig+)~f02 zRxZ}c6d_l}9=hQF-ZW_Yn$2U<#TRA#l&I3d+ADp=I+d*Mn~}J(oqs!$q#kiTvi-JgykU4>KFNo^Zlo7eFck4S--KH;BuFLX*-l{3&yNB zZDjv4PL(B)37Jcp)Lq5)hH`&+=Pu|`VuuUG49}&!U3#aGz~|_n*YNGhF}y@|Ma`ru z9U1m5e22Y9^`tqGOm)ws*5}F-6ok)ADLbVx3$J^ASMjbcEGAlB=!3(jwsxbhQm;Y+ zGzfTSLcw%I#xwk9mqbZl<)|cldFQ4TQ%FaGu9%Qi!XaYo^h8Eueb(tnvHE%+QnwTP zRK$)2gD2~!Ker&Sum3CJbot`P%}Mpv^TIIn9ymWy=aiP>{sJPI$sKO%uNc)5`J3|P zCGqP`&Vrdm%u`Js-Vtmb@d7&tK~K%ssrM$q%Hkl`Ov}ht>f^#Vteq+vrisrK612aR z3)+a`V}~2TU1lG$h4j;*egl1x!j=ijvs00ra%Lf$w_Ac^hhB#}ioCaM33Si((rcdg zzBi>J!!A18qNr{FUH**mj@lQaYqelFbK8;0q^l6P>}{=gZW#{cBIAqy#_E@P^68{BzLyvy>pVkZ6R zGjL`$7cSiB>1{EeGCwh>4A<#lf6@!z8Y);6WoXNZ4cf%yLexgHG zV<`?Sz3?cR;d`0ka6u^4qj64K_Rs|Jgk^e!G%lQJ&VfYvIxZwn1^$lCM1tN0FJPKe zQ{B*g02cyjs0V?yx=69)D28ax(aoE?!9g!hj5X_M)g(`@1TjTy|Kpqo`?f4 zzBA-{2p67XN}C`-5ZXDuoEFA0doQUJDqP&(VEq)M`an*k+@pe_Os}GOgrs3@Q|0+a zco0GmLQD_gECNIo^y%yP5ylQALCHhE=i1YSAW`3*w*bD40gpO(V`wyi3iZX&_o$Pk zctcF}`;}f4aF8mxlMbVS;4^3^xKLRNkKZAu{Gzys9OKI~bkSg9Xd2EatsdFV*uiP% zq7;sbDU1h8296sQBJWsc@f9UvYS6w!s)JUy+DmTQatXdIraQ45Ii;6qlTW|}CD#`1 zxJuEWKpta-_)5>A4^)MuC%*q)Lsg+!kC&6c1H+|~8-yX;mx{C7UlHCxT&^kYEoAnu zs|)@Ft>ey$%*2IX8a?9!##FzJuGpeIT!&Wi+FCu*9PMAL=UB7sb=qBoVVmGUFglJ! zy|pJ`F%NX-e%`Lk>R43RdN#rZ$sHFwLl416f!MQSXq4!Qn7EFnkg=fEjiuK5G>UE% z2*pUQ`mOieJNT!N^WSU&{|XaKc!~Dfl3%YQ9n@yG*Lqz}4%wt!^w1HyxYb@PKNku8 zSo>y_7wex<%fhnr&zayNrW$P_9|5Qs;lcJbSnrv|P-4a&^_?}*pLKq2fwAn>uRLyi z;kpicN}{kDRqZ!kTS=IRI3ipw ziu+p?A%SIYb15l=sNl;AEkdCu-nW#2cYpnpZy{4_-Pg$l*pPR;+T`ZEBsRo_I6AoS zt7-s2BCMk7yEYa?9lto6`UYzrE_beIsdTg(-g4_7%6>RRMTO{fR`4{02(t0;D%?Gh zQ9ul0^Z)y@Ujsrt?xs`Wr^xG>N;GHchA(Nk%dhYhkqqk?Aisbl8g-4VmT@3_dEa`W ztYu?J{nq2-pQs>Q#313@-y-G@6D(W@d#7*Vx}Me?&03%X<{celRX6>aZi{rd>TO@H z&`IgPhA>+@1PIpaoWP*;j0;{O$D~m%u@}t@Dy}B~<>Y`El#8pVZM_383)!5z7wn-Q z6I}P52;Z7P$EWY5Rl?{k5Q4;V_~+E0GCP0wAcG{~Q_Yz?Tpc07HR0@nBg!8#g%SK} z0+6@2New@7hUc#-eai#lRb?rc@FEl_(@ZzL17i0GS(mRbUzt6cv>^AWhYO;&SS%Pk z#(*okrta6UUoduvam;-?*kWkB0fKw8OT+6Kze6L#lSN0YdEWC-?+8~nEdJNssX3nB|Fql zki@pY{;b8?OlcKGaTVE4Wk~baxgw+>Y$vsJ4$8%jm03Nj3OJ|}SAN>UH1;{-sD9X+ zm-ukGKMg$wd@$`gD%>!ZU#Uo#*e=J0k4_Lbw7jU6DC`&*zO6Rjz;-Wp_kWquhyfXz zjT@^pq+Y^xY3Lf{m8@u5KZ`KD z>&9`-#TD)|8PNbN$Oa*7DP37aGOvW@b5hz3jei#+G+Hq`D(YJ$Mf8;Qhx;|OitT%0 z>$VTRMZgD#kWCClj3n#KzS}1OCOiE^fxuC^FWL5JUotZ@<#N2EP~LwXu<5t0Uw-KN z2dP_@tIcjfK};V>Z@zIjby}xaa5{&#LsjFNk^BN|e|_up+kp{+J%>)diB)qHZjHJN zf8c_MuPa-XJXst~XPjLa69@ znErU4dt#mZMkYbCEOUCZt2W4xz|qpLS`-wE(jr!wjBq)o#_8!7=};G;=aF{Nq96)X z=iADQC4(>D#`ITn=B1;xot+q-unlHWD84W2zEQ@MIjmePn-izc>?)LMFbO)1zWuYW;_Z@9H@_8!1*IFZgVjW%gRUC9jsgs5A=vkc zxuqA?2Obwa@xotrPO7#lsu&eAqMz2TEZ}m>mbA1v<~)V=sjb60xagcA=b!Vzg@_Q( zSt$831ytn{13bLSoUDrSYa=BxaLOVZxAT`zAouH=j-7=eG_qv^KI_b`gBh!QMGtS^ zDP%;!e!U3SHDdUcvwdl;0!-h9*gcNxL+CF6L&#lKNh{JlhE`9>v{BmI1iJj44khr^z067DP9>;)Mr%B7R zRiO!F%#s^FV*)7myLR*qi~O4i{>t%6q#%kM28E2#k7g2DjxSK5V7f267*W(17wz!t zV%jC>!*Ki6o@34JoW0%6$8C7mWi>PTecs=eK|pGkFz70ERCo3hrL)8|FT!;V-!@** zxBB2fNojU8!l@1b7gOR6YR5(^s!*VdMV!M)3pn7A^jj>}Karr8AZD4=ekBno$-uT+ zDV$zRKO++U*WMJJEstceW|n2_KP%EO720QCX^M~zTy?$XfTk96`$DVE=gKGVEoI9{ zCdo3uYHky&68*VmLJWJYA~MegNJ0YjP`ijU*ygB(_bk+AOw+?hunvT4Lx+VNcq)K( z8d+-VT!R-q71An&8JF-9$@LYcT}i~BEU!-^Tn?Y;Wk~VG-qbmgV4Z8U<@p5z9(tw$f#VynO;AIKZJI;r>o# zpU`^jc31z2x;#d1d?i9mlF+O_b&fg65F51txahzr`X7~I6QX8e2WsMLqva0KbhftG z>poZaJ0FFg1qyPB3x~TD?h3=)%4Zne;KQgs;dW8)qGME>F+>F>PwjkWr&D(sJ~0rd zJ2rg{ffFrb1aEpUWSqc?4= zFBhL(*wj{caj5i}ZF4{7wHyz}7?L%qvHYJG4*twb#?QfgOwz?Dmp+X8E0FX%zws^- zHhRV-(W$s;9&Yd1_-4__Obtw>vYEm3=dZ=1WNXrhY9%+CMuWt++nL^4G%B|s@WZ|u zFQ=Apem{NndT)sBA9FX2n`KcW4pc^c3u0hoZj*HQL}QzdxnJ)`JrJpt3e#UG8t&#gMktAA-?AehngJu&L&AaLMFKSH-NN-n2>{DK3OobWHM zX)9*y;5>d=m&%H&ZO5Jc6{- zJI~*EU`t8@#Vn)T5BV`a17lUw18xIZcwxEaEWQ z@*L|X&%WbBFV>umLx5PyP&)oBzei#z^C024@_wLjAi9|b2<@Krji$4j5iiSM_h)T8 zCsO~Niy8naCK~hpUk=bJYO81QlzIV6xyR1eb)U&b9%S}bKGIJV%se^-=`3(mbk24! zI(xZ~Rt=E~{cVPZ*`M#Ugh_KKB!*4`>Tzi~hs`GoKKW$0CS5V1{hnoJb1zb`?Hoai zDs#YLf2n-$a>zHKzFF^7#GEw7$NFbh@t{Ow^`MW4zeIs+bV2doty~XZ6BgC>{o3gO zA?Ndki-O#x-Sf8z)AMH3m{4!n&>Jaw2=*-xcrE4=15u;-ur~yG0Oq#1r4>fFQ&RX3 z5Fo9IbYasEd;8%S(S%Uf>795?;F7%)667I4snM@_dM_;Z1o|l%a~TsDQP_5GvtGDx zACdgR_VU?NItAB|$_bs&=ar582Y;0M;TLC0ZXK{7Q>=M`^TX~^T|05@Hx+#m2iisF zMZMqEzjELl-Ku&B|0$(HGx0k5j{O!j{mFAu!P*~dhZ2oToQPnX)bI8)-CBhSX(zwE z=U@kb%F#GHhXVZxs<4od)O2t5MnRC|N~pAR=eH)k(TcZ3=uU~fJW?-8lX?Z&c-G5I zSO3%w{b*>6kFI=MwRNz3sBJ`X)~`A5kj(*2peQfiXwu+04+cSuZ)>aHJnb|~6(&DF zFD_-Do5&G(^lo0Ke#3*omixo$9UEBz8Y;wx06+E?$FQL5kXer%C|U1ojIS^#MPNV9 zkx0-yZl^PRFHLhe`E||MHn$P*QmbdCk{#JFox3|bF6ZzKJYsbbXy2u0eI0n)-MTzC zcX|47ClsLR0l6O!at;-3eV!&* zcd_`?^X*NvF%!|Sd!c6&^CeGdpc8#vuTQL6?xH<=VOwDYe}+YRpZpLIjsyvnDLH!chO zdA|rbWQwg1h>rJY1{phEvhCXIhxi&G$6qXNls6x`8g#)yShI!NDjbkA?y{qj6M7?j zkkav&Jq(wcmLIRfLALoz*;sLO?2aH2`z;g-{l8}cT677^Th3<<;8vSDc`NfRK!2=u zdnDj+iLe#p;_J*GG1bQInrFJW1ZgajTQ{Lya^)tuV>62xAP)7a35*=+OiWCFg+Dd1 z|N8w95qf*$*VcAeWnCmpj`WkDZVPinX_G{0vgkMc{oY}g;4tujZ*?Tlm%US3QBY4r zgbA)RIZ3I}5DoAUte;7xR&oM*^!uBcHAX|$lO7Xyhu+174g2c`fs#Nyp>(boJc*GB z;y2^mh@&47o{#{qK5lsDvm(AIux4QvtCm zp@Hv)Ngo!61l{;8$n&Mxu}K*`!40Nt^#4e_{bBFQ(}N}ZbKmR-$NU%jAFq;ca+y_f zV#|LPsLCauz}iISw|mz0$B{P?$s6?ipOTDh;faJtgzd(oL4NC35c79Up+ z`%!@0V{G@}Q>udHFj4EcB>XL|e>vbAf*4d4MB8uF7h+nkFTPxBbsy3C0KVug;Bs{M z>kz-KykC@DA)O7>6=oj&0wng=)JufYiJ8OR!IW;a0dYKevI4^x^yuWWy zEqXy>J70Lv`Oe^7qRZ3V;kiZ!i8&?q+eqZhAQ~&cFnF%y#U6 zGK0#?$`oiZJ0F#(3U*vw#MK_VJ-QT4d>+#Gd(tB+EVk5U#U>-4ay&S)o73risTwaPnaSM?VRp< z+SNLjYb4i;CD6#v5!aom2`z}fy+ucnjW2Q48mC~3vttuovqgg31{zAdVj1_5f`HP2 z(9q+3-cYJFIlBkn2NJs`GS9U*Ki)LHQrYakyJrJYUm<2jf^#sZs3H`Qd&7Ha*)8o z2?MKjtVdmwVMSZQo!5{5ho-9xsH%&ykC1NZ?v@S->F(|hDUt3*y1Toi8_~M2gCir*R7)qq0N&wWsVC)7hC?TDV znofuBPbmH4j|TxM0(P%3ct0+^wLDCT*YfLhTb|cE(ptY54+h=`7-D8-X1jvkRnw-> zf!DdqQHq+LvajJeVgXF~ukVPS-R6(8!^kqMF?KuawJrb{LdBPtS^$@95Pv0))O|3E zp}N&YGZ90CB)PTiOYMIu1Ep*3PH(vnfRqr}L6smIviCmTzK1=;e@g<82DHM@L+FlI zm(q{74SonarAA}^VR7THJ!)~9tZV;bPF;eG-vp1laq@+`=m-P%KKJm-2#gCx_i}Zp!1NGsz2tTqLH-~IIs8pxGXO|f zoDI7YO2Awz>64t*f}vUMx54!A9BFn!$ICTt5+WxPt~Nc&@6CFDMRS_5MOJDizBTLQ z8xuwDj4}UZPvZz>Ci3yv(y+?@%%r<~=8Bias6z6t)5CBN7ugCv5N2RKGJKU~6jn{OmHbsF;eg7xas7J!ZHoxn3k*V(5zP;BVvI<}lhFsX2FpEP;PA|-m zuLNfd_PDkcTH35|jjv=!I5kaVQ&ZiyGe;TnhD;M*Br$sKPr|=AtfN6_XC6kcpm>j9 z0;Ai--k2BBAMWZqv>k!b;qU4hEj4w?NB#4gHV@#H)6vnv#C3gV5r|Hbr=+ak;(Ih- z<3g(0)&*rA=0m#F1O&wpKxpH&sA+JOUrH8!{^%s@WNEqMLnBSGQ4ToENUO+(+huE5+^n_1dm^3!&Q&#+0;*3<}_z?|f>H4_-i8=Qo|3rvx@d*C zoF&cI&u!_u z>zP^;|B7Ez3S9qWv{&L3)o*RyOa8s&6ylKWM_O!y^{ShB(8&F8l+;ogBYNg&>KZ|ia zU~Y@u?~azIAx)+aF_y(uvKAm#L}zfI4&Du)_r?(8GBwP(wZlPrW%QJ7nlg3zoYD$m zA@o7r7R=v#3uw(o;;-XI+6as`*K>tq`M!rHxSt(ka;-}}s;j=CiCi2~+xGGsFu+4D z7=wDJWx+}im0-?|Dc;7-7;!{w-`{O5uA5stAtwN3vcSubJ^pH!(YG%AnnbI#*j`|R zB$;S5>P-v2W5geexCZQgs+wA($6|!dwaHJiOv%PxJ2+@}!ZAJ3>_>$9$b?HMj>Ft| zei#|K*?uodxBN7p9z=2&XWAEsCoGl#0S=Z27 z{%Q+YHbfup0qGP4kI$eW!gzuv3SU0`9dB!b6%Ht+TN~vUwC}bK4$IP-0|>3(nRuxcgvx`ij8chARCB5Vp8xzebs3u3x_$G z$tD%V+1qzxMzogo|GXuTafvL|V)-?+9ZPGLz`0;K|G>0lmNnh_r@k9n9j8&PqJ`8g zhFZ2X%^PK6(dL)wwb%Ci*bveq4g_1*_DAjEWz3`drlR1bWtw-4`@>g}(i%i@Xctq( z&>GAgk-Q4%SYg(q9&36Df3kDM?`6w0;;J1T=+bvj0|GpKJC1Kp7rM;ZxF}@4S?PrK z7UA9_B>5$VlX@dS#C+dQ;h&^dHFJ|_N!MI7E#>G``0pn$lEkvQ>9D3BlBpZ_9xA}t z@Rjq2?{%+DQ)tWXg3;!;Bl{Zi12oF65f^q59ZS&M=CM?mE8A%_(5xMR7dD1NfWRZJ z0j23H?M#*(bN{hebQ6(oH1*EiR-^BIN=-aG?lX~(|3{z5sXb~?e81vbz-}4?D?xF=fY4S7~B1dlS(;WO;!3I z>l5TFuS)K7?_blORh~>ZJ54%GNHQm7qOs&e|I})I+tHvFhq>tMLNnT-r5$gu=e}s{ z_CnU3nvlT8!{`1ZWqOMcE|A0SQ|F#;Sd#xOJp?FAuwa8sa7bFaF{dnCZI;BS9CGvW zh72SvEomV81eb}eoFQUPfQ&Di!M~VNt3vO8aWNGa*2uPGlk~xM8UYeBkjK5V*!v3d zI;c(C3e7C8WR{%`y&cf+B!f58=uTCrnT&nUCDHHX60(<} z`G=2$i|IFBI)raW4xLIE1As?O5#%c7hBy{VCFmuQ8>Bbd{~*Wg);XdM?PuVENw>8Z z9Im-{E)sV~S7nx%Z#2b*yOG79Z_a#M8=rBhfRi(Fo|It8JaolD^Ml}FEaRu0vwPft z9K3NhUr23b_Bl5{|8!biD|hiGo+xv}+{Ex>q{p7}*3y)%%e3YorO0c`L0R0as%apM zcP+RNt`4#C?-ig0ko?<7~TV?irYR&;PzE7fN$nVxdb{auNio8 z2xP|2=x+I}@c>p$WR$lQFKA?2(ZA@eV_egPdeWxnb3~!Z5BXE%sNo0YLXB*iYe4>E z_f%Z-(A4jR=ixIVxMQ2IzpQus?VfTsBC%18_ND)>2g|C=@`cCb=qw`OaAL8To*j8y zlO9%5wzHgd0NUWSWomXM%RX{~PrqQB!zs11QjgVf4i6)S-AN67g}CqAVT~}GKrvtg zBMd8B-OT;F!i{qcyt6~>jj^SnyNnU<@rqDs{8=*0nFn>edOWb>-%>RmvS0q z><&cVBN*Gs(A27)Sd;3A8t1mgG2+0+$+Clx4}^lJO8rZBG_v*5HNzWffyg*nRpzKMP1;gxDwyEJg9jk=jsDr@wG^UE#t~9$0;h2u7vxu zQCLf9>0!Y-5=ZG`d&~JSTX|&2Jo|97Wag>ThiFSGSK(s&?5 z`HQ#yBM=cH^>gdRcjF##RzCy2{_w*DQJRBcYIe4r=}8Zv59+P&9Ouu&Gq*Mao3YvM z&aL^$1EXN_=k! z*Z02Mr}Mbdyr=g;p-l^LBayzDEo&1GY_L(3%)OyElcdujsE~S$8N)g0tq^2WlJ*#_ zr9_9?s0a4uznv^(@vdzxg#zPh|Q4K8GZrh8^SMCdBPVbhuUW&Mais+3-4(+An=&wzUeyyask+ATzBMzq5i|1T%U zps&nj$9F$dAxasu$QCqxwa)6E5ra=qU8d{X`Yyvi1Q@uqC98sLtXdnmzNvq`Io8=3 zdA?7^cS41_w_OxK_q(LHBmMyjvr3dLX7TT7I?^hqRx_m;i6tZOg2qs!$3pjdty;DT zw=Sqf?<#=m@A4^Tgj6ec*uB0jfp$!V(j&=SJf9qq-~n22-te@qt4Z2%L1+rWmceLK z*{+HG@aN_+1DiG!gvl8+V$A~#iIbdZ#aL>gZlFJC#$Y`}Zjj>`2xr|#{_$`7aywX0 zHhFNtwzOsH*H-2{J~1b-v_n7e+?LE?D<39A_ERU_2cuXyMFcOS>IbD(sGGwCsd%4; zsa=YGHxV&O1HZRhVksQ2`+{)fW(;oTm%TWusrZM_=vADKE*Aq6Dd#4Ebv>+ zO%&W0S+FyvKfMHfkWFiRW9VR9taJZhz3d&_PJhlst_B<~hd6HM)NG*~oaHM03{5j?Mi@ zI^?0_M*4bi>p8PW18L|mZV0ByVVqQoX6}q6*3AbIG^f~7@A3*^kgXb88^2G70*;8r z5+NqZn8M=CRK6ILs*PPzP==CS6Xs~e;NqtS4&S=!Qn~6Do%xv)0&n3oXTj2m%2r+& z2o;A{nX?4UoCFHMD66|{oF)3w4PtIvGR4bF;X2LvhSVai_X{5e)-XSyPD{l&vprR_ z;OzzGl9h)X65Ed?RF4?W;h7PVkA$N$=UhwC@kRWuz#!u*o%nV;88%m^NV**;?D@w; zOmBuPdkqf4X_H>H<^8VT`7MiKt`+Pukwa%<=X=>$7Qz#PYvt16sJ_au!<6rc%I~h{ zfa>exf}1)-?Bf>!28M%*&-vfr^L)1UoZbC)MpIudW&?n=K*i4%4Ih2U1Xzp!?mveT z)@YEGYTjQeL(sS1SdGXLD20W|Aje7_VuhZU6TDC&XY4G-Jy^*%ig~Bf{#UStUFksNoy<|p z?(PA-=muR;ENAlqtKw&d#ah;exy|nlKW;ee-uWM4*`183|D{Rrlr4|ocDMcp*9Psw z!A9rtmQ>ZU;CCt75g1_DxVT94?&K@lyDaB;Q6WM+j&j+tMV(7)!HAroV+U6xzA)NS z>g!91zg@*&jRa0cf8Z5#m{8ZGE8^_STka#P=!5C6mO;<4Iuf64l|JZdX`JHN81dpa zp43ZBF*jdFy+(R^2%|nH;X9-Gm*ENzRZRDGc#Nr7%tb-G!MAAxF0+He447VvC9WLNA|LSvyuDR8Y9=F0aB>QD@ymkv_u}eif_J0+*tQEDMZtOar-{|5+}uX$0adprN5dC~7YwgfIqA zC_mmG3=9keJOPB_vD^5e9}1GOt+5w74ILzod_X^Gomj!f%h3z|Bv`QLcU$qd=vQC9 ze0jN84=7b(Edj0nHOYndY#bbocE4C4 zBOECTLy!9g>U@p!8YV1MT3Q-s`@Q@a$d&=-HwYY3UB!mA0{nFyG0@Zfcauk#pBmym z#@sx#Z7^}d*AEQJ=rL7KZzh1D*f}nmKye^8m zG5-Gk41I}zuqo-k{)jlz>6?NssDL7`F=H~xV~`CuVIzMl1the!oRL|YqA6a$E{ z;ZVoB?~~z%pdl=OaJ=nQ^|==K8Q&;EdZBtwhFArG&kkfGw3kL1(QJAuycuV5DEnjE zJy3RKL;rlaJBddq-TWTl`A^H2-TDD8P|*Ay%I<;H|2}%BO8W|NOX&}EU}Ou4mK9sC zv!F*GP&8D+K#Vq7kC+US96o+z;iDngG7mUlRHaX=QS7+9H9q4(|7S821v_}D`;rX} z2eG9*q0^fL60~UY2t#2nHWUO@K4vQqDPMI2nb|Fp#B3Yz1R6JcN?5;L!a=~G!t8JF zbUi-&ys*DNkdYdFoj1L^kw|)@y!pLQl6GAq60zxf?}~Ex%jyJRqc6Y19(<2mZeY%* zMcs~H7xUV{q;dcof#%1*>9Iqf-Uk2?M?yojy=vn>_RRHX$^-PI6xzyJi7yqmPA!S# z9e2HFVqzsaskgI6r}rsd@&D3@s};|#x-B>)Ca-ioj;9bx0?W19@7$^R^Y5VoVQ0YH zXCCo^_NxjB^6<5fw6wV&=ifbLib`Qh>3a6g*K_vGy*bl6CPucDY=1ZJjAA-}F6i%I zefm;`zSgqE@_$|Nx47B7wY*gycaK+as!EN&21ir57o?ZhSTp7Sdy)jwlq-uoM+%xN4 z^=@8=GGSz6{Urc?!-p<&NI@h%K;cX(y?S}$8mM@Wy1+#FwJ*UzElnUduTN--9s*8n z>H*Atk2380^(=w7G@Gg_JY-l{*|)WAAzsrJ8@}SqUf^ESG`E9-pdWQ$`-JkCm3uVH zlLJb-S&gKVyQQK_c*jcwBMd|*QJ`p21l7Jcw{C*?n~8iysS-;K=+(D&J@JiO8?b4# z6Wid5$*M=5Y>!*O&;jx6eHl2KqQ^>!_dQCyWr}wvg0s$Q_4?3LeJAd&X=HA0{@ui~ zwgVb0(c?TySywY!eWp&shQi3YACq6sd!Apeu3U?!a?Yw-`R(P?S)L{@*M9~tnl+S^ zmSVz+(nnHB$5~U)5^aUUV&wTh9BkvrKj-HQJpuDAAz*l5+D4AwVTb z$IjkRQ-caQthV3NXoHwsWjT0lyMs9rm|CO44XtMj$3Fa&(c?GpgP0V4_=lfjojKl; zY2^096Xud|Z2Poyy^_?gvnpXqqb9ph9B9uC)(yi7f#pt|f1M>CGlG<)V^)zmRt{=u zgwlwqB{V2k| zfiYp2I~^kLt+DqZzvw3qe%bp4w$;~JcJ;XE9Y`<-GZC(Fku5kW&|Emqn8FuOz?(`w9tU1(AS`|uRn zRBqnB@~JV;&e7H6EA6*r@ONc?`_b8TlzxnkE4^M)3i`l)B69W}9#DUKbKRt~8g~P! zzNHy-VN5#&aSSV-L?A6a{q|?wi5iRSoygWhlp>R{%@P?L$U*=HX2R7`bTVfOR@3?} zI?2;0Kb|Kx`P_gDyD(eF#{S#GH96Vy{XW^W*e|J=7Iw#eLZ4{bqG3)}&Ov~JWjsI& zIeu3Oxls(EW6fs#LFCAh=lW!s;~3lZss@&BYm!rQq{WECLN~Vym5vy51j()##b6b; zYN@=H+q@?wsJWBF1@cp;tC+-33$eu6?wxG~`^z}MVpS1y=ii^@3y0<;ImAKt;>$$G zP#b@!6=luA+W%DPGOboyUncOrR#S(F?VAG9T-}iIApf)KONv2?s!3&53Er{$-`Z7U zJ9oEY!)t;v$u}2;)Y8qscGLe+KD7q%b(m=$xZ?}@3+X0sTBRuTv@}@KYxCwT%ya;P zz+gP`ZzAV_*+t)jzv3(`8yRi~jh6L6#Wp_pZ8bWr<#! zsgR!T)xYPlbm6|_rD`m3kpioh$KZYYDfygOBUgM908GyL8|>GiIv2E^9yjzu)c}fk zC1&O0>KREtB%1u+|I!eHS!3tp3ovkzjnnNB4k%k%LV<)=DGNPK zO$j}X&jQ<&%YhIv9czE!J0K_B?uI%FSQb4NR=ojg9SPaAj_auP-;qbQm zw#(so(eFt3_-(SkR;gO79_{*cj>rPb>jm1cUXX=uzrRC@M1SEQphWO^O6@MJ)1U$= z#jj^-Y+yyLQI=2wrpJbj|9Qx8i9U%=@O7Ti59{#n=E6Z*^ly8G17=OwAR-}jN5}Tf zBM3>3V2W?)l$yB!BUuP%CTbd_QwV#~zNN(#w5keFg67pPAzO zjHsT&+cFNxO~^qHxiNcRUOSlOwEkTDySu`UNG)YycU;4+b%Cc_X&#z>0gC%7j|VvSq!T)e*bq-bb$o$dbFxn_$yOp)&-yt1IuPIO$U-XVSasSpeS=m1tG< zJjd3-05Su*y{&8#SmKr8zqe1VA;`RJtPoSW@8zmR3d7Bi53`>2 z%?a!VXqr(lGpIOBkqnR2rC(d^BRhtOuD|7gqdT{p z_g1*S@{zus$dB2i%NkWZRe?6Nw?iDRr`q}Bk=!I71|?K8G1LM+nkA%sJmbKY`pwyR zZg1^-#RW%43KC=0_Z9hQ%#gr1uH2dTrm1>0UDqdVujw&nuhY@XC!s~En)ZTgFx1K2 zZf=zJAdvcAoIBf`ByDU-oSHMYSmttEYT40W8YtnPi|Q}e+&fPerd}yu8+cyk@=B^6 z-^Lbg(gpe3oaVL#5<;3W&B1sEfr3nCU-(o2!I0?o^?m=>W}9`fh6cFR#Q^WWZG2JUTr!BlWS#>_)sPk)f2p$n;vAB%459W zz`afUE-AA>uJsLQZYSdCjSfK#K8G7un%V&Hit2p2K2b|UUMhfGK8`4;T>t&<*PvJT zsB}vXxmz^(R1AauJ0w7hMaj$KnG2V4$wu201*c++lYU)5jbHD2z@rB>ALc)Nj)QRP zOV86uW__gqu1ak^x7j%3KseZ#C)JUUn6p?vj!~Q!LGXe@n;1TE@HJ4sClop^Axbk-0y2*aTr9 zZmm4nQk?^5`R}+-bD*A)G?Ou8o7sfW`8S`pW6 zAi<$FhHudjfzcK$x*M39cEy((7eXCAbL;BNe)ybAv#a;GE*Mkm83B56H+l2#x0r?=Ii=0f{J|k} zi-83Tc7K+6S%0#UC`=U!)#lw9bJn#G07Rh%c{aOaAs!vlmra{ zl^dTB7wYdHx4S4}a|XswxZ3eCDp!EK6XSp79foYSN|$@;f3NkH0K<}{grQYpv13l{ z7unHkUzZ#F$_CO~j3w8Yk?syhLZ4|W=K{)PyHfjbesbF4B0qUeO4_yF3ctSFDJG z4MkRND#jn;#AZkh-iG4{Pzb5n+m%TWLI`tmIWBfpuU|ED`W_qCekT4S#kvX|2<`II zwK{m?*H)c5okVgMr?N5HKdI8u#h%tpOo>I>i_LA{B|Q?QK^ zXI=`kzu_6Ze>nbK{u?Lb>;~P5`1YGafbL=S7d7`gh5s&d3pV`j%iOb#9{5gk1foHC zF)$QOND-ZUEoY6<8$R_P=Q4SPoE5ti;q>zO-TG5#F|s*=D9hEZ0oM~7k;WKXXlWY1 zg$y7Um32p)Z;Gye_05eVK0$Tts7-f@CvA0V*@~%3b z@azg_F@9t#hkSO)`c&xT0NpoBjw2f zdW6~}7PC<<+~NnY!#Aa00hg;a3q=p=JuO=0jH>BghTOE`ZyJhUI$?Dxq1ToTXdaRTm{e%}z>jM=3Rb8+4?zH-^2Wp>~k3RE>rkgnT(&IQ{*Y^nZk z#J1gkoxaigDfj@<#PySL$L^6zkI72)v!f>_MSn>M=Y4lYTB3`MwI%l%4# zZ||D;Rloeq{Di*%Di3L-DfJ%s{Q4Vi^{Nsa`c=eO9{^4Wori1#Mre8(@cZh>QOlWu zzWWs=Q)6ZW6U*VT{lXIja#Aa_NR;3JcjSt`LCp{}$&+S+=F3z5yfxQ>fAYcU`byft z0}b#M&T|B;JtU9U#!>vB9=JXZ`ADUIY6-2ZKaGk;^I?+~Lv#fs6$+{M!IiB#&|4)u zEZ{Gny;pviwBdIh7HN}_?aR&xXidBkJ@ZTR|W|FmFs^uRVhC>1(9b0{5XH>e2 zfQ+Sh15UD;5gl8SQ~zq?&#(_Qi{=Ze!iU-4ut3IK<%fxeH#?I9EDZS9%77sur~i7% zr9|Y(=HcD8M+oc?X7~Nd>)FItcM32M-$4CC_=a9Ld+?{Wf3cu)H>%xP5Ueo*bw>BVzSj<7_R5d@f2r?4Hm_C|cEIu_51K zewr$A`>Oav1Jfl7Sn|fGz2?Ers7xp&%FVTY^wxcmRm4T=JJ=9YVpcM=ir1>YTj&LN z>iwt(ABrJpzpd4zOpp{b--c%vAR$wFB?{L&q77!oy1yT&r?UEF+sp)2@NEe{^u!DX z?^-fQClX5Pkv_=Z>J+w;9ezuw;=9C;I|K7f1M1}34#CZQSO|>GcV5lkOmb!qshEpj zcH;&&PTx$$KSJ3}#Z|D5ki_9#hYHQ3L;AaA6}T@cjcx3s3|TQ#Twop|_@;DN)|*0} zB{Jy1iQ8A6TU=JQ=5R85GfApJAvO9ix#HAz^h&i776V+$cdHHWpaXvH5J+4z1T{OH z!tNqomGBv+(|J$~9F82g`jPVMbBg{1t7p=02OH3o?E?57WrYYW&UIGQm#hhA(;Y@{ z6PehwO(_e2d5XNS|v-z-?PP#+fntVP$Ie7;a76H`*+okbyJ)10a#n60I z$DUay*b`h)=^MO5XdRLl14Xo@II?*+o9VpDtsTB-9#Q6gSB{TZ&$i;VIer|zM5+jA z7Yn4#N=Yo!_E)ubz%XOunaJ8Yw;4qIC$6W*5$?8dbcuQ|T#mUVC?l?~j#g$fDAYyg z>bSs=Caqnk?_5E8{BKVIYcG|3A<4fjbKBW9nz^q|LI|Y`>JskznVb2Q2ASgr=9pH* zq_5yvWT{BaWSKLIQ;|D#ALkoC5If$?A-C+r>%K&dA`gV3vL$T@$HjkR5C&#c3t-1d9h0v!pb`;Ed!1_F;W)y?5 z0sI(@F0s*fA*p(u19+KsY;lFCM3&Ka!QGHoW*Kx%C^Yn1xMEArcFiKCLu(wQ9dh(z zIx(7Uvwg4HZ0SK+o0tLbxQd&S)J~E(7g#U2-iaA}rPo54KRrGArY}x?9(c%XTa7{X zyt*xrfkh8^vE(96n5!v~z11jIGyBH_j>JsPjcko-ah*L}36tgp;t2yB@>h(T6&ui6 z#}JX|Dyz5dubkUimOj4Q&Q1~do}Ih81^B0#MJJx(-H2Q_n5zV_5TX-7(2CjV|LrWs z7yeBnG^`W0AAT6|JD5U`1dIax8WIucpziIER}w26ouiD=bOKr*b6o~v<#x)VG$XUppTI~fk|w(q?!<-c4VC7o^IC8v#b;KOXt4LB#}nXyew{itOj+YMmKDe zo|tv3qac3moD(#ac3q4$v7TmNl{Eo2jCRt#>W#{m&)*2R0>AlggFl?G%BQ+Zk)uce zq$$CkH=RWM;~!don|g^Cetd4YaZ%m4N*jB91 z!rJzsGJ(deq7-fC_=C!uu?|Xk)C>It^nZxwk2i(`8WwSD9ERo&eS9JJGTm)hQ%?pm z>R9r^VDKoXf`j~V=>xUjXp)^2u&5R-)nDlipe^NE(u>X$B99voFiB@G4c|wbcWRs3 zGk@U`yAtZ7Pf19>{w1(o0g?Tj~AqGit>k@OLA zN?FJ=yIErr$;f{^mg^PhUi!b8ad`2=b2Ml;AkX^C3A72 zz%uUxKpD<_gz@=7Jr}^&ix{$|u5lif{)qT3**rq$4-Qag5f@JUjLx(`Ea^YIv<_Uh zNhfY1{1a!c6NA$RI<3hS3Ee4c7q-Kn_)NXUuzJt7pfi|OiD2&s%^z-I=vT+Qij}bk zhzZAAI^&R8{7(%4Yah@Hw*$cZh#@NpyXPzPtz`i30P7(WC8@^`?(SP&E*z(T#bNnY zqYbHZ26wR9l|2v4v!`BPtPqw9fz!w@!=Z$fAg-~t@=1IYHl{{AlvmE+5+&4gb=0*!vjbT>dl@Z%Ub=F5ZmA@vf+ z>8_!sJkXGnxNdKKc!&ydZVl@+EHHK{SZRB3WIe-F;hs+uy?qOj(7DK={UzxI>BZnk&nUu)N{_{fZAF8S>oOW9?~xlq3eXN*t}U6T zphZ5_z_4y3u=V+hOC}&fiS+nfHS_ByQ3KPi3Dm7_0*Isfnt^y*J|c8)f>qJ{QdG8< zZDsbK3FyG|8_OekXax)if9}&)zRq5&!>C;tLdcI$1>Fa%tYRpWao*g|tT4c7oe|7Y z35bwp3h|%@Bs#74m8?9H`cG4~&W=gNYX@TH*hi&9OEYJLP=VyH`71`RX2E_Q-TJUv zRr>Sb+Pf2DNFW>0_v!SkZ(0zxkcrSCM&={idbf=(D$-F8sodBO-rw0Z&0KOx)CgjQ z4M;w3iA#=xTOqtwE4=FVHgFK74WwAj!va!axw6^}3t32cQ_Ifb7$k734Mnk=#o`VE{98{o|k4L%-q{kOIdM z_HtD|3SAy^I*_dXl0`Sg`&Lqrg*yl7g)A%FY|wZZAzZN)LxXsu(J3@1b%+SetSEX| z5NOGCvMY=r2_jionhQ`O!1Ld>EC@g#3x5}!AQ&PaiXSF6Ab|)f6Bew9TyZ}nZXghJ zF=2sISab+1g#q5d0KA4t1^|fyU)6>lw*({8Y2h9Aw(c>Aa*rr&juZ8-B0zRRMa;iu z!$U!0OtLY#?xN6~e;`8vabqzLJ`Rm~ryLC-BoL-MpI|sjhxhJpW_g3~(1b1Z>)I~9 z86s#bh^t8jx*K#Lf*LwE|6mn_9L1uo2eGhfe8U>)R)!pr{A#B7E1xI=Z&=Z5_2{8A zM^>fk@%6VdiW@#-zOi?`Ty>-+bmv`eeeNs7be`Gbs?@c*Mw~;Fzi-?V`#=7H5<#Fe z+-7T!^!{Fih4R(MD^Cvn4yqTvkAffRC$N&wGTA%Fp;_Z6gN5ov%!`xZ@?w)v{ym{V z{X_FP4M7EB0`1dQCkrhLX`teGJ9YG@OY<3bg}B9JpZ1@FS2y3>r}bRW4KIY|yG5!0 z_R-z2g|6~#O5XuHxi??~pag?C5z zX}VrP_}!X(+-9FOI{L=A;RZj&C#(dF@}zWFMP)lcsBrrp#4e@lVu#m-JklP%! zi$dFEWap*3LPVfuCDCVlp#xD3NUq3P>?5+j!G9Csk!p8xX*QX>*4l77EP!(}0VPF( zu;L?9M*hq46!1;vyCW{gfT%zq4Kid(5D=O!NIIqL|L~fI9)xz^hwArO7fhgkXpb+d zxUZ*u!+t%K$}55IJSXgSmL-s!B8#@fO^_4ddr7K_4cd+)wfU8=7s!}lA6#zzU7ns8 z5EKBTTJC-fJ5uAlw|)Uz z(ZcIn7^uVgpwxxGJf{WLayZlWx~*O(Ge1d3d5N_AGKT!D|DOxsx9S&6&n(f5^xrRt zEgpMs)!n%{g!6suNx|_4@6CQ0JWT=@rg#*`JvfVO#IpwkojyP9tJJmHtfv%Yu4|6m zT?BbCbL7dfPK`W#G9q2ufseG0vYuLHtovjrcf9eJ@U1qA^?}1}%`dgx3ZbKIV-ojnWOVB=Y8XI<~7pmY>?j~TgdGs4{iKE}swtil%H(hK;kOzyw?(S0|*`)F2 zH@)F!%Z_-G>RUmJ`e^|SZy2~o!lWK&(H*>jCuV3pPj6^>R-5&cN-BN`LJf2gokp=)R8{Rgx7=3C8JQO6Fsj{-lsWtn6voQX%ggXyKGdgF zD4AIO;pA<2FYf3v?xUR1Z7Gg%0bl!+@I%W_4^~-)hFO+(HqX0h z@c3bX3F~0g{`;Z%h(3<7anAR)eOSAU`In>u81DzJ(b<_far6olD7Iq!XLl8)(Z~|1 zWh*rNmpG1la&TKl=n6o3N=2Iu+17gZZ+Vpdg->x3lAEJ6Od#JrAGw4<4fx?_MEwwK zqIFAMKSM`Mln~9#$r!I!$cSP#&Y}fbaY!P)GbyDY)5-I-su|^2BNoLQMcvWMPHI_^ z-o{eE`G$i|!b%3_=Q?SF!i~()`5!>YAGRa|c2r3TbuhV39IDH9)HYX|C6%kh#^6qc z4QZWpLI{nlJbe@vtY}gR_^PZjN!1i;20lJMV#L=X8?dmVfUC>Lm$~&eR7?~@!pw|v z3haErSAvfdMG0uSN$TK-!GnC2w{iUeBRs!AY=ljg)<36v4hDuuQ~du(>{y0`y^WS* zj=M;qVi>S-TM&^7jm;U)JY_k#A_77OLK+0IB=7-K#H5u-{O zxs0h=@5c{ z>&g{;sqF$`nrwKoYP2;9hN7w(f#~)!hSC_YgVQM@4n}Q>rWxdTa;mg-3Wl<(DdCq6 zy4|u#B?$5ySWRx%xKU+-&8*x`i?gFM%7{yt6f@g> zZ3ri3fRc18i|B3KWs|5X)|cufh3S-J_c}%0E-o*I!D*rScq&hu{9u)jI^Dp|m-k3N zyVF*7GzmdG?0zIIHCs0=_D@N$O0|ANnrTJ>hEZ}OBLzj!ZbpR2N8OgpvI7KVM#P=N zW=$@|zik`srFI}EQmEeT+6|@uF4H85!|CLL8(XqX_sq>E8zDHN-XesKx2%>V@s&(vxq~^grI0Z0@`m{agP0BDa$%vFGq8NMJz$@)Gkyh*z7|O|41W5E{heFS}qS{a@a^3At3k$R&;|Y zV&U_!s3Y1Plkdi;w(ku5^M#SDhQv$274Yr_u_LKHNfHd~?3i?A~f_SbxU{JecTshb=!oI5Sqf?mshZb5l^a^TMUs2*dd!#o{HF# zIWK!b|7r@k#hCH~ldk7?l*@ehKKKMvSkbRZ9YVWA!oA@#12|%T`bmvSBp+6=oWsYd z%3mUw?oMHH}3*TpXbA3(n)=?zN=f$bHy}cde_dZVbJWLBud-=RP-5Rpsol~@8V>W$BVSkuX zcz~LG>V+X2y2xk35yQ|P?22}sK=j((pDzBV;>{74O@f8ExVXTIYG`PP_-azVZFqe2 z4JN0iwvc2EL3l@!C5(b4*VE`SLH+5iuAfSYQmx zormK_(@;_I-ebfXax0&w5omrOKQ$6YFSuOkl@0UIyyhEwb_r_ z5HD`6$<57;2@3*~_`Dvgs7lqovyIQqfy_WcQqnZ4Gi}kY^s!PPf!xR2n?5S)Gd|pB zb{-xnjDhp5;W}?(>QXh?BnxF_bj;=UDkIwG`lcpz>_L$DIn2ji;<4_RP9A}b$1=bd z2RzJ|PYewWjq32mXf_GnP*C(8xT2w>d$_vdqri>38Lp~ixJ`ZkPJvJaBI56v^4i|a zNY8HW`h#Bsw2uEmw8g}N>7zgbhXk=R9jIJIrZgXdVYryAq4NAoX~781U#Ao3AR|F4hXHx>v%~+P=_YDB$B&9>TyOEGC>68u$=@OI> zq>=7!DM@K*X{1Y#l193_n{V?z*LVNo;*N99j+wP)&&)~+9b{x-x!VECJx84whw}|w zndYElgKQkPsOTfc;}OP_-VG30ube+%3hEdI;+BSniy(dT4oHwhmz9+nR$T53Bd}RM zKHLLMwuPs44Qg|=H8ru0NoS>Qtbk4Sc>#n3E)EuKD|Mc({8f>T%7WBK4a_pP(#Y@M zEq5n_wo~O^Kn5BJkcO5_QZYQGBm#9O^5+OXmrefyCBBsq1cwlItgfyCfwO;8( zA_o*+K1V|{SeSovFf}nzs#m)Ml%Bn|z6ArVEak$cMy1!+K)PtOFw>n0WbOi?l!L7; zigGRbZ|qx_w@>!ue0S;}SlAB5hD{5Z2?;fx*C&W%pO=<{$-%_62@Db?uU_67eO`W6 zF?9>1&-k!IF&(btsHv&vz>I?YwQ_?dVAKEnc_T#EHnQ0SCh-tRcLV9$?I$s$cYB&2 zh@@1X?iTh-yXgJ6C|Gm~Sw>ue*$N!py zOJc%*p=D$I-wSNfa3^l=rX<$4Ng!X;au)}BCrH*~wi0nzp;v1&S*!^M2S?IdX4EE< z`3=c$y3USR9CKRsF_7I8W(C#r>EiI>Z*UXS)0=@-?PvV2adAN49a|jpbEZ+Xg_2M; z6%x>RVKZpNeT-Bjj@FH&tg?-xf5IG@XnqtxlbzVIPd4mR^hy_~d&C~Gy1M=gw3-~( z<>6g*@*V~B&Q3(U{B&l4DFfTSdt^}-NP#IUD1c;g{NFe!%dEhXg!9bkaKm_>X*GKEY{|h*#Wg>TFhM+nsNjK3Yg;53NyWlO9l8aB-*n|BsG6FV5ujnk57x$BG z$%?U4q{BhEw_OkK`}O6sEP{Arog*S^7vDPioeWYz8#5y?=m0fyq!Vm*9c_XsLJwZm zQ#vHtSpW*m#_g=bq5bqq4>IZFt9$7hS}BQ_y1ZmLf!@}TlxF@PX*LF`~&LS<)N1T@DMN&kxtzD77`L2TU%Q^sn}Qw zjNSa4G~$>5*{>=Z4dS2%cTVS%(=RsyGQ;r}zfC|+Sy@?5u3=~POzP&UW_s-UQsVQM zULHk+9p^@N@8j?($vPnO0kqHU7lDjYX=QF!Zt{EY?Ci`oI9c9(f|tz&GEX3( zmFF6TF5dd{=c`o9%mz9+io)@tHw+xTPy6XzrOwJfAN^$MTw{U_pxf3)H+Xh?51bb0 zK@;snLX$fRy3-VN!{7SwJPow8w*6G?g1``-Q78IbNzlMm$!jc!k$pJi2-{i@pZeVU z3>C$&g*yi&>03el0)6cJf9xwFANo^3ezC*$EdCqTF)G$E%fyuryVq^u0L}GM5sLqM z$MJK)-j4!;KBOAJyWd)=bse0>R{svKkAAkm&$-h=FLDvIZ zDF;rLQ@899|NEb^kDt0uJ=N6IEG#y_5*W>u5j}M@jnxzh!$k>Puzvw>41TA}#O%@O zwU1^X%k10mGfrfz5g^t6_~UY8`BTQ^!j?!pf*@QB`!yNTx0XNnj&8otz8z}5iZ3z4 z>qG4;d16`AFT7vGBsvn{Uj|QylJ>q9l1q9&=r1Ij2?{;TevggvkBye*>I$5ajWlmM zEQtOU5ww>TP>u7x(DmUT@VM{}J}+Oc54!KY+P^GWq-q#QzMR99N0U-zVrH(e53W(v zj>}=VN@Q9IYjjwdWrk%K_eqP*8tWH)lO5SgWxfoZoi= z?%e79`=Qli5XcY`B6*HLOhgoNve`6vc1TxPS&~AQT*8&`g;H#ImPo&9h&vx;%NE8L@`2e(MzHNz@p} zN#oQ3GaykXUpNk4KoQTd!qwQAlHfULU5T^)@IfB_ZkV&zA<6uH@$h~TXj^&aZ-zY{ z92{h3WZZ)~oV7blE*GE$3A##&UN(%}uNys>&-`oALv9;znk2WMdBLcjij;$^ceuNY z1HTM}5HEnhrH$_2SFOj9Ko$>ZFwX3rx1z5i_&z!Qr(|_{(d&NE>v+-YqhK&%LZ10D zevO+z3CHv37a|6k(3Ypx1rTf_e>e&TZ7QC6Kje*DuMqvvtWbKXbV?*Q#AqA)GBK1w zo~;9CZTGWNtvyvwdLH~yw@>@!y%C&hLr~|&8Jqv(s z`p9OBVTHLaSu~J?{^#>}4?Mu+l689bK3U)r$7MZ{H?qI zO!8{lR4e#LnOcAh`P}vTC}MVjRfe|7t~2)K2)C01EbbH)TDh@ckuyq?yCM~@Fp3bc z{u-K^h#@lfElNKMk>gMmFx7DFz_tM-Err>I0cO9Up`pTS-xgl{?icypuOKwy?B|vS z`#??_a0B$IcJbuezOUGsUM%>`y;9}&5*ZFxN6XQkYt*3E+7a;-8KUPhs?pK4XRItd z6ciL>-*ykm(e&A-rrI9PCnq%-0$>05G(ZaG{dh$Rp4%HJA__*kKU{DAJC1Ul2PGRH z7ET7vcvUNPJohSlmx%sQtq&i4kcXBW8%!#vfk@`m;^KpgN}*z#lY2G#B9hxDXXmFY zUICUeIXx|l8Bo4U(hE>1SaaQk{z6GH4rC_o6}pmBF` zHZgJAjv{k&s_gCMm;(E+Nka^casf|u$Ks*CrMjmsBl+M`uuydGY0wL@$xbj%pSH(n zClCujyV};v=1t))JiI;0ZR%5>;}Dz z2Od~oU<4K*O!VN##MUzNMrkBs_J`n}#{)X`g2%dmztY@9=DJBg5nAcqNY^~@bR;}J z!ILKj_{25U>hoVF7Acy$b4gg9{rUFV=w>W=@t~m@Ph)uW<`vQ^72pCdMDMp%Oqs*$ zJ*3T<)Keec#v2nNt=+r9P1T03>XIT91n(9*(&kL@?}6!{1AG;j8*M^=o=-I;7-A0f`?T!2nl{G$e! z8E|IBAqoUEG71z<9`_LcJJ@diq=6suXy{%YSM%RZlNzY6_2{f!MnK+=ZPv;>_R_%@+S^HJzkTSr7$CUdwblBkk+Vk-DZ7WdP|417$dw0 zo7oW5xZg^v@t5k6tpom_ZLie5XvmMK%}+*xJ_~J+B?!&BslcB&(^9GkbQfw1C)W10 ziE9tw7KV_Pgn5dPdq;#&AVv53XBbt!z=2Ydwoh-KcmCl9aWN^?&zUc1M|Y0}ghiN{ zn4Aq{f}ENb3as^#G*wl6W2F#6m8oPL6r|SFNxR(2wW-4XZHa+{t04%lo{uibXC?ad1N8_k%EuNCn2f zz^sAx!fQ{Faqg1hVj;5VdPxv*($rkO1iFk&;C^pzLG}NYrj24?mzfoCETQ&kTGJ#PZ|gMw^?>MWvtSa>>WcrE~XVATNfIb$I+4m_>(; zpDy!0LOeo6|MZFM(M3=m@4qUHbN|*&E8o4kXO8Zr9;_;`4hTPTZx$L^Wlk4%{Trpw zDZ1i790c@$?SC#K2-WQHOyaeo0IOM2QYo0;yIRQtZhBzd5k#BM-NB#E2AA$F_VvWc zdnC+k|8$8QORM?OdsoKF&8*WS)N8_V-Zr_EP3@MImtVNI;3eYOPL-a27UHW63qyHt zw|)HiV-V<)&d;+MV&rO*h?l5bNM(uMcRD;2%MT102xaU#Hh@t9wBP*>{$*yG6GK}= z4YMxl+pqc!+?FPd<=WcXrtFq0X`xXGVA{ihZYn+!0=Fi0YQV@U+(&Iqt#zroSr2M) zOtxeN9{4N|B`K-E@3_Kj72!u<%-5gQ4S4ulr^V6W<#TTVw;N{Cvs>hhvj~E9&9W88 zEra_my9LEx9rHJDz`y*uw0=%C8W=|Rs%vc3wth8WOSTEYClHy^tC$)rDecu$z+@Y& zYG-bUthKLyJNhg+{HU=QEG%5+L*6NhY~w~6_NS*0WBWW$R?!3;Q87b)N%Je93Vr;U zrtHmn%i`{NapM}5zI}Z~V{s#cIg{|zvQkowME+(Y7%(Xu{eZdslQP|Ey58~0R@WtF z+-jZmhHq6>amm$W$sd#^foY%A{o=Vf>w4=c^7{>oM2qq7-y&HR6xCDOZG)RdXYMV} zQX9)x@ayNwc5;yQ@;4E(Mzmv6Z4M*Zl6$3oN(#69y?k147V;3j{Rh>JVxd=Hk?*@G zxR=k~qDS}U624rf5-JZH2ph;rFLE{t-oddvICs}nqSIfZ^8{Cy;@o$t=*|z7FCX)0 z8QF~2Bm-UFiuD1bPbvgIX41(#!=T~u;q2PeFYf%OCz-anl$4Y*je|*0zI6e3n9-Y5@l8r#@NzAnQ&l&!TICKHEY9D~E&iw$Qdy zg+s%dn0P5&F~!U%MS+y{G&M}jZ!|NBktuwknLcfg#pQGNXSBNx+Mf*) z!S3`Mz9}UJvu|ykMyu&&4~8`-$>DW=ufei|2RGFrX9Ycy#4GdgKVId#&4v{wc=Hzd zgX_oc%|y7ufAx|F&He24h}a^NtMM{<;D36GWaVu#>rc707>>VW;qc5X-r2EHW&FIL zNmgH&lhdJ_W^aX0VCZTNf`j5~O!Kw|Z1q#S>xs^_m!yUj+JE7p!Oe2;8a^=t{{d>6 z6iB0erRR$Qg&QtzE#<{PHa$I|aoAPC+&q5}Zb_@6qOqZ|QLpxDC#=?9J8)!|nc?hH z>sN>UM%vXPWci*=-BlMiFGKRysdY!)q#}Q{WkYpURZ0f8tfqne6R>NL9slm?odS3M zbONJW?ehE8;lqZE$VqIy`ui61Cp;<a zi~b_hM#F-zJ*`CMEcECg#UD!6)`UC9)$_DU<1|uR(T8-XPC>?h0@r_i_EH^6E8tHO;!!e4pb33(B3vR^G+$M| zTeRm%;r*Rqjdd{X+bsSJ4Dd9uTE_aBY_p9`?^ zW)DJthdP=$nUPABzkBn1hBr-!5~-Qu$SXF@%3WU-SD=2rx{>;A9$IHgfnKkAp_D4F zR3*C_@ra^rTF)Bw{b-|KOeG7mV(sdfneK%Qao=7}`K}`6%XGd0RJXw@i|t`47qK`R zRb0QyPJPO9Ydt1GQRU1evtL!E*2O$Y#FL*4)UKA-mUD(+A>H&;ixHv%bckykKP(Fd zk{b-(l9n5U5zFD@?ab(eSsgmY6@3OZ4HVgL-CG6ZqgDzfANo z4|8D*D7Iti{RZsI9-674eg%kvXomA5#6k|jWJWK;bw73)G8^8Qq=7;NUJPe)iNpC4 zkjtXvLhrutWbm_Yu|R8+6B4ZpuyBwTs#gTAbX3Mtl!7}x#AnT!Zv87Yc$`(vd%lWA zm;Jdq;%6Q-sDEV|*H!)%Pr6$U9}1L{Mo6{$IT6m+ijrfPm$(1{$~}vv5k-fj0xt?L zLi7-zoWLc;#%>NYh@db{J&>@I;{;ZaVD9Ux?qC&uN-JZPW*m*CX7H+v`iz^>__U`G z!3UNj-Er<0DXq^6Fh;x>TzrQsR=mjNNZ3)p2MW~6P!-!4!e)eA$J&hNhLa!9R36Vj zSn7-I(k<0f7$AUbH@WR@z3pMQ4FQ5nfYb+xX&{>JSS%M&!-#8rTYV&0UxW^hCheD8 zkeHmhdTRVt`n5hYs}hW_eLv3jYOyXnq?VqtmL?C!R*+~8y@|NfxCuaJLJz^cb!b=I zP!v~yg(^l@=do@j@NcQRVMsWJ_Ey)PL48G)m>x)oENipcC_t4aDwL5-eRwIFjaB3ifXbH+P7L|OJC6CS-CuC#z zWZq#?)gdbA$H~0sftq#uOidL$RIHn>_$oCU5>tE5ia+bnuCXDh91iPi^>KAOw~hlF z7S+wukEe$e^kRVCO!R|iwjVb6W-2m;0^t)-mQ$8U1Jl43IE?_O0i_IP7_m9S`Xal> z6tQnPKz+8MoaI5k?+q=(^cR9_V-#>1dMF=K1*>+)-AETqxle9a1ae|94DL71z-8>eM_?}WSp5-nlG zc)7$246EUVv^@QuZOCrxaP8RmmQS)GLs}>;rwzRNw@7m_np9AXrYYqGMY&hQpIW`G z&V{c_QO6)OLvQuK##74Bz^!@>9W8xTbq%WsR3IfcR6RS(VhELrk#7A#2C z!I8>j72+TW}cAIbP zi~&dU^y5l#v2eZ-Rlt<`x2263&~!UM9Ad~X&*M@NAid1g{#mZ9;mn*oIp|H9gzrqQ zjvGXge_W*KWNp$LXM%(XpXyE$gDsOmKeYLlt49dJ#k(-5cfUORhe2!XSgQtD8|Sxc z%;??^joWl-1uTOn^t)CL_|QuCpP9rgo1o{=V8cPa{ws)}fOnYe1vfhM@??j=12>B+ zx#4F@({rep628c*xd(!1htT7iK7qFHatCI4ONfx_;7xy8&HyClM~*rg?0~L5zb$Kw z3E{pbpxXTiKCSrUcak}**awqcn^tlo&H?Tm1G(_!nFue+!k^=%KYc3*%%ipno`2pP zzeprAC*}w4;d5dOiBTbe6r|ICxeSfJgq<+d(ueo0!9`Z{7~T3hQWrSB35mT*q;yo# zGkgYV=_4f|C|1!YJGDUBUr#U_=$U&VivDQCBCmpcxON67GagY0sxmx^ua!zf@U5wN z`75)%Hkb=2Yhps*g9vgk!u9YWi?L0KA>;IG=bPuW0We}?POEzkzZ0N$jB`BQGgaOJ zBC;ss&>M|yidu|IPuhRv%0?iGE&T+oGvI^Syq5D^UjrajT=hIVa?Y zh0<%dWe<9svgGPnHUy66;U)}8Vv@A{&O{b8VBYbL?{M@mj9cBts+q+JeoG_S!87wIb2i0I^zO$P%N#KuLl5w!MtK2-+QNQbwsQb6B} z&1M%M(iN%z7QG4e8O;2t6(`3pUcuflmfvy;-i{bAd(_Hp*_@Ce;Ag*KBt(7k4k_*Y zt=s3aG^RM1zLa(}Ap$p3B5 zMrFEHAkfbfu15r%h+A0o`L6y2_DS=1T&2Ui3^I^`ySPrst8Ayv*0IM?<$ zmx2f^({j5hA%^d34UI?q>8QXV8sE;v}vUvE%n}qt`=IqNua2ljk-pJm2j-Fn~ zQMTe}tlKkKjWF~{YrQgC2pSTrdzFcvjg_gI+OTrTf|#VkmZ2 zapV&DlDJ{P1#a-Gop~O=zMkbBZGx+uw=?D2ll-6YgaFXN3k%C0XrYloRDr*c(P?W% zhRHgGM;I$rH-1ENZ+KXYS;9c=LlFJ}-`i#&&J}GGX{$gmnFixlu)ml{3 zA0-9fGU;>y-PSyj0g`nuV6Ro;frmoygFfyjnFpo3{>jfziC0I__*>=y;6LZDg*_k@J=go1~t5gYSTyvA;kG`oEU`bt@95~hh zd)Cc>Uf`1aSwyIRhV2B&iGo&<%Jg}hpuHn3{!YRGG8z9wcC+5fl&~O`OQvgj7xHgpv1}PAbi){B>M;3C+80W^i$F zebiL{&nW+BvbY5C=y8sQm;+cyb%dK;#8*pA&ybW=w~K4L+KSgEh+FaSHEE|js<;ig z{Lc2-b^-?s6sFotVw9|n4PmlJ@p+2&@UHmgNMpp-eh*l=3(0*hoeFxFsE)vYcTaFt z-&PmySK@o;XDeNYf4)cH0Uy{Q-+Ia8mMjwJ_cOcT&Wu(0J)09}IzI-4uk(VcE$o!q zH>cSwb=aIOkPDbvu6)V?Es4?^4%veanDK2chJj=G+)+~YAc-ML&qEqlDm8-k)Jxj> zZ%JXe2p_G#`#S6wQz9rdB`>`m&leQ!&&ccI0PMh1#StfL^s@s&V63qX_1Tw*W)w)y zyOg~FEx9hnj@&c~*4LVldgx08$ur+{Y~q4T;v{qkwZSD}A}IfY#^@LQkFn-e8D%HS zH+n?{(^<2b>VJ}noQA!^1OxTtc>-G3N~98DeG@pyvM*PBKNip$lE6T}abFKns>+mj zF7jUjLmB1>KxmBMC~EqkA(1iq%C{QnOffErKR=7kmDPPaJ>JgltyZ5x6gF3W)8q&SMYERS~O-hRG~T&g9GMWij7#)zz=|J_}C&7@o&`LI-rL)pzEcJN1<^B zA5HLCQ_Aj3EfSj(SzF^n8YQ1MlOOm<&^t9rNx|96E4nkOD00zz^OjX*ciT3GWY`Dy8wPMpd|zbJUq6L zldUnOY40bC>3ixN@&rCE$^BouH3_?VeV-s-n-j32CEqaXk({X4UX^U0S;L<_S3rC7 zNf-F%2)@IVA+XB^uMMF-rpkB)QOSvLT)N=xpfQ}`oPHK7eVM%}zRJlCu@L?cIO)_L zcycDzeF!}S4{r7SQw(%5Yj${AVKAyH_)mGni{MSC{o#%5#29VtsB{C?=X@4TS*21R zO0(nOiuS*Eyl^tOGF(WInUTho)}`H{w+l99^BBcn4+0xY!c7Jx{`CY|!i0B~i^v=T z6qk9aUfbNWaczvbi3xXV3X*m#=UX8p>zhGdq@Mm3H^y^Dv1`S_dJ0 z4>$q1DXoLSNvE?0-I`5yG8c=ZJ42E+pJ;`m0aaL4FCA?(SZPp92Jzh1Pzj-^<)>*4 zfi&rdFL-%7at=UkCeop~eP$>S`+3PFU41q^&GrnW8N9=#^&F5+PYItLO$}3Ub$Zua zl++PJiCgJciC8y~`xip~vE=!%DH{K(5&jXIJ?> z${P^?AR0E>bk>4i)S=)lKsQE8`v; zW9$myi50dLTEl#qScBjaT0A;y?3@Rs7ghdd+r?t{fJGnB9rRuJC%3pMV!r`z4D)cV zsIi`OOnGm9Q2_^dKrD1)*m@0~E&v+{)h5Qh9qa8GAxu_uN{eTZxO)~Hnvw%3*s4xF z-TDH)(82vKQ&T$Xs$Z{}2VJWuEhlR>((qj#-xdKma4qJ7pG_k;5Z@nWksrv}vmMV- zf~aTyt-2sdNgr}UAQx*M2Qrk#Xb>h6uMLXckh!9qM1S#&cd(Gz`q&6IDlIF9uSP0y z(9^toQoDb{0B>%zMnp3~1>}$Bokm0vq1=gMOuN_ItMd-Dj?7Fog6@Q{VU70r2c5s_Sp;(#r(zyM0E;-O8qIidg@a!igzEnc^T4AU~diCH=t7F<|!2nA(k69wV#I zTdSqO`qnhhl6e?1rw%ay8EWQAm`P-McGn&wiC|NaxgZJg39kF1eXEy+>v-HZPw!(% zxf#ki)AE}1DA({g)6)D**o7AyGNj%ngk+I%KIeZ@7pXqMflr2K6;7EAb@9sM3t{T| zQF9vG>#*U*Gm|kL&{Us(_^G)PxsFiEMqKHf-tL`coUMzqX9$0QA75b?Fwg{F0b7G} zCI!fkFJ(4xjHyJDwAr55iR?86!VUKrkOCf~ViKJfo``BJLXY)$llOA0lzO0dX7&4X z8tN%5qu{@Cd`_*vbUnfM0g{3}b%p22IhP98Y%&QLc`hc3Y$cNSW@yDnGw(}qg2^qT zb3YB0D1I>E3OnK4_)a}gIBprn6x#HvhfG}cpwPx4H7Fl_9F0IuS%JCp%v{J)6O%sy@hDmYGxdHAh&zk?X zB?Ub}b9FA3PaL(VTyfT%LXwk|TKogNIi_}Bcm_x;y4;$1NRK~#XARm$;BIzSKahXl zh{m=g!4v7u=wN;3+q%ZP*7BK?uVcFPmS(Cs z?G&y(UPXjoKmf&@)e#N*Z|hTYKtY$irFZW+jAh~q#|lllA!u#lYW>RHx#opaGHDU# z0EzT%`FAzyAsF2C@P??t3VJq)33~Sx1^Q3SYrKJ*RA+_39rir} zxeF>o*59~I*u;O1RE{VSdkMZ_Q2eB^NnKpi^6a)TZb#5*-&3;hxlPhm_b)PF08?vf zMM;!2M&?1*jl#?dtV;T|L>+0?JDm#T+;nVIH4leNftB6OmoH%2Yn*|_8I7Lo@b&+J z5!du*bX0MBeuo{?EW4ZE`3Lll&gpNR9onzso`P{pcWf68>ombgt{2?)0U|o`>pR4< zc8FanTP>vl9U(+CuKm(v&_?xsl)$!}y*M>RAq}jC@QoS(STZot)xD~{Ay0Gy4ROeV zJ)4knyWzAXdO1@D#otnk>{o3C?hVHs#kQNMwYDhD)l`Qvl9M_ z`dLgYbxZ$mBstnEEc%R6`fC)wu$)XX)2OYah=}D1xq1olPD%w08R;B8hj1Uel7CxH)!6B3&dMf3i%D zysPj@qY^kAEY^)DFtdH8S)rKhWWV z042Bl3Sp?4o3%yo_@xLXwG2Z4LK-7%yL@X!4L3joOcuR#*OiNF_|4P6Go?rrr;cGZ zAd*H|8E?%GjHo6=|3Q@3Z5W_vATBf2OF0ZF@BN+n?&~o;UM^ohkD!9nd{^oj;q#n6 z>2H7rMgG&_+=Blgu)@w_?g8VAzZu0gA6{6OvM+I7^mPDf;mrgABs<9LZ-yp6#CUKP zk#S3L(@&(4mB+E3U3$Fo@du65ZQNT`ENN62`r?}O!|r^-B>e0Ps$RAYwtDHzE|~av zNJieAUrJpy~pPBgjplk41Ac!J!a!5`lCjIrl znS?E&zJQgkOFA(a_Wd&9BB=AdvQV2${9ZnkOW8pVcnam{@8*6JB8Xwm8duIY+#BM! zn#I82qle%J$54KHtvfm*e9<9l8l?qRp%YkzsO-&0LryC1#MR@-GioYP%cw6Th|~$X zuL1tb5mF8muCew2BdxGORy1Oz9aT;C$@|;9Hnm?XsGH{pEUn;;riE)$nCc%ue!^pI`KHwPS& znns%l@iO;#u(CeA5|K)V-ndP=MF zK0o2oOhC9GKbiy4;gTxw+cquXIUMj2RDY-QO6AnrQh1lZm}XfjND)ez_3;f@g|ReJQcl-&-6 zU$%i+g7zqAv{!&d*e8YDGDP2<)Mi@}hN)1ja**9X$>17@Z zirP*rX@k(nt2xyT4kD2%RV%}0^3G_~nL0JLh823-SljUvdEa8@{E}PJqGftp0>HT8 zBQuuLFi{Sb?Cm3kV8EFQ2+!nSV27qg+?U85!29Wie4TMMOe3XnUH0Xy!&0S?8<`sM z#G~)G-Q)9^_(9!RTU|jbejwHvAG@JPt+KSguhJ4GAwE{^U4<|joj-40xWgoS*jY*` zo!*9dP5S^~X>mdi-8o&o$yiz5CO{oWyexmCqifrVz*Cs%41CIZd!1@vpRwDejYRY+ zWi}GJQM}RDHu10KuCe2sx0yl?WA^XYQ#2(ujm{3jKUcIpL!Mjiiw;PUZihYZkei5V z?#Tqi>9&<+U4S&fCxJggL7m%}qq_3?ZV}Wa)es&;*mXs;ek^$A#V0qS>`=&U0Mit- zN>Of-vKXDy{5`IvzwG;J;WhQ@wLkP{cJ^kWP(+x+2^$K-%ork*3I0sy#mktG-n>>q zut6JG^f2L~aR=hMnN8XGz}-G~I3*efL=w*jM<1sOzhZPDRO!l4SSBZzyHz%E8n;n#)jP@ z%4|&*P=UI!)Imc@S0$b+N*fG`Y)0diS`?Q$!{Tqz?bg zn2piQiL!f&Qhrt+`M9w%cjYW8NK+emO91esgySqngb4J@wI%wM=ZCS zoHi)r=OiV9K<%tn?$9!26+ZM_LA3frz2;Cuoq&n*0|+j`Ct%@sevQ{w13L@L?dza^ zN0T-aoFt~tyO{aNL$t!T9G`e93Y1xdeZOn-IhDU^c!qdYG%H&Kn=5?Ltp18?U^?(d z8QIK_+|JNltTO!S4n#T={G_*fyRKsa9!uPLRH^CR(`bZR5bbOT$Bd6tU_ioEwfNcf;E1T4h;`!1yBHKn*1csYGC; zaNZwsCbtB5*z3$9E%<6R*fYJLQpvtB&G_xXhaVp zt)ifErurwE?S}F$X~W#(kl^im9R$7%k#O6#m*%{*ihLUiAtD-n-CcFlPJF=$9HGM6 z-0F@?eDdk34C_(7VV$ovSkbMb?`Qi14kFq@^lZRZo2Rl#|xsg%jhY|tD+ddaQqMMl)rK+9i`Rg<%A9eATC3o%XmHBTgri@rPQ{@X_It=ek2A}F*Kwggxl(G?#yFe0 z4*kRMaiEX1)pSh+FsKM6$)_z|{o2RK)Mw&_?JIXXrr(th}i_k zoA_EZ+4r-SL_3awv*QjBqCxE*;Pb%k#DJFQZGYs56n2r^H^%IW#W#G916w6n+Eq`F zkivDRz{HO%d#Ca)CJ}$6?1AJT@utjd&d3rDT>~94KG#HW*8T0s!{npWQ{>>m=U=P+ zt;)xC0Me1d8Dp%CJg>hXK5lbmT}PaT?y30PjH}o^4oe)vLO)i5Je7;w*qd&&+x4*bsvlGWvIE1et*5sb-c29=B5=X2Jy>DYYJB5* zSiwsq4+h?`6o6lMID8!d>!sex6C5hdFf{`RES(6ldL+oj7#s8m2+Yx8e66=PwYfhnx-H0}` z3_2AeRU~_dcbBIM_m;5boI z-C%+XJmY6hs%LEm=oZ$L8ysPWe$odRKBN^hCgr(ipNqw9Dl$}9SkdB|j!j}#G?1w< z5#^dbzUq&zEfopVvk949%^L#5H13W8GE3-t+AMWx!|CE{y&UIXCeZbX=vhB?zsjD- zl+TiY!ELjgYN{}H66Tj?%v=NgU zL6;ea+z1c57kRCQxYDN{qYjRCu*^sIbL4s0AE14Cd890zJIWP;>Qq$qc|s_pJ2&fQ zq7cdNdwIF^`4LF+U*w1wJWl>0JqBMUs&*+u?oIyi@3Q64OVs-vKTqE1C8 zZ%$rjYAPsvE-tolbK@^zt(P$p!vk!MC*2+h5OnbxJq#$l`nPrNE_!)MezduNG{Wt1 zk*spRX7H+I_afTU_ahcao&QObfZ>b z62U|*bE`ggti#?rWlEz9|CF5NwLDznxFsp26+tUrlHIQV3hYx{1_cfkvWf>pW^hrNWrWiVZ;fSYyI z(Nh>@rKSd)>-=#Bz#are;Xt~?N0gxWyDQ9E#BqS5Os5rwf7E!7F~X%2(d<9(o*8o6 zJM1bM8V&T|tPN_-$y)F{!0vbni1pX`oSDQHt`yE^kXMl%lFj;LSJ67+XyLYky{0_KiSYp0@@_2nM{V@tkZcVcz=Lv4m%w|<`hfBcgJr%pxQYlH=H|j24 zCawUNZ_&=-{R^pe1P2`f4*L10NGjIgRE{^y<-?JAuQ`9y3D;RZ_v;;SKyoXPZeLlQ z$g&Oy_+El8tCQpQFF%7o%&ywOu(PMSk&jp-BDe3ETAZ_2Loa=nKzDtM&x)D&!F_5FKKz7Kfl0& zKRzC5@lczNF5#O#9UQ1F2cn_pXfAHeT|o1eX3$ZesN)ABbhlSYjsrjX?;ktN0^ZzO z3KqdAt5tu`k?V)s?0bi_wuW0aeGdk=W~A7x$Ggo}i!~Muj(H!lH$m+Us3APO?R?v@ z{NtI0t21iP8raPsq}prZpMmv@gaL9sPxG4x0FD`Q3&ryX-eQBMdua^H<~mj@#B0We;TebO2y# zaZFDZls!TL`t_#B%PvTN*$xr`BEliD)w_CnJDv9;lH|@W)%P#3gZ=<^{v##ZVRfFf z>vvBIHJ{ku)50XO4zXjKZ*A7cA{q#>D`G{Guld_<2+~v;y;lb6sPb{uil`r8-KCV1 z(wAk8`i&qN;e5hby$JctNalhwv~^&J$V-XdQSSiN{3}X zcgvfezZtH$tIDQxz%w|G{FzU$b@)|p-wpH~@VScjV4nI6Dn$(;B&Qda4GPdl&^M%M zUXlt6&bO4O{&rgZsR}sq)uPVS$yHp$w~adhyCNHL5l9eSIj2VBJ)g->V@dPTHCWJR z@qw&SQ4k_Yo)2;;!gM+UK?D+j!Z7PcmG}X*#ROr}Ey?QFL%-sP6rK#H4oFMs>4Jy0 zW~Y6y+#($-I0n9uZpGsVpM$ul_pEI7a{sM(mX7KHsQkIGw|SKUyPBt9?VSV ztuDVi{{vNHX#94(cQFFuP~J!)%0}S9nsm*Ff}imrx`auyRVNGs?#g-~ssuN|Icn10 zpSdOfUhH$s)E1zHH);wEY`xpaW4D-I`Q0-IUCdUz-C@75r8CGaE>?r`))T9lMKzsa zAn)@D)5yrkHy2Xn;vLlg8trUtZ&RPGODZdi6$!y2MpVn}=TW={2YHg^`CX|6-G`=z zA42%e>OH5pGLF$)8b19xOz;ofdOfYK!h2#M=OGqH{*`52u(mrhwMIN>p23NLFaf)O zW1{G-JUDe7a>cHV$SVESSOy^WZVTh~ z^|qf#u!UwS$U$`>Va{aaF?^UX31s39Ew9HBfn(=xNSbeaCE#c9_t{Cc?R>cCKOOqE zYejK7{Ly3bTzQKV_yIDo8uy84OdnJ8IQS(ezrh|T**hHET~GGP{~(wISJ7>#=6pOq z{Qht%`pAV^`b$HJMHB@x_%e<+Sq{2@kVACaT$~O|01PXhqaBcL9=`Yj3+bf@*Bu$) z4j3ji16=($+43K(>Nd&{n&F zaERe^)k!im;%EoG^Se0r08JzGg+^Y~n8~cs!mYjMz4f{OW!K82%|}uvMy~jm&%h@A zJ2v(3Wntaiwr5dUs0k93bh40~GcpY+Y+xUx7;l3RS>>9b9*K=!GsfI;)XU&p7ZtAe z9|^zsFiO90+_(B>8^qnuvzj?#Hq38v3-HM^&74d^hWt-7*OkEf33w;ib&X-Fr4WIH zqSt&Nkt+qRm$p9V#jrdoV5i23Mlp-QP9S#yHJ1LUh533B1QPOljKrI&CNd2t&#$`4f{f$aWi8*#3DIUr7W#rizYWr?|GCYQAG1>}ph z2{P6~DM4U4swc?=7qNdKzfZo7=Y)oi+`{~6?+oX_+IG0B6FnoF?`TS zqe}1e;v+!dy=$v7nZ$-s4+#YDk2ju!)1p=!XZw`J|D)+E!?Jq5t`8m34bt5R(nyzd zcS$24jdXW+C`d||bfa`gD%}mzNQ1yTzyEtZ-)}f)&dlt+_F6j}8KjC-_^U$0O9f*w zs|XOsEC0buQUYuqbN3U<+wYH=DmnH)`fL01pzs#8L?PL<>~R|dO;g#KfkVbV#xwSV z)DgzZvVsu&yn}4Rnv=d_Q*R0fWk;76GHx+gUbkuOhU^9P^{-jMST7lUV}Z{5$)sJ- zw1Ac!p62h)-JMs)($(GfJATZ0amrb&r?nOz@p3BakNBtv89&|U_(U_qUO~ua=S?@A zb34?apmsK=^)X*j80xrby7B+Z@$@!`6^d0xzb`j5xf{`e0ttFGj{ac!?MqTT?#l{o zy-ff61xnOO-qWFw?RNWkWnDOm4YCIQ3~dVM4=o&m8F!BhyvP7=u_{~Kyz)ko$j zGI#eS0%%g)_i1v?o5c{+z^2R{u1tE?pd8HK5{YAF@i`)bA`}(N&m#9xOLLWauW^YZ z_4f{M=D^hE8_`EvbeQdIkRi9cD(-T#a~lIBxe+j#KswCdXl}(}ZtdTSNxm3qQM~25 z`x4Q|_tI(Y?~gK)`(YrEo1=eQh9O~R2d4SHIbT+R#D1ark2s*0eKJ$|i!T*g{HugB zgt9_Pnf)2LcjfCVGBb<-08c4+Yw;Nq*osDZa;!)tR^&i#$^Mv`!sRwf$NOP5y zuX|cPDCDp0H{2^4`VE1cJL`Y_>a4Fe@EYIsQ*1WCl=~xAQ49YDY=K?wPh+=VjT1E@ z@e3NCnd0i=)c^Q6fBlnTo^f;sx0T2+hPl`x>+sa&4DZQF`HpJ(+>I-VP;ikJS(Az318=S0m zuv=5(PQG4#F}h!@AP&z?i}+QJuS7L z>~}kU+cApGWsunH-6tDxj&K>EzSDgdmMKY;0t&~J5grVSXFj@Vwt1Z+5!1m!F$+I2 z5?27W6Ki_^o=}@&F#10AmB847G#lXJW%!AltHBRHE?r3EiMEnKcp+e;dR{p;ymGU; z!~SP=;M-JXd8Otnk+_<%&ET|~QTUP@E5~y)YJ_LC{z(T$Ol=1Mr$VJM)Sp1K;9g2F znm@kA0wvquQ0{~N1Z4hffc;_X|Bd0A8M6884H`G;Xlv7J$U&J{ho|@L30k0G510C1a{;@xKV96daG=x$g!J8V z7)kCR*|6u6N#wseh9(3E5eW$;`1Zu(`wPg`@PT^?7Q%dU7TDb5?zPSeGT;x&b|PZ9 zkRTN2+b_@csJ(2DC@-aWSgY9XNekjp{PE1EqPv@=bJ-AvKY{#I?in4_kL7J&_u@JJ z;V$wq`7f8zCJ?~xCvB%qgCY)OK_pP#GDYBn;pHgkhba6`Kl@mvD>~g1STvw&)BIPS zvS3!;-7Mpu#^#R5a)+xAavHS=vm5yD^^-k(?6&1zu=c9AZ@!dYQQiZ29b?I&oL@v< zK;=w1&(8}FC%5GX?aw~1k%it76;Luq8i1>~S^m_}JEcuwaJ=XTex{r!JRu_5;H{!$=76PtQ|>w~a_v#jK73VA+W&4HeB z7`=wuXtbK58LUPw{HJ+@%)!I{Kz5{b>BY^8|(gJQ=g94 zCEP)wq|UjjvH66|hPh(V6)nSX(fFj~`8^`@2`=5*+2ByOHJO?hzGD#6Ti`>(i}r1D96*F`j`%d zpIPn^oaEO;XcTPv$PisMrqXy7Xy(^;agxOh8^e$*eEye(ou!IZQAMTw&u$i!H}$<& z#T`yeQZj_I-wE`#11-!}-@STsce%xXJ@A89v&sHE`b%ek7_auOar6)!YNVYEEus}tFZ6J(()d~}fdX!H- zecJ1t9Lv)E7Mv?05!sk+wFiTFdv#`0-bJ%PQ9dzI&9 zT{qB*#&&juP}6ihk%w|-;|X5{Qog`9+$$@&UDppB?>%o_%6vGPTbgv!Fer^S^rGxX zRXix_x+3S3(4VRpfq9bUmzAt9!L*zIB2|Yl26CDHe)th-v7BwgTzXzL=)|R$v?%$Y zHec6Y;l@`o+zgXX=d^N;kJm!(xyb-bQiv(L3nC8tT{P$=W}iusG_#2%OX_&QsiUQ@ z>CpN78`X>s>hm&5yNQuN7zBnVy3t<8B z0@?7KFzMA3o2MPpr>8ed6}FEFHrRiOWN2BUX7tOtM1&dcO1D0|(Wl+xuXY}+KHGq? zl%6d(Q;11Ie6}7kU)IDeI7a14F~4KEf6GYaG};KEleu?|mA+Gxa58x|aT=E!Z*4zS z6CN|Z+1K{csp#*0ui$5Yl`6=?Gt#Krn-OUx@C%Vs zHl#fCy_shGo@bO)TK9~N_o^z?H_;ShTqNja@5?|#K#USN$hOm9vSqvAz~e?Z`m>Fl z(`nArAS9NGP?6bedV_=*veEV2I!0f%uHav~;(zoAx@^jlKc70x6Riu;$}uwue|)H^ zQC8y1_Bm-?ieCHs*H%pPi{pz`vs5frcaCm^a!T#>@g)2*o)#TRkB@}yBJcX)Aw0p| z{Gn_-i9y2`uT})R9}fOyd3{R9FPpr>IB-fHB^21(=sYd{jQAt9O!X^sEII`|WKgMo zlcedHUf9nw&|cALH>JEpEE3A;-XZnpO0c(5iSRlrSV*;dr^q7zLfEbIGEo+L0u>rr zp)lV@hPZD$E&cNE(z9xG`N?OKNscx$|n$X^3`;n0iAwq*#4riH3Ng z%2oyEE=4E(`)Y2q ziZ)M(jU7@9&``AQu3q#qwb;$RS1{QIDSBAqilhG`c?BXwu`=~Fjs7^AbijwV`+@ll z3(**B_+mokTlzH_O|F7$JCC*8sg`Mik=d}C@iVG7&#?ywvZIUoD{3|E!c64O>2IM| zgYrIwVGt#gM570pe4)NF7Xk#{AoH4abxX%U%efJ#AAH)K5dBZ5sjsX1=J@=$_T2g1wpKy)m|=I{8Se)%XE~gqHco}A zRvLb7_jjJRpavwC0hQFzJX)sJ+6(v%2+OiMS+y`ok7*TeKHj5qxLFPJy!65^`rR+i z@!v%A@j^{QcOrj@ApR5M*fgva%@l{B|F#i-`>RxuM-eIy1)G#llD_vRk1cDXm-}cG zg1d%!0a01qN<7r`+>j=&-Brsf;6~{r}4a$Vyxve1-qCFni&{<1FZF<8#_;Q!<-> z$REXg;~VQcF6%LCr&T6tOeASW4dcoQsxxKrt3@_Dv zA7!J9{Hqhc&n0!JvNl?BmasN#;Kv?OcQT$N@P|Yi26B~Bl1;EKbhYYniZgbijPm&x zMjcER(j&G1@QZq|mK^^&h;`SqHJF6>S}Pd7(8^HZ|IU1G>SO&AbkyQ?P-kBKPHZ06 zyzKk|^g@Po3oMbc6WZZ+b&S0%djt;PG$wK`>yfJ8+k$cx$GWXdR}nMBHK$&5#E|X{ zCuFgOmIA&tzbi24+~j=WrHI-LqW7=_chjYT&u=a?nZo>n0&3ci;Wxks z+y7~!SP|_^3O<=sgNDY&c!80=v4gk%nLs}OTnH9V7TBIQ5kpoxQx2Wt{evz zDsCL7w!D>AH~ip6#rBqp&{`jKp~VSM2%Q+Wpb zz+OBKv-_?mULk0HG>Sqb8*S*RC$)@0wiCAS!oJ`It6ND~s}Z*VQ1-w$)@uIbZH_*t zbkbEUZnEpqalo5muPe95#>EGe@+di~QtK(9O?o3irW;mCH-6ETG;1H}iVnRnV_|vZ zOy9#K7FmJ4>aJ&L(YP2}u^+x_Rx#P94`m{d=V4VdXzvR9KkPd#z3O`r*Jw9)pHHxo zlRP@-DLS>`d2w7*a9q0j9YNujy2PusC&7a$hbl89h#Tpnt!hiHyjhyDBH;xuln1;6 zhh;S8LAX8POx_G)hOO`6RkUzgj#g&!FZ|)&NL}KuhKCA98*iYq-z!4iPe_ioj&(|N zeRds(ldxEOoxmb@913gVN?bAJY5Is#abreQ7rRNjaE8ihwve0(P8YS&+{qp}4wd(u z3oMT4GHGu<0cdg}m0~>EEbtAk9!B$0qm9s~`e&y5lS-1SX9`(=_1!*FHLdo66W3kS z+*JKYw6d^)6pAa|5}BTb?bNE+XK*8Py=>$dnr&r@yX8-9rx9TlRch^mjOlS`E@9mg$U_T+_F(dc1TYJ)Bov=v zE?y(wYD-tjIGU*=Q+TjRbl}=mQqSFUp$gCH(z(dXVJmjUd9Ngy&B4ZIGP{lT5_ucT zI~;l;OWwX6*E@Yi8(bwBmHD2Erta#56r3ZiYmnrcL(r5J2NT4(TKK{jd$zdPblBI& zM)WfbF;iRZ1v}eSW8vaM)YmgqMzC?3Z+s&kpURd%N)_DyPAb{&n;nnmi5KN(TBmEl zNFg||3%ezko(%ZchGxu>X+&v3DN~yK;IX~q2&PkHbnCf9J8Fz1ynSL;6JNX?#=}vUEyNd5dFI>L+GvJ6V8wzjK$}`&nKE94kJC6{pqivb zp@1yo$~WVq^$HSwWv>#s*1q%G;iqh)^VF7fwmE zZF~}*pcUImC$gQWSpe>*T#kkOwZ+D+xTv!~&u3OOku`mP~+C+9n0qQ}>FwSqF>7y$ZQ=pK8GHz&O}s z_Mw@#d_B2`>gS6{%~UX!2c{9Wkj*%(CQ;lL;E-KYU}?XQ*Jo)^A9JM;g#L8IHI z{;wV8!^I4DSo|5GW$NWRmR+SiB<{Nar=s((!c-F99<|}DSzlWpBDmY=b!Pq2Ko>vc+<`c*knEj3ndb}$+*zBLpTk67*|`zK+2+6t6@>)YVd5DO}kmF%fJL0fchuh%-)anlu)! z=9{=i)n>r8SlnJJwf5iE&DA*kCHq%Zn!vINtW}=DzwIG#hgfYFPZfkAiE-yRD+D70 zD1WG4U}=#+bz=eI0Vp)dZ7L13&EgYrRZdlL;%i`XMT^Zj_5Wg`KU(FxouZgfTd;S( zUfGXxjMZt8wtDbmZ8g$so2yU5fZfX6B;SjY*lTZj248zhkB!;TeBHGn!N6>1VV6NQ z;UtD&bBE=vn*rlX$5P`uu|4(U4LHvA_>}9hQfb)uP10e(5Pyg6(FO?%p$At9fYSpPl;qA?k)KXB_wGbAspt z5aoSQK}h|8YA-AP61q0Xk!Ww_TPQaW^&Wl!a6O2j9quW9pfK` z&^QPlc)nO67v9Dud-<>BfhJa00W}|XP{>y6PB#q|D{tt-#^b!Jb}V3TWIH}p51ATC z)SOpe{5l3lUBq+f9*5b0?gZ1$?B1QnUE!+rtewM6-c@hKgSI}@Xuoe+eI`C>ezK8^G8l7u^UjN)$R*ge z8eF&dR=^_3XW;cnk9)OHAxXIEo9}!^No92B5EmEfSuF3cOXO^TzoA6^N?C7tQbZEy z_QIP`D(tlv-@9zB(E7tOfmz)<)1{yM*De!W%WN=hdjKy^2Li~HcsCsFHhrG1vs4TI zkVwERL1&}R43Dd;C(VY@WxQAQ4}eTn1F4mV>VN>8h5f}^>$0p|NBybe!!9Lp8HhDMf|=G8{AgK13`( zB)#f&^X0z|^WBRFIvj%zP`ysR`ISatwt^QaUNQ zjhCt&1o z_l!0|LV?}?!DG`aN$LfwztwZ)_*JJd)SLF(k&ozT=Jf;2LOfIXoM!^4D|OUhP^Nut zOgW%pLq73+(8sY1Xz&Ew!#8vErw_=Y)q%@+^JPW!4S!;Ok&lai2u#6w7@OFPBew8% zKME0CqmLDWc(zK=A&J=5foA1IVuWq#y*HiTtib)|w#6Qvl{cefKZLoc_he%549MRy zimi!x5vt9hJyQQjX0T32KX;EaaJ6WrmFYheX_51Yzs)H}rF*0w_%?DS$(L0ff(BP& zobh0ao3&kA8zZjm=wN$+P2`(#`tcWyz2f9vB9w?t>M0ZTFQNVE@wYKY+H zu}7wqf>)AyZ;K*qr$S5=eCo4IOOykEZ?iAiL;!>erBPDrSj=|_;Z%R z?4R2j=U?=L+q)Rwk&jFcG+Y0qM{B%naM8v;r7CwNzjQUn7K!pl2*NrPmJk!etK~HeuHQW*Q8sd?W{c+RMO#=WeoF;t_4Zj z9RY78NW3nd`IMvs&wHp)w;HfLA?bTxY{Nff_+xv7VwP*^^y`*c*P;eXHD`4ks#RA~ zYah-gtoS7qRLDRnjH5i8!KUp&=D+5h}uNa`>hh!tr zZEpn}rh<=YM}MAQLuXumeNTwS!3}TIy+j5GfZjwlTQt&+sP{J2mG`!}AbE?WUo-AEebkJmn7)GZR6y?zES61HyggY=Gq?*kk zWr|WU8!9*vqQZa$tQhMbfoeJ09>L2xYReNk+ged+rW@bNLLso0GE~`H$N^0|RtviV z8?TR`rmsj7ueJL-zLJw1RY%P;$|bk1+0Nbd9G>(5s<0FeO@0+PvEr7wK9`1WvB_w;ZI7f7@CDzC4HSJAjARIJR0$r$xu0m7+Guc4d30Q(7;)X-pH6Y4ct3cD&=pw>M&2cX84;1o6$U`Z)C44 zgf(5OJW?D~C2DXWJpNT}VbaRN)n}$v?M@3SM2Z+LovjtD$-1(OW5;*C)_@eq@lsaQ z#A4BOw5|JK@{DW4EMOK;pTLUP2;Y2wM4!xdhcT8yF&{sN%0c%Mc8Q2b?Kx)T-Elr# zn?P5vZjj`Q$xfSdLW_^z?})cuQMxnCy)e9DU#rEKj6^RJ-I59sY^|V^yfL%BRsE7a zY_hi&8*fIvP#&`Flgu{uS#x!LE&9HK=1JPh&ieLSPRnNy=Hn|VG`t!7OUl*b{Y
3@fCH3wEf{s=|%_0O>Y#c8ljg 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 P!q0RMANQm3@J;^%toS)o diff --git a/docs/pipeline/assets/inference-example.png b/docs/pipeline/assets/inference-example.png deleted file mode 100644 index bb6000dd923725a7bd8d20eca9e6ed4f375e1b38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 80766 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⁢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 diff --git a/docs/pipeline/assets/postprocessing-example.png b/docs/pipeline/assets/postprocessing-example.png deleted file mode 100644 index 9bd51d84e583f92f74250eeb0971d41aeec910f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64041 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 diff --git a/docs/pipeline/decision-model-card.md b/docs/pipeline/decision-model-card.md deleted file mode 100644 index e1e37bb3..00000000 --- a/docs/pipeline/decision-model-card.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -license: mit -language: -- es -tags: -- text-classification -datasets: -- ArJuzPCyF10 -metrics: -- f1 -widget: -- text: 1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas. -library_name: torch -pipeline_tag: text-classification ---- - -# Model Description -

-schema -

- -This model was developed by [{ collective.ai }](https://collectiveai.io) as part of the [AymurAI](https://aymurai.info) project by [DataGenero](https://datagenero.org). - - - -# Intended uses & limitations -AymurAI is intended to be used as a tool to address the lack of transparency in the judicial system regarding gender-based violence (GBV) cases in Latin America. The goal is to increase report levels, build trust in the justice system, and improve access to justice for women and LGBTIQ+ people. AymurAI will generate and maintain anonymized datasets from legal rulings to understand GBV and support policy making, and also contribute to feminist collectives' campaigns. - -AymurAI is still a prototype and is only being implemented in Argentina and Mexico. Its capabilities are limited to semi-automated data collection and analysis, and the results may be subject to limitations such as the quality and consistency of the data, potential biases in the AI model, and the availability of the data. Additionally, the effectiveness of AymurAI in addressing the lack of transparency in the judicial system and improving access to justice may also depend on other factors such as the level of cooperation from court officials and the broader cultural and political context. - -This model was trained with a closed dataset from an Argentine criminal court. It's is designed to identify and extract relevant information from court sentences related to GBV cases. The use of a domain specific dataset from an Argentine criminal court ensures that the model is tailored to the specific legal and cultural context, allowing for more accurate results. However, it also means that the model may not be applicable or effective in other countries or regions with different legal systems or cultural norms. - -# Usage -## How to use the model in torch - - -```python - -from aymurai.models.decision.binregex import DecisionConv1dBinRegex - -model = DecisionConv1dBinRegex( - tokenizer_path="https://drive.google.com/uc?id=1eljQOinpObdfBREIKxVnC5Y2g_sbhPHT&confirm=true", - model_checkpoint="https://drive.google.com/uc?id=19_YmBJnO06iS0qW8ak0zl0EIsJYin8kQ&confirm=true", - device="cpu", -) - -text = "1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas." - -input_ids = model.tokenizer.encode_batch([text]) -input_ids.shape - -# The model return the logsoftmax of the probabilities of the classes -probabilities = model.model(input_ids).exp().detach().numpy() -probabilities - - -``` - -This yields the following output: -``` -array([[2.2457261e-05, 9.9997759e-01]], dtype=float32) -``` -The first column is the probability of the text not being a decision, and the second column is the probability of the text being a decision. For this example, the model predicts that the text is a decision with a probability of 99.99%. - -## Using the model in aymurai pipeline -You also can run the model directly in the aymurai pipeline. - -```python -from aymurai.pipeline import AymurAIPipeline -from aymurai.models.flair.utils import FlairTextNormalize -from aymurai.models.decision.binregex import DecisionConv1dBinRegex - -config = { - "preprocess": [ - [ - "aymurai.models.flair.utils.FlairTextNormalize", - {} - ] - ], - "models": [ - - [ - "aymurai.models.decision.binregex.DecisionConv1dBinRegex", - { - "tokenizer_path": "https://drive.google.com/uc?id=1eljQOinpObdfBREIKxVnC5Y2g_sbhPHT&confirm=true", - "model_checkpoint": "https://drive.google.com/uc?id=19_YmBJnO06iS0qW8ak0zl0EIsJYin8kQ&confirm=true", - "device": "cpu", - "threshold": 0.5, - "return_only_with_detalle": true - } - ] - ], - "postprocess": [ - ], - "use_cache": false -} - - -pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") - -item = { - 'path': 'dummy', - 'data': { - 'doc.text': "1. DECLARAR EXTINGUIDA LA ACCIÓN PENAL en este caso por cumplimiento de la suspensión del proceso a prueba, y SOBRESEER a EZEQUIEL CAMILO MARCONNI, DNI 11.222.333, en orden a los delitos de lesiones leves agravadas, amenazas simples y agravadas por el uso de armas." - } -} - -pipeline.predict([item]) - - -``` - - - - -# Entities and metrics -## Description -This model only considers the classification of paragraphs being decisions or not. - -For the complete list of entities, please refer to the entities' description table ([en](../data/en/entities-table.md)|[es](../data/es/entities-table.md)). - -For a complete description about entities considered by AymurAI, refer to the [Glossary for the Dataset with gender perspective](https://docs.google.com/document/d/123B9T2abCEqBaxxOl5c7HBJZRdIMtKDWo6IKHIVil04/edit) written by [DataGenero](https://datagenero.org) (spanish only) - - -## Data -The model was trained with a dataset of 1200 legal rulings from an Argentine criminal court. - -Due to the nature of the data (personal data, complaint characteristics and victim protection) the documents are kept private. -### List of annotation contributors -The dataset was manually annotated by: -* Diego Scopetta -* Franny Rodriguez Gerzovich ([email](fraanyrodriguez@gmail.com)|[linkedin](https://www.linkedin.com/in/francescarg)) -* Laura Barreiro -* Matías Sosa -* Maximiliano Sosa -* Patricia Sandoval -* Santiago Bezchinsky ([email](santibezchinsky@gmail.com)|[linkedin](https://www.linkedin.com/in/santiago-bezchinsky)) -* Zoe Rodriguez Gerzovich -## Metrics - -

-schema -

- -Class 0: Not a decision -Class 1: Decision - - - -## Citation -Please cite [the following paper](https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view) when using AymurAI: - -```bibtex -@techreport{feldfeber2022, - author = "Feldfeber, Ivana and Quiroga, Yasmín Belén and Guevara, Clarissa and Ciolfi Felice, Marianela", - title = "Feminisms in Artificial Intelligence: Automation Tools towards a Feminist Judiciary Reform in Argentina and Mexico", - institution = "DataGenero", - year = "2022", - url = "https://drive.google.com/file/d/1P-hW0JKXWZ44Fn94fDVIxQRTExkK6m4Y/view" -} -``` diff --git a/docs/pipelines/README.md b/docs/pipelines/README.md new file mode 100644 index 00000000..b09731d6 --- /dev/null +++ b/docs/pipelines/README.md @@ -0,0 +1,25 @@ +# Pipelines +Language: **English** | [Español](../es/pipelines/README.md) + +This section documents AymurAI backend production pipelines by workflow. + +## Flow docs +- Anonymizer: [anonymizer/README.md](anonymizer/README.md) +- Datapublic: [datapublic/README.md](datapublic/README.md) + +## Related model docs +- Models index: [../models/README.md](../models/README.md) +- Flair NER model card: [../models/flair-model-card.md](../models/flair-model-card.md) +- Decision model card: [../models/decision-model-card.md](../models/decision-model-card.md) + +## Production pipeline sources +- Anonymizer config: `resources/pipelines/production/flair-anonymizer/pipeline.json` +- Datapublic config: `resources/pipelines/production/full-paragraph/pipeline.json` + +## API mapping +- `POST /anonymizer/predict` -> `flair-anonymizer` +- `POST /datapublic/predict/{document_id}` -> `full-paragraph` + +## Related docs +- API reference: [../api/README.md](../api/README.md) +- Internal database: [../database/README.md](../database/README.md) diff --git a/docs/pipelines/anonymizer/README.md b/docs/pipelines/anonymizer/README.md new file mode 100644 index 00000000..11e864e7 --- /dev/null +++ b/docs/pipelines/anonymizer/README.md @@ -0,0 +1,68 @@ +# Anonymizer Pipeline +Language: **English** | [Español](../../es/pipelines/anonymizer/README.md) + +Workflow-oriented technical reference for anonymization. + +## Scope +This flow extracts entities from judicial text and compiles anonymized output documents. + +## Diagram +![Anonymizer pipeline diagram](pipeline.png) + +Editable source: [pipeline.excalidraw](pipeline.excalidraw) + +## Runtime entrypoints +- `POST /misc/document-extract` +- `POST /anonymizer/predict` +- `POST /anonymizer/disambiguate` +- `POST /anonymizer/validation` +- `POST /anonymizer/anonymize-document` + +## Step-by-step flow +1. Text extraction (`/misc/document-extract`) splits source document into normalized paragraphs. +2. Prediction (`/anonymizer/predict`) runs NER on each paragraph. +3. Disambiguation (`/anonymizer/disambiguate`) assigns canonical entity IDs and effective anonymization/disambiguation metadata. +4. Manual review in UI edits labels and optional policies. +5. Compilation (`/anonymizer/anonymize-document`) applies replacements and exports anonymized `.odt`. + +## Technical components + +### Pipeline configuration +- Source: `resources/pipelines/production/flair-anonymizer/pipeline.json` +- Preprocess: + - `aymurai.models.flair.utils.FlairTextNormalize` +- Model: + - `aymurai.models.flair.core.FlairModel` + - base model path: `aymurai/anonymizer-beto-cased-flair` +- Postprocess: + - `aymurai.transforms.anonymization_postprocess.core.AnonymizationEntityCleaner` + - `aymurai.transforms.datetime_formatter.core.DatetimeFormatter` + +### API contracts used by this flow +- `DocumentInformation` +- `DocumentAnnotations` +- `LabelPolicy` +- `RenderPolicy` +- `EntityAttributes` (notably: `canonical_entity_id`, `aymurai_label_instance`, `aymurai_disambiguation`, `aymurai_anonymize`) + +### Core backend modules +- Router: `aymurai/api/endpoints/routers/anonymizer/anonymizer.py` +- Rendering: `aymurai/text/anonymization/doc_anonymizer.py` +- Canonical entity mapping: `aymurai/utils/entity_disambiguation/` + +## Persistence (DB) +Tables touched by this flow: +- `anonymization_paragraph` +- `anonymization_document` +- `anonymization_document_paragraph` + +## Notes +- Label policies are merged from environment and request payload. +- Render policy controls suffix behavior (`auto`, `always`, `never`) during replacement. + +## Related docs +- Pipelines index: [../README.md](../README.md) +- Anonymizer entities: [../../entities/anonymizer/README.md](../../entities/anonymizer/README.md) +- Anonymizer model card: [../../models/anonymizer-model-card.md](../../models/anonymizer-model-card.md) +- API reference: [../../api/README.md](../../api/README.md) +- Internal database: [../../database/README.md](../../database/README.md) diff --git a/docs/pipelines/anonymizer/pipeline.excalidraw b/docs/pipelines/anonymizer/pipeline.excalidraw new file mode 100644 index 00000000..f7da8a73 --- /dev/null +++ b/docs/pipelines/anonymizer/pipeline.excalidraw @@ -0,0 +1,1748 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor", + "elements": [ + { + "id": "M3_9cSeevpvgvuGOJmtLu", + "type": "rectangle", + "x": 341.0753968253973, + "y": -946.5918028903099, + "width": 215.66666666666663, + "height": 280.0447761194029, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0P", + "roundness": { + "type": 3 + }, + "seed": 630737269, + "version": 231, + "versionNonce": 857423573, + "isDeleted": false, + "boundElements": [ + { + "id": "EOtxLYz_c5dBLBZTsf6bP", + "type": "arrow" + } + ], + "updated": 1764875361089, + "link": null, + "locked": false + }, + { + "id": "e0VYlO1HBUE6Y61hMmjQS", + "type": "line", + "x": 384.5306207059946, + "y": -906.3554844823498, + "width": 94.95771144278605, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0Q", + "roundness": { + "type": 2 + }, + "seed": 924406485, + "version": 197, + "versionNonce": 1258245525, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 94.95771144278605, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "zz4q6sGFYLSQEGm4_Z_pZ", + "type": "line", + "x": 380.15053275977357, + "y": -879.2079349266717, + "width": 48.28358208955214, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0R", + "roundness": { + "type": 2 + }, + "seed": 2054303797, + "version": 300, + "versionNonce": 2102055669, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 48.28358208955214, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "S9t8FU85SfKbOpC8RR_gM", + "type": "line", + "x": 380.6970945304854, + "y": -849.4353562329334, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0S", + "roundness": { + "type": 2 + }, + "seed": 227041685, + "version": 330, + "versionNonce": 1522445397, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "DL-iPq6d9xxkjVSnghr83", + "type": "text", + "x": 394.20929106726203, + "y": -619.8728974176731, + "width": 82.81063842773438, + "height": 120.7089552238806, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0T", + "roundness": null, + "seed": 898721525, + "version": 217, + "versionNonce": 1900882722, + "isDeleted": false, + "boundElements": [], + "updated": 1772204466428, + "link": null, + "locked": false, + "text": ".docx\n.pdf\n.odt", + "fontSize": 32.189054726368155, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": ".docx\n.pdf\n.odt", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "eb7-zegRUYIJqYobn0GTg", + "type": "line", + "x": 379.7022624970393, + "y": -821.0544894574741, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0U", + "roundness": { + "type": 2 + }, + "seed": 1964163157, + "version": 228, + "versionNonce": 2143640341, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "76_13jw7FNEf9CD3vN4K7", + "type": "line", + "x": 386.86680332119363, + "y": -794.1556155836837, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0V", + "roundness": { + "type": 2 + }, + "seed": 1642196405, + "version": 262, + "versionNonce": 418590837, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "7bpvHSILjOEGoxBVuVvmL", + "type": "line", + "x": 387.21934633300566, + "y": -768.6496839272999, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0W", + "roundness": { + "type": 2 + }, + "seed": 992243477, + "version": 368, + "versionNonce": 1820285397, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "hunvhsGsscndVNFWE5PbJ", + "type": "line", + "x": 386.2245142995596, + "y": -740.2688171518405, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0X", + "roundness": { + "type": 2 + }, + "seed": 1062192245, + "version": 266, + "versionNonce": 1132418869, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "T8wwR2IwhMmplgY6InC65", + "type": "line", + "x": 393.3890551237139, + "y": -713.3699432780502, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "baV9NX1y69MAosZs6e-CT" + ], + "frameId": null, + "index": "b0Y", + "roundness": { + "type": 2 + }, + "seed": 1110011349, + "version": 300, + "versionNonce": 676898965, + "isDeleted": false, + "boundElements": [], + "updated": 1764875361089, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "EOtxLYz_c5dBLBZTsf6bP", + "type": "arrow", + "x": 560.3079384765334, + "y": -801.8590832623923, + "width": 311.10872819013355, + "height": 3.3450992498784444, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0Z", + "roundness": { + "type": 2 + }, + "seed": 46590773, + "version": 868, + "versionNonce": 416388706, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "AQOsTPNecUVIP5dcYG-CL" + } + ], + "updated": 1772207740751, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 311.10872819013355, + 3.3450992498784444 + ] + ], + "lastCommittedPoint": null, + "startBinding": { + "elementId": "M3_9cSeevpvgvuGOJmtLu", + "focus": 0.024877658056798795, + "gap": 5.80129262390335 + }, + "endBinding": { + "elementId": "vWBP3oXNVHZGwRqV71dye", + "focus": 0.16647678467610177, + "gap": 26.273809523809405 + }, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "AQOsTPNecUVIP5dcYG-CL", + "type": "text", + "x": 633.3624170125181, + "y": -825.1557337445369, + "width": 164.99977111816406, + "height": 50, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0a", + "roundness": null, + "seed": 1099807893, + "version": 58, + "versionNonce": 587560482, + "isDeleted": false, + "boundElements": [], + "updated": 1772204827339, + "link": null, + "locked": false, + "text": "/misc/document-\nextract", + "fontSize": 20, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "EOtxLYz_c5dBLBZTsf6bP", + "originalText": "/misc/document-extract", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "vWBP3oXNVHZGwRqV71dye", + "type": "text", + "x": 897.6904761904764, + "y": -891.8596681096677, + "width": 536.5656565656566, + "height": 232.7272727272728, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0b", + "roundness": null, + "seed": 372466165, + "version": 440, + "versionNonce": 1496857790, + "isDeleted": false, + "boundElements": [ + { + "id": "EOtxLYz_c5dBLBZTsf6bP", + "type": "arrow" + } + ], + "updated": 1772204827339, + "link": null, + "locked": false, + "text": "{\n \"document\": [\n \"R., MATIAS EZEQUIEL SOBRE\n128 1 párr\",\n ...\n ],\n \"document_id\": \n}", + "fontSize": 23.27272727272728, + "fontFamily": 8, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "{\n \"document\": [\n \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n ...\n ],\n \"document_id\": \n}", + "autoResize": false, + "lineHeight": 1.25 + }, + { + "id": "uIFK9kOYNJE4xD48qvRxR", + "type": "text", + "x": 1973.8949799899103, + "y": -527.8682896843161, + "width": 351.6396893419871, + "height": 74.26086756682336, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0f", + "roundness": null, + "seed": 1570520949, + "version": 508, + "versionNonce": 1517826942, + "isDeleted": false, + "boundElements": [], + "updated": 1772207749195, + "link": null, + "locked": false, + "text": "Per-paragraph prediction\n(DocumentInformation)", + "fontSize": 29.704347026729355, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": null, + "originalText": "Per-paragraph prediction\n(DocumentInformation)", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "cPvNsqjYFBYhf1dvqCfUM", + "type": "text", + "x": 5111.82726940021, + "y": -661.9813153131714, + "width": 335.071044921875, + "height": 80.4726368159204, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0o", + "roundness": null, + "seed": 183537621, + "version": 526, + "versionNonce": 1023679678, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "text": "Anonymized document\n.odt", + "fontSize": 32.189054726368155, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "top", + "containerId": null, + "originalText": "Anonymized document\n.odt", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "H45OT-nnyrYBIdX_fHnB-", + "type": "rectangle", + "x": 5171.529458527813, + "y": -988.7002207858083, + "width": 215.66666666666663, + "height": 280.0447761194029, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0o8", + "roundness": { + "type": 3 + }, + "seed": 1543168597, + "version": 491, + "versionNonce": 1377686782, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false + }, + { + "id": "HkLFBBIeoT2NmdHolQogn", + "type": "line", + "x": 5214.984682408411, + "y": -948.4639023778478, + "width": 94.95771144278605, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0oG", + "roundness": { + "type": 2 + }, + "seed": 997576629, + "version": 455, + "versionNonce": 1138132286, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 94.95771144278605, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "dP23wQQAJGa8EbTko6TLk", + "type": "line", + "x": 5210.604594462189, + "y": -921.31635282217, + "width": 48.28358208955214, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0oV", + "roundness": { + "type": 2 + }, + "seed": 1005326613, + "version": 558, + "versionNonce": 328150398, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 48.28358208955214, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "AzAxanw4nR0bo9R-OtYUW", + "type": "line", + "x": 5211.1511562329015, + "y": -891.5437741284319, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0ol", + "roundness": { + "type": 2 + }, + "seed": 1255351925, + "version": 588, + "versionNonce": 1854459326, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "FZMsE2ftxJlqlXy5y1Kot", + "type": "line", + "x": 5210.156324199455, + "y": -863.1629073529726, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0p", + "roundness": { + "type": 2 + }, + "seed": 710528309, + "version": 485, + "versionNonce": 837051902, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "c5LayQF2_U6-IqmzQigBO", + "type": "line", + "x": 5217.320865023609, + "y": -836.2640334791819, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0pG", + "roundness": { + "type": 2 + }, + "seed": 2020892309, + "version": 520, + "versionNonce": 1856173630, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "CZP0a-w2xzB-aIeBIdTfj", + "type": "line", + "x": 5217.673408035422, + "y": -810.758101822798, + "width": 131.97512437810926, + "height": 0, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0pV", + "roundness": { + "type": 2 + }, + "seed": 1005962229, + "version": 626, + "versionNonce": 1839562366, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 131.97512437810926, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "YGpIXuZRgXAXrbeyTS72v", + "type": "line", + "x": 5216.678576001976, + "y": -782.3772350473388, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0q", + "roundness": { + "type": 2 + }, + "seed": 1222868309, + "version": 524, + "versionNonce": 866975422, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "ABZSKgAIt_rm_gemO06m9", + "type": "line", + "x": 5223.8431168261295, + "y": -755.4783611735489, + "width": 128.75621890547262, + "height": 1.6094527363184077, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [ + "mnNZnb2eX5SBS_s6ArNSy" + ], + "frameId": null, + "index": "b0r", + "roundness": { + "type": 2 + }, + "seed": 1452477109, + "version": 558, + "versionNonce": 89814782, + "isDeleted": false, + "boundElements": [], + "updated": 1772207001336, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 128.75621890547262, + 1.6094527363184077 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": null + }, + { + "id": "hotXOq7-8juh39kLJem4p", + "type": "arrow", + "x": 2454.591377430666, + "y": -806.9942535766841, + "width": 374.23286489749944, + "height": 2.3331459911660204, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0u", + "roundness": { + "type": 2 + }, + "seed": 755633851, + "version": 550, + "versionNonce": 1019750946, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "XSjKuWf82l8iev5nfszlU" + } + ], + "updated": 1772206699138, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 374.23286489749944, + 2.3331459911660204 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "XSjKuWf82l8iev5nfszlU", + "type": "text", + "x": 2517.6379398842982, + "y": -818.327680581101, + "width": 248.13973999023438, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0uV", + "roundness": null, + "seed": 193864190, + "version": 43, + "versionNonce": 360400482, + "isDeleted": false, + "boundElements": null, + "updated": 1772206699138, + "link": null, + "locked": false, + "text": "/anonymizer/disambiguate", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "hotXOq7-8juh39kLJem4p", + "originalText": "/anonymizer/disambiguate", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "gXsFYxTEKv14jMJGLJI8O", + "type": "arrow", + "x": 1452.931012958739, + "y": -798.134476023053, + "width": 403.8000183105464, + "height": 5.908527289127619, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0v", + "roundness": { + "type": 2 + }, + "seed": 1974610101, + "version": 1591, + "versionNonce": 620553314, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "Q4IQFcmT8i1SnTx5DuzTS" + } + ], + "updated": 1772205508184, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 195.91698365823413, + -2.048276293639333 + ], + [ + 403.8000183105464, + -5.908527289127619 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "Q4IQFcmT8i1SnTx5DuzTS", + "type": "text", + "x": 1547.6477860456841, + "y": -810.1827523166924, + "width": 202.40042114257812, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0w", + "roundness": null, + "seed": 2134198805, + "version": 73, + "versionNonce": 1627097790, + "isDeleted": false, + "boundElements": [], + "updated": 1772205508184, + "link": null, + "locked": false, + "text": "N x /anonymizer/predict", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "gXsFYxTEKv14jMJGLJI8O", + "originalText": "N x /anonymizer/predict", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "jFnC8PtgWHvjc9weWuFWX", + "type": "text", + "x": 326.69940776522253, + "y": -1119.4404761904757, + "width": 558.84033203125, + "height": 76.99999999999986, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b0z", + "roundness": null, + "seed": 29900859, + "version": 88, + "versionNonce": 181080958, + "isDeleted": false, + "boundElements": [], + "updated": 1772204432143, + "link": null, + "locked": false, + "text": "Anonymizer pipeline", + "fontSize": 61.59999999999989, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Anonymizer pipeline", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "LUVMyylE6hgpMsgfw7aao", + "type": "rectangle", + "x": 1888.8814913275708, + "y": -991.508812100596, + "width": 521.6666666666664, + "height": 428.88888888888886, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b13", + "roundness": { + "type": 3 + }, + "seed": 1127296034, + "version": 420, + "versionNonce": 1975633314, + "isDeleted": false, + "boundElements": [], + "updated": 1772204924667, + "link": null, + "locked": false + }, + { + "id": "1ulzr8Q7P6FFgdWlFr0cp", + "type": "text", + "x": 1911.6383476101225, + "y": -918.7310343228181, + "width": 476.1529541015625, + "height": 283.3333333333333, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b14", + "roundness": null, + "seed": 238770146, + "version": 239, + "versionNonce": 7850686, + "isDeleted": false, + "boundElements": [], + "updated": 1772206121905, + "link": null, + "locked": false, + "text": "{\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n ...\n }\n }\n ]\n}", + "fontSize": 16.19047619047619, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "{\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n ...\n }\n }\n ]\n}", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "vrSceZivuOFwwm43eU0mr", + "type": "text", + "x": 924.6722658756239, + "y": -606.9260633331838, + "width": 482.6020771953618, + "height": 43.38079023612419, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b15", + "roundness": null, + "seed": 1891961378, + "version": 472, + "versionNonce": 550795810, + "isDeleted": false, + "boundElements": [], + "updated": 1772207740751, + "link": null, + "locked": false, + "text": "Document extraction output", + "fontSize": 34.70463218889935, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "Document extraction output", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "GNTtv7Qdsx0aEF6kxRZ5a", + "type": "text", + "x": 2736.8880249454437, + "y": -1160.814903248222, + "width": 1100.7685546875, + "height": 832.0238095238095, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b17", + "roundness": null, + "seed": 882291582, + "version": 555, + "versionNonce": 362426494, + "isDeleted": false, + "boundElements": [], + "updated": 1772207723129, + "link": null, + "locked": false, + "text": "{\n \"data\": [\n {\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n \"aymurai_label_instance\": 1,\n 'aymurai_disambiguation': 'fuzzy',\n 'aymurai_anonymize': True,\n 'canonical_entity_id': \n }\n }\n ]\n },\n ...\n ],\n \"label_policies\": {\n \"PER\": {\"anonymize\": True, \"disambiguation\": \"fuzzy\", \"use_subclass_when_available\": True},\n \"FECHA\": {\"anonymize\": False, \"disambiguation\": \"none\", \"use_subclass_when_available\": False}\n },\n \"render_policy\": {\n \"suffix_mode\": \"auto\",\n \"suffix_threshold\": 1\n }", + "fontSize": 22.952380952380953, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "{\n \"data\": [\n {\n \"document\": \"R., MATIAS EZEQUIEL SOBRE 128 1 párr\",\n \"labels\": [\n {\n \"text\": \"R., MATIAS EZEQUIEL\",\n \"start_char\": 0,\n \"end_char\": 23,\n \"attrs\": {\n \"aymurai_label\": \"PER\",\n \"aymurai_label_instance\": 1,\n 'aymurai_disambiguation': 'fuzzy',\n 'aymurai_anonymize': True,\n 'canonical_entity_id': \n }\n }\n ]\n },\n ...\n ],\n \"label_policies\": {\n \"PER\": {\"anonymize\": True, \"disambiguation\": \"fuzzy\", \"use_subclass_when_available\": True},\n \"FECHA\": {\"anonymize\": False, \"disambiguation\": \"none\", \"use_subclass_when_available\": False}\n },\n \"render_policy\": {\n \"suffix_mode\": \"auto\",\n \"suffix_threshold\": 1\n }", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "GpgRoWvkFU8pY8qyanTEz", + "type": "text", + "x": 2971.7865914541294, + "y": -294.843926983973, + "width": 630.971421670128, + "height": 41.08319145660856, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b18", + "roundness": null, + "seed": 440634338, + "version": 526, + "versionNonce": 60141218, + "isDeleted": false, + "boundElements": [], + "updated": 1772207760618, + "link": null, + "locked": false, + "text": "Review payload (DocumentAnnotations)", + "fontSize": 32.86655316528685, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "Review payload (DocumentAnnotations)", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "t1CVOK0LIbIN3hNMusjFo", + "type": "arrow", + "x": 3486.838089935834, + "y": -810.7442535766841, + "width": 374.23286489749944, + "height": 2.3331459911660204, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b19", + "roundness": { + "type": 2 + }, + "seed": 1603482402, + "version": 639, + "versionNonce": 2029670818, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "9SlkoqV3LCMNC6VOzAR4J" + } + ], + "updated": 1772206766396, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 374.23286489749944, + 2.3331459911660204 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "9SlkoqV3LCMNC6VOzAR4J", + "type": "text", + "x": 3609.451244288067, + "y": -828.7443472477678, + "width": 122.33988952636719, + "height": 25, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1A", + "roundness": null, + "seed": 2126806754, + "version": 83, + "versionNonce": 1522294242, + "isDeleted": false, + "boundElements": [], + "updated": 1772206766396, + "link": null, + "locked": false, + "text": "Review in UI", + "fontSize": 20, + "fontFamily": 5, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "t1CVOK0LIbIN3hNMusjFo", + "originalText": "Review in UI", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "1g5mwsMmOsivD02csjkTB", + "type": "text", + "x": 3879.9078976523183, + "y": -604.1107637238993, + "width": 809.6706988450118, + "height": 36.97264967907313, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dotted", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1C", + "roundness": null, + "seed": 306784958, + "version": 693, + "versionNonce": 1588957730, + "isDeleted": false, + "boundElements": [], + "updated": 1772207711810, + "link": null, + "locked": false, + "text": "Manual review: edit labels, label policies and render policy", + "fontSize": 29.5781197432585, + "fontFamily": 5, + "textAlign": "left", + "verticalAlign": "middle", + "containerId": null, + "originalText": "Manual review: edit labels, label policies and render policy", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "lhZO6MPRRTWy3V55I0vZM", + "type": "arrow", + "x": 4705.8560612283145, + "y": -807.5294042874617, + "width": 403.8000183105464, + "height": 5.908527289127619, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "#b2f2bb", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1G", + "roundness": { + "type": 2 + }, + "seed": 280036245, + "version": 1662, + "versionNonce": 1583584226, + "isDeleted": false, + "boundElements": [ + { + "type": "text", + "id": "GHolMdYEXJBOSjiLEJF7i" + } + ], + "updated": 1772207526341, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 195.91698365823413, + -2.048276293639333 + ], + [ + 403.8000183105464, + -5.908527289127619 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow", + "elbowed": false + }, + { + "id": "GHolMdYEXJBOSjiLEJF7i", + "type": "text", + "x": 4769.7727702283455, + "y": -819.577680581101, + "width": 264.00054931640625, + "height": 20, + "angle": 0, + "strokeColor": "#1e1e1e", + "backgroundColor": "transparent", + "fillStyle": "hachure", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1H", + "roundness": null, + "seed": 1331022069, + "version": 58, + "versionNonce": 451123582, + "isDeleted": false, + "boundElements": [], + "updated": 1772206985239, + "link": null, + "locked": false, + "text": "/anonymizer/anonymize-document", + "fontSize": 16, + "fontFamily": 8, + "textAlign": "center", + "verticalAlign": "middle", + "containerId": "lhZO6MPRRTWy3V55I0vZM", + "originalText": "/anonymizer/anonymize-document", + "autoResize": true, + "lineHeight": 1.25 + }, + { + "id": "oRmHjBYwEzoCu3wVivfxA", + "type": "image", + "x": 3870.418043822792, + "y": -974.1722733335696, + "width": 828.6504065040658, + "height": 351.8703703703709, + "angle": 0, + "strokeColor": "transparent", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "index": "b1M", + "roundness": null, + "seed": 22438654, + "version": 258, + "versionNonce": 1815649534, + "isDeleted": false, + "boundElements": [], + "updated": 1772207295559, + "link": null, + "locked": false, + "status": "pending", + "fileId": "ac6c81549182e851ebe5aa58dd0fba44c4ab568b", + "scale": [ + 1, + 1 + ], + "crop": { + "x": 0, + "y": 0, + "width": 1440, + "height": 611.4681527412586, + "naturalWidth": 1440, + "naturalHeight": 820 + } + } + ], + "appState": { + "gridSize": 20, + "gridStep": 5, + "gridModeEnabled": false, + "viewBackgroundColor": "#ffffff" + }, + "files": { + "ac6c81549182e851ebe5aa58dd0fba44c4ab568b": { + "mimeType": "image/png", + "id": "ac6c81549182e851ebe5aa58dd0fba44c4ab568b", + "dataURL": "data:image/png;base64,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", + "created": 1772207236966, + "lastRetrieved": 1772207236966 + } + } +} \ No newline at end of file diff --git a/docs/pipelines/anonymizer/pipeline.png b/docs/pipelines/anonymizer/pipeline.png new file mode 100644 index 0000000000000000000000000000000000000000..61ce789ec4b08fa347044d3a3d4f2d9866d90a14 GIT binary patch literal 601943 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

1o*FsLL`6+q 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

dw+jI80 z(K2!)E$3Z!%V}>U0ZuFSTBIj%l5Ks;_V2V*R2*$TP1hz2146BTnN|wu;+;^G-n!z8 zJ_2&b8DZ@BM(2nGws0=63;$KNT~)2PKj~O4VSId1-pPMSKDj9}eM4>N>|9+)VHSDU zz1ahKyHavfRj?V@3K(fVZnNH&*899VvAM~xMRLHill-{}gveb!IhdDrE(T8ycig6S zoLvP1h^#I>Ep4B;!%~;(_4ig|PBDR*-UULab0gh z4H9}H8*;{0$B%76&jJH}o*AHv1snG$`Hl)#DNtzI^e!MSQuJXR`<|Wn#zdI?@xhbn zQAnG3gR(Td8ztGUB~p%*{Ll+pUcCP`d!HD)*AHE{1BiWZ1X65e8f>mf z2cT`yphGB2mzMQqtWhKG8~;At&30TR7`SWkk`I`O1U3bs+3tTKs;YF}k~MIf(GX{g z_oQRFxaZ&@k3C5kfE{-Hz3(UyY|WZO=?!jw^Lh{G-Mc?fnD=mC7#IU{1*5Y&9K~bV zElK$g42*_D7)8kD1w^4&&k5f@{Q7Ec?xoq`uTyXaph4u7=S=d&(GLNTQmv|*n$!va z;y)+)M>#&X@z_kcM3R4B3ar7MNSvr{uw}K(^6_f>_FIdtrQW5GPp^#aIV^qictPp;eeB;qmPGe!?c4p8L3Otbd2Qnu3u=Ba;LCuXYzkSK54her$;H=nFmT-zkHm~!qPVkHS zP~VrE`rr5ZX_c0chWDcQ|N2H!93fxRW%P|SMYDhYJ2`uEi$sntK}RNa{e7j{ivxy1mc5)l!A?gN@- zgLeUO0tWYG<6{)?Ejkb^J19#>LY4ik%yzH?BTEzh@%SPOe^g}2Cj)4=6CLcguMTrw zCFizDpoPNHVJUA()kGOOg$XZ!e=dB4Yj8(SO4*B=fp!zx(zDvc_>HxD`k*Rq;5}ZVI7P zZi`!P*#9Q_-JukRYVOqvs+Ptk;&@)sfduznF~DchZ)A;XA#)%+WCpx)cw1sQ>&x%f ztww`Hj)EmyB~)j_acDPiuT73mTf?Rd$1d3X=kC3}g)8)VEfnbV++h=Q{k|W^L&P9N z6UaW;hsZ!q`dWFy`KV=kJHILP$s~u`+gqC z@_C)D#0EKA(Mm~41sS3+W30RHLeXz1tQ7t9%WOe*8X!T&R_?O&Qwf(tVXli5~$8moV|2@uC|Te{6A z4Kz`trQ3HFQf2F6f2&sp8A*ymTxc0Zh%5Y?*Jazz9(-)vs_!EcXD4mlY#W>xrzgl& zY7!$kvim~4$0~}7G>+_!H1k7b06Y0)e*G1XO9NnamO?1l$wp7xAbttMx22Efn^iFf z_=%SU6-LU)BI>z|si`IQMq1QYfpV|}Qgdx^8634FaJ^E;sc28Out?o*nT4K8?rd

LbU(3!01B+0d^BmwBv=c8eHx3sd%< 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 hZf*Eu4&pz|LiN1d Date: Mon, 2 Mar 2026 18:30:18 +0000 Subject: [PATCH 090/104] =?UTF-8?q?=F0=9F=9A=9A=20Rename=20full-paragraph?= =?UTF-8?q?=20pipeline=20to=20datapublic=20across=20code=20and=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.es.md | 2 +- README.md | 2 +- aymurai/api/endpoints/routers/datapublic/datapublic.py | 2 +- aymurai/api/main.py | 2 +- docs/entities/README.md | 2 +- docs/entities/datapublic/README.md | 2 +- docs/es/entities/README.md | 2 +- docs/es/entities/datapublic/README.md | 2 +- docs/es/models/README.md | 2 +- docs/es/models/decision-model-card.md | 6 +++--- docs/es/models/flair-model-card.md | 4 ++-- docs/es/pipelines/README.md | 4 ++-- docs/es/pipelines/datapublic/README.md | 4 ++-- docs/models/README.md | 2 +- docs/models/decision-model-card.md | 6 +++--- docs/models/flair-model-card.md | 4 ++-- docs/pipelines/README.md | 4 ++-- docs/pipelines/datapublic/README.md | 4 ++-- .../production/{full-paragraph => datapublic}/pipeline.json | 0 19 files changed, 28 insertions(+), 28 deletions(-) rename resources/pipelines/production/{full-paragraph => datapublic}/pipeline.json (100%) diff --git a/README.es.md b/README.es.md index eb8acd07..90e939c0 100644 --- a/README.es.md +++ b/README.es.md @@ -84,7 +84,7 @@ make api-logs - URI de DB por defecto: `sqlite:////resources/cache/sqlite/database.db` - Configs de pipeline de producción: - `resources/pipelines/production/flair-anonymizer/pipeline.json` - - `resources/pipelines/production/full-paragraph/pipeline.json` + - `resources/pipelines/production/datapublic/pipeline.json` ## Endpoints públicos principales - `GET /server/healthcheck` diff --git a/README.md b/README.md index a19c2224..fae091de 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ make api-logs - Default DB URI: `sqlite:////resources/cache/sqlite/database.db` - Production pipeline configs: - `resources/pipelines/production/flair-anonymizer/pipeline.json` - - `resources/pipelines/production/full-paragraph/pipeline.json` + - `resources/pipelines/production/datapublic/pipeline.json` ## Main Public Endpoints - `GET /server/healthcheck` diff --git a/aymurai/api/endpoints/routers/datapublic/datapublic.py b/aymurai/api/endpoints/routers/datapublic/datapublic.py index 62af6761..91e1f0d5 100644 --- a/aymurai/api/endpoints/routers/datapublic/datapublic.py +++ b/aymurai/api/endpoints/routers/datapublic/datapublic.py @@ -62,7 +62,7 @@ async def predict_over_text( logger.info("Running prediction") item = [{"path": "empty", "data": {"doc.text": text_request.text}}] pipeline = load_pipeline( - os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "full-paragraph") + os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "datapublic") ) with pipeline_lock: diff --git a/aymurai/api/main.py b/aymurai/api/main.py index d814a3f6..b4ef93d6 100644 --- a/aymurai/api/main.py +++ b/aymurai/api/main.py @@ -109,5 +109,5 @@ def healthcheck(): os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "flair-anonymizer") ) AymurAIPipeline.load( - os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "full-paragraph") + os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "datapublic") ) diff --git a/docs/entities/README.md b/docs/entities/README.md index 5f516a31..e12055f7 100644 --- a/docs/entities/README.md +++ b/docs/entities/README.md @@ -8,7 +8,7 @@ This section documents the entity catalogs used by AymurAI workflows. - Anonymizer: [anonymizer/README.md](anonymizer/README.md) ## Notes -- `datapublic` entities describe the public-data extraction taxonomy used by the production `full-paragraph` pipeline. +- `datapublic` entities describe the public-data extraction taxonomy used by the production `datapublic` pipeline. - `anonymizer` entities describe the labels currently used by the anonymization flow for disambiguation and replacement. ## Related docs diff --git a/docs/entities/datapublic/README.md b/docs/entities/datapublic/README.md index 99079a7e..578e1c30 100644 --- a/docs/entities/datapublic/README.md +++ b/docs/entities/datapublic/README.md @@ -4,7 +4,7 @@ Language: **English** | [Español](../../es/entities/datapublic/README.md) Catalog of entities used by the datapublic extraction flow. ## Scope -These entities correspond to the taxonomy extracted from judicial rulings by the production `full-paragraph` pipeline. They are used across the Flair NER model, decision post-processing, validation UI, and related dataset tooling. +These entities correspond to the taxonomy extracted from judicial rulings by the production `datapublic` pipeline. They are used across the Flair NER model, decision post-processing, validation UI, and related dataset tooling. ## Entities | Entity | Description | diff --git a/docs/es/entities/README.md b/docs/es/entities/README.md index 5152c66a..59fb1247 100644 --- a/docs/es/entities/README.md +++ b/docs/es/entities/README.md @@ -8,7 +8,7 @@ Esta sección documenta los catálogos de entidades utilizados por los distintos - Anonymizer: [anonymizer/README.md](anonymizer/README.md) ## Notas -- Las entidades de `datapublic` describen la taxonomía de extracción de datos públicos usada por el pipeline de producción `full-paragraph`. +- Las entidades de `datapublic` describen la taxonomía de extracción de datos públicos usada por el pipeline de producción `datapublic`. - Las entidades de `anonymizer` describen las labels usadas actualmente por el flujo de anonimización para desambiguación y reemplazo. ## Documentación relacionada diff --git a/docs/es/entities/datapublic/README.md b/docs/es/entities/datapublic/README.md index 9b9c1c91..e645344f 100644 --- a/docs/es/entities/datapublic/README.md +++ b/docs/es/entities/datapublic/README.md @@ -4,7 +4,7 @@ Idioma: [English](../../../entities/datapublic/README.md) | **Español** Catálogo de entidades utilizadas por el flujo de extracción de datapublic. ## Alcance -Estas entidades corresponden a la taxonomía extraída de resoluciones judiciales por el pipeline de producción `full-paragraph`. Se usan a lo largo del modelo Flair NER, el postprocesamiento de decisiones, la UI de validación y el tooling relacionado con el dataset. +Estas entidades corresponden a la taxonomía extraída de resoluciones judiciales por el pipeline de producción `datapublic`. Se usan a lo largo del modelo Flair NER, el postprocesamiento de decisiones, la UI de validación y el tooling relacionado con el dataset. ## Entidades | Entidad | Descripción | diff --git a/docs/es/models/README.md b/docs/es/models/README.md index 3067c6a6..a843aee4 100644 --- a/docs/es/models/README.md +++ b/docs/es/models/README.md @@ -10,7 +10,7 @@ Esta sección documenta los modelos individuales utilizados por el backend. ## Uso actual en producción - `flair-anonymizer` usa la model card del NER de anonymizer documentada aquí. -- `full-paragraph` usa el modelo Flair NER y el clasificador de decisiones. +- `datapublic` usa el modelo Flair NER y el clasificador de decisiones. ## Documentación relacionada - Índice de documentación: [../README.md](../README.md) diff --git a/docs/es/models/decision-model-card.md b/docs/es/models/decision-model-card.md index 22350451..0735c450 100644 --- a/docs/es/models/decision-model-card.md +++ b/docs/es/models/decision-model-card.md @@ -21,7 +21,7 @@ Idioma: [English](../../models/decision-model-card.md) | **Español** # Descripción del modelo -Este modelo es el clasificador actual de decisiones a nivel párrafo utilizado en el pipeline de producción `full-paragraph`. +Este modelo es el clasificador actual de decisiones a nivel párrafo utilizado en el pipeline de producción `datapublic`. Estima si un párrafo contiene una decisión judicial y, cuando se usa dentro del pipeline de AymurAI, emite una entidad sintética `DECISION` con una subcategoría basada en reglas. Este modelo fue desarrollado por [{ collective.ai }](https://collectiveai.io) como parte del proyecto [AymurAI](https://aymurai.info) de [DataGenero](https://datagenero.org). @@ -114,12 +114,12 @@ La primera columna es la probabilidad de que el texto no sea una decisión, y la ## Uso del modelo en un pipeline de AymurAI -El pipeline actual de producción `full-paragraph` incluye este clasificador después de la etapa NER con Flair. +El pipeline actual de producción `datapublic` incluye este clasificador después de la etapa NER con Flair. ```python from aymurai.pipeline import AymurAIPipeline -pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") +pipeline = AymurAIPipeline.load("/resources/pipelines/production/datapublic") item = { "path": "dummy", diff --git a/docs/es/models/flair-model-card.md b/docs/es/models/flair-model-card.md index 68e2763f..5efa7a81 100644 --- a/docs/es/models/flair-model-card.md +++ b/docs/es/models/flair-model-card.md @@ -26,7 +26,7 @@ Idioma: [English](../../models/flair-model-card.md) | **Español** Siguiendo las guías de Flair para entrenar un modelo de NER, este modelo se entrenó sobre [embeddings BETO](https://huggingface.co/dccuchile/bert-base-spanish-wwm-uncased), una versión en español de BERT entrenada sobre un corpus en español, con una arquitectura BiLSTM-CRF. Este modelo fue desarrollado por [{ collective.ai }](https://collectiveai.io) como parte del proyecto [AymurAI](https://aymurai.info) de [DataGenero](https://datagenero.org). -Actualmente se usa como componente NER del pipeline de producción `full-paragraph`. +Actualmente se usa como componente NER del pipeline de producción `datapublic`. # Usos previstos y limitaciones AymurAI está pensado como una herramienta para abordar la falta de transparencia en el sistema judicial en relación con casos de violencia de género (VG) en América Latina. El objetivo es aumentar los niveles de reporte, construir confianza en el sistema de justicia y mejorar el acceso a la justicia para mujeres y personas LGBTIQ+. AymurAI genera y mantiene datasets anonimizados a partir de sentencias judiciales para comprender la violencia de género y apoyar el diseño de políticas públicas, además de contribuir a campañas de colectivos feministas. @@ -83,7 +83,7 @@ También podés ejecutar el modelo a través de un pipeline de AymurAI. ```python from aymurai.pipeline import AymurAIPipeline -pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") +pipeline = AymurAIPipeline.load("/resources/pipelines/production/datapublic") item = { 'path': 'dummy', diff --git a/docs/es/pipelines/README.md b/docs/es/pipelines/README.md index f94559f8..c6ff29fa 100644 --- a/docs/es/pipelines/README.md +++ b/docs/es/pipelines/README.md @@ -14,11 +14,11 @@ Esta sección documenta los pipelines de producción del backend por flujo. ## Fuentes de configuración en producción - Config anonymizer: `resources/pipelines/production/flair-anonymizer/pipeline.json` -- Config datapublic: `resources/pipelines/production/full-paragraph/pipeline.json` +- Config datapublic: `resources/pipelines/production/datapublic/pipeline.json` ## Mapeo con API - `POST /anonymizer/predict` -> `flair-anonymizer` -- `POST /datapublic/predict/{document_id}` -> `full-paragraph` +- `POST /datapublic/predict/{document_id}` -> `datapublic` ## Documentación relacionada - Referencia API: [../api/README.md](../api/README.md) diff --git a/docs/es/pipelines/datapublic/README.md b/docs/es/pipelines/datapublic/README.md index 70bc7b36..aec3291c 100644 --- a/docs/es/pipelines/datapublic/README.md +++ b/docs/es/pipelines/datapublic/README.md @@ -24,7 +24,7 @@ Este flujo extrae información estructurada a partir de párrafos y soporta pers ## Componentes técnicos ### Configuración del pipeline -- Fuente: `resources/pipelines/production/full-paragraph/pipeline.json` +- Fuente: `resources/pipelines/production/datapublic/pipeline.json` - Preprocesamiento: - `aymurai.models.flair.utils.FlairTextNormalize` - Modelos: @@ -58,7 +58,7 @@ Tablas usadas por este flujo: - `datapublic_document_paragraph` ## Notas -- El directorio de pipeline en producción sigue llamándose `full-paragraph`. +- El directorio de pipeline en producción sigue llamándose `datapublic`. - `document_id` es la clave de agrupamiento a nivel documento para asociar predicciones por párrafo y el payload de validación. - La persistencia de validación es a nivel documento y acepta intencionalmente un objeto JSON libre. - `GET /datapublic/validation/document/{document_id}` devuelve `404` cuando el documento no existe; `POST` crea o actualiza el payload de validación. diff --git a/docs/models/README.md b/docs/models/README.md index 7f2aeafb..8893a1e4 100644 --- a/docs/models/README.md +++ b/docs/models/README.md @@ -10,7 +10,7 @@ This section documents the individual models used by the backend. ## Current production usage - `flair-anonymizer` uses the anonymizer NER model card documented here. -- `full-paragraph` uses the Flair NER model and the decision classifier. +- `datapublic` uses the Flair NER model and the decision classifier. ## Related docs - Documentation index: [../README.md](../README.md) diff --git a/docs/models/decision-model-card.md b/docs/models/decision-model-card.md index 066c2395..715f4354 100644 --- a/docs/models/decision-model-card.md +++ b/docs/models/decision-model-card.md @@ -21,7 +21,7 @@ Language: **English** | [Español](../es/models/decision-model-card.md) # Model Description -This model is the current paragraph-level decision classifier used in the production `full-paragraph` pipeline. +This model is the current paragraph-level decision classifier used in the production `datapublic` pipeline. It estimates whether a paragraph contains a judicial decision and, when used inside the AymurAI pipeline, emits a synthetic `DECISION` entity with a rule-based subclass. This model was developed by [{ collective.ai }](https://collectiveai.io) as part of the [AymurAI](https://aymurai.info) project by [DataGenero](https://datagenero.org). @@ -114,12 +114,12 @@ The first column is the probability of the text not being a decision, and the se ## Using the model in an AymurAI pipeline -The current production `full-paragraph` pipeline includes this classifier after the Flair NER stage. +The current production `datapublic` pipeline includes this classifier after the Flair NER stage. ```python from aymurai.pipeline import AymurAIPipeline -pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") +pipeline = AymurAIPipeline.load("/resources/pipelines/production/datapublic") item = { "path": "dummy", diff --git a/docs/models/flair-model-card.md b/docs/models/flair-model-card.md index 8b9ceddc..54143211 100644 --- a/docs/models/flair-model-card.md +++ b/docs/models/flair-model-card.md @@ -26,7 +26,7 @@ Language: **English** | [Español](../es/models/flair-model-card.md) Following the Flair guidelines for training a NER model, we trained this model on top of [BETO embeddings](https://huggingface.co/dccuchile/bert-base-spanish-wwm-uncased), a Spanish version of BERT trained on a Spanish corpus, with a BiLSTM-CRF architecture. This model was developed by [{ collective.ai }](https://collectiveai.io) as part of the [AymurAI](https://aymurai.info) project by [DataGenero](https://datagenero.org). -It is currently used as the NER component of the production `full-paragraph` pipeline. +It is currently used as the NER component of the production `datapublic` pipeline. # Intended uses & limitations AymurAI is intended to be used as a tool to address the lack of transparency in the judicial system regarding gender-based violence (GBV) cases in Latin America. The goal is to increase report levels, build trust in the justice system, and improve access to justice for women and LGBTIQ+ people. AymurAI will generate and maintain anonymized datasets from legal rulings to understand GBV and support policy making, and also contribute to feminist collectives' campaigns. @@ -83,7 +83,7 @@ You can also run the model through an AymurAI pipeline. ```python from aymurai.pipeline import AymurAIPipeline -pipeline = AymurAIPipeline.load("/resources/pipelines/production/full-paragraph") +pipeline = AymurAIPipeline.load("/resources/pipelines/production/datapublic") item = { 'path': 'dummy', diff --git a/docs/pipelines/README.md b/docs/pipelines/README.md index b09731d6..e62edfe0 100644 --- a/docs/pipelines/README.md +++ b/docs/pipelines/README.md @@ -14,11 +14,11 @@ This section documents AymurAI backend production pipelines by workflow. ## Production pipeline sources - Anonymizer config: `resources/pipelines/production/flair-anonymizer/pipeline.json` -- Datapublic config: `resources/pipelines/production/full-paragraph/pipeline.json` +- Datapublic config: `resources/pipelines/production/datapublic/pipeline.json` ## API mapping - `POST /anonymizer/predict` -> `flair-anonymizer` -- `POST /datapublic/predict/{document_id}` -> `full-paragraph` +- `POST /datapublic/predict/{document_id}` -> `datapublic` ## Related docs - API reference: [../api/README.md](../api/README.md) diff --git a/docs/pipelines/datapublic/README.md b/docs/pipelines/datapublic/README.md index 1d039516..53b4199c 100644 --- a/docs/pipelines/datapublic/README.md +++ b/docs/pipelines/datapublic/README.md @@ -24,7 +24,7 @@ This flow extracts structured information from paragraphs and supports document- ## Technical components ### Pipeline configuration -- Source: `resources/pipelines/production/full-paragraph/pipeline.json` +- Source: `resources/pipelines/production/datapublic/pipeline.json` - Preprocess: - `aymurai.models.flair.utils.FlairTextNormalize` - Models: @@ -58,7 +58,7 @@ Tables touched by this flow: - `datapublic_document_paragraph` ## Notes -- Current production pipeline directory name is `full-paragraph`. +- Current production pipeline directory name is `datapublic`. - `document_id` is the document-level grouping key used to associate paragraph predictions and validation payloads. - Validation persistence is document-level and intentionally accepts a free-form JSON object. - `GET /datapublic/validation/document/{document_id}` returns `404` when the document does not exist; `POST` upserts the validation payload. diff --git a/resources/pipelines/production/full-paragraph/pipeline.json b/resources/pipelines/production/datapublic/pipeline.json similarity index 100% rename from resources/pipelines/production/full-paragraph/pipeline.json rename to resources/pipelines/production/datapublic/pipeline.json From c979d2dd1bf819c3a9552d286ca9402d9b5b8e0e Mon Sep 17 00:00:00 2001 From: jed Date: Fri, 13 Mar 2026 12:37:19 -0300 Subject: [PATCH 091/104] ci(tests): add API + pipeline integration tests on linux and windows (#74) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Merge dev into main for v1.1.12 (#57) * Update README.md * 🐛 bugfix: Fix XML special character escaping in DocAnonymizer * ➕ build(deps): Add python-docx package * ✨ feat: Add watermark and hyperlink functionality to document anonymization * ✨ feat: Install Archivo font in Dockerfile * 🎨 refactor: Improve Dockerfile structure and comments for clarity * ⏪ revert: Remove Archivo font installation from Dockerfile * 🔖 feat: Update aymurai package version to 1.1.11 in uv.lock * 🐛 Improve get_extension logic to fix document extraction issues on Windows and remove python-magic dependency * 🔧 Update Dockerfile to use 'bullseye' variant for Python images for improved compatibility * 🔧 Update Makefile targets for improved Docker workflow * 🔖 feat: Bump aymurai package version to 1.1.12 * ♻️ Harden get_extension with header scans and zip safeguards * 🔧 Extend document extraction timeout to 30s * 🔧 Refactor Docker workflow to build and push images using docker/build-push-action * 🔧 Fix workflow step order to correctly extract tag name before building Docker images * 🔧 Remove tag extraction step and use github.ref_name directly for Docker image builds * ⏪ Revert Docker workflow to extract tag name and use it for image versioning * Update .github/workflows/build-docker-image.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * ✏️ Remove incomplete comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: jed Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * WIP: feat(decision): ✨ integrate TinyEmbeddingBagClassifier for decision detection (#67) * feat(decision): ✨ integrate TinyEmbeddingBagClassifier for decision detection - Introduced a new model class `DecisionEmbeddingBagBinRegex` using `TinyEmbeddingBagClassifier`. - Updated model loading and saving mechanisms to support safetensors format. - Added a new training notebook for the embedding bag classifier. - Modified the pipeline configuration to include the new model. * ⚡️ Remove unidecode usage to avoid double normalization in model_input_from_text * 📝 Add type hints and docstrings for clarity in DecisionEmbeddingBagBinRegex and TinyEmbeddingBagClassifier * 🔧 Refactor import statements for safetensors to remove try-except block * 🔥 Remove Conv1dTextClassifier, Tokenizer and SpanishTokenizer implementations * 🐛 Fix gen_aymurai_entity call by removing unused category parameter * 🔖 Update aymurai package version to 2.0.0a4.dev1 * 🔀 cherry-pick(decision): modernize decision model and upgrade ML dependencies Cherry-pick TinyEmbeddingBagClassifier (safetensors) replacing Conv1d model. Remove dead deps (torchtext, pytorch-lightning), upgrade torch to 2.x and flair to 0.15.1. * 🐛 cherry-pick(fix): datapublic and anonymizer crash when use_cache is disabled * test(infra): rewrite test infrastructure with architecture guide standards - Delete old test files (test_document_extract.py, test_anonymizer_predict.py, test_datapublic_predict.py) - Create new directory structure: tests/integration/pipelines/, tests/api/routers/{anonymizer,datapublic,misc}/ - Rewrite tests/conftest.py: - Set env vars at module level (RESOURCES_BASEPATH=resources, SQLALCHEMY_DATABASE_URI=sqlite:///:memory:) - Remove torch mock and lazy loader - Direct imports from production code - Clean fixtures: db_engine (session-scoped), db_session (function-scoped), client (with dependency override) - Test data builders: build_data_item(), build_label(), build_anonymization_paragraph(), build_datapublic_paragraph() - Update pyproject.toml with [tool.pytest.ini_options]: strict-markers, integration/slow markers Verification: uv run python -c 'import tests.conftest' succeeds, pytest collection clean * test(conftest): add pipeline loading helpers and mock factories for API tests Wave 2 complete: integration pipeline conftest + API router conftest Integration pipeline conftest: - PIPELINE_CONFIGS dict for flair-anonymizer and full-paragraph - load_test_pipeline() helper with print_config=False - Session-scoped fixtures for both pipelines (expensive model loading) - build_pipeline_input() test data builder - sample_text fixture with Spanish legal text API router conftest: - build_mock_pipeline() factory with MagicMock - Mock preprocess/predict_single/postprocess methods - build_processed_data_item() test data builder - Re-exports builders from root conftest * test(api): add document extract endpoint tests with mocked extraction * test(api): add anonymizer and datapublic endpoint tests with mocked pipelines * test(integration): add pipeline integration tests for flair-anonymizer and full-paragraph * ✅ test: refactor test infrastructure and add integration tests - Reorganize test conftest files to proper hierarchy (tests/api/conftest.py) - Add pytest to dependency groups in pyproject.toml - Refactor API router tests to use centralized fixtures and builders - Add real document extraction tests with DOCX/PDF generators - Improve pipeline integration tests with fixture-based stages - Fix label serialization to use model_dump(mode="json") - Update UUID generation for datapublic tests to use uuid.uuid5 - Add cache path environment setup for integration tests - Clean up imports and remove unused dependencies - Remove empty test file (document_extract.py) This refactoring improves test maintainability, adds proper integration testing without excessive mocking, and establishes consistent test utilities across the codebase. * 👷 ci(github): add pytest workflow for CI integration - Introduced a new GitHub Actions workflow for running pytest. - Configured to trigger on pull requests and manual dispatch. - Supports multiple OS and Python versions for comprehensive testing. * 👷fix(tests): fix env variable DISKCACHE_ROOT * 👷 ci(github): remove deprecated PR tests workflow & fix env variable - Deleted the old PR tests workflow file. - This cleanup helps streamline CI processes and reduces redundancy. * ci(github): 👷 add pipeline download and integration tests to CI workflow - Introduced a new script for downloading pipelines. - Updated the pytest workflow to include running API and pipeline tests. - Enhanced test execution with improved output formatting and failure limits. * fix(tests): 🐛 avoid context manager in TestClient to skip app startup - Changed TestClient usage to prevent app lifespan startup during tests. - Ensured proper cleanup by closing the client after use. - This improves test performance and reliability. * 👷 ci(github): add RESOURCES_BASEPATH environment variable for pipeline tests - Added RESOURCES_BASEPATH to the environment variables for both downloading pipelines data and running pipeline tests. - This change ensures that the necessary resource paths are correctly set during the CI workflow execution. * 👷 ci(github): update RESOURCES_BASEPATH for pipeline data download - Changed RESOURCES_BASEPATH from /tmp to resources in the pipeline download step. - Ensures the correct path is used for resource access during tests. * chore(pyproject): 🔧 add environment markers for platform compatibility - Introduced required-environments for tool.uv to specify platform requirements. - Updated resolution-markers and required-markers in uv.lock for better dependency management. - Added tensorflow-io-gcs-filesystem with specific markers for Windows and Linux. * ci(github): 👷 configure es_AR locale for Ubuntu runners - Added steps to configure the es_AR locale on Ubuntu. - Ensures proper locale settings for tests running in the CI environment. * 👷 ci(github): add AYMURAI_CACHE_BASEPATH environment variable for pipeline tests - Introduced AYMURAI_CACHE_BASEPATH to the environment variables for both pipeline download and pipeline tests. - This change ensures that the correct cache path is utilized during the execution of the tests. * 🐛 fix(dependencies): adjust textract dependency for platform compatibility - Added conditional dependency for textract based on the operating system. - Specified different sources for textract depending on whether the platform is Windows or not. * 🔥 chore(opencode): remove opencode.json configuration file - Deleted the opencode.json file as it is no longer needed. - This change helps to clean up the repository and remove obsolete configurations. * 🚚 Update pipeline path for datapublic in scripts, notebooks and tests * 📝 docs: replace Black references with Ruff in CONTRIBUTING and Alembic hook examples * 🔧 Add backslash to default CACHE_BASEPATH value * 🔧 Update cache path retrieval to use settings for consistency * ➖ Remove textract dependencies and update documentation for extract_document function * ✅ Update integration tests and add new test cases for anonymizer and datapublic flows * 🔥 chore(test): remove legacy /test dir and standardize sample doc path to /resources/data/sample/document-01.docx * 🔧 Update UV_VERSION to latest in devcontainer Dockerfile * 🔧 Update dependency installation command to include all groups * 📌 Update uv.lock * 🐛 Fix CACHE_BASEPATH env alias resolution for CI pipeline downloads --- .devcontainer/Dockerfile | 2 +- .devcontainer/docker-compose.yml | 2 +- .devcontainer/entrypoint.sh | 2 +- .github/workflows/pytest.yml | 86 + .gitignore | 3 + .pre-commit-config.yaml | 15 +- .vscode/settings.json | 5 + aymurai/alembic.ini | 10 +- .../routers/anonymizer/anonymizer.py | 3 +- aymurai/models/decision/binregex.py | 3 +- aymurai/models/flair/core.py | 15 +- aymurai/scripts/pipelines_download.py | 19 + aymurai/settings.py | 8 +- aymurai/text/extraction.py | 2 +- .../sentence_transformer.py | 6 +- docs/CONTRIBUTING.md | 5 +- docs/api/README.md | 4 +- docs/es/api/README.md | 4 +- .../02-tensorflow-deprecation.ipynb | 251 +- ...ence-transformer-subcategorizer-eval.ipynb | 10 +- pyproject.toml | 21 +- test/api/mock-response/input/documento.docx | Bin 27682 -> 0 bytes ...oject-9-at-2022-11-10-22-41-09a5c372.conll | 174 -- ...roject-9-at-2022-11-10-22-41-09a5c372.json | 233 -- .../mock-response/output/mock-response.json | 94 - test/api/test_file.docx | Bin 4302 -> 0 bytes tests/__init__.py | 0 tests/api/__init__.py | 0 tests/api/conftest.py | 140 + tests/api/routers/__init__.py | 0 tests/api/routers/anonymizer/__init__.py | 0 .../api/routers/anonymizer/test_anonymizer.py | 353 +++ tests/api/routers/conftest.py | 27 + tests/api/routers/datapublic/__init__.py | 0 .../api/routers/datapublic/test_datapublic.py | 233 ++ tests/api/routers/misc/__init__.py | 0 .../api/routers/misc/test_document_extract.py | 303 ++ tests/api/routers/test_pipeline_flows.py | 172 ++ tests/integration/__init__.py | 0 tests/integration/pipelines/__init__.py | 0 tests/integration/pipelines/conftest.py | 63 + .../integration/pipelines/test_anonymizer.py | 95 + .../integration/pipelines/test_datapublic.py | 95 + uv.lock | 2442 +++++++++-------- 44 files changed, 2966 insertions(+), 1934 deletions(-) create mode 100644 .github/workflows/pytest.yml create mode 100644 aymurai/scripts/pipelines_download.py delete mode 100644 test/api/mock-response/input/documento.docx delete mode 100644 test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.conll delete mode 100644 test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.json delete mode 100644 test/api/mock-response/output/mock-response.json delete mode 100644 test/api/test_file.docx create mode 100644 tests/__init__.py create mode 100644 tests/api/__init__.py create mode 100644 tests/api/conftest.py create mode 100644 tests/api/routers/__init__.py create mode 100644 tests/api/routers/anonymizer/__init__.py create mode 100644 tests/api/routers/anonymizer/test_anonymizer.py create mode 100644 tests/api/routers/conftest.py create mode 100644 tests/api/routers/datapublic/__init__.py create mode 100644 tests/api/routers/datapublic/test_datapublic.py create mode 100644 tests/api/routers/misc/__init__.py create mode 100644 tests/api/routers/misc/test_document_extract.py create mode 100644 tests/api/routers/test_pipeline_flows.py create mode 100644 tests/integration/__init__.py create mode 100644 tests/integration/pipelines/__init__.py create mode 100644 tests/integration/pipelines/conftest.py create mode 100644 tests/integration/pipelines/test_anonymizer.py create mode 100644 tests/integration/pipelines/test_datapublic.py diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 2cad5fca..9c303644 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.3 -ARG UV_VERSION=0.5.10 +ARG UV_VERSION=latest ARG CORE_IMAGE=ubuntu:noble FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS astral-uv-source diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 9477b892..c434079c 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -5,7 +5,7 @@ x-template: &template - ..:/workspace:cached - ../notebooks/:/notebooks - ../resources/:/resources - - ../test/:/test + - ../tests/:/tests - $HOME/.ssh/:/home/ubuntu/.ssh - /var/run/docker.sock:/var/run/docker.sock env_file: diff --git a/.devcontainer/entrypoint.sh b/.devcontainer/entrypoint.sh index 000c3360..5eddef91 100644 --- a/.devcontainer/entrypoint.sh +++ b/.devcontainer/entrypoint.sh @@ -1,7 +1,7 @@ #!/bin/sh # install dependencies -uv sync --frozen --all-extras +uv sync --frozen --all-extras --all-groups # configure precommit uv run pre-commit install diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml new file mode 100644 index 00000000..4636bc5c --- /dev/null +++ b/.github/workflows/pytest.yml @@ -0,0 +1,86 @@ +name: pytest + +on: + pull_request: + types: + - opened + - synchronize + - reopened + - ready_for_review + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: pr-tests-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + pytest: + if: ${{ github.event_name != 'pull_request' || github.event.pull_request.draft == false }} + name: pytest (${{ matrix.os }}, py${{ matrix.python-version }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + python-version: + - "3.10" + # - "3.11" + # - "3.12" + # - "3.13" + # - "3.14" + timeout-minutes: 30 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup uv + uses: astral-sh/setup-uv@v5 + with: + version: latest + enable-cache: true + cache-dependency-glob: uv.lock + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Configure es_AR locale (Ubuntu) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install --yes locales + sudo locale-gen es_AR.UTF-8 + sudo update-locale LANG=es_AR.UTF-8 LC_ALL=es_AR.UTF-8 + echo "LANG=es_AR.UTF-8" >> "$GITHUB_ENV" + echo "LC_ALL=es_AR.UTF-8" >> "$GITHUB_ENV" + locale -a + + - name: Install dependencies + run: | + uv sync --frozen --python python --no-dev --no-managed-python --group tests + + - name: Run api tests + env: + DISKCACHE_ROOT: /tmp + run: uv run --no-sync pytest -q --tb=short --disable-warnings --color=yes --maxfail=5 tests/api + + - name: Download pipelines data + env: + DISKCACHE_ROOT: /tmp + RESOURCES_BASEPATH: resources + AYMURAI_CACHE_BASEPATH: resources/cache/aymurai + run: uv run --no-sync pipeline-download + + - name: Run pipeline tests + env: + DISKCACHE_ROOT: /tmp + RESOURCES_BASEPATH: resources + AYMURAI_CACHE_BASEPATH: resources/cache/aymurai + run: uv run --no-sync pytest -q --tb=short --disable-warnings --color=yes --maxfail=5 tests/integration/pipelines diff --git a/.gitignore b/.gitignore index effd04a3..2dad2bac 100755 --- a/.gitignore +++ b/.gitignore @@ -129,6 +129,9 @@ resources aymurai/version.py +.agents +.opencode.json +.sisyphus notebooks/** !notebooks/**/ !notebooks/**/*.ipynb diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2aeb0810..8f7ef35f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,16 +1,11 @@ repos: - - repo: https://github.com/ambv/black - rev: 22.6.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.7.2 hooks: - - id: black - language_version: python3.10 + - id: ruff + - id: ruff-format - repo: https://github.com/kynan/nbstripout rev: 0.6.0 hooks: - - id: nbstripout - - # - repo: https://github.com/pre-commit/pre-commit-hooks - # rev: v2.20.0 - # hooks: - # - id: flake8 \ No newline at end of file + - id: nbstripout \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index dc48662f..68007232 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,9 @@ { + "python.testing.pytestArgs": [ + "tests" + ], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, "python-envs.defaultEnvManager": "ms-python.python:venv", "python-envs.pythonProjects": [], "files.associations": { diff --git a/aymurai/alembic.ini b/aymurai/alembic.ini index b9a6bd2c..87f2df84 100644 --- a/aymurai/alembic.ini +++ b/aymurai/alembic.ini @@ -68,11 +68,11 @@ version_path_separator = os # Use os.pathsep. Default configuration used for ne # on newly generated revision scripts. See the documentation for further # detail and examples -# format using "black" - use the console_scripts runner, against the "black" entrypoint -# hooks = black -# black.type = console_scripts -# black.entrypoint = black -# black.options = -l 79 REVISION_SCRIPT_FILENAME +# format using "ruff format" - use the exec runner, execute a binary +# hooks = ruff_format +# ruff_format.type = exec +# ruff_format.executable = ruff +# ruff_format.options = format REVISION_SCRIPT_FILENAME # lint with attempts to fix using "ruff" - use the exec runner, execute a binary # hooks = ruff diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 5d9b3cdc..65a36131 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -345,8 +345,7 @@ async def anonymizer_disambiguate( "List of per-paragraph predictions returned by /anonymizer/predict." ), ), - label_policies: dict[str, LabelPolicy] - | None = Body( + label_policies: dict[str, LabelPolicy] | None = Body( None, description=( "Optional per-label policy overrides for disambiguation/anonymization." diff --git a/aymurai/models/decision/binregex.py b/aymurai/models/decision/binregex.py index 9c6b0a61..bc67e2be 100644 --- a/aymurai/models/decision/binregex.py +++ b/aymurai/models/decision/binregex.py @@ -15,6 +15,7 @@ encode_text, make_offsets, ) +from aymurai.settings import settings from aymurai.utils.download import download from aymurai.utils.misc import get_element, is_url @@ -34,7 +35,7 @@ def __init__( self.threshold = threshold self.return_only_with_detalle = return_only_with_detalle - basepath = os.getenv("AYMURAI_CACHE_BASEPATH", "/resources/cache/aymurai") + basepath = settings.CACHE_BASEPATH if is_url(url := self._model_path): # Determine file extension from URL or default to safetensors if url.endswith(".pt"): diff --git a/aymurai/models/flair/core.py b/aymurai/models/flair/core.py index a3a5ad87..6fae5daf 100644 --- a/aymurai/models/flair/core.py +++ b/aymurai/models/flair/core.py @@ -1,20 +1,21 @@ +import logging import os import re -import logging from copy import deepcopy import flair import numpy as np from flair.data import Sentence -from more_itertools import collapse from flair.models import SequenceTagger +from more_itertools import collapse from aymurai.logger import get_logger -from aymurai.utils.misc import is_url -from aymurai.utils.download import download -from aymurai.meta.types import DataItem, DataBlock -from aymurai.meta.pipeline_interfaces import TrainModule from aymurai.meta.entities import Entity, EntityAttributes +from aymurai.meta.pipeline_interfaces import TrainModule +from aymurai.meta.types import DataBlock, DataItem +from aymurai.settings import settings +from aymurai.utils.download import download +from aymurai.utils.misc import is_url flair.logger.setLevel(logging.ERROR) @@ -46,7 +47,7 @@ def __init__( # load model if is_url(url := basepath): - basepath = os.getenv("AYMURAI_CACHE_BASEPATH", "/resources/cache/aymurai") + basepath = settings.CACHE_BASEPATH model_path = f"{basepath}/{self.__name__}/model.pt" logger.info(f"downloading model on {model_path}") os.makedirs(os.path.dirname(model_path), exist_ok=True) diff --git a/aymurai/scripts/pipelines_download.py b/aymurai/scripts/pipelines_download.py new file mode 100644 index 00000000..f797b613 --- /dev/null +++ b/aymurai/scripts/pipelines_download.py @@ -0,0 +1,19 @@ +import os + +from aymurai.logger import get_logger +from aymurai.pipeline.pipeline import AymurAIPipeline +from aymurai.settings import settings + +logger = get_logger(__name__) + +RESOURCES_BASEPATH = settings.RESOURCES_BASEPATH + + +def pipelines_download(): + logger.info("Loading pipelines and exit.") + AymurAIPipeline.load( + os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "flair-anonymizer") + ) + AymurAIPipeline.load( + os.path.join(RESOURCES_BASEPATH, "pipelines", "production", "datapublic") + ) diff --git a/aymurai/settings.py b/aymurai/settings.py index 51036fe8..3844d767 100644 --- a/aymurai/settings.py +++ b/aymurai/settings.py @@ -3,7 +3,7 @@ from pathlib import Path from dotenv import load_dotenv -from pydantic import ConfigDict, FilePath, field_validator +from pydantic import AliasChoices, ConfigDict, Field, FilePath, field_validator from pydantic_settings import BaseSettings import aymurai @@ -23,7 +23,7 @@ def load_env(): class Settings(BaseSettings): - model_config = ConfigDict(case_sensitive=True) + model_config = ConfigDict(case_sensitive=False) CORS_ORIGINS: list[str] | str = ",".join( [ @@ -50,6 +50,10 @@ def assemble_cors_origins(cls, v) -> list[str]: SQLALCHEMY_DATABASE_URI: str = "sqlite:////resources/cache/sqlite/database.db" RESOURCES_BASEPATH: str = "/resources" + CACHE_BASEPATH: str = Field( + default="/resources/cache", + validation_alias=AliasChoices("AYMURAI_CACHE_BASEPATH", "CACHE_BASEPATH"), + ) # Alembic Config for running migrations ALEMBIC_INI_PATH: FilePath = PARENT / "alembic.ini" diff --git a/aymurai/text/extraction.py b/aymurai/text/extraction.py index b57cb531..990eab6e 100644 --- a/aymurai/text/extraction.py +++ b/aymurai/text/extraction.py @@ -97,7 +97,7 @@ def extract_document( - If :const:`'ignore'`, then invalid parsing will be set as :const:`NaN` but not warn. use_cache (bool, optional): Toggle extractor-level caching. Defaults to True. - **kwargs: keyword arguments for textract. + **kwargs: keyword arguments for text extractors. Raises: ValueError: Invalid argument. diff --git a/aymurai/transforms/entity_subcategories/sentence_transformer.py b/aymurai/transforms/entity_subcategories/sentence_transformer.py index f662d043..790127f2 100644 --- a/aymurai/transforms/entity_subcategories/sentence_transformer.py +++ b/aymurai/transforms/entity_subcategories/sentence_transformer.py @@ -1,4 +1,3 @@ -import os from copy import deepcopy from pathlib import Path from typing import Iterable @@ -10,6 +9,7 @@ from aymurai.meta.types import DataItem from aymurai.models.sentence_encoder.base import BaseSentenceEncoder from aymurai.models.sentence_encoder.factory import create_encoder +from aymurai.settings import settings from aymurai.transforms.entity_subcategories.bm25 import BM25Scorer from aymurai.transforms.entity_subcategories.subcategories import SUBCATEGORIES from aymurai.transforms.entity_subcategories.utils import filter_by_category @@ -55,9 +55,7 @@ def __init__( self.bm25_weight = float(bm25_weight) self.batch_size = batch_size - cache_root = Path( - os.getenv("AYMURAI_CACHE_BASEPATH", "/resources/cache/aymurai") - ) + cache_root = Path(settings.CACHE_BASEPATH) self.cache_path = cache_root / self.__class__.__name__ self.cache_path.mkdir(parents=True, exist_ok=True) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 4c411155..c9b462da 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -47,7 +47,8 @@ pre-commit install ``` Configured hooks currently include: -- `black` +- `ruff` +- `ruff-format` - `nbstripout` This helps keep code formatting consistent and prevents notebook output from leaking into commits. @@ -56,7 +57,7 @@ This helps keep code formatting consistent and prevents notebook output from lea If needed, you can run the formatter manually before committing: ```bash -black aymurai/ +ruff format aymurai/ ``` ## Documentation policy diff --git a/docs/api/README.md b/docs/api/README.md index dd09f428..212e215e 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -173,7 +173,7 @@ curl -s http://localhost:8899/server/stats/summary ```bash curl -s -X POST \ - -F "file=@test/api/test_file.docx" \ + -F "file=@/resources/data/sample/document-01.docx" \ http://localhost:8899/misc/document-extract ``` @@ -241,7 +241,7 @@ curl -s -X POST http://localhost:8899/anonymizer/validation \ ```bash curl -X POST http://localhost:8899/anonymizer/anonymize-document \ - -F "file=@test/api/test_file.docx" \ + -F "file=@/resources/data/sample/document-01.docx" \ -F 'annotations={"data":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}},"render_policy":{"suffix_mode":"auto","suffix_threshold":1}}' ``` diff --git a/docs/es/api/README.md b/docs/es/api/README.md index 15f4d1e9..adb3db4e 100644 --- a/docs/es/api/README.md +++ b/docs/es/api/README.md @@ -173,7 +173,7 @@ curl -s http://localhost:8899/server/stats/summary ```bash curl -s -X POST \ - -F "file=@test/api/test_file.docx" \ + -F "file=@/resources/data/sample/document-01.docx" \ http://localhost:8899/misc/document-extract ``` @@ -241,7 +241,7 @@ curl -s -X POST http://localhost:8899/anonymizer/validation \ ```bash curl -X POST http://localhost:8899/anonymizer/anonymize-document \ - -F "file=@test/api/test_file.docx" \ + -F "file=@/resources/data/sample/document-01.docx" \ -F 'annotations={"data":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}},"render_policy":{"suffix_mode":"auto","suffix_threshold":1}}' ``` diff --git a/notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb b/notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb index d43dae54..b0ce826c 100755 --- a/notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb +++ b/notebooks/experiments/sentence-encoders/02-tensorflow-deprecation.ipynb @@ -103,23 +103,17 @@ " # Update span info if present in the current result.\n", " slot[\"text\"] = slot[\"text\"] or value.get(\"text\")\n", " slot[\"start\"] = (\n", - " slot[\"start\"]\n", - " if slot[\"start\"] is not None\n", - " else value.get(\"start\")\n", + " slot[\"start\"] if slot[\"start\"] is not None else value.get(\"start\")\n", " )\n", " slot[\"end\"] = (\n", - " slot[\"end\"]\n", - " if slot[\"end\"] is not None\n", - " else value.get(\"end\")\n", + " slot[\"end\"] if slot[\"end\"] is not None else value.get(\"end\")\n", " )\n", " slot[\"labels\"].extend(value.get(\"labels\", []))\n", " slot[\"choices\"].extend(value.get(\"choices\", []))\n", "\n", " for payload in merged.values():\n", " labels = [\n", - " label\n", - " for label in payload[\"labels\"]\n", - " if label in target_labels\n", + " label for label in payload[\"labels\"] if label in target_labels\n", " ]\n", " if not labels or payload[\"text\"] is None:\n", " continue\n", @@ -270,19 +264,14 @@ "source": [ "label_counts = samples_df.groupby(\"label\").size().sort_values(ascending=False)\n", "choice_counts = (\n", - " samples_df.explode(\"choices\")\n", - " .groupby([\"label\", \"choices\"])\n", - " .size()\n", - " .rename(\"count\")\n", + " samples_df.explode(\"choices\").groupby([\"label\", \"choices\"]).size().rename(\"count\")\n", ")\n", "\n", "summary_table = pd.DataFrame(\n", " {\n", " \"samples\": label_counts,\n", " \"unique_choices\": choice_counts.groupby(\"label\").size(),\n", - " \"avg_text_len\": samples_df.groupby(\"label\")[\"char_len\"]\n", - " .mean()\n", - " .round(1),\n", + " \"avg_text_len\": samples_df.groupby(\"label\")[\"char_len\"].mean().round(1),\n", " }\n", ")\n", "summary_table" @@ -297,9 +286,7 @@ "source": [ "fig, ax = plt.subplots()\n", "order = label_counts.index\n", - "sns.barplot(\n", - " x=label_counts.values, y=label_counts.index, ax=ax, palette=\"viridis\"\n", - ")\n", + "sns.barplot(x=label_counts.values, y=label_counts.index, ax=ax, palette=\"viridis\")\n", "ax.set_title(\"Samples per label\")\n", "ax.set_xlabel(\"Number of samples\")\n", "ax.set_ylabel(\"Label\")\n", @@ -314,9 +301,7 @@ ")\n", "\n", "for label in order:\n", - " subset = plot_data.query(\"label == @label\").sort_values(\n", - " \"count\", ascending=True\n", - " )\n", + " subset = plot_data.query(\"label == @label\").sort_values(\"count\", ascending=True)\n", " fig, ax = plt.subplots(figsize=(8, 4))\n", " sns.barplot(data=subset, x=\"count\", y=\"choices\", palette=\"viridis\", ax=ax)\n", " ax.set_title(f\"Top subcategories for {label}\")\n", @@ -379,9 +364,7 @@ "metadata": {}, "outputs": [], "source": [ - "pipeline_path = Path(\n", - " \"/resources/pipelines/production/full-paragraph/pipeline.json\"\n", - ")\n", + "pipeline_path = Path(\"/resources/pipelines/production/datapublic/pipeline.json\")\n", "\n", "with pipeline_path.open() as f:\n", " pipeline_config = json.load(f)\n", @@ -515,8 +498,7 @@ "def recompute_response_vectors(model):\n", " \"\"\"Return normalized subcategory strings and freshly encoded vectors.\"\"\"\n", " normalized = [\n", - " normalize_subcategory(subcategory)\n", - " for subcategory in model.subcategories\n", + " normalize_subcategory(subcategory) for subcategory in model.subcategories\n", " ]\n", " fresh_vectors = model.usem.encode(\n", " normalized,\n", @@ -556,19 +538,13 @@ "outputs": [], "source": [ "row_max_indices = np.argmax(cosine_matrix, axis=1)\n", - "row_max_values = cosine_matrix[\n", - " np.arange(len(row_max_indices)), row_max_indices\n", - "]\n", - "mismatched_rows = np.where(row_max_indices != np.arange(len(row_max_indices)))[\n", - " 0\n", - "]\n", + "row_max_values = cosine_matrix[np.arange(len(row_max_indices)), row_max_indices]\n", + "mismatched_rows = np.where(row_max_indices != np.arange(len(row_max_indices)))[0]\n", "diag_values = np.diag(cosine_matrix)\n", "off_identity_matches = (\n", " pd.DataFrame(\n", " {\n", - " \"subcategory\": [\n", - " model.subcategories[idx] for idx in mismatched_rows\n", - " ],\n", + " \"subcategory\": [model.subcategories[idx] for idx in mismatched_rows],\n", " \"matched_index\": row_max_indices[mismatched_rows],\n", " \"max_cosine\": row_max_values[mismatched_rows],\n", " \"diagonal_cosine\": diag_values[mismatched_rows],\n", @@ -695,9 +671,7 @@ "outputs": [], "source": [ "# Filter out samples with no annotated choices\n", - "retrieval_records = [\n", - " record for record in retrieval_records if record[\"choices\"]\n", - "]\n", + "retrieval_records = [record for record in retrieval_records if record[\"choices\"]]\n", "len(retrieval_records)" ] }, @@ -712,16 +686,11 @@ " metrics = []\n", " labels = sorted({record[\"label\"] for record in records})\n", " for label in labels:\n", - " label_records = [\n", - " record for record in records if record[\"label\"] == label\n", - " ]\n", + " label_records = [record for record in records if record[\"label\"] == label]\n", " total = len(label_records)\n", " for k in ks:\n", " hits = sum(\n", - " any(\n", - " choice in record[\"retrieved\"][:k]\n", - " for choice in record[\"choices\"]\n", - " )\n", + " any(choice in record[\"retrieved\"][:k] for choice in record[\"choices\"])\n", " for record in label_records\n", " )\n", " metrics.append(\n", @@ -735,15 +704,10 @@ " overall = []\n", " for k in ks:\n", " hits = sum(\n", - " any(\n", - " choice in record[\"retrieved\"][:k]\n", - " for choice in record[\"choices\"]\n", - " )\n", + " any(choice in record[\"retrieved\"][:k] for choice in record[\"choices\"])\n", " for record in records\n", " )\n", - " overall.append(\n", - " {\"label\": \"OVERALL\", \"k\": k, \"accuracy\": hits / len(records)}\n", - " )\n", + " overall.append({\"label\": \"OVERALL\", \"k\": k, \"accuracy\": hits / len(records)})\n", "\n", " metrics.extend(overall)\n", " return pd.DataFrame(metrics)\n", @@ -768,11 +732,7 @@ "\n", "sns.heatmap(\n", " baseline_accuracy_pivot.loc[\n", - " [\n", - " label\n", - " for label in baseline_accuracy_pivot.index\n", - " if label != \"OVERALL\"\n", - " ]\n", + " [label for label in baseline_accuracy_pivot.index if label != \"OVERALL\"]\n", " ],\n", " annot=True,\n", " fmt=\".2f\",\n", @@ -802,9 +762,7 @@ " record\n", " for record in retrieval_records\n", " if record[\"label\"] == label\n", - " and any(\n", - " choice in record[\"retrieved\"][:5] for choice in record[\"choices\"]\n", - " )\n", + " and any(choice in record[\"retrieved\"][:5] for choice in record[\"choices\"])\n", " ]\n", " for record in random.sample(label_records, k=min(3, len(label_records))):\n", " print(f\"- Text: {record['text']}\")\n", @@ -827,9 +785,7 @@ " record\n", " for record in retrieval_records\n", " if record[\"label\"] == label\n", - " and not any(\n", - " choice in record[\"retrieved\"][:5] for choice in record[\"choices\"]\n", - " )\n", + " and not any(choice in record[\"retrieved\"][:5] for choice in record[\"choices\"])\n", " ]\n", " for record in random.sample(label_records, k=min(3, len(label_records))):\n", " print(f\"- Text: {record['text']}\")\n", @@ -888,9 +844,7 @@ " self.subcategories = subcategories\n", " self._rng = random.Random(seed)\n", "\n", - " def batch_retrieve(\n", - " self, texts: list[str], top_k: int = 5\n", - " ) -> list[list[str]]:\n", + " def batch_retrieve(self, texts: list[str], top_k: int = 5) -> list[list[str]]:\n", " k = min(top_k, len(self.subcategories))\n", " if k == 0:\n", " return [[] for _ in texts]\n", @@ -937,9 +891,7 @@ " for variant, records in variant_records.items()\n", "}\n", "variant_pivots = {\n", - " variant: df.pivot(\n", - " index=\"label\", columns=\"k\", values=\"accuracy\"\n", - " ).sort_index()\n", + " variant: df.pivot(index=\"label\", columns=\"k\", values=\"accuracy\").sort_index()\n", " for variant, df in variant_accuracy.items()\n", "}\n", "\n", @@ -970,11 +922,7 @@ "\n", "sns.heatmap(\n", " variant_pivots[\"Random\"].loc[\n", - " [\n", - " label\n", - " for label in baseline_accuracy_pivot.index\n", - " if label != \"OVERALL\"\n", - " ]\n", + " [label for label in baseline_accuracy_pivot.index if label != \"OVERALL\"]\n", " ],\n", " annot=True,\n", " fmt=\".2f\",\n", @@ -1017,9 +965,7 @@ "\n", "\n", "class BM25Retriever:\n", - " def __init__(\n", - " self, subcategories: list[str], k1: float = 1.2, b: float = 0.75\n", - " ):\n", + " def __init__(self, subcategories: list[str], k1: float = 1.2, b: float = 0.75):\n", " self.subcategories = subcategories\n", " normalized = [normalize_subcategory(sub) for sub in subcategories]\n", " self.tokenized = [tokenize(text) for text in normalized]\n", @@ -1057,9 +1003,7 @@ " scores[idx] += idf * freq * (self.k1 + 1) / denom\n", " return scores\n", "\n", - " def batch_retrieve(\n", - " self, texts: list[str], top_k: int = 5\n", - " ) -> list[list[str]]:\n", + " def batch_retrieve(self, texts: list[str], top_k: int = 5) -> list[list[str]]:\n", " return [self._topk(text, top_k) for text in texts]\n", "\n", " def _topk(self, text: str, top_k: int) -> list[str]:\n", @@ -1080,9 +1024,7 @@ " self.response_vectors = usem_model.usem_vectors\n", " self.bm25_weight = bm25_weight\n", "\n", - " def batch_retrieve(\n", - " self, texts: list[str], top_k: int = 5\n", - " ) -> list[list[str]]:\n", + " def batch_retrieve(self, texts: list[str], top_k: int = 5) -> list[list[str]]:\n", " query_vectors = self.usem_model.usem.batch_encode(\n", " [normalize_text(text) for text in texts],\n", " encoder_type=\"question_encoder\",\n", @@ -1094,10 +1036,7 @@ " bm25_norm = bm25_scores / (bm25_scores.max() + 1e-9)\n", " sim_scores = similarity[row_idx]\n", " sim_norm = sim_scores / (sim_scores.max() + 1e-9)\n", - " combined = (\n", - " self.bm25_weight * bm25_norm\n", - " + (1 - self.bm25_weight) * sim_norm\n", - " )\n", + " combined = self.bm25_weight * bm25_norm + (1 - self.bm25_weight) * sim_norm\n", " k = min(top_k, combined.shape[0])\n", " top_indices = np.argsort(-combined)[:k]\n", " combined_results.append(\n", @@ -1114,13 +1053,10 @@ "outputs": [], "source": [ "bm25_models = {\n", - " label: BM25Retriever(subcats)\n", - " for label, subcats in label_subcategories.items()\n", + " label: BM25Retriever(subcats) for label, subcats in label_subcategories.items()\n", "}\n", "hybrid_models = {\n", - " label: HybridRetriever(\n", - " usem_models[label], bm25_models[label], bm25_weight=0.4\n", - " )\n", + " label: HybridRetriever(usem_models[label], bm25_models[label], bm25_weight=0.4)\n", " for label in usem_models\n", "}" ] @@ -1148,9 +1084,7 @@ " for variant, records in variant_records.items()\n", "}\n", "variant_pivots = {\n", - " variant: df.pivot(\n", - " index=\"label\", columns=\"k\", values=\"accuracy\"\n", - " ).sort_index()\n", + " variant: df.pivot(index=\"label\", columns=\"k\", values=\"accuracy\").sort_index()\n", " for variant, df in variant_accuracy.items()\n", "}\n", "\n", @@ -1162,11 +1096,7 @@ "\n", " sns.heatmap(\n", " pivot.loc[\n", - " [\n", - " label\n", - " for label in baseline_accuracy_pivot.index\n", - " if label != \"OVERALL\"\n", - " ]\n", + " [label for label in baseline_accuracy_pivot.index if label != \"OVERALL\"]\n", " ],\n", " annot=True,\n", " fmt=\".2f\",\n", @@ -1281,9 +1211,7 @@ " similarity = np.inner(query_vectors, self.response_vectors)\n", " k = min(top_k, similarity.shape[1])\n", " top_indices = np.argsort(-similarity, axis=1)[:, :k]\n", - " return [\n", - " [self.subcategories[idx] for idx in row] for row in top_indices\n", - " ]\n", + " return [[self.subcategories[idx] for idx in row] for row in top_indices]\n", "\n", "\n", "class HybridSentenceTransformerRetriever:\n", @@ -1312,21 +1240,14 @@ " bm25_norm = bm25_scores / (bm25_scores.max() + 1e-9)\n", " sim_scores = similarity[row_idx]\n", " sim_norm = sim_scores / (sim_scores.max() + 1e-9)\n", - " combined = (\n", - " self.bm25_weight * bm25_norm\n", - " + (1 - self.bm25_weight) * sim_norm\n", - " )\n", + " combined = self.bm25_weight * bm25_norm + (1 - self.bm25_weight) * sim_norm\n", " k = min(top_k, combined.shape[0])\n", " top_indices = np.argsort(-combined)[:k]\n", - " combined_results.append(\n", - " [self.subcategories[idx] for idx in top_indices]\n", - " )\n", + " combined_results.append([self.subcategories[idx] for idx in top_indices])\n", " return combined_results\n", "\n", "\n", - "def build_challenger_models(\n", - " usem_configs, encoder, encoder_name, batch_size=256\n", - "):\n", + "def build_challenger_models(usem_configs, encoder, encoder_name, batch_size=256):\n", " return {\n", " label: SentenceTransformerRetriever(\n", " label=label,\n", @@ -1339,9 +1260,7 @@ " }\n", "\n", "\n", - "def build_hybrid_sentence_transformer_models(\n", - " base_models, bm25_models, bm25_weight=0.4\n", - "):\n", + "def build_hybrid_sentence_transformer_models(base_models, bm25_models, bm25_weight=0.4):\n", " return {\n", " label: HybridSentenceTransformerRetriever(\n", " base_retriever=base_models[label],\n", @@ -1370,9 +1289,7 @@ " return records\n", "\n", "\n", - "distiluse_models = build_challenger_models(\n", - " usem_configs, distiluse_encoder, \"DistilUSE\"\n", - ")\n", + "distiluse_models = build_challenger_models(usem_configs, distiluse_encoder, \"DistilUSE\")\n", "minilm_models = build_challenger_models(usem_configs, minilm_encoder, \"MiniLM\")" ] }, @@ -1414,11 +1331,7 @@ "fig, ax = plt.subplots()\n", "sns.heatmap(\n", " distiluse_accuracy_pivot.loc[\n", - " [\n", - " label\n", - " for label in distiluse_accuracy_pivot.index\n", - " if label != \"OVERALL\"\n", - " ]\n", + " [label for label in distiluse_accuracy_pivot.index if label != \"OVERALL\"]\n", " ],\n", " annot=True,\n", " fmt=\".2f\",\n", @@ -1622,9 +1535,7 @@ " \"TensorFlow USEM\": baseline_accuracy_pivot.loc[\"OVERALL\"],\n", " \"DistilUSE\": distiluse_accuracy_pivot.loc[\"OVERALL\"],\n", " \"MiniLM\": minilm_accuracy_pivot.loc[\"OVERALL\"],\n", - " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"].loc[\n", - " \"OVERALL\"\n", - " ],\n", + " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"].loc[\"OVERALL\"],\n", " \"DistilUSE + BM25\": distiluse_hybrid_pivot.loc[\"OVERALL\"],\n", " \"MiniLM + BM25\": minilm_hybrid_pivot.loc[\"OVERALL\"],\n", " }\n", @@ -1707,7 +1618,7 @@ "outputs": [], "source": [ "# Per-label comparison for top-1 accuracy\n", - "label_index = [l for l in baseline_accuracy_pivot.index if l != \"OVERALL\"]\n", + "label_index = [label for label in baseline_accuracy_pivot.index if label != \"OVERALL\"]\n", "label_comparison = pd.DataFrame(\n", " {\n", " \"TensorFlow USEM\": baseline_accuracy_pivot.loc[label_index, 1],\n", @@ -1878,9 +1789,7 @@ " \"Top-5\": comparison_df[5].values,\n", " \"Δ vs Baseline (Top-1)\": [\n", " 0.0 if model == \"TensorFlow USEM\" else (score - baseline_score)\n", - " for model, score in zip(\n", - " comparison_df.index, comparison_df[1].values\n", - " )\n", + " for model, score in zip(comparison_df.index, comparison_df[1].values)\n", " ],\n", " }\n", ").set_index(\"Model\")\n", @@ -1944,7 +1853,7 @@ "outputs": [], "source": [ "# Best-performing model per label and k (excluding TensorFlow USEM + BM25)\n", - "label_index = [l for l in baseline_accuracy_pivot.index if l != \"OVERALL\"]\n", + "label_index = [label for label in baseline_accuracy_pivot.index if label != \"OVERALL\"]\n", "ks = [k for k in range(1, 6) if k in baseline_accuracy_pivot.columns]\n", "\n", "model_pivots = {\n", @@ -1971,10 +1880,7 @@ "scores = pd.DataFrame(records)\n", "best_models = scores.loc[scores.groupby([\"label\", \"k\"])[\"accuracy\"].idxmax()]\n", "model_ranking = (\n", - " best_models[\"model\"]\n", - " .value_counts()\n", - " .rename_axis(\"model\")\n", - " .reset_index(name=\"wins\")\n", + " best_models[\"model\"].value_counts().rename_axis(\"model\").reset_index(name=\"wins\")\n", ")\n", "\n", "best_models.reset_index(drop=True)\n", @@ -1988,9 +1894,7 @@ "metadata": {}, "outputs": [], "source": [ - "scores.query(\"k == 1\").sort_values(\n", - " [\"label\", \"accuracy\"], ascending=[True, False]\n", - ")" + "scores.query(\"k == 1\").sort_values([\"label\", \"accuracy\"], ascending=[True, False])" ] }, { @@ -2000,9 +1904,7 @@ "metadata": {}, "outputs": [], "source": [ - "scores.query(\"k == 3\").sort_values(\n", - " [\"label\", \"accuracy\"], ascending=[True, False]\n", - ")" + "scores.query(\"k == 3\").sort_values([\"label\", \"accuracy\"], ascending=[True, False])" ] }, { @@ -2012,9 +1914,7 @@ "metadata": {}, "outputs": [], "source": [ - "scores.query(\"k == 5\").sort_values(\n", - " [\"label\", \"accuracy\"], ascending=[True, False]\n", - ")" + "scores.query(\"k == 5\").sort_values([\"label\", \"accuracy\"], ascending=[True, False])" ] }, { @@ -2041,8 +1941,7 @@ "\n", "# Cache texts per label\n", "label_texts = {\n", - " label: [item[\"text\"] for item in items]\n", - " for label, items in samples_by_label.items()\n", + " label: [item[\"text\"] for item in items] for label, items in samples_by_label.items()\n", "}\n", "\n", "# Cache BM25 score vectors per label to avoid recomputing across weights\n", @@ -2087,9 +1986,7 @@ " combined = bm25_weight * bm25_norm + (1 - bm25_weight) * sim_norm\n", " k = min(top_k, combined.shape[0])\n", " top_indices = np.argsort(-combined)[:k]\n", - " combined_results.append(\n", - " [bm25_model.subcategories[i] for i in top_indices]\n", - " )\n", + " combined_results.append([bm25_model.subcategories[i] for i in top_indices])\n", " return combined_results\n", "\n", "\n", @@ -2112,9 +2009,7 @@ " bm25_weight=weight,\n", " top_k=5,\n", " )\n", - " for item, retrieved in zip(\n", - " samples_by_label[label], retrieved_lists\n", - " ):\n", + " for item, retrieved in zip(samples_by_label[label], retrieved_lists):\n", " records.append(\n", " {\n", " \"label\": label,\n", @@ -2142,9 +2037,9 @@ "search_df = pd.DataFrame(search_results)\n", "\n", "# Best weight per model by top-1 accuracy\n", - "best_rows = search_df.loc[\n", - " search_df.groupby(\"model\")[\"top1\"].idxmax()\n", - "].reset_index(drop=True)\n", + "best_rows = search_df.loc[search_df.groupby(\"model\")[\"top1\"].idxmax()].reset_index(\n", + " drop=True\n", + ")\n", "best_pivots = {\n", " row.model: pivot_lookup[(row.model, row.bm25_weight)]\n", " for _, row in best_rows.iterrows()\n", @@ -2186,9 +2081,7 @@ "for row in best_rows.itertuples():\n", " model_name = row.model\n", " weight = row.bm25_weight\n", - " base_models = (\n", - " distiluse_models if model_name == \"DistilUSE\" else minilm_models\n", - " )\n", + " base_models = distiluse_models if model_name == \"DistilUSE\" else minilm_models\n", "\n", " records = []\n", " for label, base_retriever in base_models.items():\n", @@ -2215,24 +2108,22 @@ " )\n", "\n", " accuracy = compute_topk_accuracy(records)\n", - " pivot = accuracy.pivot(\n", - " index=\"label\", columns=\"k\", values=\"accuracy\"\n", - " ).sort_index()\n", + " pivot = accuracy.pivot(index=\"label\", columns=\"k\", values=\"accuracy\").sort_index()\n", " tuned_records[model_name] = records\n", " tuned_pivots[model_name] = pivot\n", "\n", "# Show tuned weights and overall performance\n", "best_rows_display = best_rows.copy()\n", "for model_name, pivot in tuned_pivots.items():\n", - " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top1\"] = (\n", - " pivot.loc[\"OVERALL\", 1]\n", - " )\n", - " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top3\"] = (\n", - " pivot.loc[\"OVERALL\", 3]\n", - " )\n", - " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top5\"] = (\n", - " pivot.loc[\"OVERALL\", 5]\n", - " )\n", + " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top1\"] = pivot.loc[\n", + " \"OVERALL\", 1\n", + " ]\n", + " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top3\"] = pivot.loc[\n", + " \"OVERALL\", 3\n", + " ]\n", + " best_rows_display.loc[best_rows_display[\"model\"] == model_name, \"top5\"] = pivot.loc[\n", + " \"OVERALL\", 5\n", + " ]\n", "\n", "best_rows_display" ] @@ -2279,14 +2170,12 @@ "comparison_df_tuned = pd.DataFrame(\n", " {\n", " \"TensorFlow USEM\": baseline_accuracy_pivot.loc[\"OVERALL\"],\n", - " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"].loc[\n", - " \"OVERALL\"\n", - " ],\n", + " \"TensorFlow USEM + BM25\": variant_pivots[\"USEM + BM25 hybrid\"].loc[\"OVERALL\"],\n", " \"DistilUSE\": distiluse_accuracy_pivot.loc[\"OVERALL\"],\n", " \"MiniLM\": minilm_accuracy_pivot.loc[\"OVERALL\"],\n", - " \"DistilUSE + BM25 tuned\": tuned_hybrid_pivots[\n", - " \"DistilUSE + BM25 tuned\"\n", - " ].loc[\"OVERALL\"],\n", + " \"DistilUSE + BM25 tuned\": tuned_hybrid_pivots[\"DistilUSE + BM25 tuned\"].loc[\n", + " \"OVERALL\"\n", + " ],\n", " \"MiniLM + BM25 tuned\": tuned_hybrid_pivots[\"MiniLM + BM25 tuned\"].loc[\n", " \"OVERALL\"\n", " ],\n", @@ -2313,7 +2202,7 @@ " \"MiniLM + BM25 tuned\": tuned_hybrid_pivots[\"MiniLM + BM25 tuned\"],\n", "}\n", "\n", - "labels_no_overall = [l for l in label_index]\n", + "labels_no_overall = [label for label in label_index]\n", "\n", "for name, pivot in pivot_map.items():\n", " fig, ax = plt.subplots(figsize=(6, 4))\n", @@ -2344,7 +2233,7 @@ ], "metadata": { "kernelspec": { - "display_name": "aymurai (3.10.19)", + "display_name": "aymurai (3.10.12)", "language": "python", "name": "python3" }, @@ -2358,7 +2247,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.19" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb b/notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb index 83546815..1c271ecf 100644 --- a/notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb +++ b/notebooks/experiments/sentence-encoders/04-sentence-transformer-subcategorizer-eval.ipynb @@ -46,7 +46,7 @@ "outputs": [], "source": [ "# Config\n", - "pipeline_path = Path(\"/resources/pipelines/production/full-paragraph/pipeline.json\")\n", + "pipeline_path = Path(\"/resources/pipelines/production/datapublic/pipeline.json\")\n", "annotations_path = Path(\n", " \"/resources/annotations/label-studio/resos-annotations/30-nov/project-3-at-2022-11-30-16-04-2b43bf39.json\"\n", ")\n", @@ -295,7 +295,7 @@ "# Heatmap\n", "fig, ax = plt.subplots()\n", "sns.heatmap(\n", - " pivot.loc[[l for l in pivot.index if l != \"OVERALL\"]],\n", + " pivot.loc[[label for label in pivot.index if label != \"OVERALL\"]],\n", " annot=True,\n", " fmt=\".2f\",\n", " cmap=\"YlGnBu\",\n", @@ -372,7 +372,7 @@ "# Heatmap\n", "fig, ax = plt.subplots()\n", "sns.heatmap(\n", - " pivot.loc[[l for l in pivot.index if l != \"OVERALL\"]],\n", + " pivot.loc[[label for label in pivot.index if label != \"OVERALL\"]],\n", " annot=True,\n", " fmt=\".2f\",\n", " cmap=\"YlGnBu\",\n", @@ -398,7 +398,7 @@ ], "metadata": { "kernelspec": { - "display_name": "aymurai (3.10.19)", + "display_name": "aymurai (3.10.12)", "language": "python", "name": "python3" }, @@ -412,7 +412,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.19" + "version": "3.10.12" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index 4e6e0475..b5bb6d6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,6 @@ authors = [ maintainers = [ { name = "jedzill4", email = "r@collectiveai.io" }, { name = "jansaldo", email = "juli@collectiveai.io" }, - ] description = "The backend API and machine learning models of AymurAI." readme = "README.md" @@ -71,8 +70,7 @@ dependencies = [ "cachetools>=5.5.0", "diskcache>=5.6.3", "scipy<1.14.1", - "torch>=1.13.1", - "pytorch-lightning==1.8.3.post1", + "torch>=2.0", "psutil==6.1.0", "sqlmodel==0.0.22", "alembic>=1.13.3", @@ -102,12 +100,14 @@ dev = [ "jupyter>=1.1.1", "pip>=24.3.1", ] +tests = ["pytest>=9.0.2"] [tool.setuptools.packages.find] include = ["aymurai"] [project.scripts] aymurai-api = "aymurai.api.main:main" +pipeline-download = "aymurai.scripts.pipelines_download:pipelines_download" [tool.setuptools.package-data] @@ -118,6 +118,21 @@ version_file = "aymurai/version.py" version_scheme = "only-version" local_scheme = "no-local-version" +[tool.uv] +required-environments = [ + "sys_platform == 'linux' and platform_machine == 'x86_64'", + "sys_platform == 'win32' and platform_machine == 'AMD64'", +] + [tool.pylint.messages_control] disable = "C0330, C0326" + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = ["-v", "--tb=short", "--strict-markers", "--disable-warnings"] +markers = [ + "integration: marks tests as integration tests", + "slow: marks tests as slow (model loading, >30s)", + "external: marks tests that depend on optional external binaries/services", +] diff --git a/test/api/mock-response/input/documento.docx b/test/api/mock-response/input/documento.docx deleted file mode 100644 index 51b2a7cd853e7fe168b1926a9995d149d64fabcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27682 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 X5eEZMgaZM+0sQ0xl8~<9)2sgnN|qh> diff --git a/test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.conll b/test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.conll deleted file mode 100644 index b384b3c6..00000000 --- a/test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.conll +++ /dev/null @@ -1,174 +0,0 @@ --DOCSTART- -X- O -2020 -X- _ O -Año -X- _ O -del -X- _ O -General -X- _ O -Manuel -X- _ O -Belgrano -X- _ O -JUZGADO -X- _ O -DE -X- _ O -1RA -X- _ O -INSTANCIA -X- _ O -EN -X- _ O -LO -X- _ O -PENAL -X- _ O -CONTRAVENCIONAL -X- _ O -Y -X- _ O -DE -X- _ O -FALTAS -X- _ O -N°10 -X- _ O -SECRETARIA -X- _ O -N°19 -X- _ O -5 -X- _ O -MASCULINOS -X- _ O -Y -X- _ O -3 -X- _ O -FEMENINOS -X- _ O -DE -X- _ O -IDENTIDAD -X- _ O -DESCONOCIDA, -X- _ O -NN -X- _ O -Y -X- _ O -OTROS -X- _ O -SOBRE -X- _ O -5 -X- _ O -C -X- _ O -- -X- _ O -COMERCIO -X- _ O -DE -X- _ O -ESTUPEFACIENTES -X- _ O -O -X- _ O -CUALQUIER -X- _ O -MATERIA -X- _ O -PRIMA -X- _ O -PARA -X- _ O -SU -X- _ O -PRODUCCIÓN -X- _ O -/TENENCIA -X- _ O -CON -X- _ O -FINES -X- _ O -DE -X- _ O -COMERCIALIZACIÓN -X- _ O -Número: -X- _ O -IPP -X- _ O -11111/2013-0 -X- _ O -CUIJ: -X- _ O -IPP -X- _ O -J-01-06066606-6/2013-0 -X- _ O -Actuación -X- _ O -Nro: -X- _ O -66600666/2022 -X- _ O -AUDIENCIA -X- _ O -UNIPERSONAL -X- _ O -(art. -X- _ O -2 -X- _ O -bis -X- _ O -CPP) -X- _ O -Fecha: -X- _ O -7 -X- _ O -de -X- _ O -septiembre -X- _ O -de -X- _ O -2020 -X- _ O -Horario -X- _ O -de -X- _ O -inicio: -X- _ O -10:00 -X- _ O -horas -X- _ O -PARTICIPANTES -X- _ O -Juez: -X- _ O -Pablo -X- _ O -C. -X- _ O -Casas. -X- _ O -Secretario: -X- _ O -Pablo -X- _ O -Hilaire -X- _ O -Chaneton. -X- _ O -Fiscal: -X- _ O -Cristian -X- _ B-NOMBRE -Longobardi, -X- _ I-NOMBRE -UIT -X- _ O -Sur. -X- _ O -DESARROLLO -X- _ O -Juez: -X- _ O -le -X- _ O -hace -X- _ O -saber -X- _ O -al -X- _ O -Fiscal -X- _ O -que -X- _ O -tras -X- _ O -haber -X- _ O -analizado -X- _ O -en -X- _ O -forma -X- _ O -pormenorizada -X- _ O -el -X- _ O -caso, -X- _ O -lo -X- _ O -contactó -X- _ O -telefónicamente -X- _ O -para -X- _ O -realizar -X- _ O -esta -X- _ O -audiencia -X- _ O -frente -X- _ O -a -X- _ O -la -X- _ O -necesidad -X- _ O -de -X- _ O -solicitar -X- _ O -algunas -X- _ O -aclaraciones -X- _ O -y -X- _ O -precisiones -X- _ O -atinentes -X- _ O -a -X- _ O -la -X- _ O -prueba -X- _ O -presentada. -X- _ O -Fiscal: -X- _ O -refiere -X- _ O -que -X- _ O -en -X- _ O -función -X- _ O -de -X- _ O -lo -X- _ O -solicitado, -X- _ O -resolverá -X- _ O -e -X- _ O -informara -X- _ O -sobre -X- _ O -las -X- _ O -cuestiones -X- _ O -señaladas -X- _ O -a -X- _ O -la -X- _ O -mayor -X- _ O -brevedad -X- _ O -posible. -X- _ O -Juez: -X- _ O -manifiesta -X- _ O -que -X- _ O -lo -X- _ O -tiene -X- _ O -presente -X- _ O -y -X- _ O -que -X- _ O -quedará -X- _ O -a -X- _ O -la -X- _ O -espera -X- _ O -de -X- _ O -tales -X- _ O -aclaraciones -X- _ O -en -X- _ O -torno -X- _ O -a -X- _ O -la -X- _ O -prueba. -X- _ O -Horario -X- _ O -de -X- _ O -cierre: -X- _ O -10:15 -X- _ O -horas -X- _ O diff --git a/test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.json b/test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.json deleted file mode 100644 index 31684d62..00000000 --- a/test/api/mock-response/input/project-9-at-2022-11-10-22-41-09a5c372.json +++ /dev/null @@ -1,233 +0,0 @@ -[ - { - "id": 10252, - "data": { - "text": "2020 Año del General Manuel Belgrano\t\nJUZGADO DE 1RA INSTANCIA EN LO PENAL CONTRAVENCIONAL Y DE FALTAS N°10 SECRETARIA N°19 5 MASCULINOS Y 3 FEMENINOS DE IDENTIDAD DESCONOCIDA, NN Y OTROS SOBRE 5 C - COMERCIO DE ESTUPEFACIENTES O CUALQUIER MATERIA PRIMA PARA SU PRODUCCIÓN /TENENCIA CON FINES DE COMERCIALIZACIÓN \nNúmero: IPP 11111/2013-0 \nCUIJ: IPP J-01-06066606-6/2013-0 \nActuación Nro: 66600666/2022 \nAUDIENCIA UNIPERSONAL \n(art. 2 bis CPP)\n Fecha: 7 de septiembre de 2020 \n Horario de inicio: 10:00 horas \nPARTICIPANTES \nJuez: Pablo C. Casas. \t\nSecretario: Pablo Hilaire Chaneton.\nFiscal: Cristian Longobardi, UIT Sur.\nDESARROLLO \nJuez: le hace saber al Fiscal que tras haber analizado en forma pormenorizada el caso, lo contactó telefónicamente para realizar esta audiencia frente a la necesidad de solicitar algunas aclaraciones y precisiones atinentes a la prueba presentada.\nFiscal: refiere que en función de lo solicitado, resolverá e informara sobre las cuestiones señaladas a la mayor brevedad posible.\nJuez: manifiesta que lo tiene presente y que quedará a la espera de tales aclaraciones en torno a la prueba. \n \t\t\t\t\t\t Horario de cierre: 10:15 horas \n \n", - "meta_info": { - "id": "dump-20221021", - "path": "/test/api/mock-response/input/documento.docx" - } - }, - "annotations": [ - { - "id": 22, - "created_username": " rbarriga@collective.ai, 1", - "created_ago": "1 week, 6 days", - "completed_by": { - "id": 1, - "first_name": "", - "last_name": "", - "avatar": null, - "email": "rbarriga@collective.ai", - "initials": "rb" - }, - "result": [ - { - "value": { - "start": 594, - "end": 614, - "text": "Cristian Longobardi,", - "labels": [ - "NOMBRE" - ] - }, - "id": "GT6TTD8eMf", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 594, - "end": 614, - "text": "Cristian Longobardi,", - "choices": [ - "otro" - ] - }, - "id": "GT6TTD8eMf", - "from_name": "NOMBRE", - "to_name": "text", - "type": "choices", - "origin": "manual" - }, - { - "value": { - "start": 532, - "end": 547, - "text": "Pablo C. Casas.", - "labels": [ - "NOMBRE" - ] - }, - "id": "2Oq-A5l8yH", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 532, - "end": 547, - "text": "Pablo C. Casas.", - "choices": [ - "firma" - ] - }, - "id": "2Oq-A5l8yH", - "from_name": "NOMBRE", - "to_name": "text", - "type": "choices", - "origin": "manual" - }, - { - "value": { - "start": 1152, - "end": 1157, - "text": "10:15", - "labels": [ - "HORA_DE_CIERRE" - ] - }, - "id": "1bfxq1oxoG", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 498, - "end": 503, - "text": "10:00", - "labels": [ - "HORA_DE_INICIO" - ] - }, - "id": "3YLgdS7Hu7", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 453, - "end": 476, - "text": "7 de septiembre de 2020", - "labels": [ - "FECHA_RESOLUCION" - ] - }, - "id": "-HiUTvwFbK", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 327, - "end": 339, - "text": "11111/2013-0", - "labels": [ - "N_EXPTE_EJE" - ] - }, - "id": "2zZNLOfntI", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 195, - "end": 198, - "text": "5 C", - "labels": [ - "ART_INFRINGIDO" - ] - }, - "id": "eIl-etR2ye", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 201, - "end": 273, - "text": "COMERCIO DE ESTUPEFACIENTES O CUALQUIER MATERIA PRIMA PARA SU PRODUCCIÓN", - "labels": [ - "CONDUCTA" - ] - }, - "id": "sU9P19itW3", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 201, - "end": 273, - "text": "COMERCIO DE ESTUPEFACIENTES O CUALQUIER MATERIA PRIMA PARA SU PRODUCCIÓN", - "choices": [ - "estupefacientes" - ] - }, - "id": "sU9P19itW3", - "from_name": "CONDUCTA", - "to_name": "text", - "type": "choices", - "origin": "manual" - }, - { - "value": { - "start": 562, - "end": 585, - "text": "Pablo Hilaire Chaneton.", - "labels": [ - "NOMBRE" - ] - }, - "id": "7L82m_D2J3", - "from_name": "label", - "to_name": "text", - "type": "labels", - "origin": "manual" - }, - { - "value": { - "start": 562, - "end": 585, - "text": "Pablo Hilaire Chaneton.", - "choices": [ - "otro" - ] - }, - "id": "7L82m_D2J3", - "from_name": "NOMBRE", - "to_name": "text", - "type": "choices", - "origin": "manual" - } - ], - "was_cancelled": false, - "ground_truth": false, - "created_at": "2022-11-04T20:44:25.455645Z", - "updated_at": "2022-11-18T15:57:57.652671Z", - "lead_time": 228.062, - "task": 10252, - "parent_prediction": null, - "parent_annotation": null - } - ], - "predictions": [] - } -] \ No newline at end of file diff --git a/test/api/mock-response/output/mock-response.json b/test/api/mock-response/output/mock-response.json deleted file mode 100644 index 15a75e24..00000000 --- a/test/api/mock-response/output/mock-response.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "document": "2020 Año del General Manuel Belgrano\t\nJUZGADO DE 1RA INSTANCIA EN LO PENAL CONTRAVENCIONAL Y DE FALTAS N°10 SECRETARIA N°19 5 MASCULINOS Y 3 FEMENINOS DE IDENTIDAD DESCONOCIDA, NN Y OTROS SOBRE 5 C - COMERCIO DE ESTUPEFACIENTES O CUALQUIER MATERIA PRIMA PARA SU PRODUCCIÓN /TENENCIA CON FINES DE COMERCIALIZACIÓN \nNúmero: IPP 11111/2013-0 \nCUIJ: IPP J-01-06066606-6/2013-0 \nActuación Nro: 66600666/2022 \nAUDIENCIA UNIPERSONAL \n(art. 2 bis CPP)\n Fecha: 7 de septiembre de 2020 \n Horario de inicio: 10:00 horas \nPARTICIPANTES \nJuez: Pablo C. Casas. \t\nSecretario: Pablo Hilaire Chaneton.\nFiscal: Cristian Longobardi, UIT Sur.\nDESARROLLO \nJuez: le hace saber al Fiscal que tras haber analizado en forma pormenorizada el caso, lo contactó telefónicamente para realizar esta audiencia frente a la necesidad de solicitar algunas aclaraciones y precisiones atinentes a la prueba presentada.\nFiscal: refiere que en función de lo solicitado, resolverá e informara sobre las cuestiones señaladas a la mayor brevedad posible.\nJuez: manifiesta que lo tiene presente y que quedará a la espera de tales aclaraciones en torno a la prueba. \n \t\t\t\t\t\t Horario de cierre: 10:15 horas \nJuzgado PCyF No 10 - Tacuarí 138, 7o Piso - juzcyf10@jusbaires.gob.ar - 4014-6821/20 - @jpcyf10 \nJuzgado PCyF No 10 - Tacuarí 138, 7o Piso - juzcyf10@jusbaires.gob.ar - 4014-6821/20 - @jpcyf10", - "labels": [ - { - "text": "5 C", - "start_char": 195, - "end_char": 198, - "attrs": { - "aymurai_label": "ART_INFRINGIDO", - "aymurai_label_subclass": null - } - }, - { - "text": "COMERCIO DE ESTUPEFACIENTES O CUALQUIER MATERIA PRIMA PARA SU PRODUCCIÓN", - "start_char": 201, - "end_char": 273, - "attrs": { - "aymurai_label": "CONDUCTA", - "aymurai_label_subclass": [ - "estupefacientes" - ] - } - }, - { - "text": "11111/2013-0", - "start_char": 327, - "end_char": 339, - "attrs": { - "aymurai_label": "N_EXPTE_EJE", - "aymurai_label_subclass": null - } - }, - { - "text": "7 de septiembre de 2020", - "start_char": 453, - "end_char": 476, - "attrs": { - "aymurai_label": "FECHA_RESOLUCION", - "aymurai_label_subclass": null - } - }, - { - "text": "10:00", - "start_char": 498, - "end_char": 503, - "attrs": { - "aymurai_label": "HORA_DE_INICIO", - "aymurai_label_subclass": null - } - }, - { - "text": "Pablo C. Casas.", - "start_char": 532, - "end_char": 547, - "attrs": { - "aymurai_label": "NOMBRE", - "aymurai_label_subclass": [ - "firma" - ] - } - }, - { - "text": "Pablo Hilaire Chaneton.", - "start_char": 562, - "end_char": 585, - "attrs": { - "aymurai_label": "NOMBRE", - "aymurai_label_subclass": [ - "otro" - ] - } - }, - { - "text": "Cristian Longobardi,", - "start_char": 594, - "end_char": 614, - "attrs": { - "aymurai_label": "NOMBRE", - "aymurai_label_subclass": [ - "otro" - ] - } - }, - { - "text": "10:15", - "start_char": 1152, - "end_char": 1157, - "attrs": { - "aymurai_label": "HORA_DE_CIERRE", - "aymurai_label_subclass": null - } - } - ] -} \ No newline at end of file diff --git a/test/api/test_file.docx b/test/api/test_file.docx deleted file mode 100644 index 2a0e4c25f668f125922868b31ffb2584f631f866..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4302 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 RJ;X$LsZgqPkDdDM{{Sl)5n=!U diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/api/__init__.py b/tests/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/api/conftest.py b/tests/api/conftest.py new file mode 100644 index 00000000..22dd7a69 --- /dev/null +++ b/tests/api/conftest.py @@ -0,0 +1,140 @@ +import os +from pathlib import Path + +import diskcache +import pytest +from fastapi import FastAPI +from fastapi.testclient import TestClient +from sqlmodel import Session, SQLModel, StaticPool, create_engine + +os.environ.setdefault("DISKCACHE_ROOT", "/tmp/aymurai-test-diskcache") +os.environ.setdefault("AYMURAI_CACHE_BASEPATH", "/tmp/aymurai-test-cache") +os.environ.setdefault("RESOURCES_BASEPATH", "resources") + +from aymurai.api.endpoints.routers.anonymizer import anonymizer +from aymurai.api.endpoints.routers.datapublic import datapublic +from aymurai.api.endpoints.routers.misc import document_extract +from aymurai.database.meta.anonymization.paragraph import AnonymizationParagraphCreate +from aymurai.database.meta.datapublic.paragraph import DataPublicParagraphCreate +from aymurai.database.session import get_session +from aymurai.database.utils import text_to_uuid +from aymurai.meta.api_interfaces import DocLabel +from aymurai.meta.entities import EntityAttributes + + +@pytest.fixture(scope="function") +def app() -> FastAPI: + test_app = FastAPI() + test_app.include_router( + anonymizer.router, + prefix="/anonymizer", + tags=["anonymization/model"], + ) + test_app.include_router( + datapublic.router, + prefix="/datapublic", + tags=["datapublic/model"], + ) + test_app.include_router(document_extract.router, tags=["document"], deprecated=True) + test_app.include_router(document_extract.router, prefix="/misc", tags=["document"]) + return test_app + + +@pytest.fixture(scope="function", autouse=True) +def isolated_diskcache(tmp_path): + from aymurai.utils import cache as cache_module + + original_cache = cache_module.cache + test_cache = diskcache.Cache(str(tmp_path / "diskcache")) + cache_module.cache = test_cache + try: + yield test_cache + finally: + cache_module.cache = original_cache + test_cache.close() + + +@pytest.fixture(scope="function") +def db_engine(): + test_engine = create_engine( + "sqlite://", + connect_args={"check_same_thread": False}, + poolclass=StaticPool, + ) + SQLModel.metadata.create_all(test_engine) + + return test_engine + + +@pytest.fixture(scope="function") +def db_session(db_engine): + session = Session(db_engine) + yield session + session.close() + + +@pytest.fixture(scope="function") +def client(app, db_engine): + def override_get_session(): + with Session(db_engine) as session: + yield session + + app.dependency_overrides[get_session] = override_get_session + c = TestClient(app, raise_server_exceptions=False) + try: + yield c + finally: + c.close() + app.dependency_overrides.clear() + + +@pytest.fixture(scope="session") +def sample_docx(): + return Path("/resources/data/sample/document-01.docx") + + +def build_data_item(text: str = "sample text") -> dict: + return { + "path": "test", + "extension": "docx", + "dataset": "test", + "data": {"doc.text": text}, + "annotations": None, + "predictions": None, + } + + +def build_label(label: str = "PER", value: str = "John Doe") -> DocLabel: + attrs = EntityAttributes(aymurai_label=label) + return DocLabel( + text=value, + start_char=0, + end_char=len(value), + attrs=attrs, + ) + + +def build_anonymization_paragraph( + text: str = "sample text", + prediction: list[DocLabel] | None = None, + validation: list[DocLabel] | None = None, +) -> AnonymizationParagraphCreate: + return AnonymizationParagraphCreate( + id=text_to_uuid(text), + text=text, + prediction=prediction, + validation=validation, + ) + + +def build_datapublic_paragraph( + text: str = "sample text", + prediction: list[DocLabel] | None = None, + validation: list[DocLabel] | None = None, +) -> DataPublicParagraphCreate: + return DataPublicParagraphCreate( + id=text_to_uuid(text), + text=text, + prediction=prediction, + validation=validation, + ) diff --git a/tests/api/routers/__init__.py b/tests/api/routers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/api/routers/anonymizer/__init__.py b/tests/api/routers/anonymizer/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/api/routers/anonymizer/test_anonymizer.py b/tests/api/routers/anonymizer/test_anonymizer.py new file mode 100644 index 00000000..54a627e1 --- /dev/null +++ b/tests/api/routers/anonymizer/test_anonymizer.py @@ -0,0 +1,353 @@ +import json +import subprocess +from unittest.mock import patch + +import pytest + +from aymurai.database.schema import AnonymizationParagraph +from aymurai.database.utils import text_to_uuid +from tests.api.conftest import build_label +from tests.api.routers.conftest import build_mock_pipeline + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_return_prediction_when_text_provided(mock_load_pipeline, client): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + response = client.post( + "/anonymizer/predict", + json={"text": "Sample anonymization text"}, + ) + + assert response.status_code == 200 + data = response.json() + assert "document" in data + assert "labels" in data + assert data["document"] == "Sample anonymization text" + assert isinstance(data["labels"], list) + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_return_cached_prediction_when_text_in_cache( + mock_load_pipeline, client, db_session +): + text = "Cached text with entities" + labels = [build_label("PER", "Juan Pérez").model_dump(mode="json")] + + paragraph_id = text_to_uuid(text) + cached_para = AnonymizationParagraph( + id=paragraph_id, + text=text, + prediction=labels, + ) + db_session.add(cached_para) + db_session.commit() + + response = client.post( + "/anonymizer/predict", + json={"text": text}, + params={"use_cache": True}, + ) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == text + assert data["labels"] == labels + mock_load_pipeline.assert_not_called() + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_store_prediction_in_db_when_use_cache_true( + mock_load_pipeline, client, db_session +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + text = "New prediction to cache" + response = client.post( + "/anonymizer/predict", + json={"text": text}, + params={"use_cache": True}, + ) + + assert response.status_code == 200 + + paragraph_id = text_to_uuid(text) + stored = db_session.get(AnonymizationParagraph, paragraph_id) + assert stored is not None + assert stored.text == text + assert stored.prediction is not None + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_return_cached_result_when_calling_twice(mock_load_pipeline, client): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + text = "Repeated query text" + + response1 = client.post( + "/anonymizer/predict", + json={"text": text}, + params={"use_cache": True}, + ) + data1 = response1.json() + + response2 = client.post( + "/anonymizer/predict", + json={"text": text}, + params={"use_cache": True}, + ) + data2 = response2.json() + + assert response1.status_code == 200 + assert response2.status_code == 200 + assert data1["document"] == data2["document"] + assert data1["labels"] == data2["labels"] + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_return_prediction_without_storing_when_use_cache_false( + mock_load_pipeline, client, db_session +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + text = "No cache storage text" + response = client.post( + "/anonymizer/predict", + json={"text": text}, + params={"use_cache": False}, + ) + + assert response.status_code == 200 + data = response.json() + assert "document" in data + assert "labels" in data + + paragraph_id = text_to_uuid(text) + stored = db_session.get(AnonymizationParagraph, paragraph_id) + assert stored is None + + +@pytest.mark.integration +def test_should_return_422_when_payload_is_invalid_json(client): + response = client.post( + "/anonymizer/predict", + content="not json", + headers={"Content-Type": "application/json"}, + ) + + assert response.status_code == 422 + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_use_cache_by_default_when_param_omitted( + mock_load_pipeline, client, db_session +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + text = "Default cache behavior" + response = client.post( + "/anonymizer/predict", + json={"text": text}, + ) + + assert response.status_code == 200 + + paragraph_id = text_to_uuid(text) + stored = db_session.get(AnonymizationParagraph, paragraph_id) + assert stored is not None + assert stored.text == text + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_isolate_cache_when_different_texts( + mock_load_pipeline, client, db_session +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + text1 = "First text for cache" + text2 = "Second text for cache" + + para1_id = text_to_uuid(text1) + para2_id = text_to_uuid(text2) + + labels1 = [build_label("PER", "Person1").model_dump(mode="json")] + labels2 = [build_label("LOC", "Location1").model_dump(mode="json")] + + para1 = AnonymizationParagraph(id=para1_id, text=text1, prediction=labels1) + para2 = AnonymizationParagraph(id=para2_id, text=text2, prediction=labels2) + + db_session.add_all([para1, para2]) + db_session.commit() + + response1 = client.post( + "/anonymizer/predict", + json={"text": text1}, + params={"use_cache": True}, + ) + + response2 = client.post( + "/anonymizer/predict", + json={"text": text2}, + params={"use_cache": True}, + ) + + assert response1.status_code == 200 + assert response2.status_code == 200 + + data1 = response1.json() + data2 = response2.json() + + assert data1["labels"] == labels1 + assert data2["labels"] == labels2 + assert data1["labels"] != data2["labels"] + + +@pytest.mark.integration +@patch( + "aymurai.api.endpoints.routers.anonymizer.anonymizer.map_canonical_entities_ner_preds" +) +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_canonical_dates") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.build_canonical_entities") +def test_should_disambiguate_and_persist_paragraphs( + mock_build_canonical_entities, + mock_get_canonical_dates, + mock_map_canonical_entities, + client, + db_session, +): + mock_build_canonical_entities.return_value = [] + mock_get_canonical_dates.return_value = [] + mock_map_canonical_entities.side_effect = ( + lambda predictions, canonical_entities: predictions + ) + + text = "Ana Pérez denunció en el juzgado." + body = { + "paragraphs": [ + { + "document": text, + "labels": [build_label("PER", "Ana Pérez").model_dump(mode="json")], + } + ], + "label_policies": { + "PER": {"anonymize": True, "disambiguation": "none"}, + }, + } + + response = client.post("/anonymizer/disambiguate", json=body) + + assert response.status_code == 200 + payload = response.json() + assert payload["label_policies"]["PER"]["disambiguation"] == "none" + assert payload["data"][0]["labels"][0]["attrs"]["aymurai_disambiguation"] == "none" + assert payload["data"][0]["labels"][0]["attrs"]["aymurai_anonymize"] is True + + paragraph_id = text_to_uuid(text) + stored = db_session.get(AnonymizationParagraph, paragraph_id) + assert stored is not None + assert stored.prediction is not None + assert stored.prediction[0]["text"] == "Ana Pérez" + + +@pytest.mark.integration +def test_should_return_null_validation_when_paragraph_not_found(client): + response = client.post( + "/anonymizer/validation", + json={"text": "Paragraph without validation"}, + ) + + assert response.status_code == 200 + assert response.json() is None + + +@pytest.mark.integration +def test_should_return_validation_when_paragraph_exists(client, db_session): + text = "Validated paragraph" + labels = [build_label("PER", "María Soto").model_dump(mode="json")] + db_session.add( + AnonymizationParagraph( + id=text_to_uuid(text), + text=text, + validation=labels, + ) + ) + db_session.commit() + + response = client.post("/anonymizer/validation", json={"text": text}) + + assert response.status_code == 200 + assert response.json() == labels + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") +def test_should_anonymize_document_when_annotations_are_valid( + mock_check_output, client +): + def fake_convert(*args, **kwargs): + cmd = args[0] + source_path = cmd[-1] + output_path = source_path.rsplit(".", 1)[0] + ".odt" + with open(output_path, "wb") as output_file: + output_file.write(b"odt-content") + return "ok" + + mock_check_output.side_effect = fake_convert + annotations = { + "data": [ + { + "document": "Ana Pérez denunció en el juzgado.", + "labels": [build_label("PER", "Ana Pérez").model_dump(mode="json")], + } + ], + "label_policies": {"PER": {"anonymize": True, "disambiguation": "fuzzy"}}, + "render_policy": {"suffix_mode": "auto", "suffix_threshold": 1}, + } + + response = client.post( + "/anonymizer/anonymize-document", + data={"annotations": json.dumps(annotations)}, + files={"file": ("sample.txt", b"input-document", "text/plain")}, + ) + + assert response.status_code == 200 + assert response.headers["content-type"] == "application/octet-stream" + assert len(response.content) > 0 + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") +def test_should_return_500_when_anonymize_document_conversion_fails( + mock_check_output, client +): + mock_check_output.side_effect = subprocess.CalledProcessError( + 1, + ["libreoffice"], + output=b"conversion failed", + ) + annotations = { + "data": [{"document": "text", "labels": []}], + "label_policies": None, + "render_policy": {"suffix_mode": "auto", "suffix_threshold": 1}, + } + + response = client.post( + "/anonymizer/anonymize-document", + data={"annotations": json.dumps(annotations)}, + files={"file": ("sample.txt", b"input-document", "text/plain")}, + ) + + assert response.status_code == 500 diff --git a/tests/api/routers/conftest.py b/tests/api/routers/conftest.py new file mode 100644 index 00000000..c60de7a0 --- /dev/null +++ b/tests/api/routers/conftest.py @@ -0,0 +1,27 @@ +from unittest.mock import MagicMock + +from tests.api.conftest import build_label + + +def build_mock_pipeline(): + mock = MagicMock() + + mock.preprocess.side_effect = lambda item: item + + def predict_single_impl(item): + item["predictions"] = {"entities": [build_label().model_dump(mode="json")]} + return item + + mock.predict_single.side_effect = predict_single_impl + + mock.postprocess.side_effect = lambda items: items + + return mock + + +def build_processed_data_item(text: str = "sample", labels: list | None = None): + return { + "path": "empty", + "data": {"doc.text": text}, + "predictions": {"entities": labels or []}, + } diff --git a/tests/api/routers/datapublic/__init__.py b/tests/api/routers/datapublic/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/api/routers/datapublic/test_datapublic.py b/tests/api/routers/datapublic/test_datapublic.py new file mode 100644 index 00000000..69be0111 --- /dev/null +++ b/tests/api/routers/datapublic/test_datapublic.py @@ -0,0 +1,233 @@ +import uuid +from unittest.mock import patch + +import pytest + +from aymurai.database.schema import ( + DataPublicDocument, + DataPublicDocumentParagraph, + DataPublicParagraph, +) +from aymurai.database.utils import text_to_uuid +from tests.api.conftest import build_label +from tests.api.routers.conftest import build_mock_pipeline + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.datapublic.datapublic.load_pipeline") +def test_should_return_prediction_when_valid_document_id_and_text( + mock_load_pipeline, client +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-predict-valid") + response = client.post( + f"/datapublic/predict/{document_id}", + json={"text": "Sample datapublic text"}, + params={"use_cache": False}, + ) + + assert response.status_code == 200 + data = response.json() + assert "document" in data + assert "labels" in data + assert data["document"] == "Sample datapublic text" + assert isinstance(data["labels"], list) + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.datapublic.datapublic.load_pipeline") +def test_should_return_cached_prediction_when_text_in_cache( + mock_load_pipeline, client, db_session +): + text = "Cached datapublic text" + labels = [build_label("PER", "Juan González").model_dump(mode="json")] + + paragraph_id = text_to_uuid(text) + cached_para = DataPublicParagraph( + id=paragraph_id, + text=text, + prediction=labels, + ) + db_session.add(cached_para) + db_session.commit() + + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-cached-text") + response = client.post( + f"/datapublic/predict/{document_id}", + json={"text": text}, + params={"use_cache": True}, + ) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == text + assert data["labels"] == labels + mock_load_pipeline.assert_not_called() + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.datapublic.datapublic.load_pipeline") +def test_should_store_paragraph_and_document_when_use_cache_true( + mock_load_pipeline, client, db_session +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-store-cache-true") + text = "New datapublic paragraph" + + response = client.post( + f"/datapublic/predict/{document_id}", + json={"text": text}, + params={"use_cache": True}, + ) + + assert response.status_code == 200 + + paragraph_id = text_to_uuid(text) + stored_para = db_session.get(DataPublicParagraph, paragraph_id) + assert stored_para is not None + assert stored_para.text == text + assert stored_para.prediction is not None + + stored_doc = db_session.get(DataPublicDocument, document_id) + assert stored_doc is not None + + stored_link = ( + db_session.query(DataPublicDocumentParagraph) + .filter_by( + paragraph_id=paragraph_id, + document_id=document_id, + ) + .first() + ) + assert stored_link is not None + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.datapublic.datapublic.load_pipeline") +def test_should_return_prediction_without_storing_when_use_cache_false( + mock_load_pipeline, client, db_session +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-cache-false") + text = "No datapublic storage text" + + response = client.post( + f"/datapublic/predict/{document_id}", + json={"text": text}, + params={"use_cache": False}, + ) + + assert response.status_code == 200 + data = response.json() + assert "document" in data + assert "labels" in data + + paragraph_id = text_to_uuid(text) + stored = db_session.get(DataPublicParagraph, paragraph_id) + assert stored is None + + +@pytest.mark.integration +def test_should_return_422_when_document_id_not_uuid(client): + response = client.post( + "/datapublic/predict/not-a-uuid", + json={"text": "Sample text"}, + ) + + assert response.status_code == 422 + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.datapublic.datapublic.load_pipeline") +def test_should_associate_multiple_paragraphs_with_same_document( + mock_load_pipeline, client, db_session +): + mock_pipeline = build_mock_pipeline() + mock_load_pipeline.return_value = mock_pipeline + + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-associate-paragraphs") + text1 = "First paragraph for association" + text2 = "Second paragraph for association" + + response1 = client.post( + f"/datapublic/predict/{document_id}", + json={"text": text1}, + params={"use_cache": True}, + ) + + response2 = client.post( + f"/datapublic/predict/{document_id}", + json={"text": text2}, + params={"use_cache": True}, + ) + + assert response1.status_code == 200 + assert response2.status_code == 200 + + para1_id = text_to_uuid(text1) + para2_id = text_to_uuid(text2) + + stored_doc = db_session.get(DataPublicDocument, document_id) + assert stored_doc is not None + + links = ( + db_session.query(DataPublicDocumentParagraph) + .filter_by(document_id=document_id) + .all() + ) + assert len(links) == 2 + + link_para_ids = {link.paragraph_id for link in links} + assert para1_id in link_para_ids + assert para2_id in link_para_ids + + +@pytest.mark.integration +def test_should_return_404_when_validation_document_not_found(client): + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-validation-missing") + + response = client.get(f"/datapublic/validation/document/{document_id}") + + assert response.status_code == 404 + + +@pytest.mark.integration +def test_should_return_none_when_validation_not_set(client, db_session): + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-validation-empty") + db_session.add(DataPublicDocument(id=document_id)) + db_session.commit() + + response = client.get(f"/datapublic/validation/document/{document_id}") + + assert response.status_code == 200 + assert response.json() is None + + +@pytest.mark.integration +def test_should_upsert_and_read_document_validation(client, db_session): + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-validation-upsert") + payload = { + "materia": "penal", + "violencia_de_genero": "si", + "resolucion": {"tipo": "sentencia"}, + } + + post_response = client.post( + f"/datapublic/validation/document/{document_id}", + json=payload, + ) + assert post_response.status_code == 200 + + stored_doc = db_session.get(DataPublicDocument, document_id) + assert stored_doc is not None + assert stored_doc.validation == payload + + get_response = client.get(f"/datapublic/validation/document/{document_id}") + assert get_response.status_code == 200 + assert get_response.json() == payload diff --git a/tests/api/routers/misc/__init__.py b/tests/api/routers/misc/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/api/routers/misc/test_document_extract.py b/tests/api/routers/misc/test_document_extract.py new file mode 100644 index 00000000..6a67fdd6 --- /dev/null +++ b/tests/api/routers/misc/test_document_extract.py @@ -0,0 +1,303 @@ +import concurrent.futures +import io +from unittest.mock import patch + +import pytest + +from aymurai.database.utils import data_to_uuid + + +def _build_docx_bytes(paragraphs: list[str]) -> bytes: + import docx + + document = docx.Document() + for paragraph in paragraphs: + document.add_paragraph(paragraph) + + stream = io.BytesIO() + document.save(stream) + return stream.getvalue() + + +def _build_pdf_bytes(paragraphs: list[str]) -> bytes: + import pymupdf + + pdf_document = pymupdf.open() + page = pdf_document.new_page() # type: ignore + for index, paragraph in enumerate(paragraphs): + page.insert_text((72, 72 + (index * 36)), paragraph) + + try: + to_bytes = getattr(pdf_document, "tobytes", None) + if callable(to_bytes): + serialized = to_bytes() + if isinstance(serialized, bytes): + return serialized + raise TypeError("Expected bytes from pymupdf tobytes()") + + serialized = pdf_document.write() + if isinstance(serialized, bytes): + return serialized + raise TypeError("Expected bytes from pymupdf write()") + finally: + pdf_document.close() + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_extract_real_text_from_sample_docx_without_mocking(client): + """Test that a generated DOCX is extracted without mocking.""" + expected_paragraphs = [ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.", + ] + file_content = _build_docx_bytes(expected_paragraphs) + files = { + "file": ( + "sample.docx", + file_content, + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + + response = client.post("/document-extract", files=files) + + assert response.status_code == 200 + data = response.json() + assert data["document_id"] == str(data_to_uuid(file_content)) + assert data["document"] + extracted_text = " ".join(data["document"]) + for paragraph in expected_paragraphs: + assert paragraph in extracted_text + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_extract_real_text_from_pdf_without_mocking(client): + """Test that a real PDF upload is extracted without mocking.""" + expected_paragraphs = [ + "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.", + ] + file_content = _build_pdf_bytes(expected_paragraphs) + files = { + "file": ( + "sample.pdf", + file_content, + "application/pdf", + ) + } + + response = client.post("/document-extract", files=files) + + assert response.status_code == 200 + data = response.json() + assert data["document_id"] == str(data_to_uuid(file_content)) + assert data["document"] + extracted_text = " ".join(data["document"]) + for paragraph in expected_paragraphs: + assert paragraph in extracted_text + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_return_document_with_paragraphs_when_uploading_docx( + mock_extraction, client +): + """Test that document extraction returns paragraphs in response.""" + mock_extraction.return_value = "Para 1\nPara 2\nPara 3" + + files = { + "file": ( + "test.docx", + b"test content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/document-extract", files=files) + + assert response.status_code == 200 + data = response.json() + assert "document" in data + assert "document_id" in data + assert isinstance(data["document"], list) + assert len(data["document"]) == 3 + assert data["document"] == ["Para 1", "Para 2", "Para 3"] + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_return_document_via_misc_prefix_when_uploading(mock_extraction, client): + """Test that /misc/document-extract endpoint works.""" + mock_extraction.return_value = "Sample text" + + files = { + "file": ( + "test.docx", + b"content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/misc/document-extract", files=files) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == ["Sample text"] + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_return_document_via_deprecated_alias_when_uploading( + mock_extraction, client +): + """Test that deprecated /document-extract alias is still available.""" + mock_extraction.return_value = "Alias text" + + files = { + "file": ( + "test.docx", + b"content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/document-extract", files=files) + + assert response.status_code == 200 + assert response.json()["document"] == ["Alias text"] + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_return_deterministic_id_when_uploading_same_file_twice( + mock_extraction, client +): + """Test that same file bytes produce same document_id.""" + mock_extraction.return_value = "Same content" + + file_content = b"identical content" + files = { + "file": ( + "test.docx", + file_content, + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + + response1 = client.post("/document-extract", files=files) + data1 = response1.json() + + # Reset mock and upload same file again + response2 = client.post("/document-extract", files=files) + data2 = response2.json() + + assert response1.status_code == 200 + assert response2.status_code == 200 + assert data1["document_id"] == data2["document_id"] + + +@pytest.mark.integration +def test_should_return_422_when_no_file_provided(client): + """Test that missing file returns 422 Unprocessable Entity.""" + response = client.post("/document-extract", files={}) + + assert response.status_code == 422 + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_return_empty_document_when_file_is_empty(mock_extraction, client): + """Test that empty extraction returns empty document list.""" + mock_extraction.return_value = "" + + files = { + "file": ( + "test.docx", + b"content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/document-extract", files=files) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == [] + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_collapse_consecutive_duplicates_when_extracting( + mock_extraction, client +): + """Test that consecutive duplicate paragraphs are collapsed.""" + mock_extraction.return_value = "A\nA\nB\nB\nB\nC" + + files = { + "file": ( + "test.docx", + b"content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/document-extract", files=files) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == ["A", "B", "C"] + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_normalize_whitespace_when_extracting(mock_extraction, client): + """Test that multiple spaces are normalized to single space.""" + mock_extraction.return_value = "word1 word2 word3" + + files = { + "file": ( + "test.docx", + b"content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/document-extract", files=files) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == ["word1 word2 word3"] + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_return_504_when_extraction_times_out(mock_extraction, client): + """Test that TimeoutError returns 504 Gateway Timeout.""" + mock_extraction.side_effect = concurrent.futures.TimeoutError() + + files = { + "file": ( + "test.docx", + b"content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/document-extract", files=files) + + assert response.status_code == 504 + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_return_500_when_extraction_fails(mock_extraction, client): + """Test that extraction errors return 500 Internal Server Error.""" + mock_extraction.side_effect = Exception("Extraction failed") + + files = { + "file": ( + "test.docx", + b"content", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + } + response = client.post("/document-extract", files=files) + + assert response.status_code == 500 diff --git a/tests/api/routers/test_pipeline_flows.py b/tests/api/routers/test_pipeline_flows.py new file mode 100644 index 00000000..3df22aaa --- /dev/null +++ b/tests/api/routers/test_pipeline_flows.py @@ -0,0 +1,172 @@ +import json +import shutil +import uuid +from unittest.mock import patch + +import pytest + +from aymurai.database.schema import DataPublicDocumentParagraph +from tests.api.routers.conftest import build_mock_pipeline + + +def _fake_libreoffice_convert(*args, **kwargs): + cmd = args[0] + source_path = cmd[-1] + output_path = source_path.rsplit(".", 1)[0] + ".odt" + with open(output_path, "wb") as output_file: + output_file.write(b"odt-content") + return "ok" + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") +@patch( + "aymurai.api.endpoints.routers.anonymizer.anonymizer.map_canonical_entities_ner_preds" +) +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_canonical_dates") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.build_canonical_entities") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_run_anonymizer_flow_end_to_end( + mock_extract, + mock_load_pipeline, + mock_build_canonical_entities, + mock_get_canonical_dates, + mock_map_canonical_entities, + mock_check_output, + client, +): + mock_extract.return_value = "Ana Pérez denunció.\nJuan Soto declaró." + mock_load_pipeline.return_value = build_mock_pipeline() + mock_build_canonical_entities.return_value = [] + mock_get_canonical_dates.return_value = [] + mock_map_canonical_entities.side_effect = lambda predictions, canonical_entities: ( + predictions + ) + mock_check_output.side_effect = _fake_libreoffice_convert + + extract_response = client.post( + "/misc/document-extract", + files={ + "file": ( + "sample.docx", + b"doc-bytes", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + }, + ) + assert extract_response.status_code == 200 + paragraphs = extract_response.json()["document"] + assert len(paragraphs) == 2 + + predictions = [] + for paragraph in paragraphs: + predict_response = client.post("/anonymizer/predict", json={"text": paragraph}) + assert predict_response.status_code == 200 + predictions.append(predict_response.json()) + + disambiguate_response = client.post( + "/anonymizer/disambiguate", + json={ + "paragraphs": predictions, + "label_policies": { + "PER": {"anonymize": True, "disambiguation": "fuzzy"}, + }, + }, + ) + assert disambiguate_response.status_code == 200 + annotations = disambiguate_response.json() + assert len(annotations["data"]) == len(paragraphs) + + compile_response = client.post( + "/anonymizer/anonymize-document", + data={"annotations": json.dumps(annotations)}, + files={"file": ("sample.txt", b"doc-bytes", "text/plain")}, + ) + assert compile_response.status_code == 200 + assert compile_response.headers["content-type"] == "application/octet-stream" + + validation_response = client.post( + "/anonymizer/validation", + json={"text": paragraphs[0]}, + ) + assert validation_response.status_code == 200 + assert isinstance(validation_response.json(), list) + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.datapublic.datapublic.load_pipeline") +@patch("aymurai.api.endpoints.routers.misc.document_extract.run_safe_text_extraction") +def test_should_run_datapublic_flow_end_to_end( + mock_extract, + mock_load_pipeline, + client, + db_session, +): + mock_extract.return_value = "Primera oración.\nSegunda oración." + mock_load_pipeline.return_value = build_mock_pipeline() + + extract_response = client.post( + "/misc/document-extract", + files={ + "file": ( + "sample.docx", + b"doc-bytes", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + }, + ) + assert extract_response.status_code == 200 + paragraphs = extract_response.json()["document"] + assert len(paragraphs) == 2 + + document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-e2e-flow") + for paragraph in paragraphs: + predict_response = client.post( + f"/datapublic/predict/{document_id}", + json={"text": paragraph}, + ) + assert predict_response.status_code == 200 + + links = ( + db_session.query(DataPublicDocumentParagraph) + .filter_by(document_id=document_id) + .all() + ) + assert len(links) == len(paragraphs) + + validation_payload = {"materia": "penal", "violencia_de_genero": "si"} + save_response = client.post( + f"/datapublic/validation/document/{document_id}", + json=validation_payload, + ) + assert save_response.status_code == 200 + + read_response = client.get(f"/datapublic/validation/document/{document_id}") + assert read_response.status_code == 200 + assert read_response.json() == validation_payload + + +@pytest.mark.integration +@pytest.mark.slow +@pytest.mark.external +def test_should_compile_anonymized_document_with_real_libreoffice_when_available( + client, +): + if shutil.which("libreoffice") is None: + pytest.skip("LibreOffice binary is required for real compile integration test") + + annotations = { + "data": [{"document": "Texto base para anonimizar.", "labels": []}], + "label_policies": None, + "render_policy": {"suffix_mode": "auto", "suffix_threshold": 1}, + } + + response = client.post( + "/anonymizer/anonymize-document", + data={"annotations": json.dumps(annotations)}, + files={"file": ("sample.txt", b"input-document", "text/plain")}, + ) + + assert response.status_code == 200 + assert response.headers["content-type"] == "application/octet-stream" diff --git a/tests/integration/__init__.py b/tests/integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/pipelines/__init__.py b/tests/integration/pipelines/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/pipelines/conftest.py b/tests/integration/pipelines/conftest.py new file mode 100644 index 00000000..548e9110 --- /dev/null +++ b/tests/integration/pipelines/conftest.py @@ -0,0 +1,63 @@ +import os +from collections.abc import Callable +from typing import TYPE_CHECKING, Any + +import pytest + +if TYPE_CHECKING: + from aymurai.pipeline.pipeline import AymurAIPipeline + +os.environ.setdefault("DISKCACHE_ROOT", "resources/cache/diskcache") +os.environ.setdefault("AYMURAI_CACHE_BASEPATH", "resources/cache/aymurai") + + +PIPELINE_CONFIGS = { + "anonymizer": "resources/pipelines/production/flair-anonymizer", + "datapublic": "resources/pipelines/production/datapublic", +} + + +def load_test_pipeline(name: str) -> "AymurAIPipeline": + from aymurai.pipeline.pipeline import AymurAIPipeline + + if name not in PIPELINE_CONFIGS: + raise ValueError( + f"Unknown pipeline: {name}. Available: {list(PIPELINE_CONFIGS.keys())}" + ) + + path = PIPELINE_CONFIGS[name] + return AymurAIPipeline.load(path, print_config=False) + + +@pytest.fixture(scope="session") +def anonymizer_pipeline() -> "AymurAIPipeline": + return load_test_pipeline("anonymizer") + + +@pytest.fixture(scope="session") +def datapublic_pipeline() -> "AymurAIPipeline": + return load_test_pipeline("datapublic") + + +@pytest.fixture +def sample_text() -> str: + return ( + "El día 15 de marzo de 2023, el Sr. Juan Pérez fue imputado por el delito de " + "lesiones graves. La víctima, María González, declaró en el Juzgado Civil de Buenos Aires." + ) + + +def _build_pipeline_input(text: str) -> dict[str, Any]: + return { + "path": "test", + "extension": "", + "dataset": "", + "data": {"doc.text": text}, + "annotations": None, + "predictions": {}, + } + + +@pytest.fixture +def build_pipeline_input() -> Callable[[str], dict[str, Any]]: + return _build_pipeline_input diff --git a/tests/integration/pipelines/test_anonymizer.py b/tests/integration/pipelines/test_anonymizer.py new file mode 100644 index 00000000..faf461a2 --- /dev/null +++ b/tests/integration/pipelines/test_anonymizer.py @@ -0,0 +1,95 @@ +from typing import Any + +import pytest + +from aymurai.pipeline.pipeline import AymurAIPipeline + + +def _extract_entities(item: dict[str, Any]) -> list[dict[str, Any]]: + predictions = item.get("predictions") + if isinstance(predictions, dict): + entities = predictions.get("entities") or [] + if isinstance(entities, list): + return [entity for entity in entities if isinstance(entity, dict)] + return [] + + +@pytest.fixture +def input_item(sample_text: str, build_pipeline_input) -> dict[str, Any]: + return build_pipeline_input(sample_text) + + +@pytest.fixture +def preprocessed_item( + anonymizer_pipeline, + input_item: dict[str, Any], +) -> dict[str, Any]: + return anonymizer_pipeline.preprocess([input_item])[0] + + +@pytest.fixture +def predicted_item( + anonymizer_pipeline, + preprocessed_item: dict[str, Any], +) -> dict[str, Any]: + return anonymizer_pipeline.predict_single(preprocessed_item) + + +@pytest.fixture +def postprocessed_item( + anonymizer_pipeline, + predicted_item: dict[str, Any], +) -> dict[str, Any]: + return anonymizer_pipeline.postprocess([predicted_item])[0] + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_load_pipeline_when_given_production_config(anonymizer_pipeline): + assert isinstance(anonymizer_pipeline, AymurAIPipeline) + assert hasattr(anonymizer_pipeline, "pre_process") + assert hasattr(anonymizer_pipeline, "training_pipeline") + assert hasattr(anonymizer_pipeline, "post_process") + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_preprocess_when_given_text_input(preprocessed_item: dict[str, Any]): + assert isinstance(preprocessed_item, dict) + assert "data" in preprocessed_item + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_predict_single_when_given_preprocessed_item( + predicted_item: dict[str, Any], +): + assert isinstance(predicted_item, dict) + assert "predictions" in predicted_item + assert predicted_item["predictions"] is not None + entities = _extract_entities(predicted_item) + assert entities, "Expected at least one anonymizer entity in canonical sample text" + first_entity = entities[0] + assert first_entity.get("text") + assert isinstance(first_entity.get("start_char"), int) + assert isinstance(first_entity.get("end_char"), int) + assert isinstance(first_entity.get("attrs"), dict) + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_postprocess_when_given_predicted_items( + postprocessed_item: dict[str, Any], +): + assert isinstance(postprocessed_item, dict) + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_produce_anonymization_entities_when_running_full_chain( + postprocessed_item: dict[str, Any], +): + result = postprocessed_item + assert "predictions" in result + entities = _extract_entities(result) + assert entities, "Expected postprocess to preserve anonymizer entities" diff --git a/tests/integration/pipelines/test_datapublic.py b/tests/integration/pipelines/test_datapublic.py new file mode 100644 index 00000000..23a0c58b --- /dev/null +++ b/tests/integration/pipelines/test_datapublic.py @@ -0,0 +1,95 @@ +from typing import Any + +import pytest + +from aymurai.pipeline.pipeline import AymurAIPipeline + + +def _extract_entities(item: dict[str, Any]) -> list[dict[str, Any]]: + predictions = item.get("predictions") + if isinstance(predictions, dict): + entities = predictions.get("entities") or [] + if isinstance(entities, list): + return [entity for entity in entities if isinstance(entity, dict)] + return [] + + +@pytest.fixture +def input_item(sample_text: str, build_pipeline_input) -> dict[str, Any]: + return build_pipeline_input(sample_text) + + +@pytest.fixture +def preprocessed_item( + datapublic_pipeline, + input_item: dict[str, Any], +) -> dict[str, Any]: + return datapublic_pipeline.preprocess([input_item])[0] + + +@pytest.fixture +def predicted_item( + datapublic_pipeline, + preprocessed_item: dict[str, Any], +) -> dict[str, Any]: + return datapublic_pipeline.predict_single(preprocessed_item) + + +@pytest.fixture +def postprocessed_item( + datapublic_pipeline, + predicted_item: dict[str, Any], +) -> dict[str, Any]: + return datapublic_pipeline.postprocess([predicted_item])[0] + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_load_pipeline_when_given_production_config(datapublic_pipeline): + assert isinstance(datapublic_pipeline, AymurAIPipeline) + assert hasattr(datapublic_pipeline, "pre_process") + assert hasattr(datapublic_pipeline, "training_pipeline") + assert hasattr(datapublic_pipeline, "post_process") + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_preprocess_when_given_text_input(preprocessed_item: dict[str, Any]): + assert isinstance(preprocessed_item, dict) + assert "data" in preprocessed_item + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_predict_single_when_given_preprocessed_item( + predicted_item: dict[str, Any], +): + assert isinstance(predicted_item, dict) + assert "predictions" in predicted_item + assert predicted_item["predictions"] is not None + entities = _extract_entities(predicted_item) + assert entities, "Expected at least one datapublic entity in canonical sample text" + first_entity = entities[0] + assert first_entity.get("text") + assert isinstance(first_entity.get("start_char"), int) + assert isinstance(first_entity.get("end_char"), int) + assert isinstance(first_entity.get("attrs"), dict) + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_postprocess_when_given_predicted_items( + postprocessed_item: dict[str, Any], +): + assert isinstance(postprocessed_item, dict) + + +@pytest.mark.integration +@pytest.mark.slow +def test_should_produce_entities_when_running_full_chain( + postprocessed_item: dict[str, Any], +): + result = postprocessed_item + assert "predictions" in result + entities = _extract_entities(result) + assert entities, "Expected postprocess to preserve datapublic entities" diff --git a/uv.lock b/uv.lock index 738af2d2..2d4cd1e6 100644 --- a/uv.lock +++ b/uv.lock @@ -1,9 +1,14 @@ version = 1 +revision = 3 requires-python = "==3.10.*" +required-markers = [ + "platform_machine == 'x86_64' and sys_platform == 'linux'", + "platform_machine == 'AMD64' and sys_platform == 'win32'", +] [[package]] name = "accelerate" -version = "1.12.0" +version = "1.13.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, @@ -14,18 +19,18 @@ dependencies = [ { name = "safetensors" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4a/8e/ac2a9566747a93f8be36ee08532eb0160558b07630a081a6056a9f89bf1d/accelerate-1.12.0.tar.gz", hash = "sha256:70988c352feb481887077d2ab845125024b2a137a5090d6d7a32b57d03a45df6", size = 398399 } +sdist = { url = "https://files.pythonhosted.org/packages/ca/14/787e5498cd062640f0f3d92ef4ae4063174f76f9afd29d13fc52a319daae/accelerate-1.13.0.tar.gz", hash = "sha256:d631b4e0f5b3de4aff2d7e9e6857d164810dfc3237d54d017f075122d057b236", size = 402835, upload-time = "2026-03-04T19:34:12.359Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/d2/c581486aa6c4fbd7394c23c47b83fa1a919d34194e16944241daf9e762dd/accelerate-1.12.0-py3-none-any.whl", hash = "sha256:3e2091cd341423207e2f084a6654b1efcd250dc326f2a37d6dde446e07cabb11", size = 380935 }, + { url = "https://files.pythonhosted.org/packages/7e/46/02ac5e262d4af18054b3e922b2baedbb2a03289ee792162de60a865defc5/accelerate-1.13.0-py3-none-any.whl", hash = "sha256:cf1a3efb96c18f7b152eb0fa7490f3710b19c3f395699358f08decca2b8b62e0", size = 383744, upload-time = "2026-03-04T19:34:10.313Z" }, ] [[package]] name = "aiohappyeyeballs" version = "2.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760 } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265 }, + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, ] [[package]] @@ -42,25 +47,25 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556 } +sdist = { url = "https://files.pythonhosted.org/packages/50/42/32cf8e7704ceb4481406eb87161349abb46a57fee3f008ba9cb610968646/aiohttp-3.13.3.tar.gz", hash = "sha256:a949eee43d3782f2daae4f4a2819b2cb9b0c5d3b7f7a927067cc84dafdbb9f88", size = 7844556, upload-time = "2026-01-03T17:33:05.204Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950 }, - { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099 }, - { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072 }, - { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588 }, - { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334 }, - { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656 }, - { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625 }, - { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604 }, - { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370 }, - { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023 }, - { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680 }, - { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407 }, - { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047 }, - { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264 }, - { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275 }, - { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053 }, - { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687 }, + { url = "https://files.pythonhosted.org/packages/36/d6/5aec9313ee6ea9c7cde8b891b69f4ff4001416867104580670a31daeba5b/aiohttp-3.13.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a372fd5afd301b3a89582817fdcdb6c34124787c70dbcc616f259013e7eef7", size = 738950, upload-time = "2026-01-03T17:29:13.002Z" }, + { url = "https://files.pythonhosted.org/packages/68/03/8fa90a7e6d11ff20a18837a8e2b5dd23db01aabc475aa9271c8ad33299f5/aiohttp-3.13.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:147e422fd1223005c22b4fe080f5d93ced44460f5f9c105406b753612b587821", size = 496099, upload-time = "2026-01-03T17:29:15.268Z" }, + { url = "https://files.pythonhosted.org/packages/d2/23/b81f744d402510a8366b74eb420fc0cc1170d0c43daca12d10814df85f10/aiohttp-3.13.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:859bd3f2156e81dd01432f5849fc73e2243d4a487c4fd26609b1299534ee1845", size = 491072, upload-time = "2026-01-03T17:29:16.922Z" }, + { url = "https://files.pythonhosted.org/packages/d5/e1/56d1d1c0dd334cd203dd97706ce004c1aa24b34a813b0b8daf3383039706/aiohttp-3.13.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dca68018bf48c251ba17c72ed479f4dafe9dbd5a73707ad8d28a38d11f3d42af", size = 1671588, upload-time = "2026-01-03T17:29:18.539Z" }, + { url = "https://files.pythonhosted.org/packages/5f/34/8d7f962604f4bc2b4e39eb1220dac7d4e4cba91fb9ba0474b4ecd67db165/aiohttp-3.13.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fee0c6bc7db1de362252affec009707a17478a00ec69f797d23ca256e36d5940", size = 1640334, upload-time = "2026-01-03T17:29:21.028Z" }, + { url = "https://files.pythonhosted.org/packages/94/1d/fcccf2c668d87337ddeef9881537baee13c58d8f01f12ba8a24215f2b804/aiohttp-3.13.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c048058117fd649334d81b4b526e94bde3ccaddb20463a815ced6ecbb7d11160", size = 1722656, upload-time = "2026-01-03T17:29:22.531Z" }, + { url = "https://files.pythonhosted.org/packages/aa/98/c6f3b081c4c606bc1e5f2ec102e87d6411c73a9ef3616fea6f2d5c98c062/aiohttp-3.13.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:215a685b6fbbfcf71dfe96e3eba7a6f58f10da1dfdf4889c7dd856abe430dca7", size = 1817625, upload-time = "2026-01-03T17:29:24.276Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c0/cfcc3d2e11b477f86e1af2863f3858c8850d751ce8dc39c4058a072c9e54/aiohttp-3.13.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2c184bb1fe2cbd2cefba613e9db29a5ab559323f994b6737e370d3da0ac455", size = 1672604, upload-time = "2026-01-03T17:29:26.099Z" }, + { url = "https://files.pythonhosted.org/packages/1e/77/6b4ffcbcac4c6a5d041343a756f34a6dd26174ae07f977a64fe028dda5b0/aiohttp-3.13.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:75ca857eba4e20ce9f546cd59c7007b33906a4cd48f2ff6ccf1ccfc3b646f279", size = 1554370, upload-time = "2026-01-03T17:29:28.121Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f0/e3ddfa93f17d689dbe014ba048f18e0c9f9b456033b70e94349a2e9048be/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81e97251d9298386c2b7dbeb490d3d1badbdc69107fb8c9299dd04eb39bddc0e", size = 1642023, upload-time = "2026-01-03T17:29:30.002Z" }, + { url = "https://files.pythonhosted.org/packages/eb/45/c14019c9ec60a8e243d06d601b33dcc4fd92379424bde3021725859d7f99/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0e2d366af265797506f0283487223146af57815b388623f0357ef7eac9b209d", size = 1649680, upload-time = "2026-01-03T17:29:31.782Z" }, + { url = "https://files.pythonhosted.org/packages/9c/fd/09c9451dae5aa5c5ed756df95ff9ef549d45d4be663bafd1e4954fd836f0/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4e239d501f73d6db1522599e14b9b321a7e3b1de66ce33d53a765d975e9f4808", size = 1692407, upload-time = "2026-01-03T17:29:33.392Z" }, + { url = "https://files.pythonhosted.org/packages/a6/81/938bc2ec33c10efd6637ccb3d22f9f3160d08e8f3aa2587a2c2d5ab578eb/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0db318f7a6f065d84cb1e02662c526294450b314a02bd9e2a8e67f0d8564ce40", size = 1543047, upload-time = "2026-01-03T17:29:34.855Z" }, + { url = "https://files.pythonhosted.org/packages/f7/23/80488ee21c8d567c83045e412e1d9b7077d27171591a4eb7822586e8c06a/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:bfc1cc2fe31a6026a8a88e4ecfb98d7f6b1fec150cfd708adbfd1d2f42257c29", size = 1715264, upload-time = "2026-01-03T17:29:36.389Z" }, + { url = "https://files.pythonhosted.org/packages/e2/83/259a8da6683182768200b368120ab3deff5370bed93880fb9a3a86299f34/aiohttp-3.13.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af71fff7bac6bb7508956696dce8f6eec2bbb045eceb40343944b1ae62b5ef11", size = 1657275, upload-time = "2026-01-03T17:29:38.162Z" }, + { url = "https://files.pythonhosted.org/packages/3f/4f/2c41f800a0b560785c10fb316216ac058c105f9be50bdc6a285de88db625/aiohttp-3.13.3-cp310-cp310-win32.whl", hash = "sha256:37da61e244d1749798c151421602884db5270faf479cf0ef03af0ff68954c9dd", size = 434053, upload-time = "2026-01-03T17:29:40.074Z" }, + { url = "https://files.pythonhosted.org/packages/80/df/29cd63c7ecfdb65ccc12f7d808cac4fa2a19544660c06c61a4a48462de0c/aiohttp-3.13.3-cp310-cp310-win_amd64.whl", hash = "sha256:7e63f210bc1b57ef699035f2b4b6d9ce096b5914414a49b0997c839b2bd2223c", size = 456687, upload-time = "2026-01-03T17:29:41.819Z" }, ] [[package]] @@ -71,9 +76,9 @@ dependencies = [ { name = "frozenlist" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007 } +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490 }, + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, ] [[package]] @@ -86,27 +91,27 @@ dependencies = [ { name = "tomli" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725 } +sdist = { url = "https://files.pythonhosted.org/packages/94/13/8b084e0f2efb0275a1d534838844926f798bd766566b1375174e2448cd31/alembic-1.18.4.tar.gz", hash = "sha256:cb6e1fd84b6174ab8dbb2329f86d631ba9559dd78df550b57804d607672cedbc", size = 2056725, upload-time = "2026-02-10T16:00:47.195Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/29/6533c317b74f707ea28f8d633734dbda2119bbadfc61b2f3640ba835d0f7/alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", size = 263893 }, + { url = "https://files.pythonhosted.org/packages/d2/29/6533c317b74f707ea28f8d633734dbda2119bbadfc61b2f3640ba835d0f7/alembic-1.18.4-py3-none-any.whl", hash = "sha256:a5ed4adcf6d8a4cb575f3d759f071b03cd6e5c7618eb796cb52497be25bfe19a", size = 263893, upload-time = "2026-02-10T16:00:49.997Z" }, ] [[package]] name = "annotated-doc" version = "0.0.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288 } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303 }, + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, ] [[package]] name = "annotated-types" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, ] [[package]] @@ -118,18 +123,18 @@ dependencies = [ { name = "idna" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685 } +sdist = { url = "https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz", hash = "sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size = 228685, upload-time = "2026-01-06T11:45:21.246Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592 }, + { url = "https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl", hash = "sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size = 113592, upload-time = "2026-01-06T11:45:19.497Z" }, ] [[package]] name = "appnope" version = "0.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, ] [[package]] @@ -139,9 +144,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "argon2-cffi-bindings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/89/ce5af8a7d472a67cc819d5d998aa8c82c5d860608c4db9f46f1162d7dab9/argon2_cffi-25.1.0.tar.gz", hash = "sha256:694ae5cc8a42f4c4e2bf2ca0e64e51e23a040c6a517a85074683d3959e1346c1", size = 45706, upload-time = "2025-06-03T06:55:32.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657 }, + { url = "https://files.pythonhosted.org/packages/4f/d3/a8b22fa575b297cd6e3e3b0155c7e25db170edf1c74783d6a31a2490b8d9/argon2_cffi-25.1.0-py3-none-any.whl", hash = "sha256:fdc8b074db390fccb6eb4a3604ae7231f219aa669a2652e0f20e16ba513d5741", size = 14657, upload-time = "2025-06-03T06:55:30.804Z" }, ] [[package]] @@ -151,23 +156,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441 } +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/db8af0df73c1cf454f71b2bbe5e356b8c1f8041c979f505b3d3186e520a9/argon2_cffi_bindings-25.1.0.tar.gz", hash = "sha256:b957f3e6ea4d55d820e40ff76f450952807013d361a65d7f28acc0acbf29229d", size = 1783441, upload-time = "2025-07-30T10:02:05.147Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121 }, - { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177 }, - { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090 }, - { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246 }, - { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126 }, - { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343 }, - { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777 }, - { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180 }, - { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715 }, - { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149 }, - { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549 }, - { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539 }, - { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467 }, - { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355 }, - { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187 }, + { url = "https://files.pythonhosted.org/packages/1d/57/96b8b9f93166147826da5f90376e784a10582dd39a393c99bb62cfcf52f0/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:aecba1723ae35330a008418a91ea6cfcedf6d31e5fbaa056a166462ff066d500", size = 54121, upload-time = "2025-07-30T10:01:50.815Z" }, + { url = "https://files.pythonhosted.org/packages/0a/08/a9bebdb2e0e602dde230bdde8021b29f71f7841bd54801bcfd514acb5dcf/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2630b6240b495dfab90aebe159ff784d08ea999aa4b0d17efa734055a07d2f44", size = 29177, upload-time = "2025-07-30T10:01:51.681Z" }, + { url = "https://files.pythonhosted.org/packages/b6/02/d297943bcacf05e4f2a94ab6f462831dc20158614e5d067c35d4e63b9acb/argon2_cffi_bindings-25.1.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:7aef0c91e2c0fbca6fc68e7555aa60ef7008a739cbe045541e438373bc54d2b0", size = 31090, upload-time = "2025-07-30T10:01:53.184Z" }, + { url = "https://files.pythonhosted.org/packages/c1/93/44365f3d75053e53893ec6d733e4a5e3147502663554b4d864587c7828a7/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e021e87faa76ae0d413b619fe2b65ab9a037f24c60a1e6cc43457ae20de6dc6", size = 81246, upload-time = "2025-07-30T10:01:54.145Z" }, + { url = "https://files.pythonhosted.org/packages/09/52/94108adfdd6e2ddf58be64f959a0b9c7d4ef2fa71086c38356d22dc501ea/argon2_cffi_bindings-25.1.0-cp39-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d3e924cfc503018a714f94a49a149fdc0b644eaead5d1f089330399134fa028a", size = 87126, upload-time = "2025-07-30T10:01:55.074Z" }, + { url = "https://files.pythonhosted.org/packages/72/70/7a2993a12b0ffa2a9271259b79cc616e2389ed1a4d93842fac5a1f923ffd/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87b72589133f0346a1cb8d5ecca4b933e3c9b64656c9d175270a000e73b288d", size = 80343, upload-time = "2025-07-30T10:01:56.007Z" }, + { url = "https://files.pythonhosted.org/packages/78/9a/4e5157d893ffc712b74dbd868c7f62365618266982b64accab26bab01edc/argon2_cffi_bindings-25.1.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:1db89609c06afa1a214a69a462ea741cf735b29a57530478c06eb81dd403de99", size = 86777, upload-time = "2025-07-30T10:01:56.943Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/15777dfde1c29d96de7f18edf4cc94c385646852e7c7b0320aa91ccca583/argon2_cffi_bindings-25.1.0-cp39-abi3-win32.whl", hash = "sha256:473bcb5f82924b1becbb637b63303ec8d10e84c8d241119419897a26116515d2", size = 27180, upload-time = "2025-07-30T10:01:57.759Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c6/a759ece8f1829d1f162261226fbfd2c6832b3ff7657384045286d2afa384/argon2_cffi_bindings-25.1.0-cp39-abi3-win_amd64.whl", hash = "sha256:a98cd7d17e9f7ce244c0803cad3c23a7d379c301ba618a5fa76a67d116618b98", size = 31715, upload-time = "2025-07-30T10:01:58.56Z" }, + { url = "https://files.pythonhosted.org/packages/42/b9/f8d6fa329ab25128b7e98fd83a3cb34d9db5b059a9847eddb840a0af45dd/argon2_cffi_bindings-25.1.0-cp39-abi3-win_arm64.whl", hash = "sha256:b0fdbcf513833809c882823f98dc2f931cf659d9a1429616ac3adebb49f5db94", size = 27149, upload-time = "2025-07-30T10:01:59.329Z" }, + { url = "https://files.pythonhosted.org/packages/11/2d/ba4e4ca8d149f8dcc0d952ac0967089e1d759c7e5fcf0865a317eb680fbb/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:6dca33a9859abf613e22733131fc9194091c1fa7cb3e131c143056b4856aa47e", size = 24549, upload-time = "2025-07-30T10:02:00.101Z" }, + { url = "https://files.pythonhosted.org/packages/5c/82/9b2386cc75ac0bd3210e12a44bfc7fd1632065ed8b80d573036eecb10442/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:21378b40e1b8d1655dd5310c84a40fc19a9aa5e6366e835ceb8576bf0fea716d", size = 25539, upload-time = "2025-07-30T10:02:00.929Z" }, + { url = "https://files.pythonhosted.org/packages/31/db/740de99a37aa727623730c90d92c22c9e12585b3c98c54b7960f7810289f/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5d588dec224e2a83edbdc785a5e6f3c6cd736f46bfd4b441bbb5aa1f5085e584", size = 28467, upload-time = "2025-07-30T10:02:02.08Z" }, + { url = "https://files.pythonhosted.org/packages/71/7a/47c4509ea18d755f44e2b92b7178914f0c113946d11e16e626df8eaa2b0b/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5acb4e41090d53f17ca1110c3427f0a130f944b896fc8c83973219c97f57b690", size = 27355, upload-time = "2025-07-30T10:02:02.867Z" }, + { url = "https://files.pythonhosted.org/packages/ee/82/82745642d3c46e7cea25e1885b014b033f4693346ce46b7f47483cf5d448/argon2_cffi_bindings-25.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:da0c79c23a63723aa5d782250fbf51b768abca630285262fb5144ba5ae01e520", size = 29187, upload-time = "2025-07-30T10:02:03.674Z" }, ] [[package]] @@ -178,18 +183,18 @@ dependencies = [ { name = "python-dateutil" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931 } +sdist = { url = "https://files.pythonhosted.org/packages/b9/33/032cdc44182491aa708d06a68b62434140d8c50820a087fac7af37703357/arrow-1.4.0.tar.gz", hash = "sha256:ed0cc050e98001b8779e84d461b0098c4ac597e88704a655582b21d116e526d7", size = 152931, upload-time = "2025-10-18T17:46:46.761Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797 }, + { url = "https://files.pythonhosted.org/packages/ed/c9/d7977eaacb9df673210491da99e6a247e93df98c715fc43fd136ce1d3d33/arrow-1.4.0-py3-none-any.whl", hash = "sha256:749f0769958ebdc79c173ff0b0670d59051a535fa26e8eba02953dc19eb43205", size = 68797, upload-time = "2025-10-18T17:46:45.663Z" }, ] [[package]] name = "asttokens" version = "3.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308 } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047 }, + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, ] [[package]] @@ -199,32 +204,31 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/8a/ca724066c32a53fa75f59e0f21aa822fdaa8a0dffa112d223634e3caabf9/async_lru-2.2.0.tar.gz", hash = "sha256:80abae2a237dbc6c60861d621619af39f0d920aea306de34cb992c879e01370c", size = 14654 } +sdist = { url = "https://files.pythonhosted.org/packages/05/8a/ca724066c32a53fa75f59e0f21aa822fdaa8a0dffa112d223634e3caabf9/async_lru-2.2.0.tar.gz", hash = "sha256:80abae2a237dbc6c60861d621619af39f0d920aea306de34cb992c879e01370c", size = 14654, upload-time = "2026-02-20T19:11:43.848Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/5c/af990f019b8dd11c5492a6371fe74a5b0276357370030b67254a87329944/async_lru-2.2.0-py3-none-any.whl", hash = "sha256:e2c1cf731eba202b59c5feedaef14ffd9d02ad0037fcda64938699f2c380eafe", size = 7890 }, + { url = "https://files.pythonhosted.org/packages/13/5c/af990f019b8dd11c5492a6371fe74a5b0276357370030b67254a87329944/async_lru-2.2.0-py3-none-any.whl", hash = "sha256:e2c1cf731eba202b59c5feedaef14ffd9d02ad0037fcda64938699f2c380eafe", size = 7890, upload-time = "2026-02-20T19:11:42.273Z" }, ] [[package]] name = "async-timeout" version = "5.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 }, + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, ] [[package]] name = "attrs" version = "25.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251 } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615 }, + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, ] [[package]] name = "aymurai" -version = "1.5.0rc1" source = { editable = "." } dependencies = [ { name = "alembic" }, @@ -250,7 +254,6 @@ dependencies = [ { name = "python-docx" }, { name = "python-dotenv" }, { name = "python-multipart" }, - { name = "pytorch-lightning" }, { name = "requests" }, { name = "scipy" }, { name = "sentence-transformers" }, @@ -274,6 +277,9 @@ dev = [ { name = "rich" }, { name = "seaborn" }, ] +tests = [ + { name = "pytest" }, +] [package.metadata] requires-dist = [ @@ -300,14 +306,13 @@ requires-dist = [ { name = "python-docx", specifier = ">=1.2.0" }, { name = "python-dotenv", specifier = ">=1.0.1" }, { name = "python-multipart", specifier = ">=0.0.20" }, - { name = "pytorch-lightning", specifier = "==1.8.3.post1" }, { name = "requests", specifier = ">=2.32.3" }, { name = "scipy", specifier = "<1.14.1" }, { name = "sentence-transformers", specifier = ">=2.2.0" }, { name = "sentencepiece", specifier = "==0.2.0" }, { name = "sqlmodel", specifier = "==0.0.22" }, { name = "tenacity", specifier = ">=9.0.0" }, - { name = "torch", specifier = ">=1.13.1" }, + { name = "torch", specifier = ">=2.0" }, { name = "unidecode", specifier = "==1.3.8" }, { name = "uvicorn", specifier = ">=0.34.0" }, { name = "xmltodict", specifier = "==0.14.2" }, @@ -324,14 +329,15 @@ dev = [ { name = "rich", specifier = ">=13.9.4" }, { name = "seaborn", specifier = ">=0.13.2" }, ] +tests = [{ name = "pytest", specifier = ">=9.0.2" }] [[package]] name = "babel" version = "2.18.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554 } +sdist = { url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz", hash = "sha256:b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d", size = 9959554, upload-time = "2026-02-01T12:30:56.078Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845 }, + { url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl", hash = "sha256:e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35", size = 10196845, upload-time = "2026-02-01T12:30:53.445Z" }, ] [[package]] @@ -342,9 +348,9 @@ dependencies = [ { name = "soupsieve" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b0/1c6a16426d389813b48d95e26898aff79abbde42ad353958ad95cc8c9b21/beautifulsoup4-4.14.3.tar.gz", hash = "sha256:6292b1c5186d356bba669ef9f7f051757099565ad9ada5dd630bd9de5fa7fb86", size = 627737, upload-time = "2025-11-30T15:08:26.084Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721 }, + { url = "https://files.pythonhosted.org/packages/1a/39/47f9197bdd44df24d67ac8893641e16f386c984a0619ef2ee4c51fbbc019/beautifulsoup4-4.14.3-py3-none-any.whl", hash = "sha256:0918bfe44902e6ad8d57732ba310582e98da931428d231a5ecb9e7c703a735bb", size = 107721, upload-time = "2025-11-30T15:08:24.087Z" }, ] [[package]] @@ -358,9 +364,9 @@ dependencies = [ { name = "lxml" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924 } +sdist = { url = "https://files.pythonhosted.org/packages/44/9b/90086bbbffcf4aaa267a71e94f92eab1cfe4142198708129b8495e16c73f/bioc-2.1.tar.gz", hash = "sha256:7d9248198bdae291b0ebb218de2dc653c96d32a7eac2fa0ef4ed0c74ce45aaaa", size = 27924, upload-time = "2023-08-15T22:34:59.047Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419 }, + { url = "https://files.pythonhosted.org/packages/4b/05/ae6dcab59673e2d498c645903ded6c5d76f7d44920386285feb96c517b3a/bioc-2.1-py3-none-any.whl", hash = "sha256:f1730d26821330f9f625058841612d6cfb616efb906fc682297fe04dd5d9398a", size = 33419, upload-time = "2023-08-15T22:34:56.022Z" }, ] [[package]] @@ -370,9 +376,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533 } +sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437 }, + { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, ] [package.optional-dependencies] @@ -382,48 +388,48 @@ css = [ [[package]] name = "boto3" -version = "1.42.54" +version = "1.42.66" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4f/53/2e0a325e080bd83f5dfd8f964b70b93badc284bcb5680bee75327771ad4a/boto3-1.42.54.tar.gz", hash = "sha256:fe3d8ec586c39a0c96327fd317c77ca601ec5f991e9ba7211cacae8db4c07a73", size = 112747 } +sdist = { url = "https://files.pythonhosted.org/packages/0a/2e/67206daa5acb6053157ae5241421713a84ed6015d33d0781985bd5558898/boto3-1.42.66.tar.gz", hash = "sha256:3bec5300fb2429c3be8e8961fdb1f11e85195922c8a980022332c20af05616d5", size = 112805, upload-time = "2026-03-11T19:58:19.17Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/d6/695283df0a613cb723a05745cd565061add2bc5655d3493341b8b5c6b81d/boto3-1.42.54-py3-none-any.whl", hash = "sha256:71194e855bfc81a21872cbe29c41f52ffdbe67e0a184a52c13346ef00b328939", size = 140555 }, + { url = "https://files.pythonhosted.org/packages/4c/09/83224363c3f5e468e298e48beb577ffe8cb51f18c2116bc1ecf404796e60/boto3-1.42.66-py3-none-any.whl", hash = "sha256:7c6c60dc5500e8a2967a306372a5fdb4c7f9a5b8adc5eb9aa2ebb5081c51ff47", size = 140557, upload-time = "2026-03-11T19:58:17.61Z" }, ] [[package]] name = "botocore" -version = "1.42.54" +version = "1.42.66" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/9a/5ab14330e5d1c3489e91f32f6ece40f3b58cf82d2aafe1e4a61711f616b0/botocore-1.42.54.tar.gz", hash = "sha256:ab203d4e57d22913c8386a695d048e003b7508a8a4a7a46c9ddf4ebd67a20b69", size = 14921929 } +sdist = { url = "https://files.pythonhosted.org/packages/77/ef/1c8f89da69b0c3742120e19a6ea72ec46ac0596294466924fdd4cf0f36bb/botocore-1.42.66.tar.gz", hash = "sha256:39756a21142b646de552d798dde2105759b0b8fa0d881a34c26d15bd4c9448fa", size = 14977446, upload-time = "2026-03-11T19:58:07.714Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/29/cdf4ba5d0f626b7c5a74d6a615b977469960eae8c67f8e4213941f5f3dfd/botocore-1.42.54-py3-none-any.whl", hash = "sha256:853a0822de66d060aeebafa07ca13a03799f7958313d1b29f8dc7e2e1be8f527", size = 14594249 }, + { url = "https://files.pythonhosted.org/packages/13/6f/7b45ed2ca300c1ad38ecfc82c1368546d4a90512d9dff589ebbd182a7317/botocore-1.42.66-py3-none-any.whl", hash = "sha256:ac48af1ab527dfa08c4617c387413ca56a7f87780d7bfc1da34ef847a59219a5", size = 14653886, upload-time = "2026-03-11T19:58:04.922Z" }, ] [[package]] name = "cachetools" -version = "7.0.1" +version = "7.0.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d4/07/56595285564e90777d758ebd383d6b0b971b87729bbe2184a849932a3736/cachetools-7.0.1.tar.gz", hash = "sha256:e31e579d2c5b6e2944177a0397150d312888ddf4e16e12f1016068f0c03b8341", size = 36126 } +sdist = { url = "https://files.pythonhosted.org/packages/af/dd/57fe3fdb6e65b25a5987fd2cdc7e22db0aef508b91634d2e57d22928d41b/cachetools-7.0.5.tar.gz", hash = "sha256:0cd042c24377200c1dcd225f8b7b12b0ca53cc2c961b43757e774ebe190fd990", size = 37367, upload-time = "2026-03-09T20:51:29.451Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ed/9e/5faefbf9db1db466d633735faceda1f94aa99ce506ac450d232536266b32/cachetools-7.0.1-py3-none-any.whl", hash = "sha256:8f086515c254d5664ae2146d14fc7f65c9a4bce75152eb247e5a9c5e6d7b2ecf", size = 13484 }, + { url = "https://files.pythonhosted.org/packages/06/f3/39cf3367b8107baa44f861dc802cbf16263c945b62d8265d36034fc07bea/cachetools-7.0.5-py3-none-any.whl", hash = "sha256:46bc8ebefbe485407621d0a4264b23c080cedd913921bad7ac3ed2f26c183114", size = 13918, upload-time = "2026-03-09T20:51:27.33Z" }, ] [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.2.25" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268 } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900 }, + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, ] [[package]] @@ -433,54 +439,54 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser", marker = "implementation_name != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283 }, - { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504 }, - { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811 }, - { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402 }, - { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217 }, - { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079 }, - { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475 }, - { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829 }, - { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211 }, - { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036 }, - { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184 }, - { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790 }, + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, ] [[package]] name = "cfgv" version = "3.5.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz", hash = "sha256:d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132", size = 7334, upload-time = "2025-11-19T20:55:51.612Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445 }, + { url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl", hash = "sha256:a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0", size = 7445, upload-time = "2025-11-19T20:55:50.744Z" }, ] [[package]] name = "charset-normalizer" -version = "3.4.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/b8/6d51fc1d52cbd52cd4ccedd5b5b2f0f6a11bbf6765c782298b0f3e808541/charset_normalizer-3.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e824f1492727fa856dd6eda4f7cee25f8518a12f3c4a56a74e8095695089cf6d", size = 209709 }, - { url = "https://files.pythonhosted.org/packages/5c/af/1f9d7f7faafe2ddfb6f72a2e07a548a629c61ad510fe60f9630309908fef/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bd5d4137d500351a30687c2d3971758aac9a19208fc110ccb9d7188fbe709e8", size = 148814 }, - { url = "https://files.pythonhosted.org/packages/79/3d/f2e3ac2bbc056ca0c204298ea4e3d9db9b4afe437812638759db2c976b5f/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:027f6de494925c0ab2a55eab46ae5129951638a49a34d87f4c3eda90f696b4ad", size = 144467 }, - { url = "https://files.pythonhosted.org/packages/ec/85/1bf997003815e60d57de7bd972c57dc6950446a3e4ccac43bc3070721856/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f820802628d2694cb7e56db99213f930856014862f3fd943d290ea8438d07ca8", size = 162280 }, - { url = "https://files.pythonhosted.org/packages/3e/8e/6aa1952f56b192f54921c436b87f2aaf7c7a7c3d0d1a765547d64fd83c13/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:798d75d81754988d2565bff1b97ba5a44411867c0cf32b77a7e8f8d84796b10d", size = 159454 }, - { url = "https://files.pythonhosted.org/packages/36/3b/60cbd1f8e93aa25d1c669c649b7a655b0b5fb4c571858910ea9332678558/charset_normalizer-3.4.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d1bb833febdff5c8927f922386db610b49db6e0d4f4ee29601d71e7c2694313", size = 153609 }, - { url = "https://files.pythonhosted.org/packages/64/91/6a13396948b8fd3c4b4fd5bc74d045f5637d78c9675585e8e9fbe5636554/charset_normalizer-3.4.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9cd98cdc06614a2f768d2b7286d66805f94c48cde050acdbbb7db2600ab3197e", size = 151849 }, - { url = "https://files.pythonhosted.org/packages/b7/7a/59482e28b9981d105691e968c544cc0df3b7d6133152fb3dcdc8f135da7a/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:077fbb858e903c73f6c9db43374fd213b0b6a778106bc7032446a8e8b5b38b93", size = 151586 }, - { url = "https://files.pythonhosted.org/packages/92/59/f64ef6a1c4bdd2baf892b04cd78792ed8684fbc48d4c2afe467d96b4df57/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:244bfb999c71b35de57821b8ea746b24e863398194a4014e4c76adc2bbdfeff0", size = 145290 }, - { url = "https://files.pythonhosted.org/packages/6b/63/3bf9f279ddfa641ffa1962b0db6a57a9c294361cc2f5fcac997049a00e9c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:64b55f9dce520635f018f907ff1b0df1fdc31f2795a922fb49dd14fbcdf48c84", size = 163663 }, - { url = "https://files.pythonhosted.org/packages/ed/09/c9e38fc8fa9e0849b172b581fd9803bdf6e694041127933934184e19f8c3/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:faa3a41b2b66b6e50f84ae4a68c64fcd0c44355741c6374813a800cd6695db9e", size = 151964 }, - { url = "https://files.pythonhosted.org/packages/d2/d1/d28b747e512d0da79d8b6a1ac18b7ab2ecfd81b2944c4c710e166d8dd09c/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6515f3182dbe4ea06ced2d9e8666d97b46ef4c75e326b79bb624110f122551db", size = 161064 }, - { url = "https://files.pythonhosted.org/packages/bb/9a/31d62b611d901c3b9e5500c36aab0ff5eb442043fb3a1c254200d3d397d9/charset_normalizer-3.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc00f04ed596e9dc0da42ed17ac5e596c6ccba999ba6bd92b0e0aef2f170f2d6", size = 155015 }, - { url = "https://files.pythonhosted.org/packages/1f/f3/107e008fa2bff0c8b9319584174418e5e5285fef32f79d8ee6a430d0039c/charset_normalizer-3.4.4-cp310-cp310-win32.whl", hash = "sha256:f34be2938726fc13801220747472850852fe6b1ea75869a048d6f896838c896f", size = 99792 }, - { url = "https://files.pythonhosted.org/packages/eb/66/e396e8a408843337d7315bab30dbf106c38966f1819f123257f5520f8a96/charset_normalizer-3.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:a61900df84c667873b292c3de315a786dd8dac506704dea57bc957bd31e22c7d", size = 107198 }, - { url = "https://files.pythonhosted.org/packages/b5/58/01b4f815bf0312704c267f2ccb6e5d42bcc7752340cd487bc9f8c3710597/charset_normalizer-3.4.4-cp310-cp310-win_arm64.whl", hash = "sha256:cead0978fc57397645f12578bfd2d5ea9138ea0fac82b2f63f7f7c6877986a69", size = 100262 }, - { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402 }, +version = "3.4.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/35/02daf95b9cd686320bb622eb148792655c9412dbb9b67abb5694e5910a24/charset_normalizer-3.4.5.tar.gz", hash = "sha256:95adae7b6c42a6c5b5b559b1a99149f090a57128155daeea91732c8d970d8644", size = 134804, upload-time = "2026-03-06T06:03:19.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/21/a2b1505639008ba2e6ef03733a81fc6cfd6a07ea6139a2b76421230b8dad/charset_normalizer-3.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4167a621a9a1a986c73777dbc15d4b5eac8ac5c10393374109a343d4013ec765", size = 283319, upload-time = "2026-03-06T06:00:26.433Z" }, + { url = "https://files.pythonhosted.org/packages/70/67/df234c29b68f4e1e095885c9db1cb4b69b8aba49cf94fac041db4aaf1267/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3f64c6bf8f32f9133b668c7f7a7cbdbc453412bc95ecdbd157f3b1e377a92990", size = 189974, upload-time = "2026-03-06T06:00:28.222Z" }, + { url = "https://files.pythonhosted.org/packages/df/7f/fc66af802961c6be42e2c7b69c58f95cbd1f39b0e81b3365d8efe2a02a04/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:568e3c34b58422075a1b49575a6abc616d9751b4d61b23f712e12ebb78fe47b2", size = 207866, upload-time = "2026-03-06T06:00:29.769Z" }, + { url = "https://files.pythonhosted.org/packages/c9/23/404eb36fac4e95b833c50e305bba9a241086d427bb2167a42eac7c4f7da4/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:036c079aa08a6a592b82487f97c60b439428320ed1b2ea0b3912e99d30c77765", size = 203239, upload-time = "2026-03-06T06:00:31.086Z" }, + { url = "https://files.pythonhosted.org/packages/4b/2f/8a1d989bfadd120c90114ab33e0d2a0cbde05278c1fc15e83e62d570f50a/charset_normalizer-3.4.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:340810d34ef83af92148e96e3e44cb2d3f910d2bf95e5618a5c467d9f102231d", size = 196529, upload-time = "2026-03-06T06:00:32.608Z" }, + { url = "https://files.pythonhosted.org/packages/a5/0c/c75f85ff7ca1f051958bb518cd43922d86f576c03947a050fbedfdfb4f15/charset_normalizer-3.4.5-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:cd2d0f0ec9aa977a27731a3209ebbcacebebaf41f902bd453a928bfd281cf7f8", size = 184152, upload-time = "2026-03-06T06:00:33.93Z" }, + { url = "https://files.pythonhosted.org/packages/f9/20/4ed37f6199af5dde94d4aeaf577f3813a5ec6635834cda1d957013a09c76/charset_normalizer-3.4.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0b362bcd27819f9c07cbf23db4e0e8cd4b44c5ecd900c2ff907b2b92274a7412", size = 195226, upload-time = "2026-03-06T06:00:35.469Z" }, + { url = "https://files.pythonhosted.org/packages/28/31/7ba1102178cba7c34dcc050f43d427172f389729e356038f0726253dd914/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:77be992288f720306ab4108fe5c74797de327f3248368dfc7e1a916d6ed9e5a2", size = 192933, upload-time = "2026-03-06T06:00:36.83Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/f86443ab3921e6a60b33b93f4a1161222231f6c69bc24fb18f3bee7b8518/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8b78d8a609a4b82c273257ee9d631ded7fac0d875bdcdccc109f3ee8328cfcb1", size = 185647, upload-time = "2026-03-06T06:00:38.367Z" }, + { url = "https://files.pythonhosted.org/packages/82/44/08b8be891760f1f5a6d23ce11d6d50c92981603e6eb740b4f72eea9424e2/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ba20bdf69bd127f66d0174d6f2a93e69045e0b4036dc1ca78e091bcc765830c4", size = 209533, upload-time = "2026-03-06T06:00:41.931Z" }, + { url = "https://files.pythonhosted.org/packages/3b/5f/df114f23406199f8af711ddccfbf409ffbc5b7cdc18fa19644997ff0c9bb/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:76a9d0de4d0eab387822e7b35d8f89367dd237c72e82ab42b9f7bf5e15ada00f", size = 195901, upload-time = "2026-03-06T06:00:43.978Z" }, + { url = "https://files.pythonhosted.org/packages/07/83/71ef34a76fe8aa05ff8f840244bda2d61e043c2ef6f30d200450b9f6a1be/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8fff79bf5978c693c9b1a4d71e4a94fddfb5fe744eb062a318e15f4a2f63a550", size = 204950, upload-time = "2026-03-06T06:00:45.202Z" }, + { url = "https://files.pythonhosted.org/packages/58/40/0253be623995365137d7dc68e45245036207ab2227251e69a3d93ce43183/charset_normalizer-3.4.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c7e84e0c0005e3bdc1a9211cd4e62c78ba80bc37b2365ef4410cd2007a9047f2", size = 198546, upload-time = "2026-03-06T06:00:46.481Z" }, + { url = "https://files.pythonhosted.org/packages/ed/5c/5f3cb5b259a130895ef5ae16b38eaf141430fa3f7af50cd06c5d67e4f7b2/charset_normalizer-3.4.5-cp310-cp310-win32.whl", hash = "sha256:58ad8270cfa5d4bef1bc85bd387217e14ff154d6630e976c6f56f9a040757475", size = 132516, upload-time = "2026-03-06T06:00:47.924Z" }, + { url = "https://files.pythonhosted.org/packages/a5/c3/84fb174e7770f2df2e1a2115090771bfbc2227fb39a765c6d00568d1aab4/charset_normalizer-3.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:02a9d1b01c1e12c27883b0c9349e0bcd9ae92e727ff1a277207e1a262b1cbf05", size = 142906, upload-time = "2026-03-06T06:00:49.389Z" }, + { url = "https://files.pythonhosted.org/packages/d7/b2/6f852f8b969f2cbd0d4092d2e60139ab1af95af9bb651337cae89ec0f684/charset_normalizer-3.4.5-cp310-cp310-win_arm64.whl", hash = "sha256:039215608ac7b358c4da0191d10fc76868567fbf276d54c14721bdedeb6de064", size = 133258, upload-time = "2026-03-06T06:00:51.051Z" }, + { url = "https://files.pythonhosted.org/packages/c5/60/3a621758945513adfd4db86827a5bafcc615f913dbd0b4c2ed64a65731be/charset_normalizer-3.4.5-py3-none-any.whl", hash = "sha256:9db5e3fcdcee89a78c04dffb3fe33c79f77bd741a624946db2591c81b2fc85b0", size = 55455, upload-time = "2026-03-06T06:03:17.827Z" }, ] [[package]] @@ -488,38 +494,50 @@ name = "click" version = "8.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065 } +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274 }, + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, ] [[package]] name = "colorama" version = "0.4.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coloredlogs" +version = "15.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "humanfriendly" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/c7/eed8f27100517e8c0e6b923d5f0845d0cb99763da6fdee00478f91db7325/coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0", size = 278520, upload-time = "2021-06-11T10:22:45.202Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018, upload-time = "2021-06-11T10:22:42.561Z" }, ] [[package]] name = "comm" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294 }, + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, ] [[package]] name = "conllu" version = "4.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768 } +sdist = { url = "https://files.pythonhosted.org/packages/7b/48/3e539bb27777d2204381e6bd352225d02965acce6e5a8d0717e9750dcc77/conllu-4.5.3.tar.gz", hash = "sha256:a016cf77e203b2e3ace82fcf0cba2874530d1458e874521640eba36e19546acc", size = 32768, upload-time = "2023-06-19T12:37:49.632Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098 }, + { url = "https://files.pythonhosted.org/packages/ce/3f/70a1dc5bc536755ec082b806594598a10cfffaf0de978f51d4e0e4fdfa47/conllu-4.5.3-py2.py3-none-any.whl", hash = "sha256:2b962b315c3c575e429105d045c888726df780b87a6dfe7609367e861990902d", size = 16098, upload-time = "2023-06-19T12:37:47.885Z" }, ] [[package]] @@ -529,21 +547,21 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, - { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, - { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061 }, - { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956 }, - { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872 }, - { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027 }, - { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641 }, - { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075 }, - { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534 }, - { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188 }, - { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681 }, - { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101 }, - { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599 }, + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551, upload-time = "2025-04-15T17:34:46.581Z" }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399, upload-time = "2025-04-15T17:34:51.427Z" }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061, upload-time = "2025-04-15T17:34:55.961Z" }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956, upload-time = "2025-04-15T17:35:00.992Z" }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872, upload-time = "2025-04-15T17:35:06.177Z" }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027, upload-time = "2025-04-15T17:35:11.244Z" }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641, upload-time = "2025-04-15T17:35:26.701Z" }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075, upload-time = "2025-04-15T17:35:43.204Z" }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534, upload-time = "2025-04-15T17:35:46.554Z" }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188, upload-time = "2025-04-15T17:35:50.064Z" }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681, upload-time = "2025-04-15T17:44:59.314Z" }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101, upload-time = "2025-04-15T17:45:04.165Z" }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599, upload-time = "2025-04-15T17:45:08.456Z" }, ] [[package]] @@ -554,30 +572,29 @@ dependencies = [ { name = "cuda-pathfinder" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/37/31/bfcc870f69c6a017c4ad5c42316207fc7551940db6f3639aa4466ec5faf3/cuda_bindings-12.9.4-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a022c96b8bd847e8dc0675523431149a4c3e872f440e3002213dbb9e08f0331a", size = 11800959 }, - { url = "https://files.pythonhosted.org/packages/7a/d8/b546104b8da3f562c1ff8ab36d130c8fe1dd6a045ced80b4f6ad74f7d4e1/cuda_bindings-12.9.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d3c842c2a4303b2a580fe955018e31aea30278be19795ae05226235268032e5", size = 12148218 }, + { url = "https://files.pythonhosted.org/packages/7a/d8/b546104b8da3f562c1ff8ab36d130c8fe1dd6a045ced80b4f6ad74f7d4e1/cuda_bindings-12.9.4-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d3c842c2a4303b2a580fe955018e31aea30278be19795ae05226235268032e5", size = 12148218, upload-time = "2025-10-21T14:51:28.855Z" }, ] [[package]] name = "cuda-pathfinder" -version = "1.3.4" +version = "1.4.2" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/5e/db279a3bfbd18d59d0598922a3b3c1454908d0969e8372260afec9736376/cuda_pathfinder-1.3.4-py3-none-any.whl", hash = "sha256:fb983f6e0d43af27ef486e14d5989b5f904ef45cedf40538bfdcbffa6bb01fb2", size = 30878 }, + { url = "https://files.pythonhosted.org/packages/92/de/8ca2b613042550dcf9ef50c596c8b1f602afda92cf9032ac28a73f6ee410/cuda_pathfinder-1.4.2-py3-none-any.whl", hash = "sha256:eb354abc20278f8609dc5b666a24648655bef5613c6dfe78a238a6fd95566754", size = 44779, upload-time = "2026-03-10T21:57:30.974Z" }, ] [[package]] name = "cycler" version = "0.12.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, ] [[package]] name = "datasets" -version = "4.5.0" +version = "4.7.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, @@ -595,9 +612,9 @@ dependencies = [ { name = "tqdm" }, { name = "xxhash" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/bf/bb927bde63d649296c83e883171ae77074717c1b80fe2868b328bd0dbcbb/datasets-4.5.0.tar.gz", hash = "sha256:00c698ce1c2452e646cc5fad47fef39d3fe78dd650a8a6eb205bb45eb63cd500", size = 588384 } +sdist = { url = "https://files.pythonhosted.org/packages/1c/9c/ba18de0b70858533e422ed6cfe0e46789473cef7fc7fc3653e23fa494730/datasets-4.7.0.tar.gz", hash = "sha256:4984cdfc65d04464da7f95205a55cb50515fd94ae3176caacb50a1b7273792e2", size = 602008, upload-time = "2026-03-09T19:01:49.298Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/d5/0d563ea3c205eee226dc8053cf7682a8ac588db8acecd0eda2b587987a0b/datasets-4.5.0-py3-none-any.whl", hash = "sha256:b5d7e08096ffa407dd69e58b1c0271c9b2506140839b8d99af07375ad31b6726", size = 515196 }, + { url = "https://files.pythonhosted.org/packages/1e/03/c6d9c3119cf712f638fe763e887ecaac6acbb62bf1e2acc3cbde0df340fd/datasets-4.7.0-py3-none-any.whl", hash = "sha256:d5fe3025ec6acc3b5649f10d5576dff5e054134927604e6913c1467a04adc3c2", size = 527530, upload-time = "2026-03-09T19:01:47.443Z" }, ] [[package]] @@ -609,31 +626,31 @@ source = { git = "https://github.com/jedzill4/datetime_matcher#0e5793e8d1e3653f7 name = "debugpy" version = "1.8.20" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/cd8080344452e4874aae67c40d8940e2b4d47b01601a8fd9f44786c757c7/debugpy-1.8.20.tar.gz", hash = "sha256:55bc8701714969f1ab89a6d5f2f3d40c36f91b2cbe2f65d98bf8196f6a6a2c33", size = 1645207, upload-time = "2026-01-29T23:03:28.199Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/be/8bd693a0b9d53d48c8978fa5d889e06f3b5b03e45fd1ea1e78267b4887cb/debugpy-1.8.20-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:157e96ffb7f80b3ad36d808646198c90acb46fdcfd8bb1999838f0b6f2b59c64", size = 2099192 }, - { url = "https://files.pythonhosted.org/packages/77/1b/85326d07432086a06361d493d2743edd0c4fc2ef62162be7f8618441ac37/debugpy-1.8.20-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:c1178ae571aff42e61801a38b007af504ec8e05fde1c5c12e5a7efef21009642", size = 3088568 }, - { url = "https://files.pythonhosted.org/packages/e8/60/3e08462ee3eccd10998853eb35947c416e446bfe2bc37dbb886b9044586c/debugpy-1.8.20-cp310-cp310-win32.whl", hash = "sha256:c29dd9d656c0fbd77906a6e6a82ae4881514aa3294b94c903ff99303e789b4a2", size = 5284399 }, - { url = "https://files.pythonhosted.org/packages/72/43/09d49106e770fe558ced5e80df2e3c2ebee10e576eda155dcc5670473663/debugpy-1.8.20-cp310-cp310-win_amd64.whl", hash = "sha256:3ca85463f63b5dd0aa7aaa933d97cbc47c174896dcae8431695872969f981893", size = 5316388 }, - { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658 }, + { url = "https://files.pythonhosted.org/packages/71/be/8bd693a0b9d53d48c8978fa5d889e06f3b5b03e45fd1ea1e78267b4887cb/debugpy-1.8.20-cp310-cp310-macosx_15_0_x86_64.whl", hash = "sha256:157e96ffb7f80b3ad36d808646198c90acb46fdcfd8bb1999838f0b6f2b59c64", size = 2099192, upload-time = "2026-01-29T23:03:29.707Z" }, + { url = "https://files.pythonhosted.org/packages/77/1b/85326d07432086a06361d493d2743edd0c4fc2ef62162be7f8618441ac37/debugpy-1.8.20-cp310-cp310-manylinux_2_34_x86_64.whl", hash = "sha256:c1178ae571aff42e61801a38b007af504ec8e05fde1c5c12e5a7efef21009642", size = 3088568, upload-time = "2026-01-29T23:03:31.467Z" }, + { url = "https://files.pythonhosted.org/packages/e8/60/3e08462ee3eccd10998853eb35947c416e446bfe2bc37dbb886b9044586c/debugpy-1.8.20-cp310-cp310-win32.whl", hash = "sha256:c29dd9d656c0fbd77906a6e6a82ae4881514aa3294b94c903ff99303e789b4a2", size = 5284399, upload-time = "2026-01-29T23:03:33.678Z" }, + { url = "https://files.pythonhosted.org/packages/72/43/09d49106e770fe558ced5e80df2e3c2ebee10e576eda155dcc5670473663/debugpy-1.8.20-cp310-cp310-win_amd64.whl", hash = "sha256:3ca85463f63b5dd0aa7aaa933d97cbc47c174896dcae8431695872969f981893", size = 5316388, upload-time = "2026-01-29T23:03:35.095Z" }, + { url = "https://files.pythonhosted.org/packages/e0/c3/7f67dea8ccf8fdcb9c99033bbe3e90b9e7395415843accb81428c441be2d/debugpy-1.8.20-py2.py3-none-any.whl", hash = "sha256:5be9bed9ae3be00665a06acaa48f8329d2b9632f15fd09f6a9a8c8d9907e54d7", size = 5337658, upload-time = "2026-01-29T23:04:17.404Z" }, ] [[package]] name = "decorator" version = "5.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711 } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190 }, + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, ] [[package]] name = "defusedxml" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520 } +sdist = { url = "https://files.pythonhosted.org/packages/0f/d5/c66da9b79e5bdb124974bfe172b4daf3c984ebd9c2a06e2b8a4dc7331c72/defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69", size = 75520, upload-time = "2021-03-08T10:59:26.269Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604 }, + { url = "https://files.pythonhosted.org/packages/07/6c/aa3f2f849e01cb6a001cd8554a88d4c77c5c1a31c95bdf1cf9301e6d9ef4/defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61", size = 25604, upload-time = "2021-03-08T10:59:24.45Z" }, ] [[package]] @@ -643,60 +660,60 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wrapt" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523 } +sdist = { url = "https://files.pythonhosted.org/packages/49/85/12f0a49a7c4ffb70572b6c2ef13c90c88fd190debda93b23f026b25f9634/deprecated-1.3.1.tar.gz", hash = "sha256:b1b50e0ff0c1fddaa5708a2c6b0a6588bb09b892825ab2b214ac9ea9d92a5223", size = 2932523, upload-time = "2025-10-30T08:19:02.757Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298 }, + { url = "https://files.pythonhosted.org/packages/84/d0/205d54408c08b13550c733c4b85429e7ead111c7f0014309637425520a9a/deprecated-1.3.1-py2.py3-none-any.whl", hash = "sha256:597bfef186b6f60181535a29fbe44865ce137a5079f295b479886c82729d5f3f", size = 11298, upload-time = "2025-10-30T08:19:00.758Z" }, ] [[package]] name = "dill" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976 } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668 }, + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, ] [[package]] name = "diskcache" version = "5.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916 } +sdist = { url = "https://files.pythonhosted.org/packages/3f/21/1c1ffc1a039ddcc459db43cc108658f32c57d271d7289a2794e401d0fdb6/diskcache-5.6.3.tar.gz", hash = "sha256:2c3a3fa2743d8535d832ec61c2054a1641f41775aa7c556758a109941e33e4fc", size = 67916, upload-time = "2023-08-31T06:12:00.316Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550 }, + { url = "https://files.pythonhosted.org/packages/3f/27/4570e78fc0bf5ea0ca45eb1de3818a23787af9b390c0b0a0033a1b8236f9/diskcache-5.6.3-py3-none-any.whl", hash = "sha256:5e31b2d5fbad117cc363ebaf6b689474db18a1f6438bc82358b024abd4c2ca19", size = 45550, upload-time = "2023-08-31T06:11:58.822Z" }, ] [[package]] name = "distlib" version = "0.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605 } +sdist = { url = "https://files.pythonhosted.org/packages/96/8e/709914eb2b5749865801041647dc7f4e6d00b549cfe88b65ca192995f07c/distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d", size = 614605, upload-time = "2025-07-17T16:52:00.465Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047 }, + { url = "https://files.pythonhosted.org/packages/33/6b/e0547afaf41bf2c42e52430072fa5658766e3d65bd4b03a563d1b6336f57/distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16", size = 469047, upload-time = "2025-07-17T16:51:58.613Z" }, ] [[package]] name = "dnspython" version = "2.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251 } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094 }, + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, ] [[package]] name = "docopt" version = "0.6.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901 } +sdist = { url = "https://files.pythonhosted.org/packages/a2/55/8f8cab2afd404cf578136ef2cc5dfb50baa1761b68c9da1fb1e4eed343c9/docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491", size = 25901, upload-time = "2014-06-16T11:18:57.406Z" } [[package]] name = "docx2txt" version = "0.9" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613 } +sdist = { url = "https://files.pythonhosted.org/packages/ea/07/4486a038624e885e227fe79111914c01f55aa70a51920ff1a7f2bd216d10/docx2txt-0.9.tar.gz", hash = "sha256:18013f6229b14909028b19aa7bf4f8f3d6e4632d7b089ab29f7f0a4d1f660e28", size = 3613, upload-time = "2025-03-24T20:59:25.21Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025 }, + { url = "https://files.pythonhosted.org/packages/d6/51/756e71bec48ece0ecc2a10e921ef2756e197dcb7e478f2b43673b6683902/docx2txt-0.9-py3-none-any.whl", hash = "sha256:e3718c0653fd6f2fcf4b51b02a61452ad1c38a4c163bcf0a6fd9486cd38f529a", size = 4025, upload-time = "2025-03-24T20:59:24.394Z" }, ] [[package]] @@ -707,9 +724,9 @@ dependencies = [ { name = "dnspython" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238 } +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604 }, + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, ] [[package]] @@ -719,18 +736,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371 } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740 }, + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, ] [[package]] name = "executing" version = "2.2.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317 }, + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, ] [[package]] @@ -740,14 +757,14 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644 } +sdist = { url = "https://files.pythonhosted.org/packages/c3/97/d7f0b25e181738b24e25092acc160bf30c682da6ab961e28f839a5f862b2/Faker-18.11.2.tar.gz", hash = "sha256:ec6e2824bb1d3546b36c156324b9df6bca5a3d6d03adf991e6a5586756dcab9d", size = 1670644, upload-time = "2023-06-27T15:24:28.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039 }, + { url = "https://files.pythonhosted.org/packages/db/d5/cbb9d7083e1ba9ace3434f12c8bccb58e9ec5127323c09efea5d5fc59b1d/Faker-18.11.2-py3-none-any.whl", hash = "sha256:21c2c29638e98502f3bba9ad6a4f07a4b09c5e2150bb491ff02411a5888f6955", size = 1710039, upload-time = "2023-06-27T15:24:24.869Z" }, ] [[package]] name = "fastapi" -version = "0.132.0" +version = "0.135.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-doc" }, @@ -756,9 +773,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a0/55/f1b4d4e478a0a1b4b1113d0f610a1b08e539b69900f97fdc97155d62fdee/fastapi-0.132.0.tar.gz", hash = "sha256:ef687847936d8a57ea6ea04cf9a85fe5f2c6ba64e22bfa721467094b69d48d92", size = 372422 } +sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/de/6171c3363bbc5e01686e200e0880647c9270daa476d91030435cf14d32f5/fastapi-0.132.0-py3-none-any.whl", hash = "sha256:3c487d5afce196fa8ea509ae1531e96ccd5cdd2fd6eae78b73e2c20fba706689", size = 104652 }, + { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, ] [package.optional-dependencies] @@ -775,7 +792,7 @@ standard = [ [[package]] name = "fastapi-cli" -version = "0.0.23" +version = "0.0.24" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "rich-toolkit" }, @@ -783,9 +800,9 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/9f/cbd463e57de4e977b8ea0403f95347f9150441568b1d3fe3e4949ef80ef3/fastapi_cli-0.0.23.tar.gz", hash = "sha256:210ac280ea41e73aac5a57688781256beb23c2cba3a41266896fa43e6445c8e7", size = 19763 } +sdist = { url = "https://files.pythonhosted.org/packages/6e/58/74797ae9e4610cfa0c6b34c8309096d3b20bb29be3b8b5fbf1004d10fa5f/fastapi_cli-0.0.24.tar.gz", hash = "sha256:1afc9c9e21d7ebc8a3ca5e31790cd8d837742be7e4f8b9236e99cb3451f0de00", size = 19043, upload-time = "2026-02-24T10:45:10.476Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/89/19dcfd5cd289b306abdcabac68b88a4f54b7710a2c33adc16a337ecdcdfa/fastapi_cli-0.0.23-py3-none-any.whl", hash = "sha256:7e9634fc212da0b6cfc75bd3ac366cc9dfdb43b5e9ec12e58bfd1acdd2697f25", size = 12305 }, + { url = "https://files.pythonhosted.org/packages/c7/4b/68f9fe268e535d79c76910519530026a4f994ce07189ac0dded45c6af825/fastapi_cli-0.0.24-py3-none-any.whl", hash = "sha256:4a1f78ed798f106b4fee85ca93b85d8fe33c0a3570f775964d37edb80b8f0edc", size = 12304, upload-time = "2026-02-24T10:45:09.552Z" }, ] [package.optional-dependencies] @@ -796,7 +813,7 @@ standard = [ [[package]] name = "fastapi-cloud-cli" -version = "0.13.0" +version = "0.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "fastar" }, @@ -808,73 +825,61 @@ dependencies = [ { name = "typer" }, { name = "uvicorn", extra = ["standard"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/0b/f07f4976784978ef159fd2e8f5c16f1f9d610578fb1fd976ff1315c11ea6/fastapi_cloud_cli-0.13.0.tar.gz", hash = "sha256:4d8f42337e8021c648f6cb0672de7d5b31b0fc7387a83d7b12f974600ac3f2fd", size = 38436 } +sdist = { url = "https://files.pythonhosted.org/packages/63/e1/05c44e7bbc619e980fab0236cff9f5f323ac1aaa79434b4906febf98b1d3/fastapi_cloud_cli-0.15.0.tar.gz", hash = "sha256:d02515231f3f505f7669c20920343934570a88a08af9f9a6463ca2807f27ffe5", size = 45309, upload-time = "2026-03-11T22:31:32.455Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/88/71a1e989d17b9edb483f32e28b7891ffdd3005271518c98ba6415987c430/fastapi_cloud_cli-0.13.0-py3-none-any.whl", hash = "sha256:874a9ed8dba34ec828f198c72de9f9a38de77ac1b15083d6bc3a4d772b0bc477", size = 27631 }, + { url = "https://files.pythonhosted.org/packages/40/cc/1ccca747f5609be27186ea8c9219449142f40e3eded2c6089bba6a6ecc82/fastapi_cloud_cli-0.15.0-py3-none-any.whl", hash = "sha256:9ffcf90bd713747efa65447620d29cfbb7b3f7de38d97467952ca6346e418d70", size = 32267, upload-time = "2026-03-11T22:31:33.499Z" }, ] [[package]] name = "fastar" version = "0.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536 }, - { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235 }, - { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386 }, - { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955 }, - { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987 }, - { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900 }, - { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523 }, - { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268 }, - { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286 }, - { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921 }, - { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302 }, - { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141 }, - { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544 }, - { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701 }, - { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544 }, - { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020 }, - { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735 }, - { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779 }, - { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755 }, - { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732 }, - { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571 }, - { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440 }, - { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424 }, - { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675 }, - { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098 }, - { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397 }, +sdist = { url = "https://files.pythonhosted.org/packages/69/e7/f89d54fb04104114dd0552836dc2b47914f416cc0e200b409dd04a33de5e/fastar-0.8.0.tar.gz", hash = "sha256:f4d4d68dbf1c4c2808f0e730fac5843493fc849f70fe3ad3af60dfbaf68b9a12", size = 68524, upload-time = "2025-11-26T02:36:00.72Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c3/e2/51d9ee443aabcd5aa581d45b18b6198ced364b5cd97e5504c5d782ceb82c/fastar-0.8.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c9f930cff014cf79d396d0541bd9f3a3f170c9b5e45d10d634d98f9ed08788c3", size = 708536, upload-time = "2025-11-26T02:34:35.236Z" }, + { url = "https://files.pythonhosted.org/packages/07/2a/edfc6274768b8a3859a5ca4f8c29cb7f614d7f27d2378e2c88aa91cda54e/fastar-0.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07b70f712d20622346531a4b46bb332569bea621f61314c0b7e80903a16d14cf", size = 632235, upload-time = "2025-11-26T02:34:19.367Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1e/3cfbaaec464caef196700ee2ffae1c03f94f7c5e2a85d0ec0ea9cdd1da81/fastar-0.8.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:330639db3bfba4c6d132421a2a4aeb81e7bea8ce9159cdb6e247fbc5fae97686", size = 871386, upload-time = "2025-11-26T02:33:47.613Z" }, + { url = "https://files.pythonhosted.org/packages/82/50/224a674ad541054179e4e6e0b54bb6e162f04f698a2512b42a8085fc6b6f/fastar-0.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98ea7ceb6231e48d7bb0d7dc13e946baa29c7f6873eaf4afb69725d6da349033", size = 764955, upload-time = "2025-11-26T02:32:44.279Z" }, + { url = "https://files.pythonhosted.org/packages/4d/5e/4608184aa57cb6a54f62c1eb3e5133ba8d461fc7f13193c0255effbec12a/fastar-0.8.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a90695a601a78bbca910fdf2efcdf3103c55d0de5a5c6e93556d707bf886250b", size = 765987, upload-time = "2025-11-26T02:32:59.701Z" }, + { url = "https://files.pythonhosted.org/packages/e0/53/6afd2b680dddfa10df9a16bbcf6cabfee0d92435d5c7e3f4cfe3b1712662/fastar-0.8.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d0bf655ff4c9320b0ca8a5b128063d5093c0c8c1645a2b5f7167143fd8531aa", size = 930900, upload-time = "2025-11-26T02:33:16.059Z" }, + { url = "https://files.pythonhosted.org/packages/ef/1e/b7a304bfcc1d06845cbfa4b464516f6fff9c8c6692f6ef80a3a86b04e199/fastar-0.8.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d8df22cdd8d58e7689aa89b2e4a07e8e5fa4f88d2d9c2621f0e88a49be97ccea", size = 821523, upload-time = "2025-11-26T02:33:30.897Z" }, + { url = "https://files.pythonhosted.org/packages/1d/da/9ef8605c6d233cd6ca3a95f7f518ac22aa064903afe6afa57733bfb7c31b/fastar-0.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e8a5e6ad722685128521c8fb44cf25bd38669650ba3a4b466b8903e5aa28e1a0", size = 821268, upload-time = "2025-11-26T02:34:04.003Z" }, + { url = "https://files.pythonhosted.org/packages/7e/22/ed37c78a6b4420de1677d82e79742787975c34847229c33dc376334c7283/fastar-0.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:31cd541231a2456e32104da891cf9962c3b40234d0465cbf9322a6bc8a1b05d5", size = 986286, upload-time = "2025-11-26T02:34:50.279Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a6/366b15f432d85d4089e6e4b52a09cc2a2bcf4d7a1f0771e3d3194deccb1e/fastar-0.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:175db2a98d67ced106468e8987975484f8bbbd5ad99201da823b38bafb565ed5", size = 1041921, upload-time = "2025-11-26T02:35:07.292Z" }, + { url = "https://files.pythonhosted.org/packages/f4/45/45f8e6991e3ce9f8aeefdc8d4c200daada41097a36808643d1703464c3e2/fastar-0.8.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ada877ab1c65197d772ce1b1c2e244d4799680d8b3f136a4308360f3d8661b23", size = 1047302, upload-time = "2025-11-26T02:35:24.995Z" }, + { url = "https://files.pythonhosted.org/packages/c2/e2/a587796111a3cd4b78cd61ec3fc1252d8517d81f763f4164ed5680f84810/fastar-0.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:01084cb75f13ca6a8e80bd41584322523189f8e81b472053743d6e6c3062b5a6", size = 995141, upload-time = "2025-11-26T02:35:42.449Z" }, + { url = "https://files.pythonhosted.org/packages/89/c0/7a8ec86695b0b77168e220cf2af1aa30592f5ecdbd0ce6d641d29c4a8bae/fastar-0.8.0-cp310-cp310-win32.whl", hash = "sha256:ca639b9909805e44364ea13cca2682b487e74826e4ad75957115ec693228d6b6", size = 456544, upload-time = "2025-11-26T02:36:23.801Z" }, + { url = "https://files.pythonhosted.org/packages/be/a9/8da4deb840121c59deabd939ce2dca3d6beec85576f3743d1144441938b5/fastar-0.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:fbc0f2ed0f4add7fb58034c576584d44d7eaaf93dee721dfb26dbed6e222dbac", size = 490701, upload-time = "2025-11-26T02:36:09.625Z" }, + { url = "https://files.pythonhosted.org/packages/25/9f/6eaa810c240236eff2edf736cd50a17c97dbab1693cda4f7bcea09d13418/fastar-0.8.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2127cf2e80ffd49744a160201e0e2f55198af6c028a7b3f750026e0b1f1caa4e", size = 710544, upload-time = "2025-11-26T02:34:46.195Z" }, + { url = "https://files.pythonhosted.org/packages/1d/a5/58ff9e49a1cd5fbfc8f1238226cbf83b905376a391a6622cdd396b2cfa29/fastar-0.8.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ff85094f10003801339ac4fa9b20a3410c2d8f284d4cba2dc99de6e98c877812", size = 634020, upload-time = "2025-11-26T02:34:31.085Z" }, + { url = "https://files.pythonhosted.org/packages/80/94/f839257c6600a83fbdb5a7fcc06319599086137b25ba38ca3d2c0fe14562/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3dbca235f0bd804cca6602fe055d3892bebf95fb802e6c6c7d872fb10f7abc6c", size = 871735, upload-time = "2025-11-26T02:34:00.088Z" }, + { url = "https://files.pythonhosted.org/packages/eb/79/4124c54260f7ee5cb7034bfe499eff2f8512b052d54be4671e59d4f25a4f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e54bfdee6c81a0005e147319e93d8797f442308032c92fa28d03ef8fda076", size = 766779, upload-time = "2025-11-26T02:32:55.109Z" }, + { url = "https://files.pythonhosted.org/packages/36/b6/043b263c4126bf6557c942d099503989af9c5c7ee5cca9a04e00f754816f/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a78e5221b94a80800930b7fd0d0e797ae73aadf7044c05ed46cb9bdf870f022", size = 766755, upload-time = "2025-11-26T02:33:11.595Z" }, + { url = "https://files.pythonhosted.org/packages/57/ff/29a5dc06f2940439ebf98661ecc98d48d3f22fed8d6a2d5dc985d1e8da24/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997092d31ff451de8d0568f6773f3517cb87dcd0bc76184edb65d7154390a6f8", size = 932732, upload-time = "2025-11-26T02:33:27.122Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e8/2218830f422b37aad52c24b53cb84b5d88bd6fd6ad411bd6689b1a32500d/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:558e8fcf8fe574541df5db14a46cd98bfbed14a811b7014a54f2b714c0cfac42", size = 822571, upload-time = "2025-11-26T02:33:42.986Z" }, + { url = "https://files.pythonhosted.org/packages/6e/fd/ba6dfeff77cddfe58d85c490b1735c002b81c0d6f826916a8b6c4f8818bc/fastar-0.8.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1d2a54f87e2908cc19e1a6ee249620174fbefc54a219aba1eaa6f31657683c3", size = 822440, upload-time = "2025-11-26T02:34:15.439Z" }, + { url = "https://files.pythonhosted.org/packages/a7/57/54d5740c84b35de0eb12975397ecc16785b5ad8bed2dbac38b8c8a7c1edd/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef94901537be277f9ec59db939eb817960496c6351afede5b102699b5098604d", size = 987424, upload-time = "2025-11-26T02:35:02.742Z" }, + { url = "https://files.pythonhosted.org/packages/ee/c7/18115927f16deb1ddffdbd4ae992e7e33064bc6defa2b92a147948f8bc0c/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:0afbb92f78bf29d5e9db76fb46cbabc429e49015cddf72ab9e761afbe88ac100", size = 1042675, upload-time = "2025-11-26T02:35:20.252Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1a/ca884fc7973ec6d765e87af23a4dd25784fb0a36ac2df825f18c3630bbab/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fb59c7925e7710ad178d9e1a3e65edf295d9a042a0cdcb673b4040949eb8ad0a", size = 1047098, upload-time = "2025-11-26T02:35:37.643Z" }, + { url = "https://files.pythonhosted.org/packages/44/ee/25cd645db749b206bb95e1512e57e75d56ccbbb8ec3536f52a7979deab6b/fastar-0.8.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e6c4d6329da568ec36b1347b0c09c4d27f9dfdeddf9f438ddb16799ecf170098", size = 997397, upload-time = "2025-11-26T02:35:56.215Z" }, ] [[package]] name = "fastjsonschema" version = "2.21.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130 } +sdist = { url = "https://files.pythonhosted.org/packages/20/b5/23b216d9d985a956623b6bd12d4086b60f0059b27799f23016af04a74ea1/fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de", size = 374130, upload-time = "2025-08-14T18:49:36.666Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024 }, + { url = "https://files.pythonhosted.org/packages/cb/a8/20d0723294217e47de6d9e2e40fd4a9d2f7c4b6ef974babd482a59743694/fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463", size = 24024, upload-time = "2025-08-14T18:49:34.776Z" }, ] [[package]] name = "filelock" -version = "3.24.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331 }, -] - -[[package]] -name = "fire" -version = "0.7.1" +version = "3.25.2" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "termcolor" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/00/f8d10588d2019d6d6452653def1ee807353b21983db48550318424b5ff18/fire-0.7.1.tar.gz", hash = "sha256:3b208f05c736de98fb343310d090dcc4d8c78b2a89ea4f32b837c586270a9cbf", size = 88720 } +sdist = { url = "https://files.pythonhosted.org/packages/94/b8/00651a0f559862f3bb7d6f7477b192afe3f583cc5e26403b44e59a55ab34/filelock-3.25.2.tar.gz", hash = "sha256:b64ece2b38f4ca29dd3e810287aa8c48182bbecd1ae6e9ae126c9b35f1382694", size = 40480, upload-time = "2026-03-11T20:45:38.487Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/4c/93d0f85318da65923e4b91c1c2ff03d8a458cbefebe3bc612a6693c7906d/fire-0.7.1-py3-none-any.whl", hash = "sha256:e43fd8a5033a9001e7e2973bab96070694b9f12f2e0ecf96d4683971b5ab1882", size = 115945 }, + { url = "https://files.pythonhosted.org/packages/a4/a5/842ae8f0c08b61d6484b52f99a03510a3a72d23141942d216ebe81fefbce/filelock-3.25.2-py3-none-any.whl", hash = "sha256:ca8afb0da15f229774c9ad1b455ed96e85a81373065fb10446672f64444ddf70", size = 26759, upload-time = "2026-03-11T20:45:37.437Z" }, ] [[package]] @@ -908,69 +913,77 @@ dependencies = [ { name = "transformers", extra = ["sentencepiece"] }, { name = "wikipedia-api" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607 } +sdist = { url = "https://files.pythonhosted.org/packages/70/bf/f6cc2ee7fd15946fef5f7747327eeed49837a3d7fd34460129bc936f0de7/flair-0.15.1.tar.gz", hash = "sha256:780b4eeffba044c4a181f1810872fc01201c2eaed8d2ef4bcb126a6464e91933", size = 388607, upload-time = "2025-02-05T14:45:44.322Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604, upload-time = "2025-02-05T14:45:41.788Z" }, +] + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/b9/da0f10de728204eee8b582356a2dfab34bc02b1102fec061656d8db44630/flair-0.15.1-py3-none-any.whl", hash = "sha256:3b6b793f2380cd618e988e7b16fbadcec6502aaa8f11a0890390160303aed553", size = 1174604 }, + { url = "https://files.pythonhosted.org/packages/e8/2d/d2a548598be01649e2d46231d151a6c56d10b964d94043a335ae56ea2d92/flatbuffers-25.12.19-py2.py3-none-any.whl", hash = "sha256:7634f50c427838bb021c2d66a3d1168e9d199b0607e6329399f04846d42e20b4", size = 26661, upload-time = "2025-12-19T23:16:13.622Z" }, ] [[package]] name = "fonttools" -version = "4.61.1" +version = "4.62.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/ca/cf17b88a8df95691275a3d77dc0a5ad9907f328ae53acbe6795da1b2f5ed/fonttools-4.61.1.tar.gz", hash = "sha256:6675329885c44657f826ef01d9e4fb33b9158e9d93c537d84ad8399539bc6f69", size = 3565756 } +sdist = { url = "https://files.pythonhosted.org/packages/5a/96/686339e0fda8142b7ebed39af53f4a5694602a729662f42a6209e3be91d0/fonttools-4.62.0.tar.gz", hash = "sha256:0dc477c12b8076b4eb9af2e440421b0433ffa9e1dcb39e0640a6c94665ed1098", size = 3579521, upload-time = "2026-03-09T16:50:06.217Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/94/8a28707adb00bed1bf22dac16ccafe60faf2ade353dcb32c3617ee917307/fonttools-4.61.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c7db70d57e5e1089a274cbb2b1fd635c9a24de809a231b154965d415d6c6d24", size = 2854799 }, - { url = "https://files.pythonhosted.org/packages/94/93/c2e682faaa5ee92034818d8f8a8145ae73eb83619600495dcf8503fa7771/fonttools-4.61.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5fe9fd43882620017add5eabb781ebfbc6998ee49b35bd7f8f79af1f9f99a958", size = 2403032 }, - { url = "https://files.pythonhosted.org/packages/f1/62/1748f7e7e1ee41aa52279fd2e3a6d0733dc42a673b16932bad8e5d0c8b28/fonttools-4.61.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8db08051fc9e7d8bc622f2112511b8107d8f27cd89e2f64ec45e9825e8288da", size = 4897863 }, - { url = "https://files.pythonhosted.org/packages/69/69/4ca02ee367d2c98edcaeb83fc278d20972502ee071214ad9d8ca85e06080/fonttools-4.61.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a76d4cb80f41ba94a6691264be76435e5f72f2cb3cab0b092a6212855f71c2f6", size = 4859076 }, - { url = "https://files.pythonhosted.org/packages/8c/f5/660f9e3cefa078861a7f099107c6d203b568a6227eef163dd173bfc56bdc/fonttools-4.61.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a13fc8aeb24bad755eea8f7f9d409438eb94e82cf86b08fe77a03fbc8f6a96b1", size = 4875623 }, - { url = "https://files.pythonhosted.org/packages/63/d1/9d7c5091d2276ed47795c131c1bf9316c3c1ab2789c22e2f59e0572ccd38/fonttools-4.61.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b846a1fcf8beadeb9ea4f44ec5bdde393e2f1569e17d700bfc49cd69bde75881", size = 4993327 }, - { url = "https://files.pythonhosted.org/packages/6f/2d/28def73837885ae32260d07660a052b99f0aa00454867d33745dfe49dbf0/fonttools-4.61.1-cp310-cp310-win32.whl", hash = "sha256:78a7d3ab09dc47ac1a363a493e6112d8cabed7ba7caad5f54dbe2f08676d1b47", size = 1502180 }, - { url = "https://files.pythonhosted.org/packages/63/fa/bfdc98abb4dd2bd491033e85e3ba69a2313c850e759a6daa014bc9433b0f/fonttools-4.61.1-cp310-cp310-win_amd64.whl", hash = "sha256:eff1ac3cc66c2ac7cda1e64b4e2f3ffef474b7335f92fc3833fc632d595fcee6", size = 1550654 }, - { url = "https://files.pythonhosted.org/packages/c7/4e/ce75a57ff3aebf6fc1f4e9d508b8e5810618a33d900ad6c19eb30b290b97/fonttools-4.61.1-py3-none-any.whl", hash = "sha256:17d2bf5d541add43822bcf0c43d7d847b160c9bb01d15d5007d84e2217aaa371", size = 1148996 }, + { url = "https://files.pythonhosted.org/packages/82/e0/9db48ec7f6b95bae7b20667ded54f18dba8e759ef66232c8683822ae26fc/fonttools-4.62.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:62b6a3d0028e458e9b59501cf7124a84cd69681c433570e4861aff4fb54a236c", size = 2873527, upload-time = "2026-03-09T16:48:12.416Z" }, + { url = "https://files.pythonhosted.org/packages/dd/45/86eccfdc922cb9fafc63189a9793fa9f6dd60e68a07be42e454ef2c0deae/fonttools-4.62.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:966557078b55e697f65300b18025c54e872d7908d1899b7314d7c16e64868cb2", size = 2417427, upload-time = "2026-03-09T16:48:15.122Z" }, + { url = "https://files.pythonhosted.org/packages/d3/98/f547a1fceeae81a9a5c6461bde2badac8bf50bda7122a8012b32b1e65396/fonttools-4.62.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cf34861145b516cddd19b07ae6f4a61ea1c6326031b960ec9ddce8ee815e888", size = 4934993, upload-time = "2026-03-09T16:48:18.186Z" }, + { url = "https://files.pythonhosted.org/packages/5c/57/a23a051fcff998fdfabdd33c6721b5bad499da08b586d3676993410071f0/fonttools-4.62.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e2ff573de2775508c8a366351fb901c4ced5dc6cf2d87dd15c973bedcdd5216", size = 4892154, upload-time = "2026-03-09T16:48:20.736Z" }, + { url = "https://files.pythonhosted.org/packages/e2/62/e27644b433dc6db1d47bc6028a27d772eec5cc8338e24a9a1fce5d7120aa/fonttools-4.62.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:55b189a1b3033860a38e4e5bd0626c5aa25c7ce9caee7bc784a8caec7a675401", size = 4911635, upload-time = "2026-03-09T16:48:23.174Z" }, + { url = "https://files.pythonhosted.org/packages/7e/e2/1bf141911a5616bacfe9cf237c80ccd69d0d92482c38c0f7f6a55d063ad9/fonttools-4.62.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:825f98cd14907c74a4d0a3f7db8570886ffce9c6369fed1385020febf919abf6", size = 5031492, upload-time = "2026-03-09T16:48:25.095Z" }, + { url = "https://files.pythonhosted.org/packages/2f/59/790c292f4347ecfa77d9c7e0d1d91e04ab227f6e4a337ed4fe37ca388048/fonttools-4.62.0-cp310-cp310-win32.whl", hash = "sha256:c858030560f92a054444c6e46745227bfd3bb4e55383c80d79462cd47289e4b5", size = 1507656, upload-time = "2026-03-09T16:48:26.973Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ee/08c0b7f8bac6e44638de6fe9a3e710a623932f60eccd58912c4d4743516d/fonttools-4.62.0-cp310-cp310-win_amd64.whl", hash = "sha256:9bf75eb69330e34ad2a096fac67887102c8537991eb6cac1507fc835bbb70e0a", size = 1556540, upload-time = "2026-03-09T16:48:30.359Z" }, + { url = "https://files.pythonhosted.org/packages/9c/57/c2487c281dde03abb2dec244fd67059b8d118bd30a653cbf69e94084cb23/fonttools-4.62.0-py3-none-any.whl", hash = "sha256:75064f19a10c50c74b336aa5ebe7b1f89fd0fb5255807bfd4b0c6317098f4af3", size = 1152427, upload-time = "2026-03-09T16:50:04.074Z" }, ] [[package]] name = "fqdn" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015 } +sdist = { url = "https://files.pythonhosted.org/packages/30/3e/a80a8c077fd798951169626cde3e239adeba7dab75deb3555716415bd9b0/fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f", size = 6015, upload-time = "2021-03-11T07:16:29.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121 }, + { url = "https://files.pythonhosted.org/packages/cf/58/8acf1b3e91c58313ce5cb67df61001fc9dcd21be4fadb76c1a2d540e09ed/fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014", size = 9121, upload-time = "2021-03-11T07:16:28.351Z" }, ] [[package]] name = "frozenlist" version = "1.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875 } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230 }, - { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621 }, - { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889 }, - { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464 }, - { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649 }, - { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188 }, - { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748 }, - { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351 }, - { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767 }, - { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887 }, - { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785 }, - { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312 }, - { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650 }, - { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659 }, - { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837 }, - { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989 }, - { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409 }, + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] [[package]] name = "fsspec" -version = "2025.10.0" +version = "2026.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/7f/2747c0d332b9acfa75dc84447a066fdf812b5a6b8d30472b74d309bfe8cb/fsspec-2025.10.0.tar.gz", hash = "sha256:b6789427626f068f9a83ca4e8a3cc050850b6c0f71f99ddb4f542b8266a26a59", size = 309285 } +sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/02/a6b21098b1d5d6249b7c5ab69dde30108a71e4e819d4a9778f1de1d5b70d/fsspec-2025.10.0-py3-none-any.whl", hash = "sha256:7c7712353ae7d875407f97715f0e1ffcc21e33d5b24556cb1e090ae9409ec61d", size = 200966 }, + { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" }, ] [package.optional-dependencies] @@ -985,9 +998,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927 } +sdist = { url = "https://files.pythonhosted.org/packages/a5/d3/8650919bc3c7c6e90ee3fa7fd618bf373cbbe55dff043bd67353dbb20cd8/ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec", size = 308927, upload-time = "2024-10-26T00:50:35.149Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821 }, + { url = "https://files.pythonhosted.org/packages/ab/6e/81d47999aebc1b155f81eca4477a616a70f238a2549848c38983f3c22a82/ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083", size = 44821, upload-time = "2024-10-26T00:50:33.425Z" }, ] [[package]] @@ -1000,49 +1013,49 @@ dependencies = [ { name = "requests", extra = ["socks"] }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/cf/919a9fa16faf8e4572a24d941353edaf4d54e3ddcd048e6c1aeb8c7a9903/gdown-5.2.1.tar.gz", hash = "sha256:247c2ad1f579db5b66b54c04e6a871995fc8fd7021708b950b8ba7b32cf90323", size = 284743 } +sdist = { url = "https://files.pythonhosted.org/packages/f4/cf/919a9fa16faf8e4572a24d941353edaf4d54e3ddcd048e6c1aeb8c7a9903/gdown-5.2.1.tar.gz", hash = "sha256:247c2ad1f579db5b66b54c04e6a871995fc8fd7021708b950b8ba7b32cf90323", size = 284743, upload-time = "2026-01-11T09:34:01.037Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/21/35dd0a0b7428bd67b12b358d7b4277f693493a3839b071d540a4c8357b78/gdown-5.2.1-py3-none-any.whl", hash = "sha256:391f0480d495fb87644d1a1ee3ddfeb2144e1de31408fbc74f7e3b3ba927052b", size = 18241 }, + { url = "https://files.pythonhosted.org/packages/87/21/35dd0a0b7428bd67b12b358d7b4277f693493a3839b071d540a4c8357b78/gdown-5.2.1-py3-none-any.whl", hash = "sha256:391f0480d495fb87644d1a1ee3ddfeb2144e1de31408fbc74f7e3b3ba927052b", size = 18241, upload-time = "2026-01-11T09:34:02.637Z" }, ] [[package]] name = "greenlet" version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267 } +sdist = { url = "https://files.pythonhosted.org/packages/a3/51/1664f6b78fc6ebbd98019a1fd730e83fa78f2db7058f72b1463d3612b8db/greenlet-3.3.2.tar.gz", hash = "sha256:2eaf067fc6d886931c7962e8c6bede15d2f01965560f3359b27c80bde2d151f2", size = 188267, upload-time = "2026-02-20T20:54:15.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/3f/9859f655d11901e7b2996c6e3d33e0caa9a1d4572c3bc61ed0faa64b2f4c/greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d", size = 277747 }, - { url = "https://files.pythonhosted.org/packages/fb/07/cb284a8b5c6498dbd7cba35d31380bb123d7dceaa7907f606c8ff5993cbf/greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13", size = 579202 }, - { url = "https://files.pythonhosted.org/packages/ed/45/67922992b3a152f726163b19f890a85129a992f39607a2a53155de3448b8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e", size = 590620 }, - { url = "https://files.pythonhosted.org/packages/03/5f/6e2a7d80c353587751ef3d44bb947f0565ec008a2e0927821c007e96d3a7/greenlet-3.3.2-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:508c7f01f1791fbc8e011bd508f6794cb95397fdb198a46cb6635eb5b78d85a7", size = 602132 }, - { url = "https://files.pythonhosted.org/packages/ad/55/9f1ebb5a825215fadcc0f7d5073f6e79e3007e3282b14b22d6aba7ca6cb8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f", size = 591729 }, - { url = "https://files.pythonhosted.org/packages/24/b4/21f5455773d37f94b866eb3cf5caed88d6cea6dd2c6e1f9c34f463cba3ec/greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef", size = 1551946 }, - { url = "https://files.pythonhosted.org/packages/00/68/91f061a926abead128fe1a87f0b453ccf07368666bd59ffa46016627a930/greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca", size = 1618494 }, - { url = "https://files.pythonhosted.org/packages/ac/78/f93e840cbaef8becaf6adafbaf1319682a6c2d8c1c20224267a5c6c8c891/greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f", size = 230092 }, + { url = "https://files.pythonhosted.org/packages/38/3f/9859f655d11901e7b2996c6e3d33e0caa9a1d4572c3bc61ed0faa64b2f4c/greenlet-3.3.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:9bc885b89709d901859cf95179ec9f6bb67a3d2bb1f0e88456461bd4b7f8fd0d", size = 277747, upload-time = "2026-02-20T20:16:21.325Z" }, + { url = "https://files.pythonhosted.org/packages/fb/07/cb284a8b5c6498dbd7cba35d31380bb123d7dceaa7907f606c8ff5993cbf/greenlet-3.3.2-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b568183cf65b94919be4438dc28416b234b678c608cafac8874dfeeb2a9bbe13", size = 579202, upload-time = "2026-02-20T20:47:28.955Z" }, + { url = "https://files.pythonhosted.org/packages/ed/45/67922992b3a152f726163b19f890a85129a992f39607a2a53155de3448b8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:527fec58dc9f90efd594b9b700662ed3fb2493c2122067ac9c740d98080a620e", size = 590620, upload-time = "2026-02-20T20:55:55.581Z" }, + { url = "https://files.pythonhosted.org/packages/ad/55/9f1ebb5a825215fadcc0f7d5073f6e79e3007e3282b14b22d6aba7ca6cb8/greenlet-3.3.2-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ad0c8917dd42a819fe77e6bdfcb84e3379c0de956469301d9fd36427a1ca501f", size = 591729, upload-time = "2026-02-20T20:20:58.395Z" }, + { url = "https://files.pythonhosted.org/packages/24/b4/21f5455773d37f94b866eb3cf5caed88d6cea6dd2c6e1f9c34f463cba3ec/greenlet-3.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:97245cc10e5515dbc8c3104b2928f7f02b6813002770cfaffaf9a6e0fc2b94ef", size = 1551946, upload-time = "2026-02-20T20:49:31.102Z" }, + { url = "https://files.pythonhosted.org/packages/00/68/91f061a926abead128fe1a87f0b453ccf07368666bd59ffa46016627a930/greenlet-3.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8c1fdd7d1b309ff0da81d60a9688a8bd044ac4e18b250320a96fc68d31c209ca", size = 1618494, upload-time = "2026-02-20T20:21:06.541Z" }, + { url = "https://files.pythonhosted.org/packages/ac/78/f93e840cbaef8becaf6adafbaf1319682a6c2d8c1c20224267a5c6c8c891/greenlet-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:5d0e35379f93a6d0222de929a25ab47b5eb35b5ef4721c2b9cbcc4036129ff1f", size = 230092, upload-time = "2026-02-20T20:17:09.379Z" }, ] [[package]] name = "h11" version = "0.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250 } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515 }, + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] [[package]] name = "hf-xet" -version = "1.2.0" +version = "1.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/6e/0f11bacf08a67f7fb5ee09740f2ca54163863b07b70d579356e9222ce5d8/hf_xet-1.2.0.tar.gz", hash = "sha256:a8c27070ca547293b6890c4bf389f713f80e8c478631432962bb7f4bc0bd7d7f", size = 506020 } +sdist = { url = "https://files.pythonhosted.org/packages/68/01/928fd82663fb0ab455551a178303a2960e65029da66b21974594f3a20a94/hf_xet-1.4.0.tar.gz", hash = "sha256:48e6ba7422b0885c9bbd8ac8fdf5c4e1306c3499b82d489944609cc4eae8ecbd", size = 660350, upload-time = "2026-03-11T18:50:03.354Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/2d/22338486473df5923a9ab7107d375dbef9173c338ebef5098ef593d2b560/hf_xet-1.2.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:46740d4ac024a7ca9b22bebf77460ff43332868b661186a8e46c227fdae01848", size = 2866099 }, - { url = "https://files.pythonhosted.org/packages/7f/8c/c5becfa53234299bc2210ba314eaaae36c2875e0045809b82e40a9544f0c/hf_xet-1.2.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:27df617a076420d8845bea087f59303da8be17ed7ec0cd7ee3b9b9f579dff0e4", size = 2722178 }, - { url = "https://files.pythonhosted.org/packages/9a/92/cf3ab0b652b082e66876d08da57fcc6fa2f0e6c70dfbbafbd470bb73eb47/hf_xet-1.2.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3651fd5bfe0281951b988c0facbe726aa5e347b103a675f49a3fa8144c7968fd", size = 3320214 }, - { url = "https://files.pythonhosted.org/packages/46/92/3f7ec4a1b6a65bf45b059b6d4a5d38988f63e193056de2f420137e3c3244/hf_xet-1.2.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d06fa97c8562fb3ee7a378dd9b51e343bc5bc8190254202c9771029152f5e08c", size = 3229054 }, - { url = "https://files.pythonhosted.org/packages/0b/dd/7ac658d54b9fb7999a0ccb07ad863b413cbaf5cf172f48ebcd9497ec7263/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4c1428c9ae73ec0939410ec73023c4f842927f39db09b063b9482dac5a3bb737", size = 3413812 }, - { url = "https://files.pythonhosted.org/packages/92/68/89ac4e5b12a9ff6286a12174c8538a5930e2ed662091dd2572bbe0a18c8a/hf_xet-1.2.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a55558084c16b09b5ed32ab9ed38421e2d87cf3f1f89815764d1177081b99865", size = 3508920 }, - { url = "https://files.pythonhosted.org/packages/cb/44/870d44b30e1dcfb6a65932e3e1506c103a8a5aea9103c337e7a53180322c/hf_xet-1.2.0-cp37-abi3-win_amd64.whl", hash = "sha256:e6584a52253f72c9f52f9e549d5895ca7a471608495c4ecaa6cc73dba2b24d69", size = 2905735 }, + { url = "https://files.pythonhosted.org/packages/9f/f9/a0b01945726aea81d2f213457cd5f5102a51e6fd1ca9f9769f561fb57501/hf_xet-1.4.0-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:981d2b5222c3baadf9567c135cf1d1073786f546b7745686978d46b5df179e16", size = 3799223, upload-time = "2026-03-11T18:49:49.884Z" }, + { url = "https://files.pythonhosted.org/packages/5d/30/ee62b0c00412f49a7e6f509f0104ee8808692278d247234336df48029349/hf_xet-1.4.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:cc8bd050349d0d7995ce7b3a3a18732a2a8062ce118a82431602088abb373428", size = 3560682, upload-time = "2026-03-11T18:49:48.633Z" }, + { url = "https://files.pythonhosted.org/packages/93/d0/0fe5c44dbced465a651a03212e1135d0d7f95d19faada692920cb56f8e38/hf_xet-1.4.0-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5d0c38d2a280d814280b8c15eead4a43c9781e7bf6fc37843cffab06dcdc76b9", size = 4218323, upload-time = "2026-03-11T18:49:40.921Z" }, + { url = "https://files.pythonhosted.org/packages/73/df/7b3c99a4e50442039eae498e5c23db634538eb3e02214109880cf1165d4c/hf_xet-1.4.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6a883f0250682ea888a1bd0af0631feda377e59ad7aae6fb75860ecee7ae0f93", size = 3997156, upload-time = "2026-03-11T18:49:39.634Z" }, + { url = "https://files.pythonhosted.org/packages/a9/26/47dfedf271c21d95346660ae1698e7ece5ab10791fa6c4f20c59f3713083/hf_xet-1.4.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:99e1d9255fe8ecdf57149bb0543d49e7b7bd8d491ddf431eb57e114253274df5", size = 4199052, upload-time = "2026-03-11T18:49:57.097Z" }, + { url = "https://files.pythonhosted.org/packages/8d/c0/346b9aad1474e881e65f998d5c1981695f0af045bc7a99204d9d86759a89/hf_xet-1.4.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b25f06ce42bd2d5f2e79d4a2d72f783d3ac91827c80d34a38cf8e5290dd717b0", size = 4434346, upload-time = "2026-03-11T18:49:58.67Z" }, + { url = "https://files.pythonhosted.org/packages/2e/d6/88ce9d6caa397c3b935263d5bcbe3ebf6c443f7c76098b8c523d206116b9/hf_xet-1.4.0-cp37-abi3-win_amd64.whl", hash = "sha256:8d6d7816d01e0fa33f315c8ca21b05eca0ce4cdc314f13b81d953e46cc6db11d", size = 3678921, upload-time = "2026-03-11T18:50:09.496Z" }, + { url = "https://files.pythonhosted.org/packages/65/eb/17d99ed253b28a9550ca479867c66a8af4c9bcd8cdc9a26b0c8007c2000a/hf_xet-1.4.0-cp37-abi3-win_arm64.whl", hash = "sha256:cb8d9549122b5b42f34b23b14c6b662a88a586a919d418c774d8dbbc4b3ce2aa", size = 3541054, upload-time = "2026-03-11T18:50:07.963Z" }, ] [[package]] @@ -1053,24 +1066,24 @@ dependencies = [ { name = "certifi" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484 } +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784 }, + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, ] [[package]] name = "httptools" version = "0.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/46/120a669232c7bdedb9d52d4aeae7e6c7dfe151e99dc70802e2fc7a5e1993/httptools-0.7.1.tar.gz", hash = "sha256:abd72556974f8e7c74a259655924a717a2365b236c882c3f6f8a45fe94703ac9", size = 258961, upload-time = "2025-10-10T03:55:08.559Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531 }, - { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408 }, - { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889 }, - { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460 }, - { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267 }, - { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429 }, - { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173 }, + { url = "https://files.pythonhosted.org/packages/c7/e5/c07e0bcf4ec8db8164e9f6738c048b2e66aabf30e7506f440c4cc6953f60/httptools-0.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:11d01b0ff1fe02c4c32d60af61a4d613b74fad069e47e06e9067758c01e9ac78", size = 204531, upload-time = "2025-10-10T03:54:20.887Z" }, + { url = "https://files.pythonhosted.org/packages/7e/4f/35e3a63f863a659f92ffd92bef131f3e81cf849af26e6435b49bd9f6f751/httptools-0.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d86c1e5afdc479a6fdabf570be0d3eb791df0ae727e8dbc0259ed1249998d4", size = 109408, upload-time = "2025-10-10T03:54:22.455Z" }, + { url = "https://files.pythonhosted.org/packages/f5/71/b0a9193641d9e2471ac541d3b1b869538a5fb6419d52fd2669fa9c79e4b8/httptools-0.7.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c8c751014e13d88d2be5f5f14fc8b89612fcfa92a9cc480f2bc1598357a23a05", size = 440889, upload-time = "2025-10-10T03:54:23.753Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d9/2e34811397b76718750fea44658cb0205b84566e895192115252e008b152/httptools-0.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:654968cb6b6c77e37b832a9be3d3ecabb243bbe7a0b8f65fbc5b6b04c8fcabed", size = 440460, upload-time = "2025-10-10T03:54:25.313Z" }, + { url = "https://files.pythonhosted.org/packages/01/3f/a04626ebeacc489866bb4d82362c0657b2262bef381d68310134be7f40bb/httptools-0.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b580968316348b474b020edf3988eecd5d6eec4634ee6561e72ae3a2a0e00a8a", size = 425267, upload-time = "2025-10-10T03:54:26.81Z" }, + { url = "https://files.pythonhosted.org/packages/a5/99/adcd4f66614db627b587627c8ad6f4c55f18881549bab10ecf180562e7b9/httptools-0.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d496e2f5245319da9d764296e86c5bb6fcf0cf7a8806d3d000717a889c8c0b7b", size = 424429, upload-time = "2025-10-10T03:54:28.174Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/ec8fc904a8fd30ba022dfa85f3bbc64c3c7cd75b669e24242c0658e22f3c/httptools-0.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cbf8317bfccf0fed3b5680c559d3459cccf1abe9039bfa159e62e391c7270568", size = 86173, upload-time = "2025-10-10T03:54:29.5Z" }, ] [[package]] @@ -1083,9 +1096,9 @@ dependencies = [ { name = "httpcore" }, { name = "idna" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 } +sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 }, + { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] [[package]] @@ -1102,27 +1115,48 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782 } +sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395 }, + { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395, upload-time = "2026-02-06T09:24:11.133Z" }, +] + +[[package]] +name = "humanfriendly" +version = "10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyreadline3", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cc/3f/2c29224acb2e2df4d2046e4c73ee2662023c58ff5b113c4c1adac0886c43/humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc", size = 360702, upload-time = "2021-09-17T21:40:43.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/0f/310fb31e39e2d734ccaa2c0fb981ee41f7bd5056ce9bc29b2248bd569169/humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477", size = 86794, upload-time = "2021-09-17T21:40:39.897Z" }, ] [[package]] name = "identify" -version = "2.6.16" +version = "2.6.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5b/8d/e8b97e6bd3fb6fb271346f7981362f1e04d6a7463abd0de79e1fda17c067/identify-2.6.16.tar.gz", hash = "sha256:846857203b5511bbe94d5a352a48ef2359532bc8f6727b5544077a0dcfb24980", size = 99360 } +sdist = { url = "https://files.pythonhosted.org/packages/57/84/376a3b96e5a8d33a7aa2c5b3b31a4b3c364117184bf0b17418055f6ace66/identify-2.6.17.tar.gz", hash = "sha256:f816b0b596b204c9fdf076ded172322f2723cf958d02f9c3587504834c8ff04d", size = 99579, upload-time = "2026-03-01T20:04:12.702Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/58/40fbbcefeda82364720eba5cf2270f98496bdfa19ea75b4cccae79c698e6/identify-2.6.16-py2.py3-none-any.whl", hash = "sha256:391ee4d77741d994189522896270b787aed8670389bfd60f326d677d64a6dfb0", size = 99202 }, + { url = "https://files.pythonhosted.org/packages/40/66/71c1227dff78aaeb942fed29dd5651f2aec166cc7c9aeea3e8b26a539b7d/identify-2.6.17-py2.py3-none-any.whl", hash = "sha256:be5f8412d5ed4b20f2bd41a65f920990bdccaa6a4a18a08f1eefdcd0bdd885f0", size = 99382, upload-time = "2026-03-01T20:04:11.439Z" }, ] [[package]] name = "idna" version = "3.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582 } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008 }, + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, ] [[package]] @@ -1132,9 +1166,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531 } +sdist = { url = "https://files.pythonhosted.org/packages/53/c3/b2afa612aa0373f3e6bb190e6de35f293b307d1537f109e3e25dbfcdf212/intervaltree-3.2.1.tar.gz", hash = "sha256:f3f7e8baeb7dd75b9f7a6d33cf3ec10025984a8e66e3016d537e52130c73cfe2", size = 1231531, upload-time = "2025-12-24T04:25:06.773Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929 }, + { url = "https://files.pythonhosted.org/packages/83/7f/8a80a1c7c2ed05822b5a2b312d2995f30c533641f8198366ba2e26a7bb03/intervaltree-3.2.1-py2.py3-none-any.whl", hash = "sha256:a8a8381bbd35d48ceebee932c77ffc988492d22fb1d27d0ba1d74a7694eb8f0b", size = 25929, upload-time = "2025-12-24T04:25:05.298Z" }, ] [[package]] @@ -1142,7 +1176,7 @@ name = "ipykernel" version = "7.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "appnope", marker = "platform_system == 'Darwin'" }, + { name = "appnope", marker = "sys_platform == 'darwin'" }, { name = "comm" }, { name = "debugpy" }, { name = "ipython" }, @@ -1156,9 +1190,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e", size = 176046 } +sdist = { url = "https://files.pythonhosted.org/packages/ca/8d/b68b728e2d06b9e0051019640a40a9eb7a88fcd82c2e1b5ce70bef5ff044/ipykernel-7.2.0.tar.gz", hash = "sha256:18ed160b6dee2cbb16e5f3575858bc19d8f1fe6046a9a680c708494ce31d909e", size = 176046, upload-time = "2026-02-06T16:43:27.403Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/b9/e73d5d9f405cba7706c539aa8b311b49d4c2f3d698d9c12f815231169c71/ipykernel-7.2.0-py3-none-any.whl", hash = "sha256:3bbd4420d2b3cc105cbdf3756bfc04500b1e52f090a90716851f3916c62e1661", size = 118788 }, + { url = "https://files.pythonhosted.org/packages/82/b9/e73d5d9f405cba7706c539aa8b311b49d4c2f3d698d9c12f815231169c71/ipykernel-7.2.0-py3-none-any.whl", hash = "sha256:3bbd4420d2b3cc105cbdf3756bfc04500b1e52f090a90716851f3916c62e1661", size = 118788, upload-time = "2026-02-06T16:43:25.149Z" }, ] [[package]] @@ -1178,9 +1212,9 @@ dependencies = [ { name = "traitlets" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996 } +sdist = { url = "https://files.pythonhosted.org/packages/e5/61/1810830e8b93c72dcd3c0f150c80a00c3deb229562d9423807ec92c3a539/ipython-8.38.0.tar.gz", hash = "sha256:9cfea8c903ce0867cc2f23199ed8545eb741f3a69420bfcf3743ad1cec856d39", size = 5513996, upload-time = "2026-01-05T10:59:06.901Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813 }, + { url = "https://files.pythonhosted.org/packages/9f/df/db59624f4c71b39717c423409950ac3f2c8b2ce4b0aac843112c7fb3f721/ipython-8.38.0-py3-none-any.whl", hash = "sha256:750162629d800ac65bb3b543a14e7a74b0e88063eac9b92124d4b2aa3f6d8e86", size = 831813, upload-time = "2026-01-05T10:59:04.239Z" }, ] [[package]] @@ -1194,9 +1228,9 @@ dependencies = [ { name = "traitlets" }, { name = "widgetsnbextension" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739 } +sdist = { url = "https://files.pythonhosted.org/packages/4c/ae/c5ce1edc1afe042eadb445e95b0671b03cee61895264357956e61c0d2ac0/ipywidgets-8.1.8.tar.gz", hash = "sha256:61f969306b95f85fba6b6986b7fe45d73124d1d9e3023a8068710d47a22ea668", size = 116739, upload-time = "2025-11-01T21:18:12.393Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808 }, + { url = "https://files.pythonhosted.org/packages/56/6d/0d9848617b9f753b87f214f1c682592f7ca42de085f564352f10f0843026/ipywidgets-8.1.8-py3-none-any.whl", hash = "sha256:ecaca67aed704a338f88f67b1181b58f821ab5dc89c1f0f5ef99db43c1c2921e", size = 139808, upload-time = "2025-11-01T21:18:10.956Z" }, ] [[package]] @@ -1206,9 +1240,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "arrow" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649 } +sdist = { url = "https://files.pythonhosted.org/packages/7c/1a/3c8edc664e06e6bd06cce40c6b22da5f1429aa4224d0c590f3be21c91ead/isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9", size = 11649, upload-time = "2020-11-01T11:00:00.312Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321 }, + { url = "https://files.pythonhosted.org/packages/7b/55/e5326141505c5d5e34c5e0935d2908a74e4561eca44108fbfb9c13d2911a/isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042", size = 11321, upload-time = "2020-11-01T10:59:58.02Z" }, ] [[package]] @@ -1218,9 +1252,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "parso" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287 } +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 }, + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, ] [[package]] @@ -1230,9 +1264,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, ] [[package]] @@ -1243,36 +1277,36 @@ dependencies = [ { name = "click" }, { name = "rapidfuzz" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537 } +sdist = { url = "https://files.pythonhosted.org/packages/42/37/99f800e78b9cff2b6c404812e33641b6b6b5b94088081e6a28548094e46f/jiwer-3.0.5.tar.gz", hash = "sha256:4a215a774b6a2ad92838bfc9f64f072709557af48e3eb9d6bdbcee6819535b2d", size = 17537, upload-time = "2024-11-01T16:18:57.337Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990 }, + { url = "https://files.pythonhosted.org/packages/dc/7f/00bec152973661ea89628490367fa3058d7f56d51d2c1ad02a44589d12cd/jiwer-3.0.5-py3-none-any.whl", hash = "sha256:5a55758fd1ed0b46a04e51eae6325ad77810511d1372dcbb2333ec8d5850f7b2", size = 21990, upload-time = "2024-11-01T16:18:55.928Z" }, ] [[package]] name = "jmespath" version = "1.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377 } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419 }, + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, ] [[package]] name = "joblib" version = "1.5.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603 } +sdist = { url = "https://files.pythonhosted.org/packages/41/f2/d34e8b3a08a9cc79a50b2208a93dce981fe615b64d5a4d4abee421d898df/joblib-1.5.3.tar.gz", hash = "sha256:8561a3269e6801106863fd0d6d84bb737be9e7631e33aaed3fb9ce5953688da3", size = 331603, upload-time = "2025-12-15T08:41:46.427Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071 }, + { url = "https://files.pythonhosted.org/packages/7b/91/984aca2ec129e2757d1e4e3c81c3fcda9d0f85b74670a094cc443d9ee949/joblib-1.5.3-py3-none-any.whl", hash = "sha256:5fc3c5039fc5ca8c0276333a188bbd59d6b7ab37fe6632daa76bc7f9ec18e713", size = 309071, upload-time = "2025-12-15T08:41:44.973Z" }, ] [[package]] name = "json5" version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441 } +sdist = { url = "https://files.pythonhosted.org/packages/77/e8/a3f261a66e4663f22700bc8a17c08cb83e91fbf086726e7a228398968981/json5-0.13.0.tar.gz", hash = "sha256:b1edf8d487721c0bf64d83c28e91280781f6e21f4a797d3261c7c828d4c165bf", size = 52441, upload-time = "2026-01-01T19:42:14.99Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163 }, + { url = "https://files.pythonhosted.org/packages/d7/9e/038522f50ceb7e74f1f991bf1b699f24b0c2bbe7c390dd36ad69f4582258/json5-0.13.0-py3-none-any.whl", hash = "sha256:9a08e1dd65f6a4d4c6fa82d216cf2477349ec2346a38fd70cc11d2557499fbcc", size = 36163, upload-time = "2026-01-01T19:42:13.962Z" }, ] [[package]] @@ -1282,18 +1316,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359 } +sdist = { url = "https://files.pythonhosted.org/packages/35/87/bcda8e46c88d0e34cad2f09ee2d0c7f5957bccdb9791b0b934ec84d84be4/jsonlines-4.0.0.tar.gz", hash = "sha256:0c6d2c09117550c089995247f605ae4cf77dd1533041d366351f6f298822ea74", size = 11359, upload-time = "2023-09-01T12:34:44.187Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701 }, + { url = "https://files.pythonhosted.org/packages/f8/62/d9ba6323b9202dd2fe166beab8a86d29465c41a0288cbe229fac60c1ab8d/jsonlines-4.0.0-py3-none-any.whl", hash = "sha256:185b334ff2ca5a91362993f42e83588a360cf95ce4b71a73548502bda52a7c55", size = 8701, upload-time = "2023-09-01T12:34:42.563Z" }, ] [[package]] name = "jsonpointer" version = "3.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114 } +sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595 }, + { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, ] [[package]] @@ -1306,9 +1340,9 @@ dependencies = [ { name = "referencing" }, { name = "rpds-py" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583 } +sdist = { url = "https://files.pythonhosted.org/packages/b3/fc/e067678238fa451312d4c62bf6e6cf5ec56375422aee02f9cb5f909b3047/jsonschema-4.26.0.tar.gz", hash = "sha256:0c26707e2efad8aa1bfc5b7ce170f3fccc2e4918ff85989ba9ffa9facb2be326", size = 366583, upload-time = "2026-01-07T13:41:07.246Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630 }, + { url = "https://files.pythonhosted.org/packages/69/90/f63fb5873511e014207a475e2bb4e8b2e570d655b00ac19a9a0ca0a385ee/jsonschema-4.26.0-py3-none-any.whl", hash = "sha256:d489f15263b8d200f8387e64b4c3a75f06629559fb73deb8fdfb525f2dab50ce", size = 90630, upload-time = "2026-01-07T13:41:05.306Z" }, ] [package.optional-dependencies] @@ -1331,9 +1365,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855 } +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437 }, + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, ] [[package]] @@ -1348,9 +1382,9 @@ dependencies = [ { name = "nbconvert" }, { name = "notebook" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959 } +sdist = { url = "https://files.pythonhosted.org/packages/58/f3/af28ea964ab8bc1e472dba2e82627d36d470c51f5cd38c37502eeffaa25e/jupyter-1.1.1.tar.gz", hash = "sha256:d55467bceabdea49d7e3624af7e33d59c37fff53ed3a350e1ac957bed731de7a", size = 5714959, upload-time = "2024-08-30T07:15:48.299Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657 }, + { url = "https://files.pythonhosted.org/packages/38/64/285f20a31679bf547b75602702f7800e74dbabae36ef324f716c02804753/jupyter-1.1.1-py2.py3-none-any.whl", hash = "sha256:7a59533c22af65439b24bbe60373a4e95af8f16ac65a6c00820ad378e3f7cc83", size = 2657, upload-time = "2024-08-30T07:15:47.045Z" }, ] [[package]] @@ -1364,9 +1398,9 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020 } +sdist = { url = "https://files.pythonhosted.org/packages/05/e4/ba649102a3bc3fbca54e7239fb924fd434c766f855693d86de0b1f2bec81/jupyter_client-8.8.0.tar.gz", hash = "sha256:d556811419a4f2d96c869af34e854e3f059b7cc2d6d01a9cd9c85c267691be3e", size = 348020, upload-time = "2026-01-08T13:55:47.938Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371 }, + { url = "https://files.pythonhosted.org/packages/2d/0b/ceb7694d864abc0a047649aec263878acb9f792e1fec3e676f22dc9015e3/jupyter_client-8.8.0-py3-none-any.whl", hash = "sha256:f93a5b99c5e23a507b773d3a1136bd6e16c67883ccdbd9a829b0bbdb98cd7d7a", size = 107371, upload-time = "2026-01-08T13:55:45.562Z" }, ] [[package]] @@ -1383,9 +1417,9 @@ dependencies = [ { name = "pyzmq" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/2d/e2fd31e2fc41c14e2bcb6c976ab732597e907523f6b2420305f9fc7fdbdb/jupyter_console-6.6.3.tar.gz", hash = "sha256:566a4bf31c87adbfadf22cdf846e3069b59a71ed5da71d6ba4d8aaad14a53539", size = 34363, upload-time = "2023-03-06T14:13:31.02Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510 }, + { url = "https://files.pythonhosted.org/packages/ca/77/71d78d58f15c22db16328a476426f7ac4a60d3a5a7ba3b9627ee2f7903d4/jupyter_console-6.6.3-py3-none-any.whl", hash = "sha256:309d33409fcc92ffdad25f0bcdf9a4a9daa61b6f341177570fdac03de5352485", size = 24510, upload-time = "2023-03-06T14:13:28.229Z" }, ] [[package]] @@ -1396,9 +1430,9 @@ dependencies = [ { name = "platformdirs" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814 } +sdist = { url = "https://files.pythonhosted.org/packages/02/49/9d1284d0dc65e2c757b74c6687b6d319b02f822ad039e5c512df9194d9dd/jupyter_core-5.9.1.tar.gz", hash = "sha256:4d09aaff303b9566c3ce657f580bd089ff5c91f5f89cf7d8846c3cdf465b5508", size = 89814, upload-time = "2025-10-16T19:19:18.444Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032 }, + { url = "https://files.pythonhosted.org/packages/e7/e7/80988e32bf6f73919a113473a604f5a8f09094de312b9d52b79c2df7612b/jupyter_core-5.9.1-py3-none-any.whl", hash = "sha256:ebf87fdc6073d142e114c72c9e29a9d7ca03fad818c5d300ce2adc1fb0743407", size = 29032, upload-time = "2025-10-16T19:19:16.783Z" }, ] [[package]] @@ -1415,9 +1449,9 @@ dependencies = [ { name = "rfc3986-validator" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/c3/306d090461e4cf3cd91eceaff84bede12a8e52cd821c2d20c9a4fd728385/jupyter_events-0.12.0.tar.gz", hash = "sha256:fc3fce98865f6784c9cd0a56a20644fc6098f21c8c33834a8d9fe383c17e554b", size = 62196, upload-time = "2025-02-03T17:23:41.485Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430 }, + { url = "https://files.pythonhosted.org/packages/e2/48/577993f1f99c552f18a0428731a755e06171f9902fa118c379eb7c04ea22/jupyter_events-0.12.0-py3-none-any.whl", hash = "sha256:6464b2fa5ad10451c3d35fabc75eab39556ae1e2853ad0c0cc31b656731a97fb", size = 19430, upload-time = "2025-02-03T17:23:38.643Z" }, ] [[package]] @@ -1427,9 +1461,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/5a/9066c9f8e94ee517133cd98dba393459a16cd48bba71a82f16a65415206c/jupyter_lsp-2.3.0.tar.gz", hash = "sha256:458aa59339dc868fb784d73364f17dbce8836e906cd75fd471a325cba02e0245", size = 54823, upload-time = "2025-08-27T17:47:34.671Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687 }, + { url = "https://files.pythonhosted.org/packages/1a/60/1f6cee0c46263de1173894f0fafcb3475ded276c472c14d25e0280c18d6d/jupyter_lsp-2.3.0-py3-none-any.whl", hash = "sha256:e914a3cb2addf48b1c7710914771aaf1819d46b2e5a79b0f917b5478ec93f34f", size = 76687, upload-time = "2025-08-27T17:47:33.15Z" }, ] [[package]] @@ -1457,9 +1491,9 @@ dependencies = [ { name = "traitlets" }, { name = "websocket-client" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/ac/e040ec363d7b6b1f11304cc9f209dac4517ece5d5e01821366b924a64a50/jupyter_server-2.17.0.tar.gz", hash = "sha256:c38ea898566964c888b4772ae1ed58eca84592e88251d2cfc4d171f81f7e99d5", size = 731949, upload-time = "2025-08-21T14:42:54.042Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221 }, + { url = "https://files.pythonhosted.org/packages/92/80/a24767e6ca280f5a49525d987bf3e4d7552bf67c8be07e8ccf20271f8568/jupyter_server-2.17.0-py3-none-any.whl", hash = "sha256:e8cb9c7db4251f51ed307e329b81b72ccf2056ff82d50524debde1ee1870e13f", size = 388221, upload-time = "2025-08-21T14:42:52.034Z" }, ] [[package]] @@ -1470,14 +1504,14 @@ dependencies = [ { name = "pywinpty", marker = "os_name == 'nt'" }, { name = "terminado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f4/a7/bcd0a9b0cbba88986fe944aaaf91bfda603e5a50bda8ed15123f381a3b2f/jupyter_server_terminals-0.5.4.tar.gz", hash = "sha256:bbda128ed41d0be9020349f9f1f2a4ab9952a73ed5f5ac9f1419794761fb87f5", size = 31770 } +sdist = { url = "https://files.pythonhosted.org/packages/f4/a7/bcd0a9b0cbba88986fe944aaaf91bfda603e5a50bda8ed15123f381a3b2f/jupyter_server_terminals-0.5.4.tar.gz", hash = "sha256:bbda128ed41d0be9020349f9f1f2a4ab9952a73ed5f5ac9f1419794761fb87f5", size = 31770, upload-time = "2026-01-14T16:53:20.213Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl", hash = "sha256:55be353fc74a80bc7f3b20e6be50a55a61cd525626f578dcb66a5708e2007d14", size = 13704 }, + { url = "https://files.pythonhosted.org/packages/d1/2d/6674563f71c6320841fc300911a55143925112a72a883e2ca71fba4c618d/jupyter_server_terminals-0.5.4-py3-none-any.whl", hash = "sha256:55be353fc74a80bc7f3b20e6be50a55a61cd525626f578dcb66a5708e2007d14", size = 13704, upload-time = "2026-01-14T16:53:18.738Z" }, ] [[package]] name = "jupyterlab" -version = "4.5.4" +version = "4.5.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "async-lru" }, @@ -1495,18 +1529,18 @@ dependencies = [ { name = "tornado" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7c/6b/21af7c0512bdf67e0c54c121779a1f2a97a164a7657e13fced79db8fa5a0/jupyterlab-4.5.4.tar.gz", hash = "sha256:c215f48d8e4582bd2920ad61cc6a40d8ebfef7e5a517ae56b8a9413c9789fdfb", size = 23943597 } +sdist = { url = "https://files.pythonhosted.org/packages/ac/d5/730628e03fff2e8a8e8ccdaedde1489ab1309f9a4fa2536248884e30b7c7/jupyterlab-4.5.6.tar.gz", hash = "sha256:642fe2cfe7f0f5922a8a558ba7a0d246c7bc133b708dfe43f7b3a826d163cf42", size = 23970670, upload-time = "2026-03-11T14:17:04.531Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/9f/a70972ece62ead2d81acc6223188f6d18a92f665ccce17796a0cdea4fcf5/jupyterlab-4.5.4-py3-none-any.whl", hash = "sha256:cc233f70539728534669fb0015331f2a3a87656207b3bb2d07916e9289192f12", size = 12391867 }, + { url = "https://files.pythonhosted.org/packages/e1/1b/dad6fdcc658ed7af26fdf3841e7394072c9549a8b896c381ab49dd11e2d9/jupyterlab-4.5.6-py3-none-any.whl", hash = "sha256:d6b3dac883aa4d9993348e0f8e95b24624f75099aed64eab6a4351a9cdd1e580", size = 12447124, upload-time = "2026-03-11T14:17:00.229Z" }, ] [[package]] name = "jupyterlab-pygments" version = "0.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900 } +sdist = { url = "https://files.pythonhosted.org/packages/90/51/9187be60d989df97f5f0aba133fa54e7300f17616e065d1ada7d7646b6d6/jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d", size = 512900, upload-time = "2023-11-23T09:26:37.44Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884 }, + { url = "https://files.pythonhosted.org/packages/b1/dd/ead9d8ea85bf202d90cc513b533f9c363121c7792674f78e0d8a854b63b4/jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780", size = 15884, upload-time = "2023-11-23T09:26:34.325Z" }, ] [[package]] @@ -1522,44 +1556,44 @@ dependencies = [ { name = "packaging" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/2c/90153f189e421e93c4bb4f9e3f59802a1f01abd2ac5cf40b152d7f735232/jupyterlab_server-2.28.0.tar.gz", hash = "sha256:35baa81898b15f93573e2deca50d11ac0ae407ebb688299d3a5213265033712c", size = 76996, upload-time = "2025-10-22T13:59:18.37Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830 }, + { url = "https://files.pythonhosted.org/packages/e0/07/a000fe835f76b7e1143242ab1122e6362ef1c03f23f83a045c38859c2ae0/jupyterlab_server-2.28.0-py3-none-any.whl", hash = "sha256:e4355b148fdcf34d312bbbc80f22467d6d20460e8b8736bf235577dd18506968", size = 59830, upload-time = "2025-10-22T13:59:16.767Z" }, ] [[package]] name = "jupyterlab-widgets" version = "3.0.16" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423 } +sdist = { url = "https://files.pythonhosted.org/packages/26/2d/ef58fed122b268c69c0aa099da20bc67657cdfb2e222688d5731bd5b971d/jupyterlab_widgets-3.0.16.tar.gz", hash = "sha256:423da05071d55cf27a9e602216d35a3a65a3e41cdf9c5d3b643b814ce38c19e0", size = 897423, upload-time = "2025-11-01T21:11:29.724Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926 }, + { url = "https://files.pythonhosted.org/packages/ab/b5/36c712098e6191d1b4e349304ef73a8d06aed77e56ceaac8c0a306c7bda1/jupyterlab_widgets-3.0.16-py3-none-any.whl", hash = "sha256:45fa36d9c6422cf2559198e4db481aa243c7a32d9926b500781c830c80f7ecf8", size = 914926, upload-time = "2025-11-01T21:11:28.008Z" }, ] [[package]] name = "kiwisolver" -version = "1.4.9" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/5d/8ce64e36d4e3aac5ca96996457dcf33e34e6051492399a3f1fec5657f30b/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b", size = 124159 }, - { url = "https://files.pythonhosted.org/packages/96/1e/22f63ec454874378175a5f435d6ea1363dd33fb2af832c6643e4ccea0dc8/kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f", size = 66578 }, - { url = "https://files.pythonhosted.org/packages/41/4c/1925dcfff47a02d465121967b95151c82d11027d5ec5242771e580e731bd/kiwisolver-1.4.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84fd60810829c27ae375114cd379da1fa65e6918e1da405f356a775d49a62bcf", size = 65312 }, - { url = "https://files.pythonhosted.org/packages/d4/42/0f333164e6307a0687d1eb9ad256215aae2f4bd5d28f4653d6cd319a3ba3/kiwisolver-1.4.9-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b78efa4c6e804ecdf727e580dbb9cba85624d2e1c6b5cb059c66290063bd99a9", size = 1628458 }, - { url = "https://files.pythonhosted.org/packages/86/b6/2dccb977d651943995a90bfe3495c2ab2ba5cd77093d9f2318a20c9a6f59/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4efec7bcf21671db6a3294ff301d2fc861c31faa3c8740d1a94689234d1b415", size = 1225640 }, - { url = "https://files.pythonhosted.org/packages/50/2b/362ebd3eec46c850ccf2bfe3e30f2fc4c008750011f38a850f088c56a1c6/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:90f47e70293fc3688b71271100a1a5453aa9944a81d27ff779c108372cf5567b", size = 1244074 }, - { url = "https://files.pythonhosted.org/packages/6f/bb/f09a1e66dab8984773d13184a10a29fe67125337649d26bdef547024ed6b/kiwisolver-1.4.9-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fdca1def57a2e88ef339de1737a1449d6dbf5fab184c54a1fca01d541317154", size = 1293036 }, - { url = "https://files.pythonhosted.org/packages/ea/01/11ecf892f201cafda0f68fa59212edaea93e96c37884b747c181303fccd1/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9cf554f21be770f5111a1690d42313e140355e687e05cf82cb23d0a721a64a48", size = 2175310 }, - { url = "https://files.pythonhosted.org/packages/7f/5f/bfe11d5b934f500cc004314819ea92427e6e5462706a498c1d4fc052e08f/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fc1795ac5cd0510207482c3d1d3ed781143383b8cfd36f5c645f3897ce066220", size = 2270943 }, - { url = "https://files.pythonhosted.org/packages/3d/de/259f786bf71f1e03e73d87e2db1a9a3bcab64d7b4fd780167123161630ad/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ccd09f20ccdbbd341b21a67ab50a119b64a403b09288c27481575105283c1586", size = 2440488 }, - { url = "https://files.pythonhosted.org/packages/1b/76/c989c278faf037c4d3421ec07a5c452cd3e09545d6dae7f87c15f54e4edf/kiwisolver-1.4.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:540c7c72324d864406a009d72f5d6856f49693db95d1fbb46cf86febef873634", size = 2246787 }, - { url = "https://files.pythonhosted.org/packages/a2/55/c2898d84ca440852e560ca9f2a0d28e6e931ac0849b896d77231929900e7/kiwisolver-1.4.9-cp310-cp310-win_amd64.whl", hash = "sha256:ede8c6d533bc6601a47ad4046080d36b8fc99f81e6f1c17b0ac3c2dc91ac7611", size = 73730 }, - { url = "https://files.pythonhosted.org/packages/e8/09/486d6ac523dd33b80b368247f238125d027964cfacb45c654841e88fb2ae/kiwisolver-1.4.9-cp310-cp310-win_arm64.whl", hash = "sha256:7b4da0d01ac866a57dd61ac258c5607b4cd677f63abaec7b148354d2b2cdd536", size = 65036 }, - { url = "https://files.pythonhosted.org/packages/a2/63/fde392691690f55b38d5dd7b3710f5353bf7a8e52de93a22968801ab8978/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4d1d9e582ad4d63062d34077a9a1e9f3c34088a2ec5135b1f7190c07cf366527", size = 60183 }, - { url = "https://files.pythonhosted.org/packages/27/b1/6aad34edfdb7cced27f371866f211332bba215bfd918ad3322a58f480d8b/kiwisolver-1.4.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:deed0c7258ceb4c44ad5ec7d9918f9f14fd05b2be86378d86cf50e63d1e7b771", size = 58675 }, - { url = "https://files.pythonhosted.org/packages/9d/1a/23d855a702bb35a76faed5ae2ba3de57d323f48b1f6b17ee2176c4849463/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0a590506f303f512dff6b7f75fd2fd18e16943efee932008fe7140e5fa91d80e", size = 80277 }, - { url = "https://files.pythonhosted.org/packages/5a/5b/5239e3c2b8fb5afa1e8508f721bb77325f740ab6994d963e61b2b7abcc1e/kiwisolver-1.4.9-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e09c2279a4d01f099f52d5c4b3d9e208e91edcbd1a175c9662a8b16e000fece9", size = 77994 }, - { url = "https://files.pythonhosted.org/packages/f9/1c/5d4d468fb16f8410e596ed0eac02d2c68752aa7dc92997fe9d60a7147665/kiwisolver-1.4.9-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c9e7cdf45d594ee04d5be1b24dd9d49f3d1590959b2271fb30b5ca2b262c00fb", size = 73744 }, +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/67/9c61eccb13f0bdca9307614e782fec49ffdde0f7a2314935d489fa93cd9c/kiwisolver-1.5.0.tar.gz", hash = "sha256:d4193f3d9dc3f6f79aaed0e5637f45d98850ebf01f7ca20e69457f3e8946b66a", size = 103482, upload-time = "2026-03-09T13:15:53.382Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/f8/06549565caa026e540b7e7bab5c5a90eb7ca986015f4c48dace243cd24d9/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32cc0a5365239a6ea0c6ed461e8838d053b57e397443c0ca894dcc8e388d4374", size = 122802, upload-time = "2026-03-09T13:12:37.515Z" }, + { url = "https://files.pythonhosted.org/packages/84/eb/8476a0818850c563ff343ea7c9c05dcdcbd689a38e01aa31657df01f91fa/kiwisolver-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cc0b66c1eec9021353a4b4483afb12dfd50e3669ffbb9152d6842eb34c7e29fd", size = 66216, upload-time = "2026-03-09T13:12:38.812Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c4/f9c8a6b4c21aed4198566e45923512986d6cef530e7263b3a5f823546561/kiwisolver-1.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:86e0287879f75621ae85197b0877ed2f8b7aa57b511c7331dce2eb6f4de7d476", size = 63917, upload-time = "2026-03-09T13:12:40.053Z" }, + { url = "https://files.pythonhosted.org/packages/f1/0e/ba4ae25d03722f64de8b2c13e80d82ab537a06b30fc7065183c6439357e3/kiwisolver-1.5.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:62f59da443c4f4849f73a51a193b1d9d258dcad0c41bc4d1b8fb2bcc04bfeb22", size = 1628776, upload-time = "2026-03-09T13:12:41.976Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e4/3f43a011bc8a0860d1c96f84d32fa87439d3feedf66e672fef03bf5e8bac/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9190426b7aa26c5229501fa297b8d0653cfd3f5a36f7990c264e157cbf886b3b", size = 1228164, upload-time = "2026-03-09T13:12:44.002Z" }, + { url = "https://files.pythonhosted.org/packages/4b/34/3a901559a1e0c218404f9a61a93be82d45cb8f44453ba43088644980f033/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c8277104ded0a51e699c8c3aff63ce2c56d4ed5519a5f73e0fd7057f959a2b9e", size = 1246656, upload-time = "2026-03-09T13:12:45.557Z" }, + { url = "https://files.pythonhosted.org/packages/87/9e/f78c466ea20527822b95ad38f141f2de1dcd7f23fb8716b002b0d91bbe59/kiwisolver-1.5.0-cp310-cp310-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8f9baf6f0a6e7571c45c8863010b45e837c3ee1c2c77fcd6ef423be91b21fedb", size = 1295562, upload-time = "2026-03-09T13:12:47.562Z" }, + { url = "https://files.pythonhosted.org/packages/0a/66/fd0e4a612e3a286c24e6d6f3a5428d11258ed1909bc530ba3b59807fd980/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cff8e5383db4989311f99e814feeb90c4723eb4edca425b9d5d9c3fefcdd9537", size = 2178473, upload-time = "2026-03-09T13:12:50.254Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8e/6cac929e0049539e5ee25c1ee937556f379ba5204840d03008363ced662d/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ebae99ed6764f2b5771c522477b311be313e8841d2e0376db2b10922daebbba4", size = 2274035, upload-time = "2026-03-09T13:12:51.785Z" }, + { url = "https://files.pythonhosted.org/packages/ca/d3/9d0c18f1b52ea8074b792452cf17f1f5a56bd0302a85191f405cfbf9da16/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:d5cd5189fc2b6a538b75ae45433140c4823463918f7b1617c31e68b085c0022c", size = 2443217, upload-time = "2026-03-09T13:12:53.329Z" }, + { url = "https://files.pythonhosted.org/packages/45/2a/6e19368803a038b2a90857bf4ee9e3c7b667216d045866bf22d3439fd75e/kiwisolver-1.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f42c23db5d1521218a3276bb08666dcb662896a0be7347cba864eca45ff64ede", size = 2249196, upload-time = "2026-03-09T13:12:55.057Z" }, + { url = "https://files.pythonhosted.org/packages/75/2b/3f641dfcbe72e222175d626bacf2f72c3b34312afec949dd1c50afa400f5/kiwisolver-1.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:94eff26096eb5395136634622515b234ecb6c9979824c1f5004c6e3c3c85ccd2", size = 73389, upload-time = "2026-03-09T13:12:56.496Z" }, + { url = "https://files.pythonhosted.org/packages/da/88/299b137b9e0025d8982e03d2d52c123b0a2b159e84b0ef1501ef446339cf/kiwisolver-1.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:dd952e03bfbb096cfe2dd35cd9e00f269969b67536cb4370994afc20ff2d0875", size = 64782, upload-time = "2026-03-09T13:12:57.609Z" }, + { url = "https://files.pythonhosted.org/packages/17/6f/6fd4f690a40c2582fa34b97d2678f718acf3706b91d270c65ecb455d0a06/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:295d9ffe712caa9f8a3081de8d32fc60191b4b51c76f02f951fd8407253528f4", size = 59606, upload-time = "2026-03-09T13:15:40.81Z" }, + { url = "https://files.pythonhosted.org/packages/82/a0/2355d5e3b338f13ce63f361abb181e3b6ea5fffdb73f739b3e80efa76159/kiwisolver-1.5.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:51e8c4084897de9f05898c2c2a39af6318044ae969d46ff7a34ed3f96274adca", size = 57537, upload-time = "2026-03-09T13:15:42.071Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b9/1d50e610ecadebe205b71d6728fd224ce0e0ca6aba7b9cbe1da049203ac5/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b83af57bdddef03c01a9138034c6ff03181a3028d9a1003b301eb1a55e161a3f", size = 79888, upload-time = "2026-03-09T13:15:43.317Z" }, + { url = "https://files.pythonhosted.org/packages/cd/ee/b85ffcd75afed0357d74f0e6fc02a4507da441165de1ca4760b9f496390d/kiwisolver-1.5.0-pp310-pypy310_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf4679a3d71012a7c2bf360e5cd878fbd5e4fcac0896b56393dec239d81529ed", size = 77584, upload-time = "2026-03-09T13:15:44.605Z" }, + { url = "https://files.pythonhosted.org/packages/6b/dd/644d0dde6010a8583b4cd66dd41c5f83f5325464d15c4f490b3340ab73b4/kiwisolver-1.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:41024ed50e44ab1a60d3fe0a9d15a4ccc9f5f2b1d814ff283c8d01134d5b81bc", size = 73390, upload-time = "2026-03-09T13:15:45.832Z" }, ] [[package]] @@ -1569,57 +1603,45 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474 } +sdist = { url = "https://files.pythonhosted.org/packages/0e/72/a3add0e4eec4eb9e2569554f7c70f4a3c27712f40e3284d483e88094cc0e/langdetect-1.0.9.tar.gz", hash = "sha256:cbc1fef89f8d062739774bd51eda3da3274006b3661d199c2655f6b3f6d605a0", size = 981474, upload-time = "2021-05-07T07:54:13.562Z" } [[package]] name = "lark" version = "1.3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732 } +sdist = { url = "https://files.pythonhosted.org/packages/da/34/28fff3ab31ccff1fd4f6c7c7b0ceb2b6968d8ea4950663eadcb5720591a0/lark-1.3.1.tar.gz", hash = "sha256:b426a7a6d6d53189d318f2b6236ab5d6429eaf09259f1ca33eb716eed10d2905", size = 382732, upload-time = "2025-10-27T18:25:56.653Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151 }, -] - -[[package]] -name = "lightning-utilities" -version = "0.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fire" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/ee/4b206e722c4fc138436aa91299692bba4fdad1b6ce8429bf291929456b04/lightning-utilities-0.3.0.tar.gz", hash = "sha256:d769ab9b76ebdee3243d1051d509aafee57d7947734ddc22977deef8a6427f2f", size = 15292 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/fc/1f4ff2bcba4e6162276cabe831a431ef14681a7158e693a5cf828dd6fa1b/lightning_utilities-0.3.0-py3-none-any.whl", hash = "sha256:1ae9bdd8f1be3c81b1ac4820f6eeddcbafcc2505c57a5940054466f4763bc22d", size = 15594 }, + { url = "https://files.pythonhosted.org/packages/82/3d/14ce75ef66813643812f3093ab17e46d3a206942ce7376d31ec2d36229e7/lark-1.3.1-py3-none-any.whl", hash = "sha256:c629b661023a014c37da873b4ff58a817398d12635d3bbb2c5a03be7fe5d1e12", size = 113151, upload-time = "2025-10-27T18:25:54.882Z" }, ] [[package]] name = "lxml" version = "6.0.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589 }, - { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671 }, - { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961 }, - { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087 }, - { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620 }, - { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664 }, - { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397 }, - { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178 }, - { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148 }, - { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035 }, - { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111 }, - { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662 }, - { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973 }, - { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953 }, - { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695 }, - { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051 }, - { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264 }, - { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435 }, - { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913 }, - { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357 }, - { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295 }, - { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913 }, +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8a/f8192a08237ef2fb1b19733f709db88a4c43bc8ab8357f01cb41a27e7f6a/lxml-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e77dd455b9a16bbd2a5036a63ddbd479c19572af81b624e79ef422f929eef388", size = 8590589, upload-time = "2025-09-22T04:00:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/12/64/27bcd07ae17ff5e5536e8d88f4c7d581b48963817a13de11f3ac3329bfa2/lxml-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d444858b9f07cefff6455b983aea9a67f7462ba1f6cbe4a21e8bf6791bf2153", size = 4629671, upload-time = "2025-09-22T04:00:15.411Z" }, + { url = "https://files.pythonhosted.org/packages/02/5a/a7d53b3291c324e0b6e48f3c797be63836cc52156ddf8f33cd72aac78866/lxml-6.0.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f952dacaa552f3bb8834908dddd500ba7d508e6ea6eb8c52eb2d28f48ca06a31", size = 4999961, upload-time = "2025-09-22T04:00:17.619Z" }, + { url = "https://files.pythonhosted.org/packages/f5/55/d465e9b89df1761674d8672bb3e4ae2c47033b01ec243964b6e334c6743f/lxml-6.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:71695772df6acea9f3c0e59e44ba8ac50c4f125217e84aab21074a1a55e7e5c9", size = 5157087, upload-time = "2025-09-22T04:00:19.868Z" }, + { url = "https://files.pythonhosted.org/packages/62/38/3073cd7e3e8dfc3ba3c3a139e33bee3a82de2bfb0925714351ad3d255c13/lxml-6.0.2-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:17f68764f35fd78d7c4cc4ef209a184c38b65440378013d24b8aecd327c3e0c8", size = 5067620, upload-time = "2025-09-22T04:00:21.877Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d3/1e001588c5e2205637b08985597827d3827dbaaece16348c8822bfe61c29/lxml-6.0.2-cp310-cp310-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:058027e261afed589eddcfe530fcc6f3402d7fd7e89bfd0532df82ebc1563dba", size = 5406664, upload-time = "2025-09-22T04:00:23.714Z" }, + { url = "https://files.pythonhosted.org/packages/20/cf/cab09478699b003857ed6ebfe95e9fb9fa3d3c25f1353b905c9b73cfb624/lxml-6.0.2-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8ffaeec5dfea5881d4c9d8913a32d10cfe3923495386106e4a24d45300ef79c", size = 5289397, upload-time = "2025-09-22T04:00:25.544Z" }, + { url = "https://files.pythonhosted.org/packages/a3/84/02a2d0c38ac9a8b9f9e5e1bbd3f24b3f426044ad618b552e9549ee91bd63/lxml-6.0.2-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:f2e3b1a6bb38de0bc713edd4d612969dd250ca8b724be8d460001a387507021c", size = 4772178, upload-time = "2025-09-22T04:00:27.602Z" }, + { url = "https://files.pythonhosted.org/packages/56/87/e1ceadcc031ec4aa605fe95476892d0b0ba3b7f8c7dcdf88fdeff59a9c86/lxml-6.0.2-cp310-cp310-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d6690ec5ec1cce0385cb20896b16be35247ac8c2046e493d03232f1c2414d321", size = 5358148, upload-time = "2025-09-22T04:00:29.323Z" }, + { url = "https://files.pythonhosted.org/packages/fe/13/5bb6cf42bb228353fd4ac5f162c6a84fd68a4d6f67c1031c8cf97e131fc6/lxml-6.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f2a50c3c1d11cad0ebebbac357a97b26aa79d2bcaf46f256551152aa85d3a4d1", size = 5112035, upload-time = "2025-09-22T04:00:31.061Z" }, + { url = "https://files.pythonhosted.org/packages/e4/e2/ea0498552102e59834e297c5c6dff8d8ded3db72ed5e8aad77871476f073/lxml-6.0.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:3efe1b21c7801ffa29a1112fab3b0f643628c30472d507f39544fd48e9549e34", size = 4799111, upload-time = "2025-09-22T04:00:33.11Z" }, + { url = "https://files.pythonhosted.org/packages/6a/9e/8de42b52a73abb8af86c66c969b3b4c2a96567b6ac74637c037d2e3baa60/lxml-6.0.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:59c45e125140b2c4b33920d21d83681940ca29f0b83f8629ea1a2196dc8cfe6a", size = 5351662, upload-time = "2025-09-22T04:00:35.237Z" }, + { url = "https://files.pythonhosted.org/packages/28/a2/de776a573dfb15114509a37351937c367530865edb10a90189d0b4b9b70a/lxml-6.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:452b899faa64f1805943ec1c0c9ebeaece01a1af83e130b69cdefeda180bb42c", size = 5314973, upload-time = "2025-09-22T04:00:37.086Z" }, + { url = "https://files.pythonhosted.org/packages/50/a0/3ae1b1f8964c271b5eec91db2043cf8c6c0bce101ebb2a633b51b044db6c/lxml-6.0.2-cp310-cp310-win32.whl", hash = "sha256:1e786a464c191ca43b133906c6903a7e4d56bef376b75d97ccbb8ec5cf1f0a4b", size = 3611953, upload-time = "2025-09-22T04:00:39.224Z" }, + { url = "https://files.pythonhosted.org/packages/d1/70/bd42491f0634aad41bdfc1e46f5cff98825fb6185688dc82baa35d509f1a/lxml-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:dacf3c64ef3f7440e3167aa4b49aa9e0fb99e0aa4f9ff03795640bf94531bcb0", size = 4032695, upload-time = "2025-09-22T04:00:41.402Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d0/05c6a72299f54c2c561a6c6cbb2f512e047fca20ea97a05e57931f194ac4/lxml-6.0.2-cp310-cp310-win_arm64.whl", hash = "sha256:45f93e6f75123f88d7f0cfd90f2d05f441b808562bf0bc01070a00f53f5028b5", size = 3680051, upload-time = "2025-09-22T04:00:43.525Z" }, + { url = "https://files.pythonhosted.org/packages/e7/9c/780c9a8fce3f04690b374f72f41306866b0400b9d0fdf3e17aaa37887eed/lxml-6.0.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e748d4cf8fef2526bb2a589a417eba0c8674e29ffcb570ce2ceca44f1e567bf6", size = 3939264, upload-time = "2025-09-22T04:04:32.892Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5a/1ab260c00adf645d8bf7dec7f920f744b032f69130c681302821d5debea6/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4ddb1049fa0579d0cbd00503ad8c58b9ab34d1254c77bc6a5576d96ec7853dba", size = 4216435, upload-time = "2025-09-22T04:04:34.907Z" }, + { url = "https://files.pythonhosted.org/packages/f2/37/565f3b3d7ffede22874b6d86be1a1763d00f4ea9fc5b9b6ccb11e4ec8612/lxml-6.0.2-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cb233f9c95f83707dae461b12b720c1af9c28c2d19208e1be03387222151daf5", size = 4325913, upload-time = "2025-09-22T04:04:37.205Z" }, + { url = "https://files.pythonhosted.org/packages/22/ec/f3a1b169b2fb9d03467e2e3c0c752ea30e993be440a068b125fc7dd248b0/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bc456d04db0515ce3320d714a1eac7a97774ff0849e7718b492d957da4631dd4", size = 4269357, upload-time = "2025-09-22T04:04:39.322Z" }, + { url = "https://files.pythonhosted.org/packages/77/a2/585a28fe3e67daa1cf2f06f34490d556d121c25d500b10082a7db96e3bcd/lxml-6.0.2-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2613e67de13d619fd283d58bda40bff0ee07739f624ffee8b13b631abf33083d", size = 4412295, upload-time = "2025-09-22T04:04:41.647Z" }, + { url = "https://files.pythonhosted.org/packages/7b/d9/a57dd8bcebd7c69386c20263830d4fa72d27e6b72a229ef7a48e88952d9a/lxml-6.0.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:24a8e756c982c001ca8d59e87c80c4d9dcd4d9b44a4cbeb8d9be4482c514d41d", size = 3516913, upload-time = "2025-09-22T04:04:43.602Z" }, ] [[package]] @@ -1629,9 +1651,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/38/bd5b78a920a64d708fe6bc8e0a2c075e1389d53bef8413725c63ba041535/mako-1.3.10.tar.gz", hash = "sha256:99579a6f39583fa7e5630a28c3c1f440e4e97a414b80372649c0ce338da2ea28", size = 392474, upload-time = "2025-04-10T12:44:31.16Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509 }, + { url = "https://files.pythonhosted.org/packages/87/fb/99f81ac72ae23375f22b7afdb7642aba97c00a713c217124420147681a2f/mako-1.3.10-py3-none-any.whl", hash = "sha256:baef24a52fc4fc514a0887ac600f9f1cff3d82c61d4d700a1fa84d597b88db59", size = 78509, upload-time = "2025-04-10T12:50:53.297Z" }, ] [[package]] @@ -1641,28 +1663,28 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070 } +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321 }, + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, ] [[package]] name = "markupsafe" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313 } +sdist = { url = "https://files.pythonhosted.org/packages/7e/99/7690b6d4034fffd95959cbe0c02de8deb3098cc577c67bb6a24fe5d7caa7/markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698", size = 80313, upload-time = "2025-09-27T18:37:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631 }, - { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057 }, - { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050 }, - { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681 }, - { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705 }, - { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524 }, - { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282 }, - { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745 }, - { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571 }, - { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056 }, - { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932 }, + { url = "https://files.pythonhosted.org/packages/e8/4b/3541d44f3937ba468b75da9eebcae497dcf67adb65caa16760b0a6807ebb/markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559", size = 11631, upload-time = "2025-09-27T18:36:05.558Z" }, + { url = "https://files.pythonhosted.org/packages/98/1b/fbd8eed11021cabd9226c37342fa6ca4e8a98d8188a8d9b66740494960e4/markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419", size = 12057, upload-time = "2025-09-27T18:36:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/40/01/e560d658dc0bb8ab762670ece35281dec7b6c1b33f5fbc09ebb57a185519/markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695", size = 22050, upload-time = "2025-09-27T18:36:08.005Z" }, + { url = "https://files.pythonhosted.org/packages/af/cd/ce6e848bbf2c32314c9b237839119c5a564a59725b53157c856e90937b7a/markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591", size = 20681, upload-time = "2025-09-27T18:36:08.881Z" }, + { url = "https://files.pythonhosted.org/packages/c9/2a/b5c12c809f1c3045c4d580b035a743d12fcde53cf685dbc44660826308da/markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c", size = 20705, upload-time = "2025-09-27T18:36:10.131Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e3/9427a68c82728d0a88c50f890d0fc072a1484de2f3ac1ad0bfc1a7214fd5/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f", size = 21524, upload-time = "2025-09-27T18:36:11.324Z" }, + { url = "https://files.pythonhosted.org/packages/bc/36/23578f29e9e582a4d0278e009b38081dbe363c5e7165113fad546918a232/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6", size = 20282, upload-time = "2025-09-27T18:36:12.573Z" }, + { url = "https://files.pythonhosted.org/packages/56/21/dca11354e756ebd03e036bd8ad58d6d7168c80ce1fe5e75218e4945cbab7/markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1", size = 20745, upload-time = "2025-09-27T18:36:13.504Z" }, + { url = "https://files.pythonhosted.org/packages/87/99/faba9369a7ad6e4d10b6a5fbf71fa2a188fe4a593b15f0963b73859a1bbd/markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa", size = 14571, upload-time = "2025-09-27T18:36:14.779Z" }, + { url = "https://files.pythonhosted.org/packages/d6/25/55dc3ab959917602c96985cb1253efaa4ff42f71194bddeb61eb7278b8be/markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8", size = 15056, upload-time = "2025-09-27T18:36:16.125Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9e/0a02226640c255d1da0b8d12e24ac2aa6734da68bff14c05dd53b94a0fc3/markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1", size = 13932, upload-time = "2025-09-27T18:36:17.311Z" }, ] [[package]] @@ -1680,17 +1702,17 @@ dependencies = [ { name = "pyparsing" }, { name = "python-dateutil" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/76/d3c6e3a13fe484ebe7718d14e269c9569c4eb0020a968a327acb3b9a8fe6/matplotlib-3.10.8.tar.gz", hash = "sha256:2299372c19d56bcd35cf05a2738308758d32b9eaed2371898d8f5bd33f084aa3", size = 34806269, upload-time = "2025-12-10T22:56:51.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828 }, - { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050 }, - { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452 }, - { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928 }, - { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377 }, - { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127 }, - { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252 }, - { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693 }, - { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205 }, + { url = "https://files.pythonhosted.org/packages/58/be/a30bd917018ad220c400169fba298f2bb7003c8ccbc0c3e24ae2aacad1e8/matplotlib-3.10.8-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:00270d217d6b20d14b584c521f810d60c5c78406dc289859776550df837dcda7", size = 8239828, upload-time = "2025-12-10T22:55:02.313Z" }, + { url = "https://files.pythonhosted.org/packages/58/27/ca01e043c4841078e82cf6e80a6993dfecd315c3d79f5f3153afbb8e1ec6/matplotlib-3.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37b3c1cc42aa184b3f738cfa18c1c1d72fd496d85467a6cf7b807936d39aa656", size = 8128050, upload-time = "2025-12-10T22:55:04.997Z" }, + { url = "https://files.pythonhosted.org/packages/cb/aa/7ab67f2b729ae6a91bcf9dcac0affb95fb8c56f7fd2b2af894ae0b0cf6fa/matplotlib-3.10.8-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ee40c27c795bda6a5292e9cff9890189d32f7e3a0bf04e0e3c9430c4a00c37df", size = 8700452, upload-time = "2025-12-10T22:55:07.47Z" }, + { url = "https://files.pythonhosted.org/packages/73/ae/2d5817b0acee3c49b7e7ccfbf5b273f284957cc8e270adf36375db353190/matplotlib-3.10.8-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a48f2b74020919552ea25d222d5cc6af9ca3f4eb43a93e14d068457f545c2a17", size = 9534928, upload-time = "2025-12-10T22:55:10.566Z" }, + { url = "https://files.pythonhosted.org/packages/c9/5b/8e66653e9f7c39cb2e5cab25fce4810daffa2bff02cbf5f3077cea9e942c/matplotlib-3.10.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f254d118d14a7f99d616271d6c3c27922c092dac11112670b157798b89bf4933", size = 9586377, upload-time = "2025-12-10T22:55:12.362Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/fd0bbadf837f81edb0d208ba8f8cb552874c3b16e27cb91a31977d90875d/matplotlib-3.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:f9b587c9c7274c1613a30afabf65a272114cd6cdbe67b3406f818c79d7ab2e2a", size = 8128127, upload-time = "2025-12-10T22:55:14.436Z" }, + { url = "https://files.pythonhosted.org/packages/f5/43/31d59500bb950b0d188e149a2e552040528c13d6e3d6e84d0cccac593dcd/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f97aeb209c3d2511443f8797e3e5a569aebb040d4f8bc79aa3ee78a8fb9e3dd8", size = 8237252, upload-time = "2025-12-10T22:56:39.529Z" }, + { url = "https://files.pythonhosted.org/packages/0c/2c/615c09984f3c5f907f51c886538ad785cf72e0e11a3225de2c0f9442aecc/matplotlib-3.10.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fb061f596dad3a0f52b60dc6a5dec4a0c300dec41e058a7efe09256188d170b7", size = 8124693, upload-time = "2025-12-10T22:56:41.758Z" }, + { url = "https://files.pythonhosted.org/packages/91/e1/2757277a1c56041e1fc104b51a0f7b9a4afc8eb737865d63cababe30bc61/matplotlib-3.10.8-pp310-pypy310_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:12d90df9183093fcd479f4172ac26b322b1248b15729cb57f42f71f24c7e37a3", size = 8702205, upload-time = "2025-12-10T22:56:43.415Z" }, ] [[package]] @@ -1700,18 +1722,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516 }, + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, ] [[package]] name = "mdurl" version = "0.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, ] [[package]] @@ -1721,18 +1743,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467 } +sdist = { url = "https://files.pythonhosted.org/packages/9d/55/d01f0c4b45ade6536c51170b9043db8b2ec6ddf4a35c7ea3f5f559ac935b/mistune-3.2.0.tar.gz", hash = "sha256:708487c8a8cdd99c9d90eb3ed4c3ed961246ff78ac82f03418f5183ab70e398a", size = 95467, upload-time = "2025-12-23T11:36:34.994Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598 }, + { url = "https://files.pythonhosted.org/packages/9b/f7/4a5e785ec9fbd65146a27b6b70b6cdc161a66f2024e4b04ac06a67f5578b/mistune-3.2.0-py3-none-any.whl", hash = "sha256:febdc629a3c78616b94393c6580551e0e34cc289987ec6c35ed3f4be42d0eee1", size = 53598, upload-time = "2025-12-23T11:36:33.211Z" }, ] [[package]] name = "more-itertools" version = "10.8.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431 } +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/38b681d3fce7a266dd9ab73c66959406d565b3e85f21d5e66e1181d93721/more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd", size = 137431, upload-time = "2025-09-02T15:23:11.018Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667 }, + { url = "https://files.pythonhosted.org/packages/a4/8e/469e5a4a2f5855992e425f3cb33804cc07bf18d48f2db061aec61ce50270/more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b", size = 69667, upload-time = "2025-09-02T15:23:09.635Z" }, ] [[package]] @@ -1743,18 +1765,18 @@ dependencies = [ { name = "jinja2" }, { name = "matplotlib" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/b2/9943f3e0bdf4ff9968b7ac4499152162d8ee8fc8eaa55487339872f86300/mpld3-0.5.12.tar.gz", hash = "sha256:1333e2bca012ea9af3c27801ba36f65bc26540b6fad4c56a903afb19477f2c37", size = 1028433, upload-time = "2025-11-05T18:12:24.183Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051 }, + { url = "https://files.pythonhosted.org/packages/5b/69/93b34728cc386efdde0c342f8c680b9187dea7beb7adaf6b58a0713be101/mpld3-0.5.12-py3-none-any.whl", hash = "sha256:bea31799a4041029a906f53f2662bbf1c49903e0c0bc712b412354158ec7cf54", size = 203051, upload-time = "2025-11-05T18:12:22.527Z" }, ] [[package]] name = "mpmath" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198 }, + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, ] [[package]] @@ -1764,27 +1786,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176 }, - { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996 }, - { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631 }, - { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561 }, - { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223 }, - { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322 }, - { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005 }, - { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173 }, - { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273 }, - { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956 }, - { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477 }, - { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615 }, - { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930 }, - { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807 }, - { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103 }, - { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416 }, - { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022 }, - { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238 }, - { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319 }, +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176, upload-time = "2026-01-26T02:42:59.784Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996, upload-time = "2026-01-26T02:43:01.674Z" }, + { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631, upload-time = "2026-01-26T02:43:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561, upload-time = "2026-01-26T02:43:04.733Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223, upload-time = "2026-01-26T02:43:06.695Z" }, + { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322, upload-time = "2026-01-26T02:43:08.472Z" }, + { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005, upload-time = "2026-01-26T02:43:10.127Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173, upload-time = "2026-01-26T02:43:11.731Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273, upload-time = "2026-01-26T02:43:13.063Z" }, + { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956, upload-time = "2026-01-26T02:43:14.843Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477, upload-time = "2026-01-26T02:43:16.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615, upload-time = "2026-01-26T02:43:17.84Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930, upload-time = "2026-01-26T02:43:19.06Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807, upload-time = "2026-01-26T02:43:20.286Z" }, + { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103, upload-time = "2026-01-26T02:43:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416, upload-time = "2026-01-26T02:43:22.703Z" }, + { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022, upload-time = "2026-01-26T02:43:23.77Z" }, + { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238, upload-time = "2026-01-26T02:43:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, ] [[package]] @@ -1794,23 +1816,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "dill" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503 } +sdist = { url = "https://files.pythonhosted.org/packages/72/fd/2ae3826f5be24c6ed87266bc4e59c46ea5b059a103f3d7e7eb76a52aeecb/multiprocess-0.70.18.tar.gz", hash = "sha256:f9597128e6b3e67b23956da07cf3d2e5cba79e2f4e0fba8d7903636663ec6d0d", size = 1798503, upload-time = "2025-04-17T03:11:27.742Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083 }, - { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128 }, - { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132 }, - { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948 }, - { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636 }, - { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478 }, + { url = "https://files.pythonhosted.org/packages/c8/f8/7f9a8f08bf98cea1dfaa181e05cc8bbcb59cecf044b5a9ac3cce39f9c449/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:25d4012dcaaf66b9e8e955f58482b42910c2ee526d532844d8bcf661bbc604df", size = 135083, upload-time = "2025-04-17T03:11:04.223Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/b7b10dbfc17b2b3ce07d4d30b3ba8367d0ed32d6d46cd166e298f161dd46/multiprocess-0.70.18-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:06b19433de0d02afe5869aec8931dd5c01d99074664f806c73896b0d9e527213", size = 135128, upload-time = "2025-04-17T03:11:06.045Z" }, + { url = "https://files.pythonhosted.org/packages/c1/a3/5f8d3b9690ea5580bee5868ab7d7e2cfca74b7e826b28192b40aa3881cdc/multiprocess-0.70.18-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6fa1366f994373aaf2d4738b0f56e707caeaa05486e97a7f71ee0853823180c2", size = 135132, upload-time = "2025-04-17T03:11:07.533Z" }, + { url = "https://files.pythonhosted.org/packages/ba/d8/0cba6cf51a1a31f20471fbc823a716170c73012ddc4fb85d706630ed6e8f/multiprocess-0.70.18-py310-none-any.whl", hash = "sha256:60c194974c31784019c1f459d984e8f33ee48f10fcf42c309ba97b30d9bd53ea", size = 134948, upload-time = "2025-04-17T03:11:20.223Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c3/ca84c19bd14cdfc21c388fdcebf08b86a7a470ebc9f5c3c084fc2dbc50f7/multiprocess-0.70.18-py38-none-any.whl", hash = "sha256:dbf705e52a154fe5e90fb17b38f02556169557c2dd8bb084f2e06c2784d8279b", size = 132636, upload-time = "2025-04-17T03:11:24.936Z" }, + { url = "https://files.pythonhosted.org/packages/6c/28/dd72947e59a6a8c856448a5e74da6201cb5502ddff644fbc790e4bd40b9a/multiprocess-0.70.18-py39-none-any.whl", hash = "sha256:e78ca805a72b1b810c690b6b4cc32579eba34f403094bbbae962b7b5bf9dfcb8", size = 133478, upload-time = "2025-04-17T03:11:26.253Z" }, ] [[package]] name = "narwhals" -version = "2.17.0" +version = "2.18.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/75/59/81d0f4cad21484083466f278e6b392addd9f4205b48d45b5c8771670ebf8/narwhals-2.17.0.tar.gz", hash = "sha256:ebd5bc95bcfa2f8e89a8ac09e2765a63055162837208e67b42d6eeb6651d5e67", size = 620306 } +sdist = { url = "https://files.pythonhosted.org/packages/47/b4/02a8add181b8d2cd5da3b667cd102ae536e8c9572ab1a130816d70a89edb/narwhals-2.18.0.tar.gz", hash = "sha256:1de5cee338bc17c338c6278df2c38c0dd4290499fcf70d75e0a51d5f22a6e960", size = 620222, upload-time = "2026-03-10T15:51:27.14Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4b/27/20770bd6bf8fbe1e16f848ba21da9df061f38d2e6483952c29d2bb5d1d8b/narwhals-2.17.0-py3-none-any.whl", hash = "sha256:2ac5307b7c2b275a7d66eeda906b8605e3d7a760951e188dcfff86e8ebe083dd", size = 444897 }, + { url = "https://files.pythonhosted.org/packages/fe/75/0b4a10da17a44cf13567d08a9c7632a285297e46253263f1ae119129d10a/narwhals-2.18.0-py3-none-any.whl", hash = "sha256:68378155ee706ac9c5b25868ef62ecddd62947b6df7801a0a156bc0a615d2d0d", size = 444865, upload-time = "2026-03-10T15:51:24.085Z" }, ] [[package]] @@ -1823,9 +1845,9 @@ dependencies = [ { name = "nbformat" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554 } +sdist = { url = "https://files.pythonhosted.org/packages/56/91/1c1d5a4b9a9ebba2b4e32b8c852c2975c872aec1fe42ab5e516b2cecd193/nbclient-0.10.4.tar.gz", hash = "sha256:1e54091b16e6da39e297b0ece3e10f6f29f4ac4e8ee515d29f8a7099bd6553c9", size = 62554, upload-time = "2025-12-23T07:45:46.369Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465 }, + { url = "https://files.pythonhosted.org/packages/83/a0/5b0c2f11142ed1dddec842457d3f65eaf71a0080894eb6f018755b319c3a/nbclient-0.10.4-py3-none-any.whl", hash = "sha256:9162df5a7373d70d606527300a95a975a47c137776cd942e52d9c7e29ff83440", size = 25465, upload-time = "2025-12-23T07:45:44.51Z" }, ] [[package]] @@ -1848,9 +1870,9 @@ dependencies = [ { name = "pygments" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/38/47/81f886b699450d0569f7bc551df2b1673d18df7ff25cc0c21ca36ed8a5ff/nbconvert-7.17.0.tar.gz", hash = "sha256:1b2696f1b5be12309f6c7d707c24af604b87dfaf6d950794c7b07acab96dda78", size = 862855 } +sdist = { url = "https://files.pythonhosted.org/packages/38/47/81f886b699450d0569f7bc551df2b1673d18df7ff25cc0c21ca36ed8a5ff/nbconvert-7.17.0.tar.gz", hash = "sha256:1b2696f1b5be12309f6c7d707c24af604b87dfaf6d950794c7b07acab96dda78", size = 862855, upload-time = "2026-01-29T16:37:48.478Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl", hash = "sha256:4f99a63b337b9a23504347afdab24a11faa7d86b405e5c8f9881cd313336d518", size = 261510 }, + { url = "https://files.pythonhosted.org/packages/0d/4b/8d5f796a792f8a25f6925a96032f098789f448571eb92011df1ae59e8ea8/nbconvert-7.17.0-py3-none-any.whl", hash = "sha256:4f99a63b337b9a23504347afdab24a11faa7d86b405e5c8f9881cd313336d518", size = 261510, upload-time = "2026-01-29T16:37:46.322Z" }, ] [[package]] @@ -1863,9 +1885,9 @@ dependencies = [ { name = "jupyter-core" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749 } +sdist = { url = "https://files.pythonhosted.org/packages/6d/fd/91545e604bc3dad7dca9ed03284086039b294c6b3d75c0d2fa45f9e9caf3/nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a", size = 142749, upload-time = "2024-04-04T11:20:37.371Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 }, + { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454, upload-time = "2024-04-04T11:20:34.895Z" }, ] [[package]] @@ -1875,41 +1897,41 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nbformat" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f9/6f/b52c4da26babeb521078c08c78c3187a59197098ffc7a70b0fe76851813a/nbstripout-0.9.1.tar.gz", hash = "sha256:313bbb4217c8e38998567e5d790b6bd6c3a17a8c39073b205b84dadfc5d756dc", size = 32356 } +sdist = { url = "https://files.pythonhosted.org/packages/f9/6f/b52c4da26babeb521078c08c78c3187a59197098ffc7a70b0fe76851813a/nbstripout-0.9.1.tar.gz", hash = "sha256:313bbb4217c8e38998567e5d790b6bd6c3a17a8c39073b205b84dadfc5d756dc", size = 32356, upload-time = "2026-02-21T16:19:55.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/16/e777eadfa0c0305878c36fae1d5e6db474fbb15dae202b9ec378809dfb4d/nbstripout-0.9.1-py3-none-any.whl", hash = "sha256:ca027ee45742ee77e4f8e9080254f9a707f1161ba11367b82fdf4a29892c759e", size = 19136 }, + { url = "https://files.pythonhosted.org/packages/20/16/e777eadfa0c0305878c36fae1d5e6db474fbb15dae202b9ec378809dfb4d/nbstripout-0.9.1-py3-none-any.whl", hash = "sha256:ca027ee45742ee77e4f8e9080254f9a707f1161ba11367b82fdf4a29892c759e", size = 19136, upload-time = "2026-02-21T16:19:54.868Z" }, ] [[package]] name = "nest-asyncio" version = "1.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418 } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195 }, + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, ] [[package]] name = "networkx" version = "3.4.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368 } +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 }, + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, ] [[package]] name = "nodeenv" version = "1.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611 } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438 }, + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] [[package]] name = "notebook" -version = "7.5.3" +version = "7.5.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, @@ -1918,9 +1940,9 @@ dependencies = [ { name = "notebook-shim" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b8/cb/cc7f4df5cee315dd126a47eb60890690a0438d5e0dd40c32d60ce16de377/notebook-7.5.3.tar.gz", hash = "sha256:393ceb269cf9fdb02a3be607a57d7bd5c2c14604f1818a17dbeb38e04f98cbfa", size = 14073140 } +sdist = { url = "https://files.pythonhosted.org/packages/1f/6d/41052c48d6f6349ca0a7c4d1f6a78464de135e6d18f5829ba2510e62184c/notebook-7.5.5.tar.gz", hash = "sha256:dc0bfab0f2372c8278c457423d3256c34154ac2cc76bf20e9925260c461013c3", size = 14169167, upload-time = "2026-03-11T16:32:51.922Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/96/98/9286e7f35e5584ebb79f997f2fb0cb66745c86f6c5fccf15ba32aac5e908/notebook-7.5.3-py3-none-any.whl", hash = "sha256:c997bfa1a2a9eb58c9bbb7e77d50428befb1033dd6f02c482922e96851d67354", size = 14481744 }, + { url = "https://files.pythonhosted.org/packages/f8/aa/cbd1deb9f07446241e88f8d5fecccd95b249bca0b4e5482214a4d1714c49/notebook-7.5.5-py3-none-any.whl", hash = "sha256:a7c14dbeefa6592e87f72290ca982e0c10f5bbf3786be2a600fda9da2764a2b8", size = 14578929, upload-time = "2026-03-11T16:32:48.021Z" }, ] [[package]] @@ -1930,25 +1952,25 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jupyter-server" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167 } +sdist = { url = "https://files.pythonhosted.org/packages/54/d2/92fa3243712b9a3e8bafaf60aac366da1cada3639ca767ff4b5b3654ec28/notebook_shim-0.2.4.tar.gz", hash = "sha256:b4b2cfa1b65d98307ca24361f5b30fe785b53c3fd07b7a47e89acb5e6ac638cb", size = 13167, upload-time = "2024-02-14T23:35:18.353Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307 }, + { url = "https://files.pythonhosted.org/packages/f9/33/bd5b9137445ea4b680023eb0469b2bb969d61303dedb2aac6560ff3d14a1/notebook_shim-0.2.4-py3-none-any.whl", hash = "sha256:411a5be4e9dc882a074ccbcae671eda64cceb068767e9a3419096986560e1cef", size = 13307, upload-time = "2024-02-14T23:35:16.286Z" }, ] [[package]] name = "numpy" version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129 } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468 }, - { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411 }, - { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016 }, - { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889 }, - { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746 }, - { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620 }, - { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659 }, - { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905 }, + { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411, upload-time = "2024-02-05T23:48:29.038Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016, upload-time = "2024-02-05T23:48:54.098Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889, upload-time = "2024-02-05T23:49:25.361Z" }, + { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746, upload-time = "2024-02-05T23:49:51.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620, upload-time = "2024-02-05T23:50:22.515Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659, upload-time = "2024-02-05T23:50:35.834Z" }, + { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905, upload-time = "2024-02-05T23:51:03.701Z" }, ] [[package]] @@ -1956,8 +1978,7 @@ name = "nvidia-cublas-cu12" version = "12.8.4.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/99/db44d685f0e257ff0e213ade1964fc459b4a690a73293220e98feb3307cf/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b86f6dd8935884615a0683b663891d43781b819ac4f2ba2b0c9604676af346d0", size = 590537124 }, - { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921 }, + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, ] [[package]] @@ -1965,8 +1986,7 @@ name = "nvidia-cuda-cupti-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d5/1f/b3bd73445e5cb342727fd24fe1f7b748f690b460acadc27ea22f904502c8/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4412396548808ddfed3f17a467b104ba7751e6b58678a4b840675c56d21cf7ed", size = 9533318 }, - { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621 }, + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, ] [[package]] @@ -1974,8 +1994,7 @@ name = "nvidia-cuda-nvrtc-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029 }, - { url = "https://files.pythonhosted.org/packages/eb/d1/e50d0acaab360482034b84b6e27ee83c6738f7d32182b987f9c7a4e32962/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fc1fec1e1637854b4c0a65fb9a8346b51dd9ee69e61ebaccc82058441f15bce8", size = 43106076 }, + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, ] [[package]] @@ -1983,8 +2002,7 @@ name = "nvidia-cuda-runtime-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/75/f865a3b236e4647605ea34cc450900854ba123834a5f1598e160b9530c3a/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:52bf7bbee900262ffefe5e9d5a2a69a30d97e2bc5bb6cc866688caa976966e3d", size = 965265 }, - { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765 }, + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, ] [[package]] @@ -1995,8 +2013,7 @@ dependencies = [ { name = "nvidia-cublas-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/41/e79269ce215c857c935fd86bcfe91a451a584dfc27f1e068f568b9ad1ab7/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:c9132cc3f8958447b4910a1720036d9eff5928cc3179b0a51fb6d167c6cc87d8", size = 705026878 }, - { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467 }, + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, ] [[package]] @@ -2007,8 +2024,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/60/bc/7771846d3a0272026c416fbb7e5f4c1f146d6d80704534d0b187dd6f4800/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:848ef7224d6305cdb2a4df928759dca7b1201874787083b6e7550dd6765ce69a", size = 193109211 }, - { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695 }, + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, ] [[package]] @@ -2016,8 +2032,7 @@ name = "nvidia-cufile-cu12" version = "1.13.1.3" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834 }, - { url = "https://files.pythonhosted.org/packages/1e/f5/5607710447a6fe9fd9b3283956fceeee8a06cda1d2f56ce31371f595db2a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:4beb6d4cce47c1a0f1013d72e02b0994730359e17801d395bdcbf20cfb3bb00a", size = 1120705 }, + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, ] [[package]] @@ -2025,8 +2040,7 @@ name = "nvidia-curand-cu12" version = "10.3.9.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/45/5e/92aa15eca622a388b80fbf8375d4760738df6285b1e92c43d37390a33a9a/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:dfab99248034673b779bc6decafdc3404a8a6f502462201f2f31f11354204acd", size = 63625754 }, - { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976 }, + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, ] [[package]] @@ -2039,8 +2053,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/32/f7cd6ce8a7690544d084ea21c26e910a97e077c9b7f07bf5de623ee19981/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:db9ed69dbef9715071232caa9b69c52ac7de3a95773c2db65bdba85916e4e5c0", size = 267229841 }, - { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905 }, + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, ] [[package]] @@ -2051,8 +2064,7 @@ dependencies = [ { name = "nvidia-nvjitlink-cu12" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/f7/cd777c4109681367721b00a106f491e0d0d15cfa1fd59672ce580ce42a97/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9b6c161cb130be1a07a27ea6923df8141f3c295852f4b260c65f18f3e0a091dc", size = 288117129 }, - { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466 }, + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, ] [[package]] @@ -2060,8 +2072,7 @@ name = "nvidia-cusparselt-cu12" version = "0.7.1" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/73/b9/598f6ff36faaece4b3c50d26f50e38661499ff34346f00e057760b35cc9d/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8878dce784d0fac90131b6817b607e803c36e629ba34dc5b433471382196b6a5", size = 283835557 }, - { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691 }, + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, ] [[package]] @@ -2069,8 +2080,7 @@ name = "nvidia-nccl-cu12" version = "2.27.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/1c/857979db0ef194ca5e21478a0612bcdbbe59458d7694361882279947b349/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:31432ad4d1fb1004eb0c56203dc9bc2178a1ba69d1d9e02d64a6938ab5e40e7a", size = 322400625 }, - { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229 }, + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, ] [[package]] @@ -2078,8 +2088,7 @@ name = "nvidia-nvjitlink-cu12" version = "12.8.93" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836 }, - { url = "https://files.pythonhosted.org/packages/2a/a2/8cee5da30d13430e87bf99bb33455d2724d0a4a9cb5d7926d80ccb96d008/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:adccd7161ace7261e01bb91e44e88da350895c270d23f744f0820c818b7229e7", size = 38386204 }, + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, ] [[package]] @@ -2087,8 +2096,7 @@ name = "nvidia-nvshmem-cu12" version = "3.4.5" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/6a/03aa43cc9bd3ad91553a88b5f6fb25ed6a3752ae86ce2180221962bc2aa5/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0b48363fc6964dede448029434c6abed6c5e37f823cb43c3bcde7ecfc0457e15", size = 138936938 }, - { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095 }, + { url = "https://files.pythonhosted.org/packages/b5/09/6ea3ea725f82e1e76684f0708bbedd871fc96da89945adeba65c3835a64c/nvidia_nvshmem_cu12-3.4.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:042f2500f24c021db8a06c5eec2539027d57460e1c1a762055a6554f72c369bd", size = 139103095, upload-time = "2025-09-06T00:32:31.266Z" }, ] [[package]] @@ -2096,8 +2104,7 @@ name = "nvidia-nvtx-cu12" version = "12.8.90" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/c0/1b303feea90d296f6176f32a2a70b5ef230f9bdeb3a72bddb0dc922dc137/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d7ad891da111ebafbf7e015d34879f7112832fc239ff0d7d776b6cb685274615", size = 91161 }, - { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954 }, + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, ] [[package]] @@ -2107,24 +2114,44 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "defusedxml" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045 } +sdist = { url = "https://files.pythonhosted.org/packages/97/73/8ade73f6749177003f7ce3304f524774adda96e6aaab30ea79fd8fda7934/odfpy-1.4.1.tar.gz", hash = "sha256:db766a6e59c5103212f3cc92ec8dd50a0f3a02790233ed0b52148b70d3c438ec", size = 717045, upload-time = "2020-01-18T16:55:48.852Z" } + +[[package]] +name = "onnxruntime" +version = "1.23.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coloredlogs" }, + { name = "flatbuffers" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "protobuf" }, + { name = "sympy" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/d6/311b1afea060015b56c742f3531168c1644650767f27ef40062569960587/onnxruntime-1.23.2-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:a7730122afe186a784660f6ec5807138bf9d792fa1df76556b27307ea9ebcbe3", size = 17195934, upload-time = "2025-10-27T23:06:14.143Z" }, + { url = "https://files.pythonhosted.org/packages/db/db/81bf3d7cecfbfed9092b6b4052e857a769d62ed90561b410014e0aae18db/onnxruntime-1.23.2-cp310-cp310-macosx_13_0_x86_64.whl", hash = "sha256:b28740f4ecef1738ea8f807461dd541b8287d5650b5be33bca7b474e3cbd1f36", size = 19153079, upload-time = "2025-10-27T23:05:57.686Z" }, + { url = "https://files.pythonhosted.org/packages/2e/4d/a382452b17cf70a2313153c520ea4c96ab670c996cb3a95cc5d5ac7bfdac/onnxruntime-1.23.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8f7d1fe034090a1e371b7f3ca9d3ccae2fabae8c1d8844fb7371d1ea38e8e8d2", size = 15219883, upload-time = "2025-10-22T03:46:21.66Z" }, + { url = "https://files.pythonhosted.org/packages/fb/56/179bf90679984c85b417664c26aae4f427cba7514bd2d65c43b181b7b08b/onnxruntime-1.23.2-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4ca88747e708e5c67337b0f65eed4b7d0dd70d22ac332038c9fc4635760018f7", size = 17370357, upload-time = "2025-10-22T03:46:57.968Z" }, + { url = "https://files.pythonhosted.org/packages/cd/6d/738e50c47c2fd285b1e6c8083f15dac1a5f6199213378a5f14092497296d/onnxruntime-1.23.2-cp310-cp310-win_amd64.whl", hash = "sha256:0be6a37a45e6719db5120e9986fcd30ea205ac8103fd1fb74b6c33348327a0cc", size = 13467651, upload-time = "2025-10-27T23:06:11.904Z" }, +] [[package]] name = "overrides" version = "7.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812 } +sdist = { url = "https://files.pythonhosted.org/packages/36/86/b585f53236dec60aba864e050778b25045f857e17f6e5ea0ae95fe80edd2/overrides-7.7.0.tar.gz", hash = "sha256:55158fa3d93b98cc75299b1e67078ad9003ca27945c76162c1c0766d6f91820a", size = 22812, upload-time = "2024-01-27T21:01:33.423Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832 }, + { url = "https://files.pythonhosted.org/packages/2c/ab/fc8290c6a4c722e5514d80f62b2dc4c4df1a68a41d1364e625c35990fcf3/overrides-7.7.0-py3-none-any.whl", hash = "sha256:c7ed9d062f78b8e4c1a7b70bd8796b35ead4d9f510227ef9c5dc7626c60d7e49", size = 17832, upload-time = "2024-01-27T21:01:31.393Z" }, ] [[package]] name = "packaging" version = "26.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416 } +sdist = { url = "https://files.pythonhosted.org/packages/65/ee/299d360cdc32edc7d2cf530f3accf79c4fca01e96ffc950d8a52213bd8e4/packaging-26.0.tar.gz", hash = "sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4", size = 143416, upload-time = "2026-01-21T20:50:39.064Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366 }, + { url = "https://files.pythonhosted.org/packages/b7/b9/c538f279a4e237a006a2c98387d081e9eb060d203d8ed34467cc0f0b9b53/packaging-26.0-py3-none-any.whl", hash = "sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529", size = 74366, upload-time = "2026-01-21T20:50:37.788Z" }, ] [[package]] @@ -2137,33 +2164,33 @@ dependencies = [ { name = "pytz" }, { name = "tzdata" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223 } +sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763 }, - { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217 }, - { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791 }, - { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373 }, - { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444 }, - { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459 }, - { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086 }, + { url = "https://files.pythonhosted.org/packages/3d/f7/f425a00df4fcc22b292c6895c6831c0c8ae1d9fac1e024d16f98a9ce8749/pandas-2.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:376c6446ae31770764215a6c937f72d917f214b43560603cd60da6408f183b6c", size = 11555763, upload-time = "2025-09-29T23:16:53.287Z" }, + { url = "https://files.pythonhosted.org/packages/13/4f/66d99628ff8ce7857aca52fed8f0066ce209f96be2fede6cef9f84e8d04f/pandas-2.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e19d192383eab2f4ceb30b412b22ea30690c9e618f78870357ae1d682912015a", size = 10801217, upload-time = "2025-09-29T23:17:04.522Z" }, + { url = "https://files.pythonhosted.org/packages/1d/03/3fc4a529a7710f890a239cc496fc6d50ad4a0995657dccc1d64695adb9f4/pandas-2.3.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5caf26f64126b6c7aec964f74266f435afef1c1b13da3b0636c7518a1fa3e2b1", size = 12148791, upload-time = "2025-09-29T23:17:18.444Z" }, + { url = "https://files.pythonhosted.org/packages/40/a8/4dac1f8f8235e5d25b9955d02ff6f29396191d4e665d71122c3722ca83c5/pandas-2.3.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd7478f1463441ae4ca7308a70e90b33470fa593429f9d4c578dd00d1fa78838", size = 12769373, upload-time = "2025-09-29T23:17:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/df/91/82cc5169b6b25440a7fc0ef3a694582418d875c8e3ebf796a6d6470aa578/pandas-2.3.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4793891684806ae50d1288c9bae9330293ab4e083ccd1c5e383c34549c6e4250", size = 13200444, upload-time = "2025-09-29T23:17:49.341Z" }, + { url = "https://files.pythonhosted.org/packages/10/ae/89b3283800ab58f7af2952704078555fa60c807fff764395bb57ea0b0dbd/pandas-2.3.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:28083c648d9a99a5dd035ec125d42439c6c1c525098c58af0fc38dd1a7a1b3d4", size = 13858459, upload-time = "2025-09-29T23:18:03.722Z" }, + { url = "https://files.pythonhosted.org/packages/85/72/530900610650f54a35a19476eca5104f38555afccda1aa11a92ee14cb21d/pandas-2.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:503cf027cf9940d2ceaa1a93cfb5f8c8c7e6e90720a2850378f0b3f3b1e06826", size = 11346086, upload-time = "2025-09-29T23:18:18.505Z" }, ] [[package]] name = "pandocfilters" version = "1.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454 } +sdist = { url = "https://files.pythonhosted.org/packages/70/6f/3dd4940bbe001c06a65f88e36bad298bc7a0de5036115639926b0c5c0458/pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e", size = 8454, upload-time = "2024-01-18T20:08:13.726Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663 }, + { url = "https://files.pythonhosted.org/packages/ef/af/4fbc8cab944db5d21b7e2a5b8e9211a03a79852b1157e2c102fcc61ac440/pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc", size = 8663, upload-time = "2024-01-18T20:08:11.28Z" }, ] [[package]] name = "parso" version = "0.8.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621 } +sdist = { url = "https://files.pythonhosted.org/packages/81/76/a1e769043c0c0c9fe391b702539d594731a4362334cdf4dc25d0c09761e7/parso-0.8.6.tar.gz", hash = "sha256:2b9a0332696df97d454fa67b81618fd69c35a7b90327cbe6ba5c92d2c68a7bfd", size = 401621, upload-time = "2026-02-09T15:45:24.425Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894 }, + { url = "https://files.pythonhosted.org/packages/b6/61/fae042894f4296ec49e3f193aff5d7c18440da9e48102c3315e1bc4519a7/parso-0.8.6-py2.py3-none-any.whl", hash = "sha256:2c549f800b70a5c4952197248825584cb00f033b29c692671d3bf08bf380baff", size = 106894, upload-time = "2026-02-09T15:45:21.391Z" }, ] [[package]] @@ -2173,66 +2200,75 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "ptyprocess" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, ] [[package]] name = "pillow" version = "12.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264 } +sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1d/30/5bd3d794762481f8c8ae9c80e7b76ecea73b916959eb587521358ef0b2f9/pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0", size = 5304099 }, - { url = "https://files.pythonhosted.org/packages/bd/c1/aab9e8f3eeb4490180e357955e15c2ef74b31f64790ff356c06fb6cf6d84/pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713", size = 4657880 }, - { url = "https://files.pythonhosted.org/packages/f1/0a/9879e30d56815ad529d3985aeff5af4964202425c27261a6ada10f7cbf53/pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b", size = 6222587 }, - { url = "https://files.pythonhosted.org/packages/5a/5f/a1b72ff7139e4f89014e8d451442c74a774d5c43cd938fb0a9f878576b37/pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b", size = 8027678 }, - { url = "https://files.pythonhosted.org/packages/e2/c2/c7cb187dac79a3d22c3ebeae727abee01e077c8c7d930791dc592f335153/pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4", size = 6335777 }, - { url = "https://files.pythonhosted.org/packages/0c/7b/f9b09a7804ec7336effb96c26d37c29d27225783dc1501b7d62dcef6ae25/pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4", size = 7027140 }, - { url = "https://files.pythonhosted.org/packages/98/b2/2fa3c391550bd421b10849d1a2144c44abcd966daadd2f7c12e19ea988c4/pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e", size = 6449855 }, - { url = "https://files.pythonhosted.org/packages/96/ff/9caf4b5b950c669263c39e96c78c0d74a342c71c4f43fd031bb5cb7ceac9/pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff", size = 7151329 }, - { url = "https://files.pythonhosted.org/packages/7b/f8/4b24841f582704da675ca535935bccb32b00a6da1226820845fac4a71136/pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40", size = 6325574 }, - { url = "https://files.pythonhosted.org/packages/f8/f9/9f6b01c0881d7036063aa6612ef04c0e2cad96be21325a1e92d0203f8e91/pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23", size = 7032347 }, - { url = "https://files.pythonhosted.org/packages/79/13/c7922edded3dcdaf10c59297540b72785620abc0538872c819915746757d/pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9", size = 2453457 }, + { url = "https://files.pythonhosted.org/packages/1d/30/5bd3d794762481f8c8ae9c80e7b76ecea73b916959eb587521358ef0b2f9/pillow-12.1.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1f1625b72740fdda5d77b4def688eb8fd6490975d06b909fd19f13f391e077e0", size = 5304099, upload-time = "2026-02-11T04:20:06.13Z" }, + { url = "https://files.pythonhosted.org/packages/bd/c1/aab9e8f3eeb4490180e357955e15c2ef74b31f64790ff356c06fb6cf6d84/pillow-12.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:178aa072084bd88ec759052feca8e56cbb14a60b39322b99a049e58090479713", size = 4657880, upload-time = "2026-02-11T04:20:09.291Z" }, + { url = "https://files.pythonhosted.org/packages/f1/0a/9879e30d56815ad529d3985aeff5af4964202425c27261a6ada10f7cbf53/pillow-12.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b66e95d05ba806247aaa1561f080abc7975daf715c30780ff92a20e4ec546e1b", size = 6222587, upload-time = "2026-02-11T04:20:10.82Z" }, + { url = "https://files.pythonhosted.org/packages/5a/5f/a1b72ff7139e4f89014e8d451442c74a774d5c43cd938fb0a9f878576b37/pillow-12.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89c7e895002bbe49cdc5426150377cbbc04767d7547ed145473f496dfa40408b", size = 8027678, upload-time = "2026-02-11T04:20:12.455Z" }, + { url = "https://files.pythonhosted.org/packages/e2/c2/c7cb187dac79a3d22c3ebeae727abee01e077c8c7d930791dc592f335153/pillow-12.1.1-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a5cbdcddad0af3da87cb16b60d23648bc3b51967eb07223e9fed77a82b457c4", size = 6335777, upload-time = "2026-02-11T04:20:14.441Z" }, + { url = "https://files.pythonhosted.org/packages/0c/7b/f9b09a7804ec7336effb96c26d37c29d27225783dc1501b7d62dcef6ae25/pillow-12.1.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9f51079765661884a486727f0729d29054242f74b46186026582b4e4769918e4", size = 7027140, upload-time = "2026-02-11T04:20:16.387Z" }, + { url = "https://files.pythonhosted.org/packages/98/b2/2fa3c391550bd421b10849d1a2144c44abcd966daadd2f7c12e19ea988c4/pillow-12.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:99c1506ea77c11531d75e3a412832a13a71c7ebc8192ab9e4b2e355555920e3e", size = 6449855, upload-time = "2026-02-11T04:20:18.554Z" }, + { url = "https://files.pythonhosted.org/packages/96/ff/9caf4b5b950c669263c39e96c78c0d74a342c71c4f43fd031bb5cb7ceac9/pillow-12.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:36341d06738a9f66c8287cf8b876d24b18db9bd8740fa0672c74e259ad408cff", size = 7151329, upload-time = "2026-02-11T04:20:20.646Z" }, + { url = "https://files.pythonhosted.org/packages/7b/f8/4b24841f582704da675ca535935bccb32b00a6da1226820845fac4a71136/pillow-12.1.1-cp310-cp310-win32.whl", hash = "sha256:6c52f062424c523d6c4db85518774cc3d50f5539dd6eed32b8f6229b26f24d40", size = 6325574, upload-time = "2026-02-11T04:20:22.43Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f9/9f6b01c0881d7036063aa6612ef04c0e2cad96be21325a1e92d0203f8e91/pillow-12.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:c6008de247150668a705a6338156efb92334113421ceecf7438a12c9a12dab23", size = 7032347, upload-time = "2026-02-11T04:20:23.932Z" }, + { url = "https://files.pythonhosted.org/packages/79/13/c7922edded3dcdaf10c59297540b72785620abc0538872c819915746757d/pillow-12.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:1a9b0ee305220b392e1124a764ee4265bd063e54a751a6b62eff69992f457fa9", size = 2453457, upload-time = "2026-02-11T04:20:25.392Z" }, ] [[package]] name = "pip" version = "26.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747 } +sdist = { url = "https://files.pythonhosted.org/packages/48/83/0d7d4e9efe3344b8e2fe25d93be44f64b65364d3c8d7bc6dc90198d5422e/pip-26.0.1.tar.gz", hash = "sha256:c4037d8a277c89b320abe636d59f91e6d0922d08a05b60e85e53b296613346d8", size = 1812747, upload-time = "2026-02-05T02:20:18.702Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723 }, + { url = "https://files.pythonhosted.org/packages/de/f0/c81e05b613866b76d2d1066490adf1a3dbc4ee9d9c839961c3fc8a6997af/pip-26.0.1-py3-none-any.whl", hash = "sha256:bdb1b08f4274833d62c1aa29e20907365a2ceb950410df15fc9521bad440122b", size = 1787723, upload-time = "2026-02-05T02:20:16.416Z" }, ] [[package]] name = "platformdirs" -version = "4.9.2" +version = "4.9.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/04/fea538adf7dbbd6d186f551d595961e564a3b6715bdf276b477460858672/platformdirs-4.9.2.tar.gz", hash = "sha256:9a33809944b9db043ad67ca0db94b14bf452cc6aeaac46a88ea55b26e2e9d291", size = 28394 } +sdist = { url = "https://files.pythonhosted.org/packages/19/56/8d4c30c8a1d07013911a8fdbd8f89440ef9f08d07a1b50ab8ca8be5a20f9/platformdirs-4.9.4.tar.gz", hash = "sha256:1ec356301b7dc906d83f371c8f487070e99d3ccf9e501686456394622a01a934", size = 28737, upload-time = "2026-03-05T18:34:13.271Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/31/05e764397056194206169869b50cf2fee4dbbbc71b344705b9c0d878d4d8/platformdirs-4.9.2-py3-none-any.whl", hash = "sha256:9170634f126f8efdae22fb58ae8a0eaa86f38365bc57897a6c4f781d1f5875bd", size = 21168 }, + { url = "https://files.pythonhosted.org/packages/63/d7/97f7e3a6abb67d8080dd406fd4df842c2be0efaf712d1c899c32a075027c/platformdirs-4.9.4-py3-none-any.whl", hash = "sha256:68a9a4619a666ea6439f2ff250c12a853cd1cbd5158d258bd824a7df6be2f868", size = 21216, upload-time = "2026-03-05T18:34:12.172Z" }, ] [[package]] name = "plotly" -version = "6.5.2" +version = "6.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "narwhals" }, { name = "packaging" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e3/4f/8a10a9b9f5192cb6fdef62f1d77fa7d834190b2c50c0cd256bd62879212b/plotly-6.5.2.tar.gz", hash = "sha256:7478555be0198562d1435dee4c308268187553cc15516a2f4dd034453699e393", size = 7015695 } +sdist = { url = "https://files.pythonhosted.org/packages/24/fb/41efe84970cfddefd4ccf025e2cbfafe780004555f583e93dba3dac2cdef/plotly-6.6.0.tar.gz", hash = "sha256:b897f15f3b02028d69f755f236be890ba950d0a42d7dfc619b44e2d8cea8748c", size = 7027956, upload-time = "2026-03-02T21:10:25.321Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/d2/c6e44dba74f17c6216ce1b56044a9b93a929f1c2d5bdaff892512b260f5e/plotly-6.6.0-py3-none-any.whl", hash = "sha256:8d6daf0f87412e0c0bfe72e809d615217ab57cc715899a1e5145135a7800d1d0", size = 9910315, upload-time = "2026-03-02T21:10:18.131Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/67/f95b5460f127840310d2187f916cf0023b5875c0717fdf893f71e1325e87/plotly-6.5.2-py3-none-any.whl", hash = "sha256:91757653bd9c550eeea2fa2404dba6b85d1e366d54804c340b2c874e5a7eb4a4", size = 9895973 }, + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, ] [[package]] name = "pptree" version = "3.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043 } +sdist = { url = "https://files.pythonhosted.org/packages/01/cd/f4f2b79d20a10563d071c38b6ad14bf9c5d75a0edef877d2bed60c024247/pptree-3.1.tar.gz", hash = "sha256:4dd0ba2f58000cbd29d68a5b64bac29bcb5a663642f79404877c0059668a69f6", size = 3043, upload-time = "2020-04-15T18:28:53.362Z" } [[package]] name = "pre-commit" @@ -2245,18 +2281,18 @@ dependencies = [ { name = "pyyaml" }, { name = "virtualenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232 } +sdist = { url = "https://files.pythonhosted.org/packages/40/f1/6d86a29246dfd2e9b6237f0b5823717f60cad94d47ddc26afa916d21f525/pre_commit-4.5.1.tar.gz", hash = "sha256:eb545fcff725875197837263e977ea257a402056661f09dae08e4b149b030a61", size = 198232, upload-time = "2025-12-16T21:14:33.552Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437 }, + { url = "https://files.pythonhosted.org/packages/5d/19/fd3ef348460c80af7bb4669ea7926651d1f95c23ff2df18b9d24bab4f3fa/pre_commit-4.5.1-py2.py3-none-any.whl", hash = "sha256:3b3afd891e97337708c1674210f8eba659b52a38ea5f822ff142d10786221f77", size = 226437, upload-time = "2025-12-16T21:14:32.409Z" }, ] [[package]] name = "prometheus-client" version = "0.24.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616 } +sdist = { url = "https://files.pythonhosted.org/packages/f0/58/a794d23feb6b00fc0c72787d7e87d872a6730dd9ed7c7b3e954637d8f280/prometheus_client-0.24.1.tar.gz", hash = "sha256:7e0ced7fbbd40f7b84962d5d2ab6f17ef88a72504dcf7c0b40737b43b2a461f9", size = 85616, upload-time = "2026-01-14T15:26:26.965Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057 }, + { url = "https://files.pythonhosted.org/packages/74/c3/24a2f845e3917201628ecaba4f18bab4d18a337834c1df2a159ee9d22a42/prometheus_client-0.24.1-py3-none-any.whl", hash = "sha256:150db128af71a5c2482b36e588fc8a6b95e498750da4b17065947c16070f4055", size = 64057, upload-time = "2026-01-14T15:26:24.42Z" }, ] [[package]] @@ -2266,105 +2302,105 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "wcwidth" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198 } +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431 }, + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, ] [[package]] name = "propcache" version = "0.4.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442 } +sdist = { url = "https://files.pythonhosted.org/packages/9e/da/e9fc233cf63743258bff22b3dfa7ea5baef7b5bc324af47a0ad89b8ffc6f/propcache-0.4.1.tar.gz", hash = "sha256:f48107a8c637e80362555f37ecf49abe20370e557cc4ab374f04ec4423c97c3d", size = 46442, upload-time = "2025-10-08T19:49:02.291Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534 }, - { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526 }, - { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263 }, - { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012 }, - { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491 }, - { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319 }, - { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856 }, - { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241 }, - { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552 }, - { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113 }, - { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778 }, - { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047 }, - { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093 }, - { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638 }, - { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229 }, - { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305 }, + { url = "https://files.pythonhosted.org/packages/3c/0e/934b541323035566a9af292dba85a195f7b78179114f2c6ebb24551118a9/propcache-0.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c2d1fa3201efaf55d730400d945b5b3ab6e672e100ba0f9a409d950ab25d7db", size = 79534, upload-time = "2025-10-08T19:46:02.083Z" }, + { url = "https://files.pythonhosted.org/packages/a1/6b/db0d03d96726d995dc7171286c6ba9d8d14251f37433890f88368951a44e/propcache-0.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1eb2994229cc8ce7fe9b3db88f5465f5fd8651672840b2e426b88cdb1a30aac8", size = 45526, upload-time = "2025-10-08T19:46:03.884Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c3/82728404aea669e1600f304f2609cde9e665c18df5a11cdd57ed73c1dceb/propcache-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:66c1f011f45a3b33d7bcb22daed4b29c0c9e2224758b6be00686731e1b46f925", size = 47263, upload-time = "2025-10-08T19:46:05.405Z" }, + { url = "https://files.pythonhosted.org/packages/df/1b/39313ddad2bf9187a1432654c38249bab4562ef535ef07f5eb6eb04d0b1b/propcache-0.4.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9a52009f2adffe195d0b605c25ec929d26b36ef986ba85244891dee3b294df21", size = 201012, upload-time = "2025-10-08T19:46:07.165Z" }, + { url = "https://files.pythonhosted.org/packages/5b/01/f1d0b57d136f294a142acf97f4ed58c8e5b974c21e543000968357115011/propcache-0.4.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5d4e2366a9c7b837555cf02fb9be2e3167d333aff716332ef1b7c3a142ec40c5", size = 209491, upload-time = "2025-10-08T19:46:08.909Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c8/038d909c61c5bb039070b3fb02ad5cccdb1dde0d714792e251cdb17c9c05/propcache-0.4.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9d2b6caef873b4f09e26ea7e33d65f42b944837563a47a94719cc3544319a0db", size = 215319, upload-time = "2025-10-08T19:46:10.7Z" }, + { url = "https://files.pythonhosted.org/packages/08/57/8c87e93142b2c1fa2408e45695205a7ba05fb5db458c0bf5c06ba0e09ea6/propcache-0.4.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b16ec437a8c8a965ecf95739448dd938b5c7f56e67ea009f4300d8df05f32b7", size = 196856, upload-time = "2025-10-08T19:46:12.003Z" }, + { url = "https://files.pythonhosted.org/packages/42/df/5615fec76aa561987a534759b3686008a288e73107faa49a8ae5795a9f7a/propcache-0.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:296f4c8ed03ca7476813fe666c9ea97869a8d7aec972618671b33a38a5182ef4", size = 193241, upload-time = "2025-10-08T19:46:13.495Z" }, + { url = "https://files.pythonhosted.org/packages/d5/21/62949eb3a7a54afe8327011c90aca7e03547787a88fb8bd9726806482fea/propcache-0.4.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:1f0978529a418ebd1f49dad413a2b68af33f85d5c5ca5c6ca2a3bed375a7ac60", size = 190552, upload-time = "2025-10-08T19:46:14.938Z" }, + { url = "https://files.pythonhosted.org/packages/30/ee/ab4d727dd70806e5b4de96a798ae7ac6e4d42516f030ee60522474b6b332/propcache-0.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fd138803047fb4c062b1c1dd95462f5209456bfab55c734458f15d11da288f8f", size = 200113, upload-time = "2025-10-08T19:46:16.695Z" }, + { url = "https://files.pythonhosted.org/packages/8a/0b/38b46208e6711b016aa8966a3ac793eee0d05c7159d8342aa27fc0bc365e/propcache-0.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8c9b3cbe4584636d72ff556d9036e0c9317fa27b3ac1f0f558e7e84d1c9c5900", size = 200778, upload-time = "2025-10-08T19:46:18.023Z" }, + { url = "https://files.pythonhosted.org/packages/cf/81/5abec54355ed344476bee711e9f04815d4b00a311ab0535599204eecc257/propcache-0.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f93243fdc5657247533273ac4f86ae106cc6445a0efacb9a1bfe982fcfefd90c", size = 193047, upload-time = "2025-10-08T19:46:19.449Z" }, + { url = "https://files.pythonhosted.org/packages/ec/b6/1f237c04e32063cb034acd5f6ef34ef3a394f75502e72703545631ab1ef6/propcache-0.4.1-cp310-cp310-win32.whl", hash = "sha256:a0ee98db9c5f80785b266eb805016e36058ac72c51a064040f2bc43b61101cdb", size = 38093, upload-time = "2025-10-08T19:46:20.643Z" }, + { url = "https://files.pythonhosted.org/packages/a6/67/354aac4e0603a15f76439caf0427781bcd6797f370377f75a642133bc954/propcache-0.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:1cdb7988c4e5ac7f6d175a28a9aa0c94cb6f2ebe52756a3c0cda98d2809a9e37", size = 41638, upload-time = "2025-10-08T19:46:21.935Z" }, + { url = "https://files.pythonhosted.org/packages/e0/e1/74e55b9fd1a4c209ff1a9a824bf6c8b3d1fc5a1ac3eabe23462637466785/propcache-0.4.1-cp310-cp310-win_arm64.whl", hash = "sha256:d82ad62b19645419fe79dd63b3f9253e15b30e955c0170e5cebc350c1844e581", size = 38229, upload-time = "2025-10-08T19:46:23.368Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] [[package]] name = "protobuf" -version = "6.33.5" +version = "7.34.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ba/25/7c72c307aafc96fa87062aa6291d9f7c94836e43214d43722e86037aac02/protobuf-6.33.5.tar.gz", hash = "sha256:6ddcac2a081f8b7b9642c09406bc6a4290128fce5f471cddd165960bb9119e5c", size = 444465 } +sdist = { url = "https://files.pythonhosted.org/packages/f2/00/04a2ab36b70a52d0356852979e08b44edde0435f2115dc66e25f2100f3ab/protobuf-7.34.0.tar.gz", hash = "sha256:3871a3df67c710aaf7bb8d214cc997342e63ceebd940c8c7fc65c9b3d697591a", size = 454726, upload-time = "2026-02-27T00:30:25.421Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b1/79/af92d0a8369732b027e6d6084251dd8e782c685c72da161bd4a2e00fbabb/protobuf-6.33.5-cp310-abi3-win32.whl", hash = "sha256:d71b040839446bac0f4d162e758bea99c8251161dae9d0983a3b88dee345153b", size = 425769 }, - { url = "https://files.pythonhosted.org/packages/55/75/bb9bc917d10e9ee13dee8607eb9ab963b7cf8be607c46e7862c748aa2af7/protobuf-6.33.5-cp310-abi3-win_amd64.whl", hash = "sha256:3093804752167bcab3998bec9f1048baae6e29505adaf1afd14a37bddede533c", size = 437118 }, - { url = "https://files.pythonhosted.org/packages/a2/6b/e48dfc1191bc5b52950246275bf4089773e91cb5ba3592621723cdddca62/protobuf-6.33.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:a5cb85982d95d906df1e2210e58f8e4f1e3cdc088e52c921a041f9c9a0386de5", size = 427766 }, - { url = "https://files.pythonhosted.org/packages/4e/b1/c79468184310de09d75095ed1314b839eb2f72df71097db9d1404a1b2717/protobuf-6.33.5-cp39-abi3-manylinux2014_aarch64.whl", hash = "sha256:9b71e0281f36f179d00cbcb119cb19dec4d14a81393e5ea220f64b286173e190", size = 324638 }, - { url = "https://files.pythonhosted.org/packages/c5/f5/65d838092fd01c44d16037953fd4c2cc851e783de9b8f02b27ec4ffd906f/protobuf-6.33.5-cp39-abi3-manylinux2014_s390x.whl", hash = "sha256:8afa18e1d6d20af15b417e728e9f60f3aa108ee76f23c3b2c07a2c3b546d3afd", size = 339411 }, - { url = "https://files.pythonhosted.org/packages/9b/53/a9443aa3ca9ba8724fdfa02dd1887c1bcd8e89556b715cfbacca6b63dbec/protobuf-6.33.5-cp39-abi3-manylinux2014_x86_64.whl", hash = "sha256:cbf16ba3350fb7b889fca858fb215967792dc125b35c7976ca4818bee3521cf0", size = 323465 }, - { url = "https://files.pythonhosted.org/packages/57/bf/2086963c69bdac3d7cff1cc7ff79b8ce5ea0bec6797a017e1be338a46248/protobuf-6.33.5-py3-none-any.whl", hash = "sha256:69915a973dd0f60f31a08b8318b73eab2bd6a392c79184b3612226b0a3f8ec02", size = 170687 }, + { url = "https://files.pythonhosted.org/packages/13/c4/6322ab5c8f279c4c358bc14eb8aefc0550b97222a39f04eb3c1af7a830fa/protobuf-7.34.0-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:8e329966799f2c271d5e05e236459fe1cbfdb8755aaa3b0914fa60947ddea408", size = 429248, upload-time = "2026-02-27T00:30:14.924Z" }, + { url = "https://files.pythonhosted.org/packages/45/99/b029bbbc61e8937545da5b79aa405ab2d9cf307a728f8c9459ad60d7a481/protobuf-7.34.0-cp310-abi3-manylinux2014_aarch64.whl", hash = "sha256:9d7a5005fb96f3c1e64f397f91500b0eb371b28da81296ae73a6b08a5b76cdd6", size = 325753, upload-time = "2026-02-27T00:30:17.247Z" }, + { url = "https://files.pythonhosted.org/packages/cc/79/09f02671eb75b251c5550a1c48e7b3d4b0623efd7c95a15a50f6f9fc1e2e/protobuf-7.34.0-cp310-abi3-manylinux2014_s390x.whl", hash = "sha256:4a72a8ec94e7a9f7ef7fe818ed26d073305f347f8b3b5ba31e22f81fd85fca02", size = 340200, upload-time = "2026-02-27T00:30:18.672Z" }, + { url = "https://files.pythonhosted.org/packages/b5/57/89727baef7578897af5ed166735ceb315819f1c184da8c3441271dbcfde7/protobuf-7.34.0-cp310-abi3-manylinux2014_x86_64.whl", hash = "sha256:964cf977e07f479c0697964e83deda72bcbc75c3badab506fb061b352d991b01", size = 324268, upload-time = "2026-02-27T00:30:20.088Z" }, + { url = "https://files.pythonhosted.org/packages/1f/3e/38ff2ddee5cc946f575c9d8cc822e34bde205cf61acf8099ad88ef19d7d2/protobuf-7.34.0-cp310-abi3-win32.whl", hash = "sha256:f791ec509707a1d91bd02e07df157e75e4fb9fbdad12a81b7396201ec244e2e3", size = 426628, upload-time = "2026-02-27T00:30:21.555Z" }, + { url = "https://files.pythonhosted.org/packages/cb/71/7c32eaf34a61a1bae1b62a2ac4ffe09b8d1bb0cf93ad505f42040023db89/protobuf-7.34.0-cp310-abi3-win_amd64.whl", hash = "sha256:9f9079f1dde4e32342ecbd1c118d76367090d4aaa19da78230c38101c5b3dd40", size = 437901, upload-time = "2026-02-27T00:30:22.836Z" }, + { url = "https://files.pythonhosted.org/packages/a4/e7/14dc9366696dcb53a413449881743426ed289d687bcf3d5aee4726c32ebb/protobuf-7.34.0-py3-none-any.whl", hash = "sha256:e3b914dd77fa33fa06ab2baa97937746ab25695f389869afdf03e81f34e45dc7", size = 170716, upload-time = "2026-02-27T00:30:23.994Z" }, ] [[package]] name = "psutil" version = "6.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565 } +sdist = { url = "https://files.pythonhosted.org/packages/26/10/2a30b13c61e7cf937f4adf90710776b7918ed0a9c434e2c38224732af310/psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a", size = 508565, upload-time = "2024-10-17T21:31:45.68Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762 }, - { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777 }, - { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259 }, - { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255 }, - { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804 }, - { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386 }, - { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228 }, + { url = "https://files.pythonhosted.org/packages/01/9e/8be43078a171381953cfee33c07c0d628594b5dbfc5157847b85022c2c1b/psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688", size = 247762, upload-time = "2024-10-17T21:32:05.991Z" }, + { url = "https://files.pythonhosted.org/packages/1d/cb/313e80644ea407f04f6602a9e23096540d9dc1878755f3952ea8d3d104be/psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e", size = 248777, upload-time = "2024-10-17T21:32:07.872Z" }, + { url = "https://files.pythonhosted.org/packages/65/8e/bcbe2025c587b5d703369b6a75b65d41d1367553da6e3f788aff91eaf5bd/psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38", size = 284259, upload-time = "2024-10-17T21:32:10.177Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/8245e6f76a93c98aab285a43ea71ff1b171bcd90c9d238bf81f7021fb233/psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b", size = 287255, upload-time = "2024-10-17T21:32:11.964Z" }, + { url = "https://files.pythonhosted.org/packages/27/c2/d034856ac47e3b3cdfa9720d0e113902e615f4190d5d1bdb8df4b2015fb2/psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a", size = 288804, upload-time = "2024-10-17T21:32:13.785Z" }, + { url = "https://files.pythonhosted.org/packages/ea/55/5389ed243c878725feffc0d6a3bc5ef6764312b6fc7c081faaa2cfa7ef37/psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e", size = 250386, upload-time = "2024-10-17T21:32:21.399Z" }, + { url = "https://files.pythonhosted.org/packages/11/91/87fa6f060e649b1e1a7b19a4f5869709fbf750b7c8c262ee776ec32f3028/psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be", size = 254228, upload-time = "2024-10-17T21:32:23.88Z" }, ] [[package]] name = "ptyprocess" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, ] [[package]] name = "pure-eval" version = "0.2.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752 } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842 }, + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, ] [[package]] name = "pyarrow" version = "23.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336 } +sdist = { url = "https://files.pythonhosted.org/packages/88/22/134986a4cc224d593c1afde5494d18ff629393d74cc2eddb176669f234a4/pyarrow-23.0.1.tar.gz", hash = "sha256:b8c5873e33440b2bc2f4a79d2b47017a89c5a24116c055625e6f2ee50523f019", size = 1167336, upload-time = "2026-02-16T10:14:12.39Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bc/a8/24e5dc6855f50a62936ceb004e6e9645e4219a8065f304145d7fb8a79d5d/pyarrow-23.0.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:3fab8f82571844eb3c460f90a75583801d14ca0cc32b1acc8c361650e006fd56", size = 34307390 }, - { url = "https://files.pythonhosted.org/packages/bc/8e/4be5617b4aaae0287f621ad31c6036e5f63118cfca0dc57d42121ff49b51/pyarrow-23.0.1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:3f91c038b95f71ddfc865f11d5876c42f343b4495535bd262c7b321b0b94507c", size = 35853761 }, - { url = "https://files.pythonhosted.org/packages/2e/08/3e56a18819462210432ae37d10f5c8eed3828be1d6c751b6e6a2e93c286a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d0744403adabef53c985a7f8a082b502a368510c40d184df349a0a8754533258", size = 44493116 }, - { url = "https://files.pythonhosted.org/packages/f8/82/c40b68001dbec8a3faa4c08cd8c200798ac732d2854537c5449dc859f55a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c33b5bf406284fd0bba436ed6f6c3ebe8e311722b441d89397c54f871c6863a2", size = 47564532 }, - { url = "https://files.pythonhosted.org/packages/20/bc/73f611989116b6f53347581b02177f9f620efdf3cd3f405d0e83cdf53a83/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ddf743e82f69dcd6dbbcb63628895d7161e04e56794ef80550ac6f3315eeb1d5", size = 48183685 }, - { url = "https://files.pythonhosted.org/packages/b0/cc/6c6b3ecdae2a8c3aced99956187e8302fc954cc2cca2a37cf2111dad16ce/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e052a211c5ac9848ae15d5ec875ed0943c0221e2fcfe69eee80b604b4e703222", size = 50605582 }, - { url = "https://files.pythonhosted.org/packages/8d/94/d359e708672878d7638a04a0448edf7c707f9e5606cee11e15aaa5c7535a/pyarrow-23.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:5abde149bb3ce524782d838eb67ac095cd3fd6090eba051130589793f1a7f76d", size = 27521148 }, + { url = "https://files.pythonhosted.org/packages/bc/a8/24e5dc6855f50a62936ceb004e6e9645e4219a8065f304145d7fb8a79d5d/pyarrow-23.0.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:3fab8f82571844eb3c460f90a75583801d14ca0cc32b1acc8c361650e006fd56", size = 34307390, upload-time = "2026-02-16T10:08:08.654Z" }, + { url = "https://files.pythonhosted.org/packages/bc/8e/4be5617b4aaae0287f621ad31c6036e5f63118cfca0dc57d42121ff49b51/pyarrow-23.0.1-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:3f91c038b95f71ddfc865f11d5876c42f343b4495535bd262c7b321b0b94507c", size = 35853761, upload-time = "2026-02-16T10:08:17.811Z" }, + { url = "https://files.pythonhosted.org/packages/2e/08/3e56a18819462210432ae37d10f5c8eed3828be1d6c751b6e6a2e93c286a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d0744403adabef53c985a7f8a082b502a368510c40d184df349a0a8754533258", size = 44493116, upload-time = "2026-02-16T10:08:25.792Z" }, + { url = "https://files.pythonhosted.org/packages/f8/82/c40b68001dbec8a3faa4c08cd8c200798ac732d2854537c5449dc859f55a/pyarrow-23.0.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c33b5bf406284fd0bba436ed6f6c3ebe8e311722b441d89397c54f871c6863a2", size = 47564532, upload-time = "2026-02-16T10:08:34.27Z" }, + { url = "https://files.pythonhosted.org/packages/20/bc/73f611989116b6f53347581b02177f9f620efdf3cd3f405d0e83cdf53a83/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ddf743e82f69dcd6dbbcb63628895d7161e04e56794ef80550ac6f3315eeb1d5", size = 48183685, upload-time = "2026-02-16T10:08:42.889Z" }, + { url = "https://files.pythonhosted.org/packages/b0/cc/6c6b3ecdae2a8c3aced99956187e8302fc954cc2cca2a37cf2111dad16ce/pyarrow-23.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e052a211c5ac9848ae15d5ec875ed0943c0221e2fcfe69eee80b604b4e703222", size = 50605582, upload-time = "2026-02-16T10:08:51.641Z" }, + { url = "https://files.pythonhosted.org/packages/8d/94/d359e708672878d7638a04a0448edf7c707f9e5606cee11e15aaa5c7535a/pyarrow-23.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:5abde149bb3ce524782d838eb67ac095cd3fd6090eba051130589793f1a7f76d", size = 27521148, upload-time = "2026-02-16T10:08:58.077Z" }, ] [[package]] name = "pycparser" version = "3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492 } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172 }, + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, ] [[package]] @@ -2377,9 +2413,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591 } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580 }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, ] [package.optional-dependencies] @@ -2394,37 +2430,29 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298 }, - { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475 }, - { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815 }, - { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567 }, - { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442 }, - { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956 }, - { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253 }, - { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050 }, - { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178 }, - { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833 }, - { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156 }, - { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378 }, - { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622 }, - { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441 }, - { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291 }, - { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632 }, - { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905 }, - { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495 }, - { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388 }, - { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879 }, - { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017 }, - { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351 }, - { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363 }, - { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615 }, - { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369 }, - { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218 }, - { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951 }, - { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428 }, - { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009 }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, ] [[package]] @@ -2435,9 +2463,9 @@ dependencies = [ { name = "pydantic" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226 } +sdist = { url = "https://files.pythonhosted.org/packages/fd/35/2fee58b1316a73e025728583d3b1447218a97e621933fc776fb8c0f2ebdd/pydantic_extra_types-2.11.0.tar.gz", hash = "sha256:4e9991959d045b75feb775683437a97991d02c138e00b59176571db9ce634f0e", size = 157226, upload-time = "2025-12-31T16:18:27.944Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296 }, + { url = "https://files.pythonhosted.org/packages/fe/17/fabd56da47096d240dd45ba627bead0333b0cf0ee8ada9bec579287dadf3/pydantic_extra_types-2.11.0-py3-none-any.whl", hash = "sha256:84b864d250a0fc62535b7ec591e36f2c5b4d1325fa0017eb8cda9aeb63b374a6", size = 74296, upload-time = "2025-12-31T16:18:26.38Z" }, ] [[package]] @@ -2449,73 +2477,119 @@ dependencies = [ { name = "python-dotenv" }, { name = "typing-inspection" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826 } +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/fffca34caecc4a3f97bda81b2098da5e8ab7efc9a66e819074a11955d87e/pydantic_settings-2.13.1.tar.gz", hash = "sha256:b4c11847b15237fb0171e1462bf540e294affb9b86db4d9aa5c01730bdbe4025", size = 223826, upload-time = "2026-02-19T13:45:08.055Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929 }, + { url = "https://files.pythonhosted.org/packages/00/4b/ccc026168948fec4f7555b9164c724cf4125eac006e176541483d2c959be/pydantic_settings-2.13.1-py3-none-any.whl", hash = "sha256:d56fd801823dbeae7f0975e1f8c8e25c258eb75d278ea7abb5d9cebb01b56237", size = 58929, upload-time = "2026-02-19T13:45:06.034Z" }, ] [[package]] name = "pygments" version = "2.19.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631 } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217 }, + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] [[package]] name = "pymupdf" -version = "1.27.1" +version = "1.27.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1b/0c/40dda0cc4bd2220a2ef75f8c53dd7d8ed1e29681fcb3df75db6ee9677a7e/pymupdf-1.27.1.tar.gz", hash = "sha256:4afbde0769c336717a149ab0de3330dcb75378f795c1a8c5af55c1a628b17d55", size = 85303479 } +sdist = { url = "https://files.pythonhosted.org/packages/a4/fb/d80374ab091ab7ad5a5e7981a45c877ae094db668c1ab4d30f1109a4ec6a/pymupdf-1.27.2.tar.gz", hash = "sha256:37fc9cedeafb40839f86a074d4d9feab725144bdd4bbfd20308ff8957e2b10af", size = 85353104, upload-time = "2026-03-10T12:53:01.697Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/19/fde6ea4712a904b65e8f41124a0e4233879b87a770fe6a8ce857964de6d5/pymupdf-1.27.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bee9f95512f9556dbf2cacfd1413c61b29a55baa07fa7f8fc83d221d8419888a", size = 23986707 }, - { url = "https://files.pythonhosted.org/packages/75/c2/070dff91ad3f1bc16fd6c6ceff23495601fcce4c92d28be534417596418a/pymupdf-1.27.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:3de95a0889395b0966fafd11b94980b7543a816e89dd1c218597a08543ac3415", size = 23263493 }, - { url = "https://files.pythonhosted.org/packages/8e/db/937377f4b3e0fbf6273c17436a49f7db17df1a46b1be9e26653b6fafc0e1/pymupdf-1.27.1-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2c9d9353b840040cbc724341f4095fb7e2cc1a12a9147d0ec1a0a79f5d773147", size = 24317651 }, - { url = "https://files.pythonhosted.org/packages/72/d5/c701cf2d0cdd6e5d6bca3ca9188d7f5d7ce3ae67dd1368d658cd4bae2707/pymupdf-1.27.1-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:aeaed76e72cbc061149a825ab0811c5f4752970c56591c2938c5042ec06b26e1", size = 24945742 }, - { url = "https://files.pythonhosted.org/packages/2b/29/690202b38b93cf77b73a29c25a63a2b6f3fcb36b1f75006e50b8dee7c108/pymupdf-1.27.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:4f1837554134fb45d390a44de8844b2ca9b6c901c82ccc90b340e3b7f3b126ca", size = 25167965 }, - { url = "https://files.pythonhosted.org/packages/8a/81/f937e6aa606fd263c3a45d0ff0f0bbdbf3fb779933091fc0f6179513cc93/pymupdf-1.27.1-cp310-abi3-win32.whl", hash = "sha256:fa33b512d82c6c4852edadf57f22d5f27d16243bb33dac0fbe4eb0f281c5b17e", size = 18006253 }, - { url = "https://files.pythonhosted.org/packages/3e/99/fe4a7752990bf65277718fffbead4478de9afd1c7288d7a6d643f79a6fa7/pymupdf-1.27.1-cp310-abi3-win_amd64.whl", hash = "sha256:4b6268dff3a9d713034eba5c2ffce0da37c62443578941ac5df433adcde57b2f", size = 19236703 }, + { url = "https://files.pythonhosted.org/packages/98/ee/2c10b6bde83ee42f5150b690ace952a802a7e632776dadd42bbfe5b68601/pymupdf-1.27.2-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:a60ff9010d7025428e31d92ac2c9b4218c7c4844409d0b31a050565ea0a955fd", size = 23987468, upload-time = "2026-03-10T12:37:06.593Z" }, + { url = "https://files.pythonhosted.org/packages/44/06/c8cc8c8ade83f5a75ac0f543edc2bc3c52d8c38c1d55d1e0713558258540/pymupdf-1.27.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:5095efb242cfe1c46fec1c864a13f000098564829c98366582dde7ad9e61aa32", size = 23262964, upload-time = "2026-03-10T12:37:23.915Z" }, + { url = "https://files.pythonhosted.org/packages/1a/8e/df2ab91a680a77c82bc4501cdca60767b3758d75552e4d2849647a16cbc0/pymupdf-1.27.2-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1081235fcfad268d801cd73a7b69c629939e2c46ed4d97035cb1bb7b5b90dc54", size = 24318675, upload-time = "2026-03-10T12:37:42.249Z" }, + { url = "https://files.pythonhosted.org/packages/ab/56/c6c16fa2dcfe2476ec28a9aaaca773dc35c593699e81e573211c91442770/pymupdf-1.27.2-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:917f4dd52daea504d5c60e1430c17d637b5014a43e66d068b4b356effe087dba", size = 24947974, upload-time = "2026-03-10T12:38:00.779Z" }, + { url = "https://files.pythonhosted.org/packages/7b/4f/1659f1d80b5d2f5aad134c2ca63894c63daf47a3ffb7e18987fe25e49097/pymupdf-1.27.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9617d5e71c334937c804544fa201946c5f73d0a97b5842b96857bdabfefbc343", size = 25169417, upload-time = "2026-03-10T12:38:18.912Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/e34d704f7242885dd1d67cfbe1040051a04b4b7e2cf1cbd27af9bd4500a3/pymupdf-1.27.2-cp310-abi3-win32.whl", hash = "sha256:6deef49e06c9a5d8670bf5835a911ab887dac4b3ed4bd60ab7d93da6aa8ff6f1", size = 18008725, upload-time = "2026-03-10T12:38:31.915Z" }, + { url = "https://files.pythonhosted.org/packages/f5/fb/a3f1f8813f6e93c65d1f7ebca6530a889f1ae109229b537f7a617b2aab57/pymupdf-1.27.2-cp310-abi3-win_amd64.whl", hash = "sha256:acdfdb7329882246545a0f6bc85f91739e2773ed81f9301c1687cffb826470f3", size = 19237944, upload-time = "2026-03-10T12:38:45.603Z" }, +] + +[[package]] +name = "pymupdf-layout" +version = "1.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "networkx" }, + { name = "numpy" }, + { name = "onnxruntime" }, + { name = "pymupdf" }, + { name = "pyyaml" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/2e/c0d80ff460babfb91ae708ff2d75a9bbf074322ce4f4ef1afcd911c2f209/pymupdf_layout-1.27.2-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:bee613779fd1053979b7bfbfb9d2a8937066002fe6981fe9290c5f806d27e44e", size = 15799804, upload-time = "2026-03-10T12:50:59.231Z" }, + { url = "https://files.pythonhosted.org/packages/db/b7/436d0011e0d7e5a94ef23f3ac1f5198f0584f3dd1a29fb1deae2647bd01e/pymupdf_layout-1.27.2-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:447c2f20524a1cca26dbb30611521758fe464ced7fdedb441c884bf40564e92c", size = 15795181, upload-time = "2026-03-10T12:51:10.582Z" }, + { url = "https://files.pythonhosted.org/packages/2e/f4/9a9a984f172979ee850ccade9d20ad8a9ce0194a517e8b07e69c57c73f7c/pymupdf_layout-1.27.2-cp310-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:96767de7f05695d771171ed39077363a280bae6e9d5de70e484a888ae44e3cab", size = 15805201, upload-time = "2026-03-10T12:51:22.472Z" }, + { url = "https://files.pythonhosted.org/packages/be/2d/e0545dcbe65d0e762004c4266f3f272a508a414a9359f452099bf3283dd1/pymupdf_layout-1.27.2-cp310-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:962cd43d70b1816df1ac10405bfb3a85545449253f0813a30198829cae64e053", size = 15806229, upload-time = "2026-03-10T12:51:32.981Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b4/f9f7293162a7ce4ccd490241e1e1bd6f415b05809e8f75704cca47e6e32e/pymupdf_layout-1.27.2-cp310-abi3-win_amd64.whl", hash = "sha256:57f63186ab7170dfe1b6918c2ad5c241fdab34a1ed27a75b020306fa29aaf0ec", size = 15809666, upload-time = "2026-03-10T12:51:43.679Z" }, ] [[package]] name = "pymupdf4llm" -version = "0.3.4" +version = "1.27.2.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pymupdf" }, + { name = "pymupdf-layout" }, { name = "tabulate" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/9b/97c4fad642f0147af3e884126d80635a1fae02c836fde9c22f0efc053254/pymupdf4llm-0.3.4.tar.gz", hash = "sha256:48d396a5fb3c14351493c7f1dd25b2a843efdbdc4526e489ee100643a2cebec1", size = 74956 } wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/67/4394de2e5967d80a9b01ec323049163410b3553185c42dea0c346fa27a41/pymupdf4llm-0.3.4-py3-none-any.whl", hash = "sha256:0517492f82af978541162ade20fc54649cdca52acd478e33b97cb6171d69956f", size = 78669 }, + { url = "https://files.pythonhosted.org/packages/e9/23/ac3edfdd7ede9d01895f444b7d4ffffc3f044809e00791808ccc8ea194eb/pymupdf4llm-1.27.2.1-py3-none-any.whl", hash = "sha256:3d1e40d34dbe806e6a8cc7f55999cbd4e5ff5dd8629cfc42d885014b4662ec67", size = 78177, upload-time = "2026-03-10T16:20:02.852Z" }, ] [[package]] name = "pypandoc" version = "1.16.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/18/9f5f70567b97758625335209b98d5cb857e19aa1a9306e9749567a240634/pypandoc-1.16.2.tar.gz", hash = "sha256:7a72a9fbf4a5dc700465e384c3bb333d22220efc4e972cb98cf6fc723cdca86b", size = 31477, upload-time = "2025-11-13T16:30:29.608Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451 }, + { url = "https://files.pythonhosted.org/packages/bb/e9/b145683854189bba84437ea569bfa786f408c8dc5bc16d8eb0753f5583bf/pypandoc-1.16.2-py3-none-any.whl", hash = "sha256:c200c1139c8e3247baf38d1e9279e85d9f162499d1999c6aa8418596558fe79b", size = 19451, upload-time = "2025-11-13T16:30:07.66Z" }, ] [[package]] name = "pyparsing" version = "3.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574 } +sdist = { url = "https://files.pythonhosted.org/packages/f3/91/9c6ee907786a473bf81c5f53cf703ba0957b23ab84c264080fb5a450416f/pyparsing-3.3.2.tar.gz", hash = "sha256:c777f4d763f140633dcb6d8a3eda953bf7a214dc4eff598413c070bcdc117cbc", size = 6851574, upload-time = "2026-01-21T03:57:59.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781, upload-time = "2026-01-21T03:57:55.912Z" }, +] + +[[package]] +name = "pyreadline3" +version = "3.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0f/49/4cea918a08f02817aabae639e3d0ac046fef9f9180518a3ad394e22da148/pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7", size = 99839, upload-time = "2024-09-19T02:40:10.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/10/bd/c038d7cc38edc1aa5bf91ab8068b63d4308c66c4c8bb3cbba7dfbc049f9c/pyparsing-3.3.2-py3-none-any.whl", hash = "sha256:850ba148bd908d7e2411587e247a1e4f0327839c40e2e5e6d05a007ecc69911d", size = 122781 }, + { url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6", size = 83178, upload-time = "2024-09-19T02:40:08.598Z" }, ] [[package]] name = "pysocks" version = "1.7.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429, upload-time = "2019-09-20T02:07:35.714Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 }, + { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725, upload-time = "2019-09-20T02:06:22.938Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, + { name = "tomli" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d1/db/7ef3487e0fb0049ddb5ce41d3a49c235bf9ad299b6a25d5780a89f19230f/pytest-9.0.2.tar.gz", hash = "sha256:75186651a92bd89611d1d9fc20f0b4345fd827c41ccd5c299a868a05d70edf11", size = 1568901, upload-time = "2025-12-06T21:30:51.014Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/ab/b3226f0bd7cdcf710fbede2b3548584366da3b19b5021e74f5bde2a8fa3f/pytest-9.0.2-py3-none-any.whl", hash = "sha256:711ffd45bf766d5264d487b917733b453d917afd2b0ad65223959f59089f875b", size = 374801, upload-time = "2025-12-06T21:30:49.154Z" }, ] [[package]] @@ -2525,9 +2599,22 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-discovery" +version = "1.1.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d7/7e/9f3b0dd3a074a6c3e1e79f35e465b1f2ee4b262d619de00cfce523cc9b24/python_discovery-1.1.3.tar.gz", hash = "sha256:7acca36e818cd88e9b2ba03e045ad7e93e1713e29c6bbfba5d90202310b7baa5", size = 56945, upload-time = "2026-03-10T15:08:15.038Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, + { url = "https://files.pythonhosted.org/packages/e7/80/73211fc5bfbfc562369b4aa61dc1e4bf07dc7b34df7b317e4539316b809c/python_discovery-1.1.3-py3-none-any.whl", hash = "sha256:90e795f0121bc84572e737c9aa9966311b9fde44ffb88a5953b3ec9b31c6945e", size = 31485, upload-time = "2026-03-10T15:08:13.06Z" }, ] [[package]] @@ -2538,57 +2625,36 @@ dependencies = [ { name = "lxml" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/f7/eddfe33871520adab45aaa1a71f0402a2252050c14c7e3009446c8f4701c/python_docx-1.2.0.tar.gz", hash = "sha256:7bc9d7b7d8a69c9c02ca09216118c86552704edc23bac179283f2e38f86220ce", size = 5723256, upload-time = "2025-06-16T20:46:27.921Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987 }, + { url = "https://files.pythonhosted.org/packages/d0/00/1e03a4989fa5795da308cd774f05b704ace555a70f9bf9d3be057b680bcf/python_docx-1.2.0-py3-none-any.whl", hash = "sha256:3fd478f3250fbbbfd3b94fe1e985955737c145627498896a8a6bf81f4baf66c7", size = 252987, upload-time = "2025-06-16T20:46:22.506Z" }, ] [[package]] name = "python-dotenv" -version = "1.2.1" +version = "1.2.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f0/26/19cadc79a718c5edbec86fd4919a6b6d3f681039a2f6d66d14be94e75fb9/python_dotenv-1.2.1.tar.gz", hash = "sha256:42667e897e16ab0d66954af0e60a9caa94f0fd4ecf3aaf6d2d260eec1aa36ad6", size = 44221 } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230 }, + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] [[package]] name = "python-json-logger" version = "4.0.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683 } +sdist = { url = "https://files.pythonhosted.org/packages/29/bf/eca6a3d43db1dae7070f70e160ab20b807627ba953663ba07928cdd3dc58/python_json_logger-4.0.0.tar.gz", hash = "sha256:f58e68eb46e1faed27e0f574a55a0455eecd7b8a5b88b85a784519ba3cff047f", size = 17683, upload-time = "2025-10-06T04:15:18.984Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548 }, + { url = "https://files.pythonhosted.org/packages/51/e5/fecf13f06e5e5f67e8837d777d1bc43fac0ed2b77a676804df5c34744727/python_json_logger-4.0.0-py3-none-any.whl", hash = "sha256:af09c9daf6a813aa4cc7180395f50f2a9e5fa056034c9953aec92e381c5ba1e2", size = 15548, upload-time = "2025-10-06T04:15:17.553Z" }, ] [[package]] name = "python-multipart" version = "0.0.22" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579 }, -] - -[[package]] -name = "pytorch-lightning" -version = "1.8.3.post1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "fsspec", extra = ["http"] }, - { name = "lightning-utilities" }, - { name = "numpy" }, - { name = "packaging" }, - { name = "pyyaml" }, - { name = "tensorboardx" }, - { name = "torch" }, - { name = "torchmetrics" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/a3/92533d6b7af907849eb491e867ae488689c4b6207b513ecd31d9febb7a5b/pytorch-lightning-1.8.3.post1.tar.gz", hash = "sha256:4a1804d55c3aa675a2dd21ee17282cad0bc703dfeace70e75dc956f1faf31411", size = 574889 } +sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/ea/7cb6830785a844eddf45f88b9b14cbf8c3ecce718d4de35503783522f894/pytorch_lightning-1.8.3.post1-py3-none-any.whl", hash = "sha256:2b04cdb876f4e8749161510712b22081dab8db3e6548530608680a415844b6e3", size = 798949 }, + { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, ] [[package]] @@ -2599,45 +2665,45 @@ dependencies = [ { name = "numpy" }, { name = "torch" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086 } +sdist = { url = "https://files.pythonhosted.org/packages/90/c3/aecc90deea743b93757e05e235f70eef479509eb3eb11b19f3aa0d528541/pytorch_revgrad-0.2.0.tar.gz", hash = "sha256:9cf097a7d18cbadddeaec9fef74b258d70b6cb8d0c77f524baab18bffc7d7be9", size = 7086, upload-time = "2021-01-09T17:35:49.131Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564 }, + { url = "https://files.pythonhosted.org/packages/ec/e9/10b11b186b99c40213dca68cf6c38051b6704a74e1056d3f3ca4c12f14b9/pytorch_revgrad-0.2.0-py3-none-any.whl", hash = "sha256:2276fb189b2ce26f756a97effe2a6bcf8f7fdc60542c5dfb45c53f09ef123aa7", size = 4564, upload-time = "2021-01-09T17:35:47.543Z" }, ] [[package]] name = "pytz" -version = "2025.2" +version = "2026.1.post1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884 } +sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225 }, + { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, ] [[package]] name = "pywinpty" version = "3.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/54/37c7370ba91f579235049dc26cd2c5e657d2a943e01820844ffc81f32176/pywinpty-3.0.3.tar.gz", hash = "sha256:523441dc34d231fb361b4b00f8c99d3f16de02f5005fd544a0183112bcc22412", size = 31309 } +sdist = { url = "https://files.pythonhosted.org/packages/f7/54/37c7370ba91f579235049dc26cd2c5e657d2a943e01820844ffc81f32176/pywinpty-3.0.3.tar.gz", hash = "sha256:523441dc34d231fb361b4b00f8c99d3f16de02f5005fd544a0183112bcc22412", size = 31309, upload-time = "2026-02-04T21:51:09.524Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/62/28/a652709bd76ca7533cd1c443b03add9f5051fdf71bc6bdb8801dddd4e7a3/pywinpty-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:ff05f12d775b142b11c6fe085129bdd759b61cf7d41da6c745e78e3a1ef5bf40", size = 2114320 }, - { url = "https://files.pythonhosted.org/packages/b2/13/a0181cc5c2d5635d3dbc3802b97bc8e3ad4fa7502ccef576651a5e08e54c/pywinpty-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:340ccacb4d74278a631923794ccd758471cfc8eeeeee4610b280420a17ad1e82", size = 235670 }, + { url = "https://files.pythonhosted.org/packages/62/28/a652709bd76ca7533cd1c443b03add9f5051fdf71bc6bdb8801dddd4e7a3/pywinpty-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:ff05f12d775b142b11c6fe085129bdd759b61cf7d41da6c745e78e3a1ef5bf40", size = 2114320, upload-time = "2026-02-04T21:53:50.972Z" }, + { url = "https://files.pythonhosted.org/packages/b2/13/a0181cc5c2d5635d3dbc3802b97bc8e3ad4fa7502ccef576651a5e08e54c/pywinpty-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:340ccacb4d74278a631923794ccd758471cfc8eeeeee4610b280420a17ad1e82", size = 235670, upload-time = "2026-02-04T21:50:20.324Z" }, ] [[package]] name = "pyyaml" version = "6.0.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960 } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227 }, - { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019 }, - { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646 }, - { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793 }, - { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293 }, - { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872 }, - { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828 }, - { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415 }, - { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561 }, + { url = "https://files.pythonhosted.org/packages/f4/a0/39350dd17dd6d6c6507025c0e53aef67a9293a6d37d3511f23ea510d5800/pyyaml-6.0.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:214ed4befebe12df36bcc8bc2b64b396ca31be9304b8f59e25c11cf94a4c033b", size = 184227, upload-time = "2025-09-25T21:31:46.04Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/52d505b5c59ce73244f59c7a50ecf47093ce4765f116cdb98286a71eeca2/pyyaml-6.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:02ea2dfa234451bbb8772601d7b8e426c2bfa197136796224e50e35a78777956", size = 174019, upload-time = "2025-09-25T21:31:47.706Z" }, + { url = "https://files.pythonhosted.org/packages/43/f7/0e6a5ae5599c838c696adb4e6330a59f463265bfa1e116cfd1fbb0abaaae/pyyaml-6.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b30236e45cf30d2b8e7b3e85881719e98507abed1011bf463a8fa23e9c3e98a8", size = 740646, upload-time = "2025-09-25T21:31:49.21Z" }, + { url = "https://files.pythonhosted.org/packages/2f/3a/61b9db1d28f00f8fd0ae760459a5c4bf1b941baf714e207b6eb0657d2578/pyyaml-6.0.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:66291b10affd76d76f54fad28e22e51719ef9ba22b29e1d7d03d6777a9174198", size = 840793, upload-time = "2025-09-25T21:31:50.735Z" }, + { url = "https://files.pythonhosted.org/packages/7a/1e/7acc4f0e74c4b3d9531e24739e0ab832a5edf40e64fbae1a9c01941cabd7/pyyaml-6.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9c7708761fccb9397fe64bbc0395abcae8c4bf7b0eac081e12b809bf47700d0b", size = 770293, upload-time = "2025-09-25T21:31:51.828Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/abd085f06853af0cd59fa5f913d61a8eab65d7639ff2a658d18a25d6a89d/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:418cf3f2111bc80e0933b2cd8cd04f286338bb88bdc7bc8e6dd775ebde60b5e0", size = 732872, upload-time = "2025-09-25T21:31:53.282Z" }, + { url = "https://files.pythonhosted.org/packages/1f/15/2bc9c8faf6450a8b3c9fc5448ed869c599c0a74ba2669772b1f3a0040180/pyyaml-6.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5e0b74767e5f8c593e8c9b5912019159ed0533c70051e9cce3e8b6aa699fcd69", size = 758828, upload-time = "2025-09-25T21:31:54.807Z" }, + { url = "https://files.pythonhosted.org/packages/a3/00/531e92e88c00f4333ce359e50c19b8d1de9fe8d581b1534e35ccfbc5f393/pyyaml-6.0.3-cp310-cp310-win32.whl", hash = "sha256:28c8d926f98f432f88adc23edf2e6d4921ac26fb084b028c733d01868d19007e", size = 142415, upload-time = "2025-09-25T21:31:55.885Z" }, + { url = "https://files.pythonhosted.org/packages/2a/fa/926c003379b19fca39dd4634818b00dec6c62d87faf628d1394e137354d4/pyyaml-6.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:bdb2c67c6c1390b63c6ff89f210c8fd09d9a1217a465701eac7316313c915e4c", size = 158561, upload-time = "2025-09-25T21:31:57.406Z" }, ] [[package]] @@ -2647,52 +2713,52 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "implementation_name == 'pypy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850 }, - { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380 }, - { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421 }, - { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149 }, - { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070 }, - { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441 }, - { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529 }, - { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276 }, - { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208 }, - { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766 }, - { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279 }, - { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645 }, - { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574 }, - { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995 }, - { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070 }, - { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121 }, - { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550 }, - { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184 }, - { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480 }, - { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993 }, - { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266 }, - { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206 }, - { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747 }, - { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371 }, - { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862 }, +sdist = { url = "https://files.pythonhosted.org/packages/04/0b/3c9baedbdf613ecaa7aa07027780b8867f57b6293b6ee50de316c9f3222b/pyzmq-27.1.0.tar.gz", hash = "sha256:ac0765e3d44455adb6ddbf4417dcce460fc40a05978c08efdf2948072f6db540", size = 281750, upload-time = "2025-09-08T23:10:18.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/67/b9/52aa9ec2867528b54f1e60846728d8b4d84726630874fee3a91e66c7df81/pyzmq-27.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:508e23ec9bc44c0005c4946ea013d9317ae00ac67778bd47519fdf5a0e930ff4", size = 1329850, upload-time = "2025-09-08T23:07:26.274Z" }, + { url = "https://files.pythonhosted.org/packages/99/64/5653e7b7425b169f994835a2b2abf9486264401fdef18df91ddae47ce2cc/pyzmq-27.1.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:507b6f430bdcf0ee48c0d30e734ea89ce5567fd7b8a0f0044a369c176aa44556", size = 906380, upload-time = "2025-09-08T23:07:29.78Z" }, + { url = "https://files.pythonhosted.org/packages/73/78/7d713284dbe022f6440e391bd1f3c48d9185673878034cfb3939cdf333b2/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf7b38f9fd7b81cb6d9391b2946382c8237fd814075c6aa9c3b746d53076023b", size = 666421, upload-time = "2025-09-08T23:07:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/30/76/8f099f9d6482450428b17c4d6b241281af7ce6a9de8149ca8c1c649f6792/pyzmq-27.1.0-cp310-cp310-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03ff0b279b40d687691a6217c12242ee71f0fba28bf8626ff50e3ef0f4410e1e", size = 854149, upload-time = "2025-09-08T23:07:33.17Z" }, + { url = "https://files.pythonhosted.org/packages/59/f0/37fbfff06c68016019043897e4c969ceab18bde46cd2aca89821fcf4fb2e/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:677e744fee605753eac48198b15a2124016c009a11056f93807000ab11ce6526", size = 1655070, upload-time = "2025-09-08T23:07:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/47/14/7254be73f7a8edc3587609554fcaa7bfd30649bf89cd260e4487ca70fdaa/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:dd2fec2b13137416a1c5648b7009499bcc8fea78154cd888855fa32514f3dad1", size = 2033441, upload-time = "2025-09-08T23:07:37.432Z" }, + { url = "https://files.pythonhosted.org/packages/22/dc/49f2be26c6f86f347e796a4d99b19167fc94503f0af3fd010ad262158822/pyzmq-27.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:08e90bb4b57603b84eab1d0ca05b3bbb10f60c1839dc471fc1c9e1507bef3386", size = 1891529, upload-time = "2025-09-08T23:07:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/a3/3e/154fb963ae25be70c0064ce97776c937ecc7d8b0259f22858154a9999769/pyzmq-27.1.0-cp310-cp310-win32.whl", hash = "sha256:a5b42d7a0658b515319148875fcb782bbf118dd41c671b62dae33666c2213bda", size = 567276, upload-time = "2025-09-08T23:07:40.695Z" }, + { url = "https://files.pythonhosted.org/packages/62/b2/f4ab56c8c595abcb26b2be5fd9fa9e6899c1e5ad54964e93ae8bb35482be/pyzmq-27.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:c0bb87227430ee3aefcc0ade2088100e528d5d3298a0a715a64f3d04c60ba02f", size = 632208, upload-time = "2025-09-08T23:07:42.298Z" }, + { url = "https://files.pythonhosted.org/packages/3b/e3/be2cc7ab8332bdac0522fdb64c17b1b6241a795bee02e0196636ec5beb79/pyzmq-27.1.0-cp310-cp310-win_arm64.whl", hash = "sha256:9a916f76c2ab8d045b19f2286851a38e9ac94ea91faf65bd64735924522a8b32", size = 559766, upload-time = "2025-09-08T23:07:43.869Z" }, + { url = "https://files.pythonhosted.org/packages/92/e7/038aab64a946d535901103da16b953c8c9cc9c961dadcbf3609ed6428d23/pyzmq-27.1.0-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:452631b640340c928fa343801b0d07eb0c3789a5ffa843f6e1a9cee0ba4eb4fc", size = 1306279, upload-time = "2025-09-08T23:08:03.807Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5e/c3c49fdd0f535ef45eefcc16934648e9e59dace4a37ee88fc53f6cd8e641/pyzmq-27.1.0-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:1c179799b118e554b66da67d88ed66cd37a169f1f23b5d9f0a231b4e8d44a113", size = 895645, upload-time = "2025-09-08T23:08:05.301Z" }, + { url = "https://files.pythonhosted.org/packages/f8/e5/b0b2504cb4e903a74dcf1ebae157f9e20ebb6ea76095f6cfffea28c42ecd/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3837439b7f99e60312f0c926a6ad437b067356dc2bc2ec96eb395fd0fe804233", size = 652574, upload-time = "2025-09-08T23:08:06.828Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9b/c108cdb55560eaf253f0cbdb61b29971e9fb34d9c3499b0e96e4e60ed8a5/pyzmq-27.1.0-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43ad9a73e3da1fab5b0e7e13402f0b2fb934ae1c876c51d0afff0e7c052eca31", size = 840995, upload-time = "2025-09-08T23:08:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/c2/bb/b79798ca177b9eb0825b4c9998c6af8cd2a7f15a6a1a4272c1d1a21d382f/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0de3028d69d4cdc475bfe47a6128eb38d8bc0e8f4d69646adfbcd840facbac28", size = 1642070, upload-time = "2025-09-08T23:08:09.989Z" }, + { url = "https://files.pythonhosted.org/packages/9c/80/2df2e7977c4ede24c79ae39dcef3899bfc5f34d1ca7a5b24f182c9b7a9ca/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:cf44a7763aea9298c0aa7dbf859f87ed7012de8bda0f3977b6fb1d96745df856", size = 2021121, upload-time = "2025-09-08T23:08:11.907Z" }, + { url = "https://files.pythonhosted.org/packages/46/bd/2d45ad24f5f5ae7e8d01525eb76786fa7557136555cac7d929880519e33a/pyzmq-27.1.0-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:f30f395a9e6fbca195400ce833c731e7b64c3919aa481af4d88c3759e0cb7496", size = 1878550, upload-time = "2025-09-08T23:08:13.513Z" }, + { url = "https://files.pythonhosted.org/packages/e6/2f/104c0a3c778d7c2ab8190e9db4f62f0b6957b53c9d87db77c284b69f33ea/pyzmq-27.1.0-cp312-abi3-win32.whl", hash = "sha256:250e5436a4ba13885494412b3da5d518cd0d3a278a1ae640e113c073a5f88edd", size = 559184, upload-time = "2025-09-08T23:08:15.163Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/a21b20d577e4100c6a41795842028235998a643b1ad406a6d4163ea8f53e/pyzmq-27.1.0-cp312-abi3-win_amd64.whl", hash = "sha256:9ce490cf1d2ca2ad84733aa1d69ce6855372cb5ce9223802450c9b2a7cba0ccf", size = 619480, upload-time = "2025-09-08T23:08:17.192Z" }, + { url = "https://files.pythonhosted.org/packages/78/c2/c012beae5f76b72f007a9e91ee9401cb88c51d0f83c6257a03e785c81cc2/pyzmq-27.1.0-cp312-abi3-win_arm64.whl", hash = "sha256:75a2f36223f0d535a0c919e23615fc85a1e23b71f40c7eb43d7b1dedb4d8f15f", size = 552993, upload-time = "2025-09-08T23:08:18.926Z" }, + { url = "https://files.pythonhosted.org/packages/f3/81/a65e71c1552f74dec9dff91d95bafb6e0d33338a8dfefbc88aa562a20c92/pyzmq-27.1.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c17e03cbc9312bee223864f1a2b13a99522e0dc9f7c5df0177cd45210ac286e6", size = 836266, upload-time = "2025-09-08T23:09:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/0202ca350f4f2b69faa95c6d931e3c05c3a397c184cacb84cb4f8f42f287/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f328d01128373cb6763823b2b4e7f73bdf767834268c565151eacb3b7a392f90", size = 800206, upload-time = "2025-09-08T23:09:41.902Z" }, + { url = "https://files.pythonhosted.org/packages/47/42/1ff831fa87fe8f0a840ddb399054ca0009605d820e2b44ea43114f5459f4/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1790386614232e1b3a40a958454bdd42c6d1811837b15ddbb052a032a43f62", size = 567747, upload-time = "2025-09-08T23:09:43.741Z" }, + { url = "https://files.pythonhosted.org/packages/d1/db/5c4d6807434751e3f21231bee98109aa57b9b9b55e058e450d0aef59b70f/pyzmq-27.1.0-pp310-pypy310_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:448f9cb54eb0cee4732b46584f2710c8bc178b0e5371d9e4fc8125201e413a74", size = 747371, upload-time = "2025-09-08T23:09:45.575Z" }, + { url = "https://files.pythonhosted.org/packages/26/af/78ce193dbf03567eb8c0dc30e3df2b9e56f12a670bf7eb20f9fb532c7e8a/pyzmq-27.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:05b12f2d32112bf8c95ef2e74ec4f1d4beb01f8b5e703b38537f8849f92cb9ba", size = 544862, upload-time = "2025-09-08T23:09:47.448Z" }, ] [[package]] name = "rapidfuzz" version = "3.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900 } +sdist = { url = "https://files.pythonhosted.org/packages/d3/28/9d808fe62375b9aab5ba92fa9b29371297b067c2790b2d7cda648b1e2f8d/rapidfuzz-3.14.3.tar.gz", hash = "sha256:2491937177868bc4b1e469087601d53f925e8d270ccc21e07404b4b5814b7b5f", size = 57863900, upload-time = "2025-11-01T11:54:52.321Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376 }, - { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903 }, - { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655 }, - { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708 }, - { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106 }, - { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048 }, - { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020 }, - { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958 }, - { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043 }, - { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273 }, - { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875 }, + { url = "https://files.pythonhosted.org/packages/69/d1/0efa42a602ed466d3ca1c462eed5d62015c3fd2a402199e2c4b87aa5aa25/rapidfuzz-3.14.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b9fcd4d751a4fffa17aed1dde41647923c72c74af02459ad1222e3b0022da3a1", size = 1952376, upload-time = "2025-11-01T11:52:29.175Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/37a169bb28b23850a164e6624b1eb299e1ad73c9e7c218ee15744e68d628/rapidfuzz-3.14.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4ad73afb688b36864a8d9b7344a9cf6da186c471e5790cbf541a635ee0f457f2", size = 1390903, upload-time = "2025-11-01T11:52:31.239Z" }, + { url = "https://files.pythonhosted.org/packages/3c/91/b37207cbbdb6eaafac3da3f55ea85287b27745cb416e75e15769b7d8abe8/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5fb2d978a601820d2cfd111e2c221a9a7bfdf84b41a3ccbb96ceef29f2f1ac7", size = 1385655, upload-time = "2025-11-01T11:52:32.852Z" }, + { url = "https://files.pythonhosted.org/packages/f2/bb/ca53e518acf43430be61f23b9c5987bd1e01e74fcb7a9ee63e00f597aefb/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d83b8b712fa37e06d59f29a4b49e2e9e8635e908fbc21552fe4d1163db9d2a1", size = 3164708, upload-time = "2025-11-01T11:52:34.618Z" }, + { url = "https://files.pythonhosted.org/packages/df/e1/7667bf2db3e52adb13cb933dd4a6a2efc66045d26fa150fc0feb64c26d61/rapidfuzz-3.14.3-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:dc8c07801df5206b81ed6bd6c35cb520cf9b6c64b9b0d19d699f8633dc942897", size = 1221106, upload-time = "2025-11-01T11:52:36.069Z" }, + { url = "https://files.pythonhosted.org/packages/05/8a/84d9f2d46a2c8eb2ccae81747c4901fa10fe4010aade2d57ce7b4b8e02ec/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c71ce6d4231e5ef2e33caa952bfe671cb9fd42e2afb11952df9fad41d5c821f9", size = 2406048, upload-time = "2025-11-01T11:52:37.936Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a9/a0b7b7a1b81a020c034eb67c8e23b7e49f920004e295378de3046b0d99e1/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0e38828d1381a0cceb8a4831212b2f673d46f5129a1897b0451c883eaf4a1747", size = 2527020, upload-time = "2025-11-01T11:52:39.657Z" }, + { url = "https://files.pythonhosted.org/packages/b4/bc/416df7d108b99b4942ba04dd4cf73c45c3aadb3ef003d95cad78b1d12eb9/rapidfuzz-3.14.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da2a007434323904719158e50f3076a4dadb176ce43df28ed14610c773cc9825", size = 4273958, upload-time = "2025-11-01T11:52:41.017Z" }, + { url = "https://files.pythonhosted.org/packages/81/d0/b81e041c17cd475002114e0ab8800e4305e60837882cb376a621e520d70f/rapidfuzz-3.14.3-cp310-cp310-win32.whl", hash = "sha256:fce3152f94afcfd12f3dd8cf51e48fa606e3cb56719bccebe3b401f43d0714f9", size = 1725043, upload-time = "2025-11-01T11:52:42.465Z" }, + { url = "https://files.pythonhosted.org/packages/09/6b/64ad573337d81d64bc78a6a1df53a72a71d54d43d276ce0662c2e95a1f35/rapidfuzz-3.14.3-cp310-cp310-win_amd64.whl", hash = "sha256:37d3c653af15cd88592633e942f5407cb4c64184efab163c40fcebad05f25141", size = 1542273, upload-time = "2025-11-01T11:52:44.005Z" }, + { url = "https://files.pythonhosted.org/packages/f4/5e/faf76e259bc15808bc0b86028f510215c3d755b6c3a3911113079485e561/rapidfuzz-3.14.3-cp310-cp310-win_arm64.whl", hash = "sha256:cc594bbcd3c62f647dfac66800f307beaee56b22aaba1c005e9c4c40ed733923", size = 814875, upload-time = "2025-11-01T11:52:45.405Z" }, ] [[package]] @@ -2704,34 +2770,34 @@ dependencies = [ { name = "rpds-py" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036 } +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766 }, + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, ] [[package]] name = "regex" -version = "2026.2.19" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ff/c0/d8079d4f6342e4cec5c3e7d7415b5cd3e633d5f4124f7a4626908dbe84c7/regex-2026.2.19.tar.gz", hash = "sha256:6fb8cb09b10e38f3ae17cc6dc04a1df77762bd0351b6ba9041438e7cc85ec310", size = 414973 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/de/f10b4506acfd684de4e42b0aa56ccea1a778a18864da8f6d319a40591062/regex-2026.2.19-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f5a37a17d110f9d5357a43aa7e3507cb077bf3143d1c549a45c4649e90e40a70", size = 488369 }, - { url = "https://files.pythonhosted.org/packages/8b/2f/b4eaef1f0b4d0bf2a73eaf07c08f6c13422918a4180c9211ce0521746d0c/regex-2026.2.19-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:676c4e6847a83a1d5732b4ed553881ad36f0a8133627bb695a89ecf3571499d3", size = 290743 }, - { url = "https://files.pythonhosted.org/packages/76/7c/805413bd0a88d04688c0725c222cfb811bd54a2f571004c24199a1ae55d6/regex-2026.2.19-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82336faeecac33297cd42857c3b36f12b91810e3fdd276befdd128f73a2b43fa", size = 288652 }, - { url = "https://files.pythonhosted.org/packages/08/ff/2c4cd530a878b1975398e76faef4285f11e7c9ccf1aaedfd528bfcc1f580/regex-2026.2.19-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:52136f5b71f095cb74b736cc3a1b578030dada2e361ef2f07ca582240b703946", size = 781759 }, - { url = "https://files.pythonhosted.org/packages/37/45/9608ab1b41f6740ff4076eabadde8e8b3f3400942b348ac41e8599ccc131/regex-2026.2.19-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4192464fe3e6cb0ef6751f7d3b16f886d8270d359ed1590dd555539d364f0ff7", size = 850947 }, - { url = "https://files.pythonhosted.org/packages/90/3a/66471b6c4f7cac17e14bf5300e46661bba2b17ffb0871bd2759e837a6f82/regex-2026.2.19-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e561dd47a85d2660d3d3af4e6cb2da825cf20f121e577147963f875b83d32786", size = 898794 }, - { url = "https://files.pythonhosted.org/packages/c2/d2/38c53929a5931f7398e5e49f5a5a3079cb2aba30119b4350608364cfad8c/regex-2026.2.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00ec994d7824bf01cd6c7d14c7a6a04d9aeaf7c42a2bc22d2359d715634d539b", size = 791922 }, - { url = "https://files.pythonhosted.org/packages/8b/bd/b046e065630fa25059d9c195b7b5308ea94da45eee65d40879772500f74c/regex-2026.2.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2cb00aabd96b345d56a8c2bc328c8d6c4d29935061e05078bf1f02302e12abf5", size = 783345 }, - { url = "https://files.pythonhosted.org/packages/d4/8f/045c643d2fa255a985e8f87d848e4be230b711a8935e4bdc58e60b8f7b84/regex-2026.2.19-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f374366ed35673ea81b86a8859c457d4fae6ba092b71024857e9e237410c7404", size = 768055 }, - { url = "https://files.pythonhosted.org/packages/72/9f/ab7ae9f5447559562f1a788bbc85c0e526528c5e6c20542d18e4afc86aad/regex-2026.2.19-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f9417fd853fcd00b7d55167e692966dd12d95ba1a88bf08a62002ccd85030790", size = 774955 }, - { url = "https://files.pythonhosted.org/packages/37/5c/f16fc23c56f60b6f4ff194604a6e53bb8aec7b6e8e4a23a482dee8d77235/regex-2026.2.19-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:12e86a01594031abf892686fcb309b041bf3de3d13d99eb7e2b02a8f3c687df1", size = 846010 }, - { url = "https://files.pythonhosted.org/packages/51/c8/6be4c854135d7c9f35d4deeafdaf124b039ecb4ffcaeb7ed0495ad2c97ca/regex-2026.2.19-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:79014115e6fdf18fd9b32e291d58181bf42d4298642beaa13fd73e69810e4cb6", size = 755938 }, - { url = "https://files.pythonhosted.org/packages/d6/8d/f683d49b9663a5324b95a328e69d397f6dade7cb84154eec116bf79fe150/regex-2026.2.19-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:31aefac2506967b7dd69af2c58eca3cc8b086d4110b66d6ac6e9026f0ee5b697", size = 835773 }, - { url = "https://files.pythonhosted.org/packages/16/cd/619224b90da09f167fe4497c350a0d0b30edc539ee9244bf93e604c073c3/regex-2026.2.19-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:49cef7bb2a491f91a8869c7cdd90babf0a417047ab0bf923cd038ed2eab2ccb8", size = 780075 }, - { url = "https://files.pythonhosted.org/packages/5b/88/19cfb0c262d6f9d722edef29157125418bf90eb3508186bf79335afeedae/regex-2026.2.19-cp310-cp310-win32.whl", hash = "sha256:3a039474986e7a314ace6efb9ce52f5da2bdb80ac4955358723d350ec85c32ad", size = 266004 }, - { url = "https://files.pythonhosted.org/packages/82/af/5b487e0287ef72545d7ae92edecdacbe3d44e531cac24fda7de5598ba8dd/regex-2026.2.19-cp310-cp310-win_amd64.whl", hash = "sha256:5b81ff4f9cad99f90c807a00c5882fbcda86d8b3edd94e709fb531fc52cb3d25", size = 277895 }, - { url = "https://files.pythonhosted.org/packages/4c/19/b6715a187ffca4d2979af92a46ce922445ba41f910bf187ccd666a2d52ef/regex-2026.2.19-cp310-cp310-win_arm64.whl", hash = "sha256:a032bc01a4bc73fc3cadba793fce28eb420da39338f47910c59ffcc11a5ba5ef", size = 270465 }, +version = "2026.2.28" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/71/41455aa99a5a5ac1eaf311f5d8efd9ce6433c03ac1e0962de163350d0d97/regex-2026.2.28.tar.gz", hash = "sha256:a729e47d418ea11d03469f321aaf67cdee8954cde3ff2cf8403ab87951ad10f2", size = 415184, upload-time = "2026-02-28T02:19:42.792Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/b8/845a927e078f5e5cc55d29f57becbfde0003d52806544531ab3f2da4503c/regex-2026.2.28-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fc48c500838be6882b32748f60a15229d2dea96e59ef341eaa96ec83538f498d", size = 488461, upload-time = "2026-02-28T02:15:48.405Z" }, + { url = "https://files.pythonhosted.org/packages/32/f9/8a0034716684e38a729210ded6222249f29978b24b684f448162ef21f204/regex-2026.2.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2afa673660928d0b63d84353c6c08a8a476ddfc4a47e11742949d182e6863ce8", size = 290774, upload-time = "2026-02-28T02:15:51.738Z" }, + { url = "https://files.pythonhosted.org/packages/a6/ba/b27feefffbb199528dd32667cd172ed484d9c197618c575f01217fbe6103/regex-2026.2.28-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7ab218076eb0944549e7fe74cf0e2b83a82edb27e81cc87411f76240865e04d5", size = 288737, upload-time = "2026-02-28T02:15:53.534Z" }, + { url = "https://files.pythonhosted.org/packages/18/c5/65379448ca3cbfe774fcc33774dc8295b1ee97dc3237ae3d3c7b27423c9d/regex-2026.2.28-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:94d63db12e45a9b9f064bfe4800cefefc7e5f182052e4c1b774d46a40ab1d9bb", size = 782675, upload-time = "2026-02-28T02:15:55.488Z" }, + { url = "https://files.pythonhosted.org/packages/aa/30/6fa55bef48090f900fbd4649333791fc3e6467380b9e775e741beeb3231f/regex-2026.2.28-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:195237dc327858a7721bf8b0bbbef797554bc13563c3591e91cd0767bacbe359", size = 850514, upload-time = "2026-02-28T02:15:57.509Z" }, + { url = "https://files.pythonhosted.org/packages/a9/28/9ca180fb3787a54150209754ac06a42409913571fa94994f340b3bba4e1e/regex-2026.2.28-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b387a0d092dac157fb026d737dde35ff3e49ef27f285343e7c6401851239df27", size = 896612, upload-time = "2026-02-28T02:15:59.682Z" }, + { url = "https://files.pythonhosted.org/packages/46/b5/f30d7d3936d6deecc3ea7bea4f7d3c5ee5124e7c8de372226e436b330a55/regex-2026.2.28-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3935174fa4d9f70525a4367aaff3cb8bc0548129d114260c29d9dfa4a5b41692", size = 791691, upload-time = "2026-02-28T02:16:01.752Z" }, + { url = "https://files.pythonhosted.org/packages/f5/34/96631bcf446a56ba0b2a7f684358a76855dfe315b7c2f89b35388494ede0/regex-2026.2.28-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2b2b23587b26496ff5fd40df4278becdf386813ec00dc3533fa43a4cf0e2ad3c", size = 783111, upload-time = "2026-02-28T02:16:03.651Z" }, + { url = "https://files.pythonhosted.org/packages/39/54/f95cb7a85fe284d41cd2f3625e0f2ae30172b55dfd2af1d9b4eaef6259d7/regex-2026.2.28-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3b24bd7e9d85dc7c6a8bd2aa14ecd234274a0248335a02adeb25448aecdd420d", size = 767512, upload-time = "2026-02-28T02:16:05.616Z" }, + { url = "https://files.pythonhosted.org/packages/3d/af/a650f64a79c02a97f73f64d4e7fc4cc1984e64affab14075e7c1f9a2db34/regex-2026.2.28-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bd477d5f79920338107f04aa645f094032d9e3030cc55be581df3d1ef61aa318", size = 773920, upload-time = "2026-02-28T02:16:08.325Z" }, + { url = "https://files.pythonhosted.org/packages/72/f8/3f9c2c2af37aedb3f5a1e7227f81bea065028785260d9cacc488e43e6997/regex-2026.2.28-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b49eb78048c6354f49e91e4b77da21257fecb92256b6d599ae44403cab30b05b", size = 846681, upload-time = "2026-02-28T02:16:10.381Z" }, + { url = "https://files.pythonhosted.org/packages/54/12/8db04a334571359f4d127d8f89550917ec6561a2fddfd69cd91402b47482/regex-2026.2.28-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:a25c7701e4f7a70021db9aaf4a4a0a67033c6318752146e03d1b94d32006217e", size = 755565, upload-time = "2026-02-28T02:16:11.972Z" }, + { url = "https://files.pythonhosted.org/packages/da/bc/91c22f384d79324121b134c267a86ca90d11f8016aafb1dc5bee05890ee3/regex-2026.2.28-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:9dd450db6458387167e033cfa80887a34c99c81d26da1bf8b0b41bf8c9cac88e", size = 835789, upload-time = "2026-02-28T02:16:14.036Z" }, + { url = "https://files.pythonhosted.org/packages/46/a7/4cc94fd3af01dcfdf5a9ed75c8e15fd80fcd62cc46da7592b1749e9c35db/regex-2026.2.28-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2954379dd20752e82d22accf3ff465311cbb2bac6c1f92c4afd400e1757f7451", size = 780094, upload-time = "2026-02-28T02:16:15.468Z" }, + { url = "https://files.pythonhosted.org/packages/3c/21/e5a38f420af3c77cab4a65f0c3a55ec02ac9babf04479cfd282d356988a6/regex-2026.2.28-cp310-cp310-win32.whl", hash = "sha256:1f8b17be5c27a684ea6759983c13506bd77bfc7c0347dff41b18ce5ddd2ee09a", size = 266025, upload-time = "2026-02-28T02:16:16.828Z" }, + { url = "https://files.pythonhosted.org/packages/4d/0a/205c4c1466a36e04d90afcd01d8908bac327673050c7fe316b2416d99d3d/regex-2026.2.28-cp310-cp310-win_amd64.whl", hash = "sha256:dd8847c4978bc3c7e6c826fb745f5570e518b8459ac2892151ce6627c7bc00d5", size = 277965, upload-time = "2026-02-28T02:16:18.752Z" }, + { url = "https://files.pythonhosted.org/packages/c3/4d/29b58172f954b6ec2c5ed28529a65e9026ab96b4b7016bcd3858f1c31d3c/regex-2026.2.28-cp310-cp310-win_arm64.whl", hash = "sha256:73cdcdbba8028167ea81490c7f45280113e41db2c7afb65a276f4711fa3bcbff", size = 270336, upload-time = "2026-02-28T02:16:20.735Z" }, ] [[package]] @@ -2744,9 +2810,9 @@ dependencies = [ { name = "idna" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738 }, + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, ] [package.optional-dependencies] @@ -2761,18 +2827,18 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513 } +sdist = { url = "https://files.pythonhosted.org/packages/28/ea/a9387748e2d111c3c2b275ba970b735e04e15cdb1eb30693b6b5708c4dbd/rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b", size = 5513, upload-time = "2021-05-12T16:37:54.178Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490 }, + { url = "https://files.pythonhosted.org/packages/7b/44/4e421b96b67b2daff264473f7465db72fbdf36a07e05494f50300cc7b0c6/rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa", size = 3490, upload-time = "2021-05-12T16:37:52.536Z" }, ] [[package]] name = "rfc3986-validator" version = "0.1.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760 } +sdist = { url = "https://files.pythonhosted.org/packages/da/88/f270de456dd7d11dcc808abfa291ecdd3f45ff44e3b549ffa01b126464d0/rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055", size = 6760, upload-time = "2019-10-28T16:00:19.144Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242 }, + { url = "https://files.pythonhosted.org/packages/9e/51/17023c0f8f1869d8806b979a2bffa3f861f26a3f1a66b094288323fba52f/rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9", size = 4242, upload-time = "2019-10-28T16:00:13.976Z" }, ] [[package]] @@ -2782,9 +2848,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "lark" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/06/37c1a5557acf449e8e406a830a05bf885ac47d33270aec454ef78675008d/rfc3987_syntax-1.1.0.tar.gz", hash = "sha256:717a62cbf33cffdd16dfa3a497d81ce48a660ea691b1ddd7be710c22f00b4a0d", size = 14239, upload-time = "2025-07-18T01:05:05.015Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046 }, + { url = "https://files.pythonhosted.org/packages/7e/71/44ce230e1b7fadd372515a97e32a83011f906ddded8d03e3c6aafbdedbb7/rfc3987_syntax-1.1.0-py3-none-any.whl", hash = "sha256:6c3d97604e4c5ce9f714898e05401a0445a641cfa276432b0a648c80856f6a3f", size = 8046, upload-time = "2025-07-18T01:05:03.843Z" }, ] [[package]] @@ -2795,79 +2861,79 @@ dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582 } +sdist = { url = "https://files.pythonhosted.org/packages/b3/c6/f3b320c27991c46f43ee9d856302c70dc2d0fb2dba4842ff739d5f46b393/rich-14.3.3.tar.gz", hash = "sha256:b8daa0b9e4eef54dd8cf7c86c03713f53241884e814f4e2f5fb342fe520f639b", size = 230582, upload-time = "2026-02-19T17:23:12.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458 }, + { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, ] [[package]] name = "rich-toolkit" -version = "0.19.4" +version = "0.19.7" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d0/c9/4bbf4bfee195ed1b7d7a6733cc523ca61dbfb4a3e3c12ea090aaffd97597/rich_toolkit-0.19.4.tar.gz", hash = "sha256:52e23d56f9dc30d1343eb3b3f6f18764c313fbfea24e52e6a1d6069bec9c18eb", size = 193951 } +sdist = { url = "https://files.pythonhosted.org/packages/42/ba/dae9e3096651042754da419a4042bc1c75e07d615f9b15066d738838e4df/rich_toolkit-0.19.7.tar.gz", hash = "sha256:133c0915872da91d4c25d85342d5ec1dfacc69b63448af1a08a0d4b4f23ef46e", size = 195877, upload-time = "2026-02-24T16:06:20.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/28/31/97d39719def09c134385bfcfbedfed255168b571e7beb3ad7765aae660ca/rich_toolkit-0.19.4-py3-none-any.whl", hash = "sha256:34ac344de8862801644be8b703e26becf44b047e687f208d7829e8f7cfc311d6", size = 32757 }, + { url = "https://files.pythonhosted.org/packages/fb/3c/c923619f6d2f5fafcc96fec0aaf9550a46cd5b6481f06e0c6b66a2a4fed0/rich_toolkit-0.19.7-py3-none-any.whl", hash = "sha256:0288e9203728c47c5a4eb60fd2f0692d9df7455a65901ab6f898437a2ba5989d", size = 32963, upload-time = "2026-02-24T16:06:22.066Z" }, ] [[package]] name = "rignore" version = "0.7.6" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999 }, - { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824 }, - { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121 }, - { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813 }, - { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019 }, - { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822 }, - { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820 }, - { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050 }, - { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164 }, - { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028 }, - { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024 }, - { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531 }, - { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817 }, - { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001 }, - { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462 }, - { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918 }, - { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922 }, - { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987 }, - { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110 }, - { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339 }, - { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680 }, - { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045 }, - { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310 }, - { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998 }, - { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178 }, - { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190 }, +sdist = { url = "https://files.pythonhosted.org/packages/e5/f5/8bed2310abe4ae04b67a38374a4d311dd85220f5d8da56f47ae9361be0b0/rignore-0.7.6.tar.gz", hash = "sha256:00d3546cd793c30cb17921ce674d2c8f3a4b00501cb0e3dd0e82217dbeba2671", size = 57140, upload-time = "2025-11-05T21:41:21.968Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/7a/b970cd0138b0ece72eb28f086e933f9ed75b795716ad3de5ab22994b3b54/rignore-0.7.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f3c74a7e5ee77aea669c95fdb3933f2a6c7549893700082e759128a29cf67e45", size = 884999, upload-time = "2025-11-05T20:42:38.373Z" }, + { url = "https://files.pythonhosted.org/packages/ca/05/23faca29616d8966ada63fb0e13c214107811fa9a0aba2275e4c7ca63bd5/rignore-0.7.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b7202404958f5fe3474bac91f65350f0b1dde1a5e05089f2946549b7e91e79ec", size = 824824, upload-time = "2025-11-05T20:42:22.1Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/05a1e61f04cf2548524224f0b5f21ca19ea58f7273a863bac10846b8ff69/rignore-0.7.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bde7c5835fa3905bfb7e329a4f1d7eccb676de63da7a3f934ddd5c06df20597", size = 899121, upload-time = "2025-11-05T20:40:48.94Z" }, + { url = "https://files.pythonhosted.org/packages/ff/35/71518847e10bdbf359badad8800e4681757a01f4777b3c5e03dbde8a42d8/rignore-0.7.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:626c3d4ba03af266694d25101bc1d8d16eda49c5feb86cedfec31c614fceca7d", size = 873813, upload-time = "2025-11-05T20:41:04.71Z" }, + { url = "https://files.pythonhosted.org/packages/f6/c8/32ae405d3e7fd4d9f9b7838f2fcca0a5005bb87fa514b83f83fd81c0df22/rignore-0.7.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0a43841e651e7a05a4274b9026cc408d1912e64016ede8cd4c145dae5d0635be", size = 1168019, upload-time = "2025-11-05T20:41:20.723Z" }, + { url = "https://files.pythonhosted.org/packages/25/98/013c955982bc5b4719bf9a5bea58be317eea28aa12bfd004025e3cd7c000/rignore-0.7.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7978c498dbf7f74d30cdb8859fe612167d8247f0acd377ae85180e34490725da", size = 942822, upload-time = "2025-11-05T20:41:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/90/fb/9a3f3156c6ed30bcd597e63690353edac1fcffe9d382ad517722b56ac195/rignore-0.7.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d22f72ab695c07d2d96d2a645208daff17084441b5d58c07378c9dd6f9c4c87", size = 959820, upload-time = "2025-11-05T20:42:06.364Z" }, + { url = "https://files.pythonhosted.org/packages/5e/b2/93bf609633021e9658acaff24cfb055d8cdaf7f5855d10ebb35307900dda/rignore-0.7.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5bd8e1a91ed1a789b2cbe39eeea9204a6719d4f2cf443a9544b521a285a295f", size = 985050, upload-time = "2025-11-05T20:41:51.124Z" }, + { url = "https://files.pythonhosted.org/packages/69/bc/ec2d040469bdfd7b743df10f2201c5d285009a4263d506edbf7a06a090bb/rignore-0.7.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc1fc03efad5789365018e94ac4079f851a999bc154d1551c45179f7fcf45322", size = 1079164, upload-time = "2025-11-05T21:40:10.368Z" }, + { url = "https://files.pythonhosted.org/packages/df/26/4b635f4ea5baf4baa8ba8eee06163f6af6e76dfbe72deb57da34bb24b19d/rignore-0.7.6-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:ce2617fe28c51367fd8abfd4eeea9e61664af63c17d4ea00353d8ef56dfb95fa", size = 1139028, upload-time = "2025-11-05T21:40:27.977Z" }, + { url = "https://files.pythonhosted.org/packages/6a/54/a3147ebd1e477b06eb24e2c2c56d951ae5faa9045b7b36d7892fec5080d9/rignore-0.7.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c4ad2cee85068408e7819a38243043214e2c3047e9bd4c506f8de01c302709e", size = 1119024, upload-time = "2025-11-05T21:40:45.148Z" }, + { url = "https://files.pythonhosted.org/packages/fb/f4/27475db769a57cff18fe7e7267b36e6cdb5b1281caa185ba544171106cba/rignore-0.7.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:02cd240bfd59ecc3907766f4839cbba20530a2e470abca09eaa82225e4d946fb", size = 1128531, upload-time = "2025-11-05T21:41:02.734Z" }, + { url = "https://files.pythonhosted.org/packages/97/32/6e782d3b352e4349fa0e90bf75b13cb7f11d8908b36d9e2b262224b65d9a/rignore-0.7.6-cp310-cp310-win32.whl", hash = "sha256:fe2bd8fa1ff555259df54c376abc73855cb02628a474a40d51b358c3a1ddc55b", size = 646817, upload-time = "2025-11-05T21:41:47.51Z" }, + { url = "https://files.pythonhosted.org/packages/c0/8a/53185c69abb3bb362e8a46b8089999f820bf15655629ff8395107633c8ab/rignore-0.7.6-cp310-cp310-win_amd64.whl", hash = "sha256:d80afd6071c78baf3765ec698841071b19e41c326f994cfa69b5a1df676f5d39", size = 727001, upload-time = "2025-11-05T21:41:32.778Z" }, + { url = "https://files.pythonhosted.org/packages/85/12/62d690b4644c330d7ac0f739b7f078190ab4308faa909a60842d0e4af5b2/rignore-0.7.6-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3d3a523af1cd4ed2c0cba8d277a32d329b0c96ef9901fb7ca45c8cfaccf31a5", size = 887462, upload-time = "2025-11-05T20:42:50.804Z" }, + { url = "https://files.pythonhosted.org/packages/05/bc/6528a0e97ed2bd7a7c329183367d1ffbc5b9762ae8348d88dae72cc9d1f5/rignore-0.7.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:990853566e65184a506e1e2af2d15045afad3ebaebb8859cb85b882081915110", size = 826918, upload-time = "2025-11-05T20:42:33.689Z" }, + { url = "https://files.pythonhosted.org/packages/3e/2c/7d7bad116e09a04e9e1688c6f891fa2d4fd33f11b69ac0bd92419ddebeae/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cab9ff2e436ce7240d7ee301c8ef806ed77c1fd6b8a8239ff65f9bbbcb5b8a3", size = 900922, upload-time = "2025-11-05T20:41:00.361Z" }, + { url = "https://files.pythonhosted.org/packages/09/ba/e5ea89fbde8e37a90ce456e31c5e9d85512cef5ae38e0f4d2426eb776a19/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1a6671b2082c13bfd9a5cf4ce64670f832a6d41470556112c4ab0b6519b2fc4", size = 876987, upload-time = "2025-11-05T20:41:16.219Z" }, + { url = "https://files.pythonhosted.org/packages/d0/fb/93d14193f0ec0c3d35b763f0a000e9780f63b2031f3d3756442c2152622d/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2468729b4c5295c199d084ab88a40afcb7c8b974276805105239c07855bbacee", size = 1171110, upload-time = "2025-11-05T20:41:32.631Z" }, + { url = "https://files.pythonhosted.org/packages/9e/46/08436312ff96ffa29cfa4e1a987efc37e094531db46ba5e9fda9bb792afd/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:775710777fd71e5fdf54df69cdc249996a1d6f447a2b5bfb86dbf033fddd9cf9", size = 943339, upload-time = "2025-11-05T20:41:47.128Z" }, + { url = "https://files.pythonhosted.org/packages/34/28/3b3c51328f505cfaf7e53f408f78a1e955d561135d02f9cb0341ea99f69a/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4565407f4a77f72cf9d91469e75d15d375f755f0a01236bb8aaa176278cc7085", size = 961680, upload-time = "2025-11-05T20:42:18.061Z" }, + { url = "https://files.pythonhosted.org/packages/5c/9e/cbff75c8676d4f4a90bd58a1581249d255c7305141b0868f0abc0324836b/rignore-0.7.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc44c33f8fb2d5c9da748de7a6e6653a78aa740655e7409895e94a247ffa97c8", size = 987045, upload-time = "2025-11-05T20:42:02.315Z" }, + { url = "https://files.pythonhosted.org/packages/8c/25/d802d1d369502a7ddb8816059e7c79d2d913e17df975b863418e0aca4d8a/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:8f32478f05540513c11923e8838afab9efef0131d66dca7f67f0e1bbd118af6a", size = 1080310, upload-time = "2025-11-05T21:40:23.184Z" }, + { url = "https://files.pythonhosted.org/packages/43/f0/250b785c2e473b1ab763eaf2be820934c2a5409a722e94b279dddac21c7d/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:1b63a3dd76225ea35b01dd6596aa90b275b5d0f71d6dc28fce6dd295d98614aa", size = 1140998, upload-time = "2025-11-05T21:40:40.603Z" }, + { url = "https://files.pythonhosted.org/packages/f5/d6/bb42fd2a8bba6aea327962656e20621fd495523259db40cfb4c5f760f05c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:fe6c41175c36554a4ef0994cd1b4dbd6d73156fca779066456b781707402048e", size = 1121178, upload-time = "2025-11-05T21:40:57.585Z" }, + { url = "https://files.pythonhosted.org/packages/97/f4/aeb548374129dce3dc191a4bb598c944d9ed663f467b9af830315d86059c/rignore-0.7.6-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:9a0c6792406ae36f4e7664dc772da909451d46432ff8485774526232d4885063", size = 1130190, upload-time = "2025-11-05T21:41:16.403Z" }, ] [[package]] name = "rpds-py" version = "0.30.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469 } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490 }, - { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751 }, - { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696 }, - { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136 }, - { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699 }, - { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022 }, - { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522 }, - { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579 }, - { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305 }, - { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503 }, - { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322 }, - { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792 }, - { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901 }, - { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823 }, + { url = "https://files.pythonhosted.org/packages/06/0c/0c411a0ec64ccb6d104dcabe0e713e05e153a9a2c3c2bd2b32ce412166fe/rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288", size = 370490, upload-time = "2025-11-30T20:21:33.256Z" }, + { url = "https://files.pythonhosted.org/packages/19/6a/4ba3d0fb7297ebae71171822554abe48d7cab29c28b8f9f2c04b79988c05/rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00", size = 359751, upload-time = "2025-11-30T20:21:34.591Z" }, + { url = "https://files.pythonhosted.org/packages/cd/7c/e4933565ef7f7a0818985d87c15d9d273f1a649afa6a52ea35ad011195ea/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6", size = 389696, upload-time = "2025-11-30T20:21:36.122Z" }, + { url = "https://files.pythonhosted.org/packages/5e/01/6271a2511ad0815f00f7ed4390cf2567bec1d4b1da39e2c27a41e6e3b4de/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7", size = 403136, upload-time = "2025-11-30T20:21:37.728Z" }, + { url = "https://files.pythonhosted.org/packages/55/64/c857eb7cd7541e9b4eee9d49c196e833128a55b89a9850a9c9ac33ccf897/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324", size = 524699, upload-time = "2025-11-30T20:21:38.92Z" }, + { url = "https://files.pythonhosted.org/packages/9c/ed/94816543404078af9ab26159c44f9e98e20fe47e2126d5d32c9d9948d10a/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df", size = 412022, upload-time = "2025-11-30T20:21:40.407Z" }, + { url = "https://files.pythonhosted.org/packages/61/b5/707f6cf0066a6412aacc11d17920ea2e19e5b2f04081c64526eb35b5c6e7/rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3", size = 390522, upload-time = "2025-11-30T20:21:42.17Z" }, + { url = "https://files.pythonhosted.org/packages/13/4e/57a85fda37a229ff4226f8cbcf09f2a455d1ed20e802ce5b2b4a7f5ed053/rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221", size = 404579, upload-time = "2025-11-30T20:21:43.769Z" }, + { url = "https://files.pythonhosted.org/packages/f9/da/c9339293513ec680a721e0e16bf2bac3db6e5d7e922488de471308349bba/rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7", size = 421305, upload-time = "2025-11-30T20:21:44.994Z" }, + { url = "https://files.pythonhosted.org/packages/f9/be/522cb84751114f4ad9d822ff5a1aa3c98006341895d5f084779b99596e5c/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff", size = 572503, upload-time = "2025-11-30T20:21:46.91Z" }, + { url = "https://files.pythonhosted.org/packages/a2/9b/de879f7e7ceddc973ea6e4629e9b380213a6938a249e94b0cdbcc325bb66/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7", size = 598322, upload-time = "2025-11-30T20:21:48.709Z" }, + { url = "https://files.pythonhosted.org/packages/48/ac/f01fc22efec3f37d8a914fc1b2fb9bcafd56a299edbe96406f3053edea5a/rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139", size = 560792, upload-time = "2025-11-30T20:21:50.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/da/4e2b19d0f131f35b6146425f846563d0ce036763e38913d917187307a671/rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464", size = 221901, upload-time = "2025-11-30T20:21:51.32Z" }, + { url = "https://files.pythonhosted.org/packages/96/cb/156d7a5cf4f78a7cc571465d8aec7a3c447c94f6749c5123f08438bcf7bc/rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169", size = 235823, upload-time = "2025-11-30T20:21:52.505Z" }, ] [[package]] @@ -2877,35 +2943,35 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827 } +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830 }, + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, ] [[package]] name = "safetensors" version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781 }, - { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058 }, - { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748 }, - { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881 }, - { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463 }, - { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855 }, - { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152 }, - { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856 }, - { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060 }, - { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715 }, - { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377 }, - { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368 }, - { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423 }, - { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380 }, - { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430 }, - { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977 }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890 }, - { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885 }, +sdist = { url = "https://files.pythonhosted.org/packages/29/9c/6e74567782559a63bd040a236edca26fd71bc7ba88de2ef35d75df3bca5e/safetensors-0.7.0.tar.gz", hash = "sha256:07663963b67e8bd9f0b8ad15bb9163606cd27cc5a1b96235a50d8369803b96b0", size = 200878, upload-time = "2025-11-19T15:18:43.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/47/aef6c06649039accf914afef490268e1067ed82be62bcfa5b7e886ad15e8/safetensors-0.7.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c82f4d474cf725255d9e6acf17252991c3c8aac038d6ef363a4bf8be2f6db517", size = 467781, upload-time = "2025-11-19T15:18:35.84Z" }, + { url = "https://files.pythonhosted.org/packages/e8/00/374c0c068e30cd31f1e1b46b4b5738168ec79e7689ca82ee93ddfea05109/safetensors-0.7.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:94fd4858284736bb67a897a41608b5b0c2496c9bdb3bf2af1fa3409127f20d57", size = 447058, upload-time = "2025-11-19T15:18:34.416Z" }, + { url = "https://files.pythonhosted.org/packages/f1/06/578ffed52c2296f93d7fd2d844cabfa92be51a587c38c8afbb8ae449ca89/safetensors-0.7.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e07d91d0c92a31200f25351f4acb2bc6aff7f48094e13ebb1d0fb995b54b6542", size = 491748, upload-time = "2025-11-19T15:18:09.79Z" }, + { url = "https://files.pythonhosted.org/packages/ae/33/1debbbb70e4791dde185edb9413d1fe01619255abb64b300157d7f15dddd/safetensors-0.7.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8469155f4cb518bafb4acf4865e8bb9d6804110d2d9bdcaa78564b9fd841e104", size = 503881, upload-time = "2025-11-19T15:18:16.145Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1c/40c2ca924d60792c3be509833df711b553c60effbd91da6f5284a83f7122/safetensors-0.7.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:54bef08bf00a2bff599982f6b08e8770e09cc012d7bba00783fc7ea38f1fb37d", size = 623463, upload-time = "2025-11-19T15:18:21.11Z" }, + { url = "https://files.pythonhosted.org/packages/9b/3a/13784a9364bd43b0d61eef4bea2845039bc2030458b16594a1bd787ae26e/safetensors-0.7.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:42cb091236206bb2016d245c377ed383aa7f78691748f3bb6ee1bfa51ae2ce6a", size = 532855, upload-time = "2025-11-19T15:18:25.719Z" }, + { url = "https://files.pythonhosted.org/packages/a0/60/429e9b1cb3fc651937727befe258ea24122d9663e4d5709a48c9cbfceecb/safetensors-0.7.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac7252938f0696ddea46f5e855dd3138444e82236e3be475f54929f0c510d48", size = 507152, upload-time = "2025-11-19T15:18:33.023Z" }, + { url = "https://files.pythonhosted.org/packages/3c/a8/4b45e4e059270d17af60359713ffd83f97900d45a6afa73aaa0d737d48b6/safetensors-0.7.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1d060c70284127fa805085d8f10fbd0962792aed71879d00864acda69dbab981", size = 541856, upload-time = "2025-11-19T15:18:31.075Z" }, + { url = "https://files.pythonhosted.org/packages/06/87/d26d8407c44175d8ae164a95b5a62707fcc445f3c0c56108e37d98070a3d/safetensors-0.7.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:cdab83a366799fa730f90a4ebb563e494f28e9e92c4819e556152ad55e43591b", size = 674060, upload-time = "2025-11-19T15:18:37.211Z" }, + { url = "https://files.pythonhosted.org/packages/11/f5/57644a2ff08dc6325816ba7217e5095f17269dada2554b658442c66aed51/safetensors-0.7.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:672132907fcad9f2aedcb705b2d7b3b93354a2aec1b2f706c4db852abe338f85", size = 771715, upload-time = "2025-11-19T15:18:38.689Z" }, + { url = "https://files.pythonhosted.org/packages/86/31/17883e13a814bd278ae6e266b13282a01049b0c81341da7fd0e3e71a80a3/safetensors-0.7.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:5d72abdb8a4d56d4020713724ba81dac065fedb7f3667151c4a637f1d3fb26c0", size = 714377, upload-time = "2025-11-19T15:18:40.162Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d8/0c8a7dc9b41dcac53c4cbf9df2b9c83e0e0097203de8b37a712b345c0be5/safetensors-0.7.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0f6d66c1c538d5a94a73aa9ddca8ccc4227e6c9ff555322ea40bdd142391dd4", size = 677368, upload-time = "2025-11-19T15:18:41.627Z" }, + { url = "https://files.pythonhosted.org/packages/05/e5/cb4b713c8a93469e3c5be7c3f8d77d307e65fe89673e731f5c2bfd0a9237/safetensors-0.7.0-cp38-abi3-win32.whl", hash = "sha256:c74af94bf3ac15ac4d0f2a7c7b4663a15f8c2ab15ed0fc7531ca61d0835eccba", size = 326423, upload-time = "2025-11-19T15:18:45.74Z" }, + { url = "https://files.pythonhosted.org/packages/5d/e6/ec8471c8072382cb91233ba7267fd931219753bb43814cbc71757bfd4dab/safetensors-0.7.0-cp38-abi3-win_amd64.whl", hash = "sha256:d1239932053f56f3456f32eb9625590cc7582e905021f94636202a864d470755", size = 341380, upload-time = "2025-11-19T15:18:44.427Z" }, + { url = "https://files.pythonhosted.org/packages/a7/6a/4d08d89a6fcbe905c5ae68b8b34f0791850882fc19782d0d02c65abbdf3b/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4729811a6640d019a4b7ba8638ee2fd21fa5ca8c7e7bdf0fed62068fcaac737", size = 492430, upload-time = "2025-11-19T15:18:11.884Z" }, + { url = "https://files.pythonhosted.org/packages/dd/29/59ed8152b30f72c42d00d241e58eaca558ae9dbfa5695206e2e0f54c7063/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:12f49080303fa6bb424b362149a12949dfbbf1e06811a88f2307276b0c131afd", size = 503977, upload-time = "2025-11-19T15:18:17.523Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4811bfec67fa260e791369b16dab105e4bae82686120554cc484064e22b4/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0071bffba4150c2f46cae1432d31995d77acfd9f8db598b5d1a2ce67e8440ad2", size = 623890, upload-time = "2025-11-19T15:18:22.666Z" }, + { url = "https://files.pythonhosted.org/packages/58/5b/632a58724221ef03d78ab65062e82a1010e1bef8e8e0b9d7c6d7b8044841/safetensors-0.7.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:473b32699f4200e69801bf5abf93f1a4ecd432a70984df164fc22ccf39c4a6f3", size = 531885, upload-time = "2025-11-19T15:18:27.146Z" }, ] [[package]] @@ -2918,13 +2984,13 @@ dependencies = [ { name = "scipy" }, { name = "threadpoolctl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136 } +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221 }, - { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834 }, - { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938 }, - { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818 }, - { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969 }, + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, ] [[package]] @@ -2934,16 +3000,16 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/e5/0230da034a2e1b1feb32621d7cd57c59484091d6dccc9e6b855b0d309fc9/scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b", size = 58618870, upload-time = "2024-06-24T20:35:18.532Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226 }, - { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893 }, - { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258 }, - { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715 }, - { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038 }, - { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959 }, - { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514 }, - { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252 }, + { url = "https://files.pythonhosted.org/packages/c6/90/face72921ce52d74880b380e6f86b3caa6c65766c5808fbe179e208b9c6d/scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484", size = 39120226, upload-time = "2024-06-24T20:31:50.451Z" }, + { url = "https://files.pythonhosted.org/packages/6e/a1/0093566d31ae662e942d4079e2a4dea4256723bf3d072ae67f5ba41aee0d/scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6", size = 29866893, upload-time = "2024-06-24T20:31:57.337Z" }, + { url = "https://files.pythonhosted.org/packages/52/21/05a182fb405a53dfbdf6415308bf185677e89188bc2206de011a3653f48e/scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7", size = 23076258, upload-time = "2024-06-24T20:32:02.711Z" }, + { url = "https://files.pythonhosted.org/packages/5c/63/9954d14012a2f4aff4570f1aaf076d7f65f3fc246ae4483b765488d57d51/scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1", size = 25454715, upload-time = "2024-06-24T20:32:07.648Z" }, + { url = "https://files.pythonhosted.org/packages/57/b8/ca969a99d34956c6546cbb9ea3f863a387009f68cdbad13cdb07db0cc23d/scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0", size = 35569038, upload-time = "2024-06-24T20:32:17.305Z" }, + { url = "https://files.pythonhosted.org/packages/e2/20/15c8fe0dfebb6facd81b3d08bf45dfa080e305deb17172b0a40eba59e927/scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0", size = 41135959, upload-time = "2024-06-24T20:32:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/8721f93fbf98a69067d20bdfded36a7de2a3d811f192edba9eeefbde61b8/scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d", size = 41118514, upload-time = "2024-06-24T20:32:32.618Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0c/82c1330c08f31d61142d38cb9a185e01c2403c990d10dab208032e62d0fa/scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359", size = 44763252, upload-time = "2024-06-24T20:32:45.06Z" }, ] [[package]] @@ -2955,9 +3021,9 @@ dependencies = [ { name = "numpy" }, { name = "pandas" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696 } +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 }, + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, ] [[package]] @@ -2967,23 +3033,23 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244 } +sdist = { url = "https://files.pythonhosted.org/packages/0c/8a/1ae8e3deb805831933b63d58851ab41ff2472099e15511fc62039421ad70/segtok-1.5.11.tar.gz", hash = "sha256:8ab2dd44245bcbfec25b575dc4618473bbdf2af8c2649698cd5a370f42f3db23", size = 25244, upload-time = "2021-12-15T21:56:14.555Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332 }, + { url = "https://files.pythonhosted.org/packages/dd/60/d384dbae5d4756e33f1750fa3472303de2c827011907a64e213e114d0556/segtok-1.5.11-py3-none-any.whl", hash = "sha256:910616b76198c3141b2772df530270d3b706e42ae69a5b30ef115c7bd5d1501a", size = 24332, upload-time = "2021-12-15T21:56:12.508Z" }, ] [[package]] name = "send2trash" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c5/f0/184b4b5f8d00f2a92cf96eec8967a3d550b52cf94362dad1100df9e48d57/send2trash-2.1.0.tar.gz", hash = "sha256:1c72b39f09457db3c05ce1d19158c2cbef4c32b8bedd02c155e49282b7ea7459", size = 17255 } +sdist = { url = "https://files.pythonhosted.org/packages/c5/f0/184b4b5f8d00f2a92cf96eec8967a3d550b52cf94362dad1100df9e48d57/send2trash-2.1.0.tar.gz", hash = "sha256:1c72b39f09457db3c05ce1d19158c2cbef4c32b8bedd02c155e49282b7ea7459", size = 17255, upload-time = "2026-01-14T06:27:36.056Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610 }, + { url = "https://files.pythonhosted.org/packages/1c/78/504fdd027da3b84ff1aecd9f6957e65f35134534ccc6da8628eb71e76d3f/send2trash-2.1.0-py3-none-any.whl", hash = "sha256:0da2f112e6d6bb22de6aa6daa7e144831a4febf2a87261451c4ad849fe9a873c", size = 17610, upload-time = "2026-01-14T06:27:35.218Z" }, ] [[package]] name = "sentence-transformers" -version = "5.2.3" +version = "5.3.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, @@ -2995,110 +3061,110 @@ dependencies = [ { name = "transformers" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/5b/30/21664028fc0776eb1ca024879480bbbab36f02923a8ff9e4cae5a150fa35/sentence_transformers-5.2.3.tar.gz", hash = "sha256:3cd3044e1f3fe859b6a1b66336aac502eaae5d3dd7d5c8fc237f37fbf58137c7", size = 381623 } +sdist = { url = "https://files.pythonhosted.org/packages/fe/26/448453925b6ce0c29d8b54327caa71ee4835511aef02070467402273079c/sentence_transformers-5.3.0.tar.gz", hash = "sha256:414a0a881f53a4df0e6cbace75f823bfcb6b94d674c42a384b498959b7c065e2", size = 403330, upload-time = "2026-03-12T14:53:40.778Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/9f/dba4b3e18ebbe1eaa29d9f1764fbc7da0cd91937b83f2b7928d15c5d2d36/sentence_transformers-5.2.3-py3-none-any.whl", hash = "sha256:6437c62d4112b615ddebda362dfc16a4308d604c5b68125ed586e3e95d5b2e30", size = 494225 }, + { url = "https://files.pythonhosted.org/packages/e2/9c/2fa7224058cad8df68d84bafee21716f30892cecc7ad1ad73bde61d23754/sentence_transformers-5.3.0-py3-none-any.whl", hash = "sha256:dca6b98db790274a68185d27a65801b58b4caf653a4e556b5f62827509347c7d", size = 512390, upload-time = "2026-03-12T14:53:39.035Z" }, ] [[package]] name = "sentencepiece" version = "0.2.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106 } +sdist = { url = "https://files.pythonhosted.org/packages/c9/d2/b9c7ca067c26d8ff085d252c89b5f69609ca93fb85a00ede95f4857865d4/sentencepiece-0.2.0.tar.gz", hash = "sha256:a52c19171daaf2e697dc6cbe67684e0fa341b1248966f6aebb541de654d15843", size = 2632106, upload-time = "2024-02-19T17:06:47.428Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979 }, - { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845 }, - { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472 }, - { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151 }, - { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931 }, - { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537 }, - { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747 }, - { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525 }, + { url = "https://files.pythonhosted.org/packages/f6/71/98648c3b64b23edb5403f74bcc906ad21766872a6e1ada26ea3f1eb941ab/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:188779e1298a1c8b8253c7d3ad729cb0a9891e5cef5e5d07ce4592c54869e227", size = 2408979, upload-time = "2024-02-19T17:05:34.651Z" }, + { url = "https://files.pythonhosted.org/packages/77/9f/7efbaa6d4c0c718a9affbecc536b03ca62f99f421bdffb531c16030e2d2b/sentencepiece-0.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bed9cf85b296fa2b76fc2547b9cbb691a523864cebaee86304c43a7b4cb1b452", size = 1238845, upload-time = "2024-02-19T17:05:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/1c/e4/c2541027a43ec6962ba9b601805d17ba3f86b38bdeae0e8ac65a2981e248/sentencepiece-0.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d7b67e724bead13f18db6e1d10b6bbdc454af574d70efbb36f27d90387be1ca3", size = 1181472, upload-time = "2024-02-19T17:05:39.775Z" }, + { url = "https://files.pythonhosted.org/packages/fd/46/316c1ba6c52b97de76aff7b9da678f7afbb52136afb2987c474d95630e65/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fde4b08cfe237be4484c6c7c2e2c75fb862cfeab6bd5449ce4caeafd97b767a", size = 1259151, upload-time = "2024-02-19T17:05:42.594Z" }, + { url = "https://files.pythonhosted.org/packages/aa/5a/3c48738a0835d76dd06c62b6ac48d39c923cde78dd0f587353bdcbb99851/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c378492056202d1c48a4979650981635fd97875a00eabb1f00c6a236b013b5e", size = 1355931, upload-time = "2024-02-19T17:05:44.695Z" }, + { url = "https://files.pythonhosted.org/packages/a6/27/33019685023221ca8ed98e8ceb7ae5e166032686fa3662c68f1f1edf334e/sentencepiece-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1380ce6540a368de2ef6d7e6ba14ba8f3258df650d39ba7d833b79ee68a52040", size = 1301537, upload-time = "2024-02-19T17:05:46.713Z" }, + { url = "https://files.pythonhosted.org/packages/ca/e4/55f97cef14293171fef5f96e96999919ab5b4d1ce95b53547ad653d7e3bf/sentencepiece-0.2.0-cp310-cp310-win32.whl", hash = "sha256:a1151d6a6dd4b43e552394aed0edfe9292820272f0194bd56c7c1660a0c06c3d", size = 936747, upload-time = "2024-02-19T17:05:48.705Z" }, + { url = "https://files.pythonhosted.org/packages/85/f4/4ef1a6e0e9dbd8a60780a91df8b7452ada14cfaa0e17b3b8dfa42cecae18/sentencepiece-0.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:d490142b0521ef22bc1085f061d922a2a6666175bb6b42e588ff95c0db6819b2", size = 991525, upload-time = "2024-02-19T17:05:55.145Z" }, ] [[package]] name = "sentry-sdk" -version = "2.53.0" +version = "2.54.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d3/06/66c8b705179bc54087845f28fd1b72f83751b6e9a195628e2e9af9926505/sentry_sdk-2.53.0.tar.gz", hash = "sha256:6520ef2c4acd823f28efc55e43eb6ce2e6d9f954a95a3aa96b6fd14871e92b77", size = 412369 } +sdist = { url = "https://files.pythonhosted.org/packages/c8/e9/2e3a46c304e7fa21eaa70612f60354e32699c7102eb961f67448e222ad7c/sentry_sdk-2.54.0.tar.gz", hash = "sha256:2620c2575128d009b11b20f7feb81e4e4e8ae08ec1d36cbc845705060b45cc1b", size = 413813, upload-time = "2026-03-02T15:12:41.355Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/47/d4/2fdf854bc3b9c7f55219678f812600a20a138af2dd847d99004994eada8f/sentry_sdk-2.53.0-py2.py3-none-any.whl", hash = "sha256:46e1ed8d84355ae54406c924f6b290c3d61f4048625989a723fd622aab838899", size = 437908 }, + { url = "https://files.pythonhosted.org/packages/53/39/be412cc86bc6247b8f69e9383d7950711bd86f8d0a4a4b0fe8fad685bc21/sentry_sdk-2.54.0-py2.py3-none-any.whl", hash = "sha256:fd74e0e281dcda63afff095d23ebcd6e97006102cdc8e78a29f19ecdf796a0de", size = 439198, upload-time = "2026-03-02T15:12:39.546Z" }, ] [[package]] name = "setuptools" -version = "82.0.0" +version = "82.0.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/f3/748f4d6f65d1756b9ae577f329c951cda23fb900e4de9f70900ced962085/setuptools-82.0.0.tar.gz", hash = "sha256:22e0a2d69474c6ae4feb01951cb69d515ed23728cf96d05513d36e42b62b37cb", size = 1144893 } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/c6/76dc613121b793286a3f91621d7b75a2b493e0390ddca50f11993eadf192/setuptools-82.0.0-py3-none-any.whl", hash = "sha256:70b18734b607bd1da571d097d236cfcfacaf01de45717d59e6e04b96877532e0", size = 1003468 }, + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, ] [[package]] name = "shellingham" version = "1.5.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, ] [[package]] name = "six" version = "1.17.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, ] [[package]] name = "sortedcontainers" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 }, + { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, ] [[package]] name = "soupsieve" version = "2.8.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627 } +sdist = { url = "https://files.pythonhosted.org/packages/7b/ae/2d9c981590ed9999a0d91755b47fc74f74de286b0f5cee14c9269041e6c4/soupsieve-2.8.3.tar.gz", hash = "sha256:3267f1eeea4251fb42728b6dfb746edc9acaffc4a45b27e19450b676586e8349", size = 118627, upload-time = "2026-01-20T04:27:02.457Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016 }, + { url = "https://files.pythonhosted.org/packages/46/2c/1462b1d0a634697ae9e55b3cecdcb64788e8b7d63f54d923fcd0bb140aed/soupsieve-2.8.3-py3-none-any.whl", hash = "sha256:ed64f2ba4eebeab06cc4962affce381647455978ffc1e36bb79a545b91f45a95", size = 37016, upload-time = "2026-01-20T04:27:01.012Z" }, ] [[package]] name = "sqlalchemy" -version = "2.0.46" +version = "2.0.48" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/aa/9ce0f3e7a9829ead5c8ce549392f33a12c4555a6c0609bb27d882e9c7ddf/sqlalchemy-2.0.46.tar.gz", hash = "sha256:cf36851ee7219c170bb0793dbc3da3e80c582e04a5437bc601bfe8c85c9216d7", size = 9865393 } +sdist = { url = "https://files.pythonhosted.org/packages/1f/73/b4a9737255583b5fa858e0bb8e116eb94b88c910164ed2ed719147bde3de/sqlalchemy-2.0.48.tar.gz", hash = "sha256:5ca74f37f3369b45e1f6b7b06afb182af1fd5dde009e4ffd831830d98cbe5fe7", size = 9886075, upload-time = "2026-03-02T15:28:51.474Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/26/66ba59328dc25e523bfcb0f8db48bdebe2035e0159d600e1f01c0fc93967/sqlalchemy-2.0.46-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:895296687ad06dc9b11a024cf68e8d9d3943aa0b4964278d2553b86f1b267735", size = 2155051 }, - { url = "https://files.pythonhosted.org/packages/21/cd/9336732941df972fbbfa394db9caa8bb0cf9fe03656ec728d12e9cbd6edc/sqlalchemy-2.0.46-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab65cb2885a9f80f979b85aa4e9c9165a31381ca322cbde7c638fe6eefd1ec39", size = 3234666 }, - { url = "https://files.pythonhosted.org/packages/38/62/865ae8b739930ec433cd4123760bee7f8dafdc10abefd725a025604fb0de/sqlalchemy-2.0.46-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:52fe29b3817bd191cc20bad564237c808967972c97fa683c04b28ec8979ae36f", size = 3232917 }, - { url = "https://files.pythonhosted.org/packages/24/38/805904b911857f2b5e00fdea44e9570df62110f834378706939825579296/sqlalchemy-2.0.46-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:09168817d6c19954d3b7655da6ba87fcb3a62bb575fb396a81a8b6a9fadfe8b5", size = 3185790 }, - { url = "https://files.pythonhosted.org/packages/69/4f/3260bb53aabd2d274856337456ea52f6a7eccf6cce208e558f870cec766b/sqlalchemy-2.0.46-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:be6c0466b4c25b44c5d82b0426b5501de3c424d7a3220e86cd32f319ba56798e", size = 3207206 }, - { url = "https://files.pythonhosted.org/packages/ce/b3/67c432d7f9d88bb1a61909b67e29f6354d59186c168fb5d381cf438d3b73/sqlalchemy-2.0.46-cp310-cp310-win32.whl", hash = "sha256:1bc3f601f0a818d27bfe139f6766487d9c88502062a2cd3a7ee6c342e81d5047", size = 2115296 }, - { url = "https://files.pythonhosted.org/packages/4a/8c/25fb284f570f9d48e6c240f0269a50cec9cf009a7e08be4c0aaaf0654972/sqlalchemy-2.0.46-cp310-cp310-win_amd64.whl", hash = "sha256:e0c05aff5c6b1bb5fb46a87e0f9d2f733f83ef6cbbbcd5c642b6c01678268061", size = 2138540 }, - { url = "https://files.pythonhosted.org/packages/fc/a1/9c4efa03300926601c19c18582531b45aededfb961ab3c3585f1e24f120b/sqlalchemy-2.0.46-py3-none-any.whl", hash = "sha256:f9c11766e7e7c0a2767dda5acb006a118640c9fc0a4104214b96269bfb78399e", size = 1937882 }, + { url = "https://files.pythonhosted.org/packages/9a/67/1235676e93dd3b742a4a8eddfae49eea46c85e3eed29f0da446a8dd57500/sqlalchemy-2.0.48-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7001dc9d5f6bb4deb756d5928eaefe1930f6f4179da3924cbd95ee0e9f4dce89", size = 2157384, upload-time = "2026-03-02T15:38:26.781Z" }, + { url = "https://files.pythonhosted.org/packages/4d/d7/fa728b856daa18c10e1390e76f26f64ac890c947008284387451d56ca3d0/sqlalchemy-2.0.48-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1a89ce07ad2d4b8cfc30bd5889ec40613e028ed80ef47da7d9dd2ce969ad30e0", size = 3236981, upload-time = "2026-03-02T15:58:53.53Z" }, + { url = "https://files.pythonhosted.org/packages/5c/ad/6c4395649a212a6c603a72c5b9ab5dce3135a1546cfdffa3c427e71fd535/sqlalchemy-2.0.48-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:10853a53a4a00417a00913d270dddda75815fcb80675874285f41051c094d7dd", size = 3235232, upload-time = "2026-03-02T15:52:25.654Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/58f845e511ac0509765a6f85eb24924c1ef0d54fb50de9d15b28c3601458/sqlalchemy-2.0.48-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:fac0fa4e4f55f118fd87177dacb1c6522fe39c28d498d259014020fec9164c29", size = 3188106, upload-time = "2026-03-02T15:58:55.193Z" }, + { url = "https://files.pythonhosted.org/packages/3f/f9/6dcc7bfa5f5794c3a095e78cd1de8269dfb5584dfd4c2c00a50d3c1ade44/sqlalchemy-2.0.48-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3713e21ea67bca727eecd4a24bf68bcd414c403faae4989442be60994301ded0", size = 3209522, upload-time = "2026-03-02T15:52:27.407Z" }, + { url = "https://files.pythonhosted.org/packages/d7/5a/b632875ab35874d42657f079529f0745410604645c269a8c21fb4272ff7a/sqlalchemy-2.0.48-cp310-cp310-win32.whl", hash = "sha256:d404dc897ce10e565d647795861762aa2d06ca3f4a728c5e9a835096c7059018", size = 2117695, upload-time = "2026-03-02T15:46:51.389Z" }, + { url = "https://files.pythonhosted.org/packages/de/03/9752eb2a41afdd8568e41ac3c3128e32a0a73eada5ab80483083604a56d1/sqlalchemy-2.0.48-cp310-cp310-win_amd64.whl", hash = "sha256:841a94c66577661c1f088ac958cd767d7c9bf507698f45afffe7a4017049de76", size = 2140928, upload-time = "2026-03-02T15:46:52.992Z" }, + { url = "https://files.pythonhosted.org/packages/46/2c/9664130905f03db57961b8980b05cab624afd114bf2be2576628a9f22da4/sqlalchemy-2.0.48-py3-none-any.whl", hash = "sha256:a66fe406437dd65cacd96a72689a3aaaecaebbcd62d81c5ac1c0fdbeac835096", size = 1940202, upload-time = "2026-03-02T15:52:43.285Z" }, ] [[package]] name = "sqlitedict" version = "2.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846 } +sdist = { url = "https://files.pythonhosted.org/packages/12/9a/7620d1e9dcb02839ed6d4b14064e609cdd7a8ae1e47289aa0456796dd9ca/sqlitedict-2.1.0.tar.gz", hash = "sha256:03d9cfb96d602996f1d4c2db2856f1224b96a9c431bdd16e78032a72940f9e8c", size = 21846, upload-time = "2022-12-03T13:39:13.102Z" } [[package]] name = "sqlmodel" @@ -3108,9 +3174,9 @@ dependencies = [ { name = "pydantic" }, { name = "sqlalchemy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/39/8641040ab0d5e1d8a1c2325ae89a01ae659fc96c61a43d158fb71c9a0bf0/sqlmodel-0.0.22.tar.gz", hash = "sha256:7d37c882a30c43464d143e35e9ecaf945d88035e20117bf5ec2834a23cbe505e", size = 116392, upload-time = "2024-08-31T09:43:24.088Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276 }, + { url = "https://files.pythonhosted.org/packages/dd/b1/3af5104b716c420e40a6ea1b09886cae3a1b9f4538343875f637755cae5b/sqlmodel-0.0.22-py3-none-any.whl", hash = "sha256:a1ed13e28a1f4057cbf4ff6cdb4fc09e85702621d3259ba17b3c230bfb2f941b", size = 28276, upload-time = "2024-08-31T09:43:22.358Z" }, ] [[package]] @@ -3122,9 +3188,9 @@ dependencies = [ { name = "executing" }, { name = "pure-eval" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] [[package]] @@ -3135,9 +3201,9 @@ dependencies = [ { name = "anyio" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702 } +sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272 }, + { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" }, ] [[package]] @@ -3147,50 +3213,27 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mpmath" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921 } +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353 }, + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, ] [[package]] name = "tabulate" -version = "0.9.0" +version = "0.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/fe/802052aecb21e3797b8f7902564ab6ea0d60ff8ca23952079064155d1ae1/tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c", size = 81090 } +sdist = { url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz", hash = "sha256:e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d", size = 91754, upload-time = "2026-03-04T18:55:34.402Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 }, + { url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl", hash = "sha256:f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3", size = 39814, upload-time = "2026-03-04T18:55:31.284Z" }, ] [[package]] name = "tenacity" version = "9.1.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413 } +sdist = { url = "https://files.pythonhosted.org/packages/47/c6/ee486fd809e357697ee8a44d3d69222b344920433d3b6666ccd9b374630c/tenacity-9.1.4.tar.gz", hash = "sha256:adb31d4c263f2bd041081ab33b498309a57c77f9acf2db65aadf0898179cf93a", size = 49413, upload-time = "2026-02-07T10:45:33.841Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926 }, -] - -[[package]] -name = "tensorboardx" -version = "2.6.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "packaging" }, - { name = "protobuf" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2b/c5/d4cc6e293fb837aaf9f76dd7745476aeba8ef7ef5146c3b3f9ee375fe7a5/tensorboardx-2.6.4.tar.gz", hash = "sha256:b163ccb7798b31100b9f5fa4d6bc22dad362d7065c2f24b51e50731adde86828", size = 4769801 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/1d/b5d63f1a6b824282b57f7b581810d20b7a28ca951f2d5b59f1eb0782c12b/tensorboardx-2.6.4-py3-none-any.whl", hash = "sha256:5970cf3a1f0a6a6e8b180ccf46f3fe832b8a25a70b86e5a237048a7c0beb18e2", size = 87201 }, -] - -[[package]] -name = "termcolor" -version = "3.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/46/79/cf31d7a93a8fdc6aa0fbb665be84426a8c5a557d9240b6239e9e11e35fc5/termcolor-3.3.0.tar.gz", hash = "sha256:348871ca648ec6a9a983a13ab626c0acce02f515b9e1983332b17af7979521c5", size = 14434 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/d1/8bb87d21e9aeb323cc03034f5eaf2c8f69841e40e4853c2627edf8111ed3/termcolor-3.3.0-py3-none-any.whl", hash = "sha256:cf642efadaf0a8ebbbf4bc7a31cec2f9b5f21a9f726f4ccbb08192c9c26f43a5", size = 7734 }, + { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, ] [[package]] @@ -3202,18 +3245,18 @@ dependencies = [ { name = "pywinpty", marker = "os_name == 'nt'" }, { name = "tornado" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701 } +sdist = { url = "https://files.pythonhosted.org/packages/8a/11/965c6fd8e5cc254f1fe142d547387da17a8ebfd75a3455f637c663fb38a0/terminado-0.18.1.tar.gz", hash = "sha256:de09f2c4b85de4765f7714688fff57d3e75bad1f909b589fde880460c753fd2e", size = 32701, upload-time = "2024-03-12T14:34:39.026Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154 }, + { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, ] [[package]] name = "threadpoolctl" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274 } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638 }, + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, ] [[package]] @@ -3223,9 +3266,9 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085 } +sdist = { url = "https://files.pythonhosted.org/packages/7a/fd/7a5ee21fd08ff70d3d33a5781c255cbe779659bd03278feb98b19ee550f4/tinycss2-1.4.0.tar.gz", hash = "sha256:10c0972f6fc0fbee87c3edb76549357415e94548c1ae10ebccdea16fb404a9b7", size = 87085, upload-time = "2024-10-24T14:58:29.895Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610 }, + { url = "https://files.pythonhosted.org/packages/e6/34/ebdc18bae6aa14fbee1a08b63c015c72b64868ff7dae68808ab500c492e2/tinycss2-1.4.0-py3-none-any.whl", hash = "sha256:3a49cf47b7675da0b15d0c6e1df8df4ebd96e9394bb905a5775adb0d884c5289", size = 26610, upload-time = "2024-10-24T14:58:28.029Z" }, ] [[package]] @@ -3235,36 +3278,36 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275 }, - { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472 }, - { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736 }, - { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835 }, - { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673 }, - { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818 }, - { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195 }, - { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982 }, - { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245 }, - { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069 }, - { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263 }, - { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429 }, - { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363 }, - { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786 }, - { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133 }, - { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301 }, - { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308 }, - { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964 }, - { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542 }, +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, + { url = "https://files.pythonhosted.org/packages/84/04/655b79dbcc9b3ac5f1479f18e931a344af67e5b7d3b251d2dcdcd7558592/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:753d47ebd4542742ef9261d9da92cd545b2cacbb48349a1225466745bb866ec4", size = 3282301, upload-time = "2026-01-05T10:40:34.858Z" }, + { url = "https://files.pythonhosted.org/packages/46/cd/e4851401f3d8f6f45d8480262ab6a5c8cb9c4302a790a35aa14eeed6d2fd/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e10bf9113d209be7cd046d40fbabbaf3278ff6d18eb4da4c500443185dc1896c", size = 3161308, upload-time = "2026-01-05T10:40:40.737Z" }, + { url = "https://files.pythonhosted.org/packages/6f/6e/55553992a89982cd12d4a66dddb5e02126c58677ea3931efcbe601d419db/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64d94e84f6660764e64e7e0b22baa72f6cd942279fdbb21d46abd70d179f0195", size = 3718964, upload-time = "2026-01-05T10:40:46.56Z" }, + { url = "https://files.pythonhosted.org/packages/59/8c/b1c87148aa15e099243ec9f0cf9d0e970cc2234c3257d558c25a2c5304e6/tokenizers-0.22.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f01a9c019878532f98927d2bacb79bbb404b43d3437455522a00a30718cdedb5", size = 3373542, upload-time = "2026-01-05T10:40:52.803Z" }, ] [[package]] name = "tomli" version = "2.4.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477 } +sdist = { url = "https://files.pythonhosted.org/packages/82/30/31573e9457673ab10aa432461bee537ce6cef177667deca369efb79df071/tomli-2.4.0.tar.gz", hash = "sha256:aa89c3f6c277dd275d8e243ad24f3b5e701491a860d5121f2cdd399fbb31fc9c", size = 17477, upload-time = "2026-01-11T11:22:38.165Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477 }, + { url = "https://files.pythonhosted.org/packages/23/d1/136eb2cb77520a31e1f64cbae9d33ec6df0d78bdf4160398e86eec8a8754/tomli-2.4.0-py3-none-any.whl", hash = "sha256:1f776e7d669ebceb01dee46484485f43a4048746235e683bcdffacdf1fb4785a", size = 14477, upload-time = "2026-01-11T11:22:37.446Z" }, ] [[package]] @@ -3272,69 +3315,54 @@ name = "torch" version = "2.10.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "cuda-bindings", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "cuda-bindings", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "filelock" }, { name = "fsspec" }, { name = "jinja2" }, { name = "networkx" }, - { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, - { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "sympy" }, - { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, { name = "typing-extensions" }, ] wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/30/bfebdd8ec77db9a79775121789992d6b3b75ee5494971294d7b4b7c999bc/torch-2.10.0-2-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:2b980edd8d7c0a68c4e951ee1856334a43193f98730d97408fbd148c1a933313", size = 79411457 }, - { url = "https://files.pythonhosted.org/packages/0c/1a/c61f36cfd446170ec27b3a4984f072fd06dab6b5d7ce27e11adb35d6c838/torch-2.10.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5276fa790a666ee8becaffff8acb711922252521b28fbce5db7db5cf9cb2026d", size = 145992962 }, - { url = "https://files.pythonhosted.org/packages/b5/60/6662535354191e2d1555296045b63e4279e5a9dbad49acf55a5d38655a39/torch-2.10.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:aaf663927bcd490ae971469a624c322202a2a1e68936eb952535ca4cd3b90444", size = 915599237 }, - { url = "https://files.pythonhosted.org/packages/40/b8/66bbe96f0d79be2b5c697b2e0b187ed792a15c6c4b8904613454651db848/torch-2.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:a4be6a2a190b32ff5c8002a0977a25ea60e64f7ba46b1be37093c141d9c49aeb", size = 113720931 }, - { url = "https://files.pythonhosted.org/packages/76/bb/d820f90e69cda6c8169b32a0c6a3ab7b17bf7990b8f2c680077c24a3c14c/torch-2.10.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:35e407430795c8d3edb07a1d711c41cc1f9eaddc8b2f1cc0a165a6767a8fb73d", size = 79411450 }, -] - -[[package]] -name = "torchmetrics" -version = "0.11.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, - { name = "packaging" }, - { name = "torch" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f3/ed/9f76e2d65d2e6d67a0ba097f34f4b618fb7466d731476d3d3440dfe2cb8e/torchmetrics-0.11.4.tar.gz", hash = "sha256:1fe45a14b44dd65d90199017dd5a4b5a128d56a8a311da7916c402c18c671494", size = 307144 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/47/6e9f9b41c48750a45ad07cc6d43a2979bfc09e6989656aece97cc59cbef1/torchmetrics-0.11.4-py3-none-any.whl", hash = "sha256:45f892f3534e91f3ad9e2488d1b05a93b7cb76b7d037969435a41a1f24750d9a", size = 519162 }, + { url = "https://files.pythonhosted.org/packages/5b/30/bfebdd8ec77db9a79775121789992d6b3b75ee5494971294d7b4b7c999bc/torch-2.10.0-2-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:2b980edd8d7c0a68c4e951ee1856334a43193f98730d97408fbd148c1a933313", size = 79411457, upload-time = "2026-02-10T21:44:59.189Z" }, + { url = "https://files.pythonhosted.org/packages/16/ee/efbd56687be60ef9af0c9c0ebe106964c07400eade5b0af8902a1d8cd58c/torch-2.10.0-3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a1ff626b884f8c4e897c4c33782bdacdff842a165fee79817b1dd549fdda1321", size = 915510070, upload-time = "2026-03-11T14:16:39.386Z" }, + { url = "https://files.pythonhosted.org/packages/0c/1a/c61f36cfd446170ec27b3a4984f072fd06dab6b5d7ce27e11adb35d6c838/torch-2.10.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5276fa790a666ee8becaffff8acb711922252521b28fbce5db7db5cf9cb2026d", size = 145992962, upload-time = "2026-01-21T16:24:14.04Z" }, + { url = "https://files.pythonhosted.org/packages/b5/60/6662535354191e2d1555296045b63e4279e5a9dbad49acf55a5d38655a39/torch-2.10.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:aaf663927bcd490ae971469a624c322202a2a1e68936eb952535ca4cd3b90444", size = 915599237, upload-time = "2026-01-21T16:23:25.497Z" }, + { url = "https://files.pythonhosted.org/packages/40/b8/66bbe96f0d79be2b5c697b2e0b187ed792a15c6c4b8904613454651db848/torch-2.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:a4be6a2a190b32ff5c8002a0977a25ea60e64f7ba46b1be37093c141d9c49aeb", size = 113720931, upload-time = "2026-01-21T16:24:23.743Z" }, + { url = "https://files.pythonhosted.org/packages/76/bb/d820f90e69cda6c8169b32a0c6a3ab7b17bf7990b8f2c680077c24a3c14c/torch-2.10.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:35e407430795c8d3edb07a1d711c41cc1f9eaddc8b2f1cc0a165a6767a8fb73d", size = 79411450, upload-time = "2026-01-21T16:25:30.692Z" }, ] [[package]] name = "tornado" -version = "6.5.4" +version = "6.5.5" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/1d/0a336abf618272d53f62ebe274f712e213f5a03c0b2339575430b8362ef2/tornado-6.5.4.tar.gz", hash = "sha256:a22fa9047405d03260b483980635f0b041989d8bcc9a313f8fe18b411d84b1d7", size = 513632 } +sdist = { url = "https://files.pythonhosted.org/packages/f8/f1/3173dfa4a18db4a9b03e5d55325559dab51ee653763bb8745a75af491286/tornado-6.5.5.tar.gz", hash = "sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9", size = 516006, upload-time = "2026-03-10T21:31:02.067Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/a9/e94a9d5224107d7ce3cc1fab8d5dc97f5ea351ccc6322ee4fb661da94e35/tornado-6.5.4-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:d6241c1a16b1c9e4cc28148b1cda97dd1c6cb4fb7068ac1bedc610768dff0ba9", size = 443909 }, - { url = "https://files.pythonhosted.org/packages/db/7e/f7b8d8c4453f305a51f80dbb49014257bb7d28ccb4bbb8dd328ea995ecad/tornado-6.5.4-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2d50f63dda1d2cac3ae1fa23d254e16b5e38153758470e9956cbc3d813d40843", size = 442163 }, - { url = "https://files.pythonhosted.org/packages/ba/b5/206f82d51e1bfa940ba366a8d2f83904b15942c45a78dd978b599870ab44/tornado-6.5.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1cf66105dc6acb5af613c054955b8137e34a03698aa53272dbda4afe252be17", size = 445746 }, - { url = "https://files.pythonhosted.org/packages/8e/9d/1a3338e0bd30ada6ad4356c13a0a6c35fbc859063fa7eddb309183364ac1/tornado-6.5.4-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50ff0a58b0dc97939d29da29cd624da010e7f804746621c78d14b80238669335", size = 445083 }, - { url = "https://files.pythonhosted.org/packages/50/d4/e51d52047e7eb9a582da59f32125d17c0482d065afd5d3bc435ff2120dc5/tornado-6.5.4-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5fb5e04efa54cf0baabdd10061eb4148e0be137166146fff835745f59ab9f7f", size = 445315 }, - { url = "https://files.pythonhosted.org/packages/27/07/2273972f69ca63dbc139694a3fc4684edec3ea3f9efabf77ed32483b875c/tornado-6.5.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9c86b1643b33a4cd415f8d0fe53045f913bf07b4a3ef646b735a6a86047dda84", size = 446003 }, - { url = "https://files.pythonhosted.org/packages/d1/83/41c52e47502bf7260044413b6770d1a48dda2f0246f95ee1384a3cd9c44a/tornado-6.5.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:6eb82872335a53dd063a4f10917b3efd28270b56a33db69009606a0312660a6f", size = 445412 }, - { url = "https://files.pythonhosted.org/packages/10/c7/bc96917f06cbee182d44735d4ecde9c432e25b84f4c2086143013e7b9e52/tornado-6.5.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:6076d5dda368c9328ff41ab5d9dd3608e695e8225d1cd0fd1e006f05da3635a8", size = 445392 }, - { url = "https://files.pythonhosted.org/packages/0c/1a/d7592328d037d36f2d2462f4bc1fbb383eec9278bc786c1b111cbbd44cfa/tornado-6.5.4-cp39-abi3-win32.whl", hash = "sha256:1768110f2411d5cd281bac0a090f707223ce77fd110424361092859e089b38d1", size = 446481 }, - { url = "https://files.pythonhosted.org/packages/d6/6d/c69be695a0a64fd37a97db12355a035a6d90f79067a3cf936ec2b1dc38cd/tornado-6.5.4-cp39-abi3-win_amd64.whl", hash = "sha256:fa07d31e0cd85c60713f2b995da613588aa03e1303d75705dca6af8babc18ddc", size = 446886 }, - { url = "https://files.pythonhosted.org/packages/50/49/8dc3fd90902f70084bd2cd059d576ddb4f8bb44c2c7c0e33a11422acb17e/tornado-6.5.4-cp39-abi3-win_arm64.whl", hash = "sha256:053e6e16701eb6cbe641f308f4c1a9541f91b6261991160391bfc342e8a551a1", size = 445910 }, + { url = "https://files.pythonhosted.org/packages/59/8c/77f5097695f4dd8255ecbd08b2a1ed8ba8b953d337804dd7080f199e12bf/tornado-6.5.5-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:487dc9cc380e29f58c7ab88f9e27cdeef04b2140862e5076a66fb6bb68bb1bfa", size = 445983, upload-time = "2026-03-10T21:30:44.28Z" }, + { url = "https://files.pythonhosted.org/packages/ab/5e/7625b76cd10f98f1516c36ce0346de62061156352353ef2da44e5c21523c/tornado-6.5.5-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:65a7f1d46d4bb41df1ac99f5fcb685fb25c7e61613742d5108b010975a9a6521", size = 444246, upload-time = "2026-03-10T21:30:46.571Z" }, + { url = "https://files.pythonhosted.org/packages/b2/04/7b5705d5b3c0fab088f434f9c83edac1573830ca49ccf29fb83bf7178eec/tornado-6.5.5-cp39-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:e74c92e8e65086b338fd56333fb9a68b9f6f2fe7ad532645a290a464bcf46be5", size = 447229, upload-time = "2026-03-10T21:30:48.273Z" }, + { url = "https://files.pythonhosted.org/packages/34/01/74e034a30ef59afb4097ef8659515e96a39d910b712a89af76f5e4e1f93c/tornado-6.5.5-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:435319e9e340276428bbdb4e7fa732c2d399386d1de5686cb331ec8eee754f07", size = 448192, upload-time = "2026-03-10T21:30:51.22Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/fe9e02c5a96429fce1a1d15a517f5d8444f9c412e0bb9eadfbe3b0fc55bf/tornado-6.5.5-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:3f54aa540bdbfee7b9eb268ead60e7d199de5021facd276819c193c0fb28ea4e", size = 448039, upload-time = "2026-03-10T21:30:53.52Z" }, + { url = "https://files.pythonhosted.org/packages/82/9e/656ee4cec0398b1d18d0f1eb6372c41c6b889722641d84948351ae19556d/tornado-6.5.5-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:36abed1754faeb80fbd6e64db2758091e1320f6bba74a4cf8c09cd18ccce8aca", size = 447445, upload-time = "2026-03-10T21:30:55.541Z" }, + { url = "https://files.pythonhosted.org/packages/5a/76/4921c00511f88af86a33de770d64141170f1cfd9c00311aea689949e274e/tornado-6.5.5-cp39-abi3-win32.whl", hash = "sha256:dd3eafaaeec1c7f2f8fdcd5f964e8907ad788fe8a5a32c4426fbbdda621223b7", size = 448582, upload-time = "2026-03-10T21:30:57.142Z" }, + { url = "https://files.pythonhosted.org/packages/2c/23/f6c6112a04d28eed765e374435fb1a9198f73e1ec4b4024184f21faeb1ad/tornado-6.5.5-cp39-abi3-win_amd64.whl", hash = "sha256:6443a794ba961a9f619b1ae926a2e900ac20c34483eea67be4ed8f1e58d3ef7b", size = 448990, upload-time = "2026-03-10T21:30:58.857Z" }, + { url = "https://files.pythonhosted.org/packages/b7/c8/876602cbc96469911f0939f703453c1157b0c826ecb05bdd32e023397d4e/tornado-6.5.5-cp39-abi3-win_arm64.whl", hash = "sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6", size = 448016, upload-time = "2026-03-10T21:31:00.43Z" }, ] [[package]] @@ -3342,20 +3370,20 @@ name = "tqdm" version = "4.67.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598 } +sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374 }, + { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" }, ] [[package]] name = "traitlets" version = "5.14.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, ] [[package]] @@ -3366,9 +3394,9 @@ dependencies = [ { name = "torch" }, { name = "transformers", extra = ["sentencepiece", "torch"] }, ] -sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754 } +sdist = { url = "https://files.pythonhosted.org/packages/45/6f/85142d145fd2c453053e7dcd5500c31cd26ce51f9010cf0fe698001853f2/transformer_smaller_training_vocab-0.4.2.tar.gz", hash = "sha256:aed4390331e63d9a0998d76f277b7d44ad5d38b8427ad7792b1e28c807801ed8", size = 11754, upload-time = "2025-06-15T13:34:38.522Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073 }, + { url = "https://files.pythonhosted.org/packages/6c/88/94fa030995bc9a54e911172fd6ca26a81c2a5ddafd896ff62ad9cc99088b/transformer_smaller_training_vocab-0.4.2-py3-none-any.whl", hash = "sha256:49fcdb3134ede5faca41d3bed2588bd21a4098b64f261e7b198f163d394c3ef0", size = 14073, upload-time = "2025-06-15T13:34:37.468Z" }, ] [[package]] @@ -3387,9 +3415,9 @@ dependencies = [ { name = "tokenizers" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912 } +sdist = { url = "https://files.pythonhosted.org/packages/c4/35/67252acc1b929dc88b6602e8c4a982e64f31e733b804c14bc24b47da35e6/transformers-4.57.6.tar.gz", hash = "sha256:55e44126ece9dc0a291521b7e5492b572e6ef2766338a610b9ab5afbb70689d3", size = 10134912, upload-time = "2026-01-16T10:38:39.284Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498 }, + { url = "https://files.pythonhosted.org/packages/03/b8/e484ef633af3887baeeb4b6ad12743363af7cce68ae51e938e00aaa0529d/transformers-4.57.6-py3-none-any.whl", hash = "sha256:4c9e9de11333ddfe5114bc872c9f370509198acf0b87a832a0ab9458e2bd0550", size = 11993498, upload-time = "2026-01-16T10:38:31.289Z" }, ] [package.optional-dependencies] @@ -3407,8 +3435,7 @@ name = "triton" version = "3.6.0" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/44/ba/b1b04f4b291a3205d95ebd24465de0e5bf010a2df27a4e58a9b5f039d8f2/triton-3.6.0-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6c723cfb12f6842a0ae94ac307dba7e7a44741d720a40cf0e270ed4a4e3be781", size = 175972180 }, - { url = "https://files.pythonhosted.org/packages/8c/f7/f1c9d3424ab199ac53c2da567b859bcddbb9c9e7154805119f8bd95ec36f/triton-3.6.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6550fae429e0667e397e5de64b332d1e5695b73650ee75a6146e2e902770bea", size = 188105201 }, + { url = "https://files.pythonhosted.org/packages/8c/f7/f1c9d3424ab199ac53c2da567b859bcddbb9c9e7154805119f8bd95ec36f/triton-3.6.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a6550fae429e0667e397e5de64b332d1e5695b73650ee75a6146e2e902770bea", size = 188105201, upload-time = "2026-01-20T16:00:29.272Z" }, ] [[package]] @@ -3421,18 +3448,18 @@ dependencies = [ { name = "rich" }, { name = "shellingham" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613 } +sdist = { url = "https://files.pythonhosted.org/packages/f5/24/cb09efec5cc954f7f9b930bf8279447d24618bb6758d4f6adf2574c41780/typer-0.24.1.tar.gz", hash = "sha256:e39b4732d65fbdcde189ae76cf7cd48aeae72919dea1fdfc16593be016256b45", size = 118613, upload-time = "2026-02-21T16:54:40.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085 }, + { url = "https://files.pythonhosted.org/packages/4a/91/48db081e7a63bb37284f9fbcefda7c44c277b18b0e13fbc36ea2335b71e6/typer-0.24.1-py3-none-any.whl", hash = "sha256:112c1f0ce578bfb4cab9ffdabc68f031416ebcc216536611ba21f04e9aa84c9e", size = 56085, upload-time = "2026-02-21T16:54:41.616Z" }, ] [[package]] name = "typing-extensions" version = "4.15.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391 } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614 }, + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, ] [[package]] @@ -3442,45 +3469,45 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949 } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611 }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] name = "tzdata" version = "2025.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772 } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521 }, + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, ] [[package]] name = "unidecode" version = "1.3.8" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701 } +sdist = { url = "https://files.pythonhosted.org/packages/f7/89/19151076a006b9ac0dd37b1354e031f5297891ee507eb624755e58e10d3e/Unidecode-1.3.8.tar.gz", hash = "sha256:cfdb349d46ed3873ece4586b96aa75258726e2fa8ec21d6f00a591d98806c2f4", size = 192701, upload-time = "2024-01-11T11:58:35.609Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494 }, + { url = "https://files.pythonhosted.org/packages/84/b7/6ec57841fb67c98f52fc8e4a2d96df60059637cba077edc569a302a8ffc7/Unidecode-1.3.8-py3-none-any.whl", hash = "sha256:d130a61ce6696f8148a3bd8fe779c99adeb4b870584eeb9526584e9aa091fd39", size = 235494, upload-time = "2024-01-11T11:58:33.012Z" }, ] [[package]] name = "uri-template" version = "1.3.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678 } +sdist = { url = "https://files.pythonhosted.org/packages/31/c7/0336f2bd0bcbada6ccef7aaa25e443c118a704f828a0620c6fa0207c1b64/uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7", size = 21678, upload-time = "2023-06-21T01:49:05.374Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140 }, + { url = "https://files.pythonhosted.org/packages/e7/00/3fca040d7cf8a32776d3d81a00c8ee7457e00f80c649f1e4a863c8321ae9/uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363", size = 11140, upload-time = "2023-06-21T01:49:03.467Z" }, ] [[package]] name = "urllib3" version = "2.6.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556 } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584 }, + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, ] [[package]] @@ -3492,9 +3519,9 @@ dependencies = [ { name = "h11" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/32/ce/eeb58ae4ac36fe09e3842eb02e0eb676bf2c53ae062b98f1b2531673efdd/uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", size = 82633 } +sdist = { url = "https://files.pythonhosted.org/packages/32/ce/eeb58ae4ac36fe09e3842eb02e0eb676bf2c53ae062b98f1b2531673efdd/uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", size = 82633, upload-time = "2026-02-16T23:07:24.1Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187", size = 68783 }, + { url = "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187", size = 68783, upload-time = "2026-02-16T23:07:22.357Z" }, ] [package.optional-dependencies] @@ -3512,29 +3539,30 @@ standard = [ name = "uvloop" version = "0.22.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250 } +sdist = { url = "https://files.pythonhosted.org/packages/06/f0/18d39dbd1971d6d62c4629cc7fa67f74821b0dc1f5a77af43719de7936a7/uvloop-0.22.1.tar.gz", hash = "sha256:6c84bae345b9147082b17371e3dd5d42775bddce91f885499017f4607fdaf39f", size = 2443250, upload-time = "2025-10-16T22:17:19.342Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335 }, - { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903 }, - { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499 }, - { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133 }, - { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681 }, - { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261 }, + { url = "https://files.pythonhosted.org/packages/eb/14/ecceb239b65adaaf7fde510aa8bd534075695d1e5f8dadfa32b5723d9cfb/uvloop-0.22.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ef6f0d4cc8a9fa1f6a910230cd53545d9a14479311e87e3cb225495952eb672c", size = 1343335, upload-time = "2025-10-16T22:16:11.43Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ae/6f6f9af7f590b319c94532b9567409ba11f4fa71af1148cab1bf48a07048/uvloop-0.22.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7cd375a12b71d33d46af85a3343b35d98e8116134ba404bd657b3b1d15988792", size = 742903, upload-time = "2025-10-16T22:16:12.979Z" }, + { url = "https://files.pythonhosted.org/packages/09/bd/3667151ad0702282a1f4d5d29288fce8a13c8b6858bf0978c219cd52b231/uvloop-0.22.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ac33ed96229b7790eb729702751c0e93ac5bc3bcf52ae9eccbff30da09194b86", size = 3648499, upload-time = "2025-10-16T22:16:14.451Z" }, + { url = "https://files.pythonhosted.org/packages/b3/f6/21657bb3beb5f8c57ce8be3b83f653dd7933c2fd00545ed1b092d464799a/uvloop-0.22.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:481c990a7abe2c6f4fc3d98781cc9426ebd7f03a9aaa7eb03d3bfc68ac2a46bd", size = 3700133, upload-time = "2025-10-16T22:16:16.272Z" }, + { url = "https://files.pythonhosted.org/packages/09/e0/604f61d004ded805f24974c87ddd8374ef675644f476f01f1df90e4cdf72/uvloop-0.22.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a592b043a47ad17911add5fbd087c76716d7c9ccc1d64ec9249ceafd735f03c2", size = 3512681, upload-time = "2025-10-16T22:16:18.07Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ce/8491fd370b0230deb5eac69c7aae35b3be527e25a911c0acdffb922dc1cd/uvloop-0.22.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1489cf791aa7b6e8c8be1c5a080bae3a672791fcb4e9e12249b05862a2ca9cec", size = 3615261, upload-time = "2025-10-16T22:16:19.596Z" }, ] [[package]] name = "virtualenv" -version = "20.39.0" +version = "21.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, { name = "filelock" }, { name = "platformdirs" }, + { name = "python-discovery" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ed/54/809199edc537dbace273495ac0884d13df26436e910a5ed4d0ec0a69806b/virtualenv-20.39.0.tar.gz", hash = "sha256:a15f0cebd00d50074fd336a169d53422436a12dfe15149efec7072cfe817df8b", size = 5869141 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/92/58199fe10049f9703c2666e809c4f686c54ef0a68b0f6afccf518c0b1eb9/virtualenv-21.2.0.tar.gz", hash = "sha256:1720dc3a62ef5b443092e3f499228599045d7fea4c79199770499df8becf9098", size = 5840618, upload-time = "2026-03-09T17:24:38.013Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/b4/8268da45f26f4fe84f6eae80a6ca1485ffb490a926afecff75fc48f61979/virtualenv-20.39.0-py3-none-any.whl", hash = "sha256:44888bba3775990a152ea1f73f8e5f566d49f11bbd1de61d426fd7732770043e", size = 5839121 }, + { url = "https://files.pythonhosted.org/packages/c6/59/7d02447a55b2e55755011a647479041bc92a82e143f96a8195cb33bd0a1c/virtualenv-21.2.0-py3-none-any.whl", hash = "sha256:1bd755b504931164a5a496d217c014d098426cddc79363ad66ac78125f9d908f", size = 5825084, upload-time = "2026-03-09T17:24:35.378Z" }, ] [[package]] @@ -3544,174 +3572,182 @@ source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440 } +sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318 }, - { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478 }, - { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894 }, - { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065 }, - { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377 }, - { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837 }, - { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456 }, - { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614 }, - { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690 }, - { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459 }, - { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663 }, - { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453 }, - { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611 }, - { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889 }, - { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616 }, - { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413 }, + { url = "https://files.pythonhosted.org/packages/a7/1a/206e8cf2dd86fddf939165a57b4df61607a1e0add2785f170a3f616b7d9f/watchfiles-1.1.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:eef58232d32daf2ac67f42dea51a2c80f0d03379075d44a587051e63cc2e368c", size = 407318, upload-time = "2025-10-14T15:04:18.753Z" }, + { url = "https://files.pythonhosted.org/packages/b3/0f/abaf5262b9c496b5dad4ed3c0e799cbecb1f8ea512ecb6ddd46646a9fca3/watchfiles-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:03fa0f5237118a0c5e496185cafa92878568b652a2e9a9382a5151b1a0380a43", size = 394478, upload-time = "2025-10-14T15:04:20.297Z" }, + { url = "https://files.pythonhosted.org/packages/b1/04/9cc0ba88697b34b755371f5ace8d3a4d9a15719c07bdc7bd13d7d8c6a341/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca65483439f9c791897f7db49202301deb6e15fe9f8fe2fed555bf986d10c31", size = 449894, upload-time = "2025-10-14T15:04:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/d2/9c/eda4615863cd8621e89aed4df680d8c3ec3da6a4cf1da113c17decd87c7f/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0ab1c1af0cb38e3f598244c17919fb1a84d1629cc08355b0074b6d7f53138ac", size = 459065, upload-time = "2025-10-14T15:04:22.795Z" }, + { url = "https://files.pythonhosted.org/packages/84/13/f28b3f340157d03cbc8197629bc109d1098764abe1e60874622a0be5c112/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bc570d6c01c206c46deb6e935a260be44f186a2f05179f52f7fcd2be086a94d", size = 488377, upload-time = "2025-10-14T15:04:24.138Z" }, + { url = "https://files.pythonhosted.org/packages/86/93/cfa597fa9389e122488f7ffdbd6db505b3b915ca7435ecd7542e855898c2/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e84087b432b6ac94778de547e08611266f1f8ffad28c0ee4c82e028b0fc5966d", size = 595837, upload-time = "2025-10-14T15:04:25.057Z" }, + { url = "https://files.pythonhosted.org/packages/57/1e/68c1ed5652b48d89fc24d6af905d88ee4f82fa8bc491e2666004e307ded1/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:620bae625f4cb18427b1bb1a2d9426dc0dd5a5ba74c7c2cdb9de405f7b129863", size = 473456, upload-time = "2025-10-14T15:04:26.497Z" }, + { url = "https://files.pythonhosted.org/packages/d5/dc/1a680b7458ffa3b14bb64878112aefc8f2e4f73c5af763cbf0bd43100658/watchfiles-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:544364b2b51a9b0c7000a4b4b02f90e9423d97fbbf7e06689236443ebcad81ab", size = 455614, upload-time = "2025-10-14T15:04:27.539Z" }, + { url = "https://files.pythonhosted.org/packages/61/a5/3d782a666512e01eaa6541a72ebac1d3aae191ff4a31274a66b8dd85760c/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:bbe1ef33d45bc71cf21364df962af171f96ecaeca06bd9e3d0b583efb12aec82", size = 630690, upload-time = "2025-10-14T15:04:28.495Z" }, + { url = "https://files.pythonhosted.org/packages/9b/73/bb5f38590e34687b2a9c47a244aa4dd50c56a825969c92c9c5fc7387cea1/watchfiles-1.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1a0bb430adb19ef49389e1ad368450193a90038b5b752f4ac089ec6942c4dff4", size = 622459, upload-time = "2025-10-14T15:04:29.491Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ac/c9bb0ec696e07a20bd58af5399aeadaef195fb2c73d26baf55180fe4a942/watchfiles-1.1.1-cp310-cp310-win32.whl", hash = "sha256:3f6d37644155fb5beca5378feb8c1708d5783145f2a0f1c4d5a061a210254844", size = 272663, upload-time = "2025-10-14T15:04:30.435Z" }, + { url = "https://files.pythonhosted.org/packages/11/a0/a60c5a7c2ec59fa062d9a9c61d02e3b6abd94d32aac2d8344c4bdd033326/watchfiles-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a36d8efe0f290835fd0f33da35042a1bb5dc0e83cbc092dcf69bce442579e88e", size = 287453, upload-time = "2025-10-14T15:04:31.53Z" }, + { url = "https://files.pythonhosted.org/packages/ba/4c/a888c91e2e326872fa4705095d64acd8aa2fb9c1f7b9bd0588f33850516c/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:17ef139237dfced9da49fb7f2232c86ca9421f666d78c264c7ffca6601d154c3", size = 409611, upload-time = "2025-10-14T15:06:05.809Z" }, + { url = "https://files.pythonhosted.org/packages/1e/c7/5420d1943c8e3ce1a21c0a9330bcf7edafb6aa65d26b21dbb3267c9e8112/watchfiles-1.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:672b8adf25b1a0d35c96b5888b7b18699d27d4194bac8beeae75be4b7a3fc9b2", size = 396889, upload-time = "2025-10-14T15:06:07.035Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e5/0072cef3804ce8d3aaddbfe7788aadff6b3d3f98a286fdbee9fd74ca59a7/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77a13aea58bc2b90173bc69f2a90de8e282648939a00a602e1dc4ee23e26b66d", size = 451616, upload-time = "2025-10-14T15:06:08.072Z" }, + { url = "https://files.pythonhosted.org/packages/83/4e/b87b71cbdfad81ad7e83358b3e447fedd281b880a03d64a760fe0a11fc2e/watchfiles-1.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b495de0bb386df6a12b18335a0285dda90260f51bdb505503c02bcd1ce27a8b", size = 458413, upload-time = "2025-10-14T15:06:09.209Z" }, ] [[package]] name = "wcwidth" version = "0.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684 } +sdist = { url = "https://files.pythonhosted.org/packages/35/a2/8e3becb46433538a38726c948d3399905a4c7cabd0df578ede5dc51f0ec2/wcwidth-0.6.0.tar.gz", hash = "sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159", size = 159684, upload-time = "2026-02-06T19:19:40.919Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189 }, + { url = "https://files.pythonhosted.org/packages/68/5a/199c59e0a824a3db2b89c5d2dade7ab5f9624dbf6448dc291b46d5ec94d3/wcwidth-0.6.0-py3-none-any.whl", hash = "sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad", size = 94189, upload-time = "2026-02-06T19:19:39.646Z" }, ] [[package]] name = "webcolors" version = "25.10.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491 } +sdist = { url = "https://files.pythonhosted.org/packages/1d/7a/eb316761ec35664ea5174709a68bbd3389de60d4a1ebab8808bfc264ed67/webcolors-25.10.0.tar.gz", hash = "sha256:62abae86504f66d0f6364c2a8520de4a0c47b80c03fc3a5f1815fedbef7c19bf", size = 53491, upload-time = "2025-10-31T07:51:03.977Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905 }, + { url = "https://files.pythonhosted.org/packages/e2/cc/e097523dd85c9cf5d354f78310927f1656c422bd7b2613b2db3e3f9a0f2c/webcolors-25.10.0-py3-none-any.whl", hash = "sha256:032c727334856fc0b968f63daa252a1ac93d33db2f5267756623c210e57a4f1d", size = 14905, upload-time = "2025-10-31T07:51:01.778Z" }, ] [[package]] name = "webencodings" version = "0.5.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/02/ae6ceac1baeda530866a85075641cec12989bd8d31af6d5ab4a3e8c92f47/webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923", size = 9721, upload-time = "2017-04-05T20:21:34.189Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774 }, + { url = "https://files.pythonhosted.org/packages/f4/24/2a3e3df732393fed8b3ebf2ec078f05546de641fe1b667ee316ec1dcf3b7/webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78", size = 11774, upload-time = "2017-04-05T20:21:32.581Z" }, ] [[package]] name = "websocket-client" version = "1.9.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576 } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616 }, + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, ] [[package]] name = "websockets" version = "16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346 } +sdist = { url = "https://files.pythonhosted.org/packages/04/24/4b2031d72e840ce4c1ccb255f693b15c334757fc50023e4db9537080b8c4/websockets-16.0.tar.gz", hash = "sha256:5f6261a5e56e8d5c42a4497b364ea24d94d9563e8fbd44e78ac40879c60179b5", size = 179346, upload-time = "2026-01-10T09:23:47.181Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343 }, - { url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021 }, - { url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320 }, - { url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815 }, - { url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054 }, - { url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565 }, - { url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848 }, - { url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249 }, - { url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685 }, - { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598 }, + { url = "https://files.pythonhosted.org/packages/20/74/221f58decd852f4b59cc3354cccaf87e8ef695fede361d03dc9a7396573b/websockets-16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:04cdd5d2d1dacbad0a7bf36ccbcd3ccd5a30ee188f2560b7a62a30d14107b31a", size = 177343, upload-time = "2026-01-10T09:22:21.28Z" }, + { url = "https://files.pythonhosted.org/packages/19/0f/22ef6107ee52ab7f0b710d55d36f5a5d3ef19e8a205541a6d7ffa7994e5a/websockets-16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8ff32bb86522a9e5e31439a58addbb0166f0204d64066fb955265c4e214160f0", size = 175021, upload-time = "2026-01-10T09:22:22.696Z" }, + { url = "https://files.pythonhosted.org/packages/10/40/904a4cb30d9b61c0e278899bf36342e9b0208eb3c470324a9ecbaac2a30f/websockets-16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:583b7c42688636f930688d712885cf1531326ee05effd982028212ccc13e5957", size = 175320, upload-time = "2026-01-10T09:22:23.94Z" }, + { url = "https://files.pythonhosted.org/packages/9d/2f/4b3ca7e106bc608744b1cdae041e005e446124bebb037b18799c2d356864/websockets-16.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7d837379b647c0c4c2355c2499723f82f1635fd2c26510e1f587d89bc2199e72", size = 183815, upload-time = "2026-01-10T09:22:25.469Z" }, + { url = "https://files.pythonhosted.org/packages/86/26/d40eaa2a46d4302becec8d15b0fc5e45bdde05191e7628405a19cf491ccd/websockets-16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df57afc692e517a85e65b72e165356ed1df12386ecb879ad5693be08fac65dde", size = 185054, upload-time = "2026-01-10T09:22:27.101Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ba/6500a0efc94f7373ee8fefa8c271acdfd4dca8bd49a90d4be7ccabfc397e/websockets-16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2b9f1e0d69bc60a4a87349d50c09a037a2607918746f07de04df9e43252c77a3", size = 184565, upload-time = "2026-01-10T09:22:28.293Z" }, + { url = "https://files.pythonhosted.org/packages/04/b4/96bf2cee7c8d8102389374a2616200574f5f01128d1082f44102140344cc/websockets-16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:335c23addf3d5e6a8633f9f8eda77efad001671e80b95c491dd0924587ece0b3", size = 183848, upload-time = "2026-01-10T09:22:30.394Z" }, + { url = "https://files.pythonhosted.org/packages/02/8e/81f40fb00fd125357814e8c3025738fc4ffc3da4b6b4a4472a82ba304b41/websockets-16.0-cp310-cp310-win32.whl", hash = "sha256:37b31c1623c6605e4c00d466c9d633f9b812ea430c11c8a278774a1fde1acfa9", size = 178249, upload-time = "2026-01-10T09:22:32.083Z" }, + { url = "https://files.pythonhosted.org/packages/b4/5f/7e40efe8df57db9b91c88a43690ac66f7b7aa73a11aa6a66b927e44f26fa/websockets-16.0-cp310-cp310-win_amd64.whl", hash = "sha256:8e1dab317b6e77424356e11e99a432b7cb2f3ec8c5ab4dabbcee6add48f72b35", size = 178685, upload-time = "2026-01-10T09:22:33.345Z" }, + { url = "https://files.pythonhosted.org/packages/6f/28/258ebab549c2bf3e64d2b0217b973467394a9cea8c42f70418ca2c5d0d2e/websockets-16.0-py3-none-any.whl", hash = "sha256:1637db62fad1dc833276dded54215f2c7fa46912301a24bd94d45d46a011ceec", size = 171598, upload-time = "2026-01-10T09:23:45.395Z" }, ] [[package]] name = "widgetsnbextension" version = "4.0.15" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402 } +sdist = { url = "https://files.pythonhosted.org/packages/bd/f4/c67440c7fb409a71b7404b7aefcd7569a9c0d6bd071299bf4198ae7a5d95/widgetsnbextension-4.0.15.tar.gz", hash = "sha256:de8610639996f1567952d763a5a41af8af37f2575a41f9852a38f947eb82a3b9", size = 1097402, upload-time = "2025-11-01T21:15:55.178Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503 }, + { url = "https://files.pythonhosted.org/packages/3f/0e/fa3b193432cfc60c93b42f3be03365f5f909d2b3ea410295cf36df739e31/widgetsnbextension-4.0.15-py3-none-any.whl", hash = "sha256:8156704e4346a571d9ce73b84bee86a29906c9abfd7223b7228a28899ccf3366", size = 2196503, upload-time = "2025-11-01T21:15:53.565Z" }, ] [[package]] name = "wikipedia-api" -version = "0.9.0" +version = "0.10.2" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "click" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/49/7b/8b775cf22f266086cefa762b58df0a35a4c4532de3f2f6a0b7432fd31fd1/wikipedia_api-0.9.0.tar.gz", hash = "sha256:6aabd1f9fe34f594f4d36f5af67e468b0a50d713aa9a1d102b4d996bc76dd58e", size = 20041 } +sdist = { url = "https://files.pythonhosted.org/packages/cb/59/a6f5790043cff046658d44bc5b594a7d0cc0d9a1a6911a0df6e7aba2179c/wikipedia_api-0.10.2.tar.gz", hash = "sha256:93fc84d2d88b043c626a03bc013a741c206ab60c0517bfce51fa60a0edc5087d", size = 29841, upload-time = "2026-03-06T22:01:16.615Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/41/cf1ceb3071b58175d6960d5f45bfd5c007fc8ab5bec8ca189efd02bb05e4/wikipedia_api-0.10.2-py3-none-any.whl", hash = "sha256:0aa6d09e46909d396d81af97de5dee06004c1f823725b4f66c352b1096d48163", size = 22690, upload-time = "2026-03-06T22:01:15.024Z" }, +] [[package]] name = "wrapt" -version = "2.1.1" +version = "2.1.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f7/37/ae31f40bec90de2f88d9597d0b5281e23ffe85b893a47ca5d9c05c63a4f6/wrapt-2.1.1.tar.gz", hash = "sha256:5fdcb09bf6db023d88f312bd0767594b414655d58090fc1c46b3414415f67fac", size = 81329 } +sdist = { url = "https://files.pythonhosted.org/packages/2e/64/925f213fdcbb9baeb1530449ac71a4d57fc361c053d06bf78d0c5c7cd80c/wrapt-2.1.2.tar.gz", hash = "sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e", size = 81678, upload-time = "2026-03-06T02:53:25.134Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ca/21/293b657a27accfbbbb6007ebd78af0efa2083dac83e8f523272ea09b4638/wrapt-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e927375e43fd5a985b27a8992327c22541b6dede1362fc79df337d26e23604f", size = 60554 }, - { url = "https://files.pythonhosted.org/packages/25/e9/96dd77728b54a899d4ce2798d7b1296989ce687ed3c0cb917d6b3154bf5d/wrapt-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c99544b6a7d40ca22195563b6d8bc3986ee8bb82f272f31f0670fe9440c869", size = 61496 }, - { url = "https://files.pythonhosted.org/packages/44/79/4c755b45df6ef30c0dd628ecfaa0c808854be147ca438429da70a162833c/wrapt-2.1.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b2be3fa5f4efaf16ee7c77d0556abca35f5a18ad4ac06f0ef3904c3399010ce9", size = 113528 }, - { url = "https://files.pythonhosted.org/packages/9f/63/23ce28f7b841217d9a6337a340fbb8d4a7fbd67a89d47f377c8550fa34aa/wrapt-2.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67c90c1ae6489a6cb1a82058902caa8006706f7b4e8ff766f943e9d2c8e608d0", size = 115536 }, - { url = "https://files.pythonhosted.org/packages/23/7b/5ca8d3b12768670d16c8329e29960eedd56212770365a02a8de8bf73dc01/wrapt-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:05c0db35ccffd7480143e62df1e829d101c7b86944ae3be7e4869a7efa621f53", size = 114716 }, - { url = "https://files.pythonhosted.org/packages/c7/3a/9789ccb14a096d30bb847bf3ee137bf682cc9750c2ce155f4c5ae1962abf/wrapt-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0c2ec9f616755b2e1e0bf4d0961f59bb5c2e7a77407e7e2c38ef4f7d2fdde12c", size = 113200 }, - { url = "https://files.pythonhosted.org/packages/cf/e5/4ec3526ce6ce920b267c8d35d2c2f0874d3fad2744c8b7259353f1132baa/wrapt-2.1.1-cp310-cp310-win32.whl", hash = "sha256:203ba6b3f89e410e27dbd30ff7dccaf54dcf30fda0b22aa1b82d560c7f9fe9a1", size = 57876 }, - { url = "https://files.pythonhosted.org/packages/d1/4e/661c7c76ecd85375b2bc03488941a3a1078642af481db24949e2b9de01f4/wrapt-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:6f9426d9cfc2f8732922fc96198052e55c09bb9db3ddaa4323a18e055807410e", size = 60224 }, - { url = "https://files.pythonhosted.org/packages/5f/b7/53c7252d371efada4cb119e72e774fa2c6b3011fc33e3e552cdf48fb9488/wrapt-2.1.1-cp310-cp310-win_arm64.whl", hash = "sha256:69c26f51b67076b40714cff81bdd5826c0b10c077fb6b0678393a6a2f952a5fc", size = 58645 }, - { url = "https://files.pythonhosted.org/packages/c4/da/5a086bf4c22a41995312db104ec2ffeee2cf6accca9faaee5315c790377d/wrapt-2.1.1-py3-none-any.whl", hash = "sha256:3b0f4629eb954394a3d7c7a1c8cca25f0b07cefe6aa8545e862e9778152de5b7", size = 43886 }, + { url = "https://files.pythonhosted.org/packages/da/d2/387594fb592d027366645f3d7cc9b4d7ca7be93845fbaba6d835a912ef3c/wrapt-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b7a86d99a14f76facb269dc148590c01aaf47584071809a70da30555228158c", size = 60669, upload-time = "2026-03-06T02:52:40.671Z" }, + { url = "https://files.pythonhosted.org/packages/c9/18/3f373935bc5509e7ac444c8026a56762e50c1183e7061797437ca96c12ce/wrapt-2.1.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a819e39017f95bf7aede768f75915635aa8f671f2993c036991b8d3bfe8dbb6f", size = 61603, upload-time = "2026-03-06T02:54:21.032Z" }, + { url = "https://files.pythonhosted.org/packages/c2/7a/32758ca2853b07a887a4574b74e28843919103194bb47001a304e24af62f/wrapt-2.1.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5681123e60aed0e64c7d44f72bbf8b4ce45f79d81467e2c4c728629f5baf06eb", size = 113632, upload-time = "2026-03-06T02:53:54.121Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d5/eeaa38f670d462e97d978b3b0d9ce06d5b91e54bebac6fbed867809216e7/wrapt-2.1.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b8b28e97a44d21836259739ae76284e180b18abbb4dcfdff07a415cf1016c3e", size = 115644, upload-time = "2026-03-06T02:54:53.33Z" }, + { url = "https://files.pythonhosted.org/packages/e3/09/2a41506cb17affb0bdf9d5e2129c8c19e192b388c4c01d05e1b14db23c00/wrapt-2.1.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cef91c95a50596fcdc31397eb6955476f82ae8a3f5a8eabdc13611b60ee380ba", size = 112016, upload-time = "2026-03-06T02:54:43.274Z" }, + { url = "https://files.pythonhosted.org/packages/64/15/0e6c3f5e87caadc43db279724ee36979246d5194fa32fed489c73643ba59/wrapt-2.1.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dad63212b168de8569b1c512f4eac4b57f2c6934b30df32d6ee9534a79f1493f", size = 114823, upload-time = "2026-03-06T02:54:29.392Z" }, + { url = "https://files.pythonhosted.org/packages/56/b2/0ad17c8248f4e57bedf44938c26ec3ee194715f812d2dbbd9d7ff4be6c06/wrapt-2.1.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d307aa6888d5efab2c1cde09843d48c843990be13069003184b67d426d145394", size = 111244, upload-time = "2026-03-06T02:54:02.149Z" }, + { url = "https://files.pythonhosted.org/packages/ff/04/bcdba98c26f2c6522c7c09a726d5d9229120163493620205b2f76bd13c01/wrapt-2.1.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c87cf3f0c85e27b3ac7d9ad95da166bf8739ca215a8b171e8404a2d739897a45", size = 113307, upload-time = "2026-03-06T02:54:12.428Z" }, + { url = "https://files.pythonhosted.org/packages/0e/1b/5e2883c6bc14143924e465a6fc5a92d09eeabe35310842a481fb0581f832/wrapt-2.1.2-cp310-cp310-win32.whl", hash = "sha256:d1c5fea4f9fe3762e2b905fdd67df51e4be7a73b7674957af2d2ade71a5c075d", size = 57986, upload-time = "2026-03-06T02:54:26.823Z" }, + { url = "https://files.pythonhosted.org/packages/42/5a/4efc997bccadd3af5749c250b49412793bc41e13a83a486b2b54a33e240c/wrapt-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:d8f7740e1af13dff2684e4d56fe604a7e04d6c94e737a60568d8d4238b9a0c71", size = 60336, upload-time = "2026-03-06T02:54:18Z" }, + { url = "https://files.pythonhosted.org/packages/c1/f5/a2bb833e20181b937e87c242645ed5d5aa9c373006b0467bfe1a35c727d0/wrapt-2.1.2-cp310-cp310-win_arm64.whl", hash = "sha256:1c6cc827c00dc839350155f316f1f8b4b0c370f52b6a19e782e2bda89600c7dc", size = 58757, upload-time = "2026-03-06T02:53:51.545Z" }, + { url = "https://files.pythonhosted.org/packages/1a/c7/8528ac2dfa2c1e6708f647df7ae144ead13f0a31146f43c7264b4942bf12/wrapt-2.1.2-py3-none-any.whl", hash = "sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8", size = 43993, upload-time = "2026-03-06T02:53:12.905Z" }, ] [[package]] name = "xmltodict" version = "0.14.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942 } +sdist = { url = "https://files.pythonhosted.org/packages/50/05/51dcca9a9bf5e1bce52582683ce50980bcadbc4fa5143b9f2b19ab99958f/xmltodict-0.14.2.tar.gz", hash = "sha256:201e7c28bb210e374999d1dde6382923ab0ed1a8a5faeece48ab525b7810a553", size = 51942, upload-time = "2024-10-16T06:10:29.683Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981 }, + { url = "https://files.pythonhosted.org/packages/d6/45/fc303eb433e8a2a271739c98e953728422fa61a3c1f36077a49e395c972e/xmltodict-0.14.2-py2.py3-none-any.whl", hash = "sha256:20cc7d723ed729276e808f26fb6b3599f786cbc37e06c65e192ba77c40f20aac", size = 9981, upload-time = "2024-10-16T06:10:27.649Z" }, ] [[package]] name = "xxhash" version = "3.6.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160 } +sdist = { url = "https://files.pythonhosted.org/packages/02/84/30869e01909fb37a6cc7e18688ee8bf1e42d57e7e0777636bd47524c43c7/xxhash-3.6.0.tar.gz", hash = "sha256:f0162a78b13a0d7617b2845b90c763339d1f1d82bb04a4b07f4ab535cc5e05d6", size = 85160, upload-time = "2025-10-02T14:37:08.097Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845 }, - { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807 }, - { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786 }, - { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830 }, - { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606 }, - { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872 }, - { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217 }, - { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139 }, - { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669 }, - { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018 }, - { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058 }, - { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628 }, - { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577 }, - { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487 }, - { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863 }, + { url = "https://files.pythonhosted.org/packages/34/ee/f9f1d656ad168681bb0f6b092372c1e533c4416b8069b1896a175c46e484/xxhash-3.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87ff03d7e35c61435976554477a7f4cd1704c3596a89a8300d5ce7fc83874a71", size = 32845, upload-time = "2025-10-02T14:33:51.573Z" }, + { url = "https://files.pythonhosted.org/packages/a3/b1/93508d9460b292c74a09b83d16750c52a0ead89c51eea9951cb97a60d959/xxhash-3.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f572dfd3d0e2eb1a57511831cf6341242f5a9f8298a45862d085f5b93394a27d", size = 30807, upload-time = "2025-10-02T14:33:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/07/55/28c93a3662f2d200c70704efe74aab9640e824f8ce330d8d3943bf7c9b3c/xxhash-3.6.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:89952ea539566b9fed2bbd94e589672794b4286f342254fad28b149f9615fef8", size = 193786, upload-time = "2025-10-02T14:33:54.272Z" }, + { url = "https://files.pythonhosted.org/packages/c1/96/fec0be9bb4b8f5d9c57d76380a366f31a1781fb802f76fc7cda6c84893c7/xxhash-3.6.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:48e6f2ffb07a50b52465a1032c3cf1f4a5683f944acaca8a134a2f23674c2058", size = 212830, upload-time = "2025-10-02T14:33:55.706Z" }, + { url = "https://files.pythonhosted.org/packages/c4/a0/c706845ba77b9611f81fd2e93fad9859346b026e8445e76f8c6fd057cc6d/xxhash-3.6.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b5b848ad6c16d308c3ac7ad4ba6bede80ed5df2ba8ed382f8932df63158dd4b2", size = 211606, upload-time = "2025-10-02T14:33:57.133Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/164126a2999e5045f04a69257eea946c0dc3e86541b400d4385d646b53d7/xxhash-3.6.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a034590a727b44dd8ac5914236a7b8504144447a9682586c3327e935f33ec8cc", size = 444872, upload-time = "2025-10-02T14:33:58.446Z" }, + { url = "https://files.pythonhosted.org/packages/2d/4b/55ab404c56cd70a2cf5ecfe484838865d0fea5627365c6c8ca156bd09c8f/xxhash-3.6.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a8f1972e75ebdd161d7896743122834fe87378160c20e97f8b09166213bf8cc", size = 193217, upload-time = "2025-10-02T14:33:59.724Z" }, + { url = "https://files.pythonhosted.org/packages/45/e6/52abf06bac316db33aa269091ae7311bd53cfc6f4b120ae77bac1b348091/xxhash-3.6.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ee34327b187f002a596d7b167ebc59a1b729e963ce645964bbc050d2f1b73d07", size = 210139, upload-time = "2025-10-02T14:34:02.041Z" }, + { url = "https://files.pythonhosted.org/packages/34/37/db94d490b8691236d356bc249c08819cbcef9273a1a30acf1254ff9ce157/xxhash-3.6.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:339f518c3c7a850dd033ab416ea25a692759dc7478a71131fe8869010d2b75e4", size = 197669, upload-time = "2025-10-02T14:34:03.664Z" }, + { url = "https://files.pythonhosted.org/packages/b7/36/c4f219ef4a17a4f7a64ed3569bc2b5a9c8311abdb22249ac96093625b1a4/xxhash-3.6.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf48889c9630542d4709192578aebbd836177c9f7a4a2778a7d6340107c65f06", size = 210018, upload-time = "2025-10-02T14:34:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/fd/06/bfac889a374fc2fc439a69223d1750eed2e18a7db8514737ab630534fa08/xxhash-3.6.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5576b002a56207f640636056b4160a378fe36a58db73ae5c27a7ec8db35f71d4", size = 413058, upload-time = "2025-10-02T14:34:06.925Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d1/555d8447e0dd32ad0930a249a522bb2e289f0d08b6b16204cfa42c1f5a0c/xxhash-3.6.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:af1f3278bd02814d6dedc5dec397993b549d6f16c19379721e5a1d31e132c49b", size = 190628, upload-time = "2025-10-02T14:34:08.669Z" }, + { url = "https://files.pythonhosted.org/packages/d1/15/8751330b5186cedc4ed4b597989882ea05e0408b53fa47bcb46a6125bfc6/xxhash-3.6.0-cp310-cp310-win32.whl", hash = "sha256:aed058764db109dc9052720da65fafe84873b05eb8b07e5e653597951af57c3b", size = 30577, upload-time = "2025-10-02T14:34:10.234Z" }, + { url = "https://files.pythonhosted.org/packages/bb/cc/53f87e8b5871a6eb2ff7e89c48c66093bda2be52315a8161ddc54ea550c4/xxhash-3.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:e82da5670f2d0d98950317f82a0e4a0197150ff19a6df2ba40399c2a3b9ae5fb", size = 31487, upload-time = "2025-10-02T14:34:11.618Z" }, + { url = "https://files.pythonhosted.org/packages/9f/00/60f9ea3bb697667a14314d7269956f58bf56bb73864f8f8d52a3c2535e9a/xxhash-3.6.0-cp310-cp310-win_arm64.whl", hash = "sha256:4a082ffff8c6ac07707fb6b671caf7c6e020c75226c561830b73d862060f281d", size = 27863, upload-time = "2025-10-02T14:34:12.619Z" }, ] [[package]] name = "yarl" -version = "1.22.0" +version = "1.23.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, { name = "propcache" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/63/0c6ebca57330cd313f6102b16dd57ffaf3ec4c83403dcb45dbd15c6f3ea1/yarl-1.22.0.tar.gz", hash = "sha256:bebf8557577d4401ba8bd9ff33906f1376c877aa78d1fe216ad01b4d6745af71", size = 187169 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/43/a2204825342f37c337f5edb6637040fa14e365b2fcc2346960201d457579/yarl-1.22.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c7bd6683587567e5a49ee6e336e0612bec8329be1b7d4c8af5687dcdeb67ee1e", size = 140517 }, - { url = "https://files.pythonhosted.org/packages/44/6f/674f3e6f02266428c56f704cd2501c22f78e8b2eeb23f153117cc86fb28a/yarl-1.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5cdac20da754f3a723cceea5b3448e1a2074866406adeb4ef35b469d089adb8f", size = 93495 }, - { url = "https://files.pythonhosted.org/packages/b8/12/5b274d8a0f30c07b91b2f02cba69152600b47830fcfb465c108880fcee9c/yarl-1.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:07a524d84df0c10f41e3ee918846e1974aba4ec017f990dc735aad487a0bdfdf", size = 94400 }, - { url = "https://files.pythonhosted.org/packages/e2/7f/df1b6949b1fa1aa9ff6de6e2631876ad4b73c4437822026e85d8acb56bb1/yarl-1.22.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e1b329cb8146d7b736677a2440e422eadd775d1806a81db2d4cded80a48efc1a", size = 347545 }, - { url = "https://files.pythonhosted.org/packages/84/09/f92ed93bd6cd77872ab6c3462df45ca45cd058d8f1d0c9b4f54c1704429f/yarl-1.22.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:75976c6945d85dbb9ee6308cd7ff7b1fb9409380c82d6119bd778d8fcfe2931c", size = 319598 }, - { url = "https://files.pythonhosted.org/packages/c3/97/ac3f3feae7d522cf7ccec3d340bb0b2b61c56cb9767923df62a135092c6b/yarl-1.22.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:80ddf7a5f8c86cb3eb4bc9028b07bbbf1f08a96c5c0bc1244be5e8fefcb94147", size = 363893 }, - { url = "https://files.pythonhosted.org/packages/06/49/f3219097403b9c84a4d079b1d7bda62dd9b86d0d6e4428c02d46ab2c77fc/yarl-1.22.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d332fc2e3c94dad927f2112395772a4e4fedbcf8f80efc21ed7cdfae4d574fdb", size = 371240 }, - { url = "https://files.pythonhosted.org/packages/35/9f/06b765d45c0e44e8ecf0fe15c9eacbbde342bb5b7561c46944f107bfb6c3/yarl-1.22.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0cf71bf877efeac18b38d3930594c0948c82b64547c1cf420ba48722fe5509f6", size = 346965 }, - { url = "https://files.pythonhosted.org/packages/c5/69/599e7cea8d0fcb1694323b0db0dda317fa3162f7b90166faddecf532166f/yarl-1.22.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:663e1cadaddae26be034a6ab6072449a8426ddb03d500f43daf952b74553bba0", size = 342026 }, - { url = "https://files.pythonhosted.org/packages/95/6f/9dfd12c8bc90fea9eab39832ee32ea48f8e53d1256252a77b710c065c89f/yarl-1.22.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:6dcbb0829c671f305be48a7227918cfcd11276c2d637a8033a99a02b67bf9eda", size = 335637 }, - { url = "https://files.pythonhosted.org/packages/57/2e/34c5b4eb9b07e16e873db5b182c71e5f06f9b5af388cdaa97736d79dd9a6/yarl-1.22.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f0d97c18dfd9a9af4490631905a3f131a8e4c9e80a39353919e2cfed8f00aedc", size = 359082 }, - { url = "https://files.pythonhosted.org/packages/31/71/fa7e10fb772d273aa1f096ecb8ab8594117822f683bab7d2c5a89914c92a/yarl-1.22.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:437840083abe022c978470b942ff832c3940b2ad3734d424b7eaffcd07f76737", size = 357811 }, - { url = "https://files.pythonhosted.org/packages/26/da/11374c04e8e1184a6a03cf9c8f5688d3e5cec83ed6f31ad3481b3207f709/yarl-1.22.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a899cbd98dce6f5d8de1aad31cb712ec0a530abc0a86bd6edaa47c1090138467", size = 351223 }, - { url = "https://files.pythonhosted.org/packages/82/8f/e2d01f161b0c034a30410e375e191a5d27608c1f8693bab1a08b089ca096/yarl-1.22.0-cp310-cp310-win32.whl", hash = "sha256:595697f68bd1f0c1c159fcb97b661fc9c3f5db46498043555d04805430e79bea", size = 82118 }, - { url = "https://files.pythonhosted.org/packages/62/46/94c76196642dbeae634c7a61ba3da88cd77bed875bf6e4a8bed037505aa6/yarl-1.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:cb95a9b1adaa48e41815a55ae740cfda005758104049a640a398120bf02515ca", size = 86852 }, - { url = "https://files.pythonhosted.org/packages/af/af/7df4f179d3b1a6dcb9a4bd2ffbc67642746fcafdb62580e66876ce83fff4/yarl-1.22.0-cp310-cp310-win_arm64.whl", hash = "sha256:b85b982afde6df99ecc996990d4ad7ccbdbb70e2a4ba4de0aecde5922ba98a0b", size = 82012 }, - { url = "https://files.pythonhosted.org/packages/73/ae/b48f95715333080afb75a4504487cbe142cae1268afc482d06692d605ae6/yarl-1.22.0-py3-none-any.whl", hash = "sha256:1380560bdba02b6b6c90de54133c81c9f2a453dee9912fe58c1dcced1edb7cff", size = 46814 }, +sdist = { url = "https://files.pythonhosted.org/packages/23/6e/beb1beec874a72f23815c1434518bfc4ed2175065173fb138c3705f658d4/yarl-1.23.0.tar.gz", hash = "sha256:53b1ea6ca88ebd4420379c330aea57e258408dd0df9af0992e5de2078dc9f5d5", size = 194676, upload-time = "2026-03-01T22:07:53.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/0d/9cc638702f6fc3c7a3685bcc8cf2a9ed7d6206e932a49f5242658047ef51/yarl-1.23.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cff6d44cb13d39db2663a22b22305d10855efa0fa8015ddeacc40bc59b9d8107", size = 123764, upload-time = "2026-03-01T22:04:09.7Z" }, + { url = "https://files.pythonhosted.org/packages/7a/35/5a553687c5793df5429cd1db45909d4f3af7eee90014888c208d086a44f0/yarl-1.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c53f8347cd4200f0d70a48ad059cabaf24f5adc6ba08622a23423bc7efa10d", size = 86282, upload-time = "2026-03-01T22:04:11.892Z" }, + { url = "https://files.pythonhosted.org/packages/68/2e/c5a2234238f8ce37a8312b52801ee74117f576b1539eec8404a480434acc/yarl-1.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a6940a074fb3c48356ed0158a3ca5699c955ee4185b4d7d619be3c327143e05", size = 86053, upload-time = "2026-03-01T22:04:13.292Z" }, + { url = "https://files.pythonhosted.org/packages/74/3f/bbd8ff36fb038622797ffbaf7db314918bb4d76f1cc8a4f9ca7a55fe5195/yarl-1.23.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ed5f69ce7be7902e5c70ea19eb72d20abf7d725ab5d49777d696e32d4fc1811d", size = 99395, upload-time = "2026-03-01T22:04:15.133Z" }, + { url = "https://files.pythonhosted.org/packages/77/04/9516bc4e269d2a3ec9c6779fcdeac51ce5b3a9b0156f06ac7152e5bba864/yarl-1.23.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:389871e65468400d6283c0308e791a640b5ab5c83bcee02a2f51295f95e09748", size = 92143, upload-time = "2026-03-01T22:04:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/c7/63/88802d1f6b1cb1fc67d67a58cd0cf8a1790de4ce7946e434240f1d60ab4a/yarl-1.23.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dda608c88cf709b1d406bdfcd84d8d63cff7c9e577a403c6108ce8ce9dcc8764", size = 107643, upload-time = "2026-03-01T22:04:18.519Z" }, + { url = "https://files.pythonhosted.org/packages/8e/db/4f9b838f4d8bdd6f0f385aed8bbf21c71ed11a0b9983305c302cbd557815/yarl-1.23.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8c4fe09e0780c6c3bf2b7d4af02ee2394439d11a523bbcf095cf4747c2932007", size = 108700, upload-time = "2026-03-01T22:04:20.373Z" }, + { url = "https://files.pythonhosted.org/packages/50/12/95a1d33f04a79c402664070d43b8b9f72dc18914e135b345b611b0b1f8cc/yarl-1.23.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c9921eb8bd12633b41ad27686bbb0b1a2a9b8452bfdf221e34f311e9942ed4", size = 102769, upload-time = "2026-03-01T22:04:23.055Z" }, + { url = "https://files.pythonhosted.org/packages/86/65/91a0285f51321369fd1a8308aa19207520c5f0587772cfc2e03fc2467e90/yarl-1.23.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5f10fd85e4b75967468af655228fbfd212bdf66db1c0d135065ce288982eda26", size = 101114, upload-time = "2026-03-01T22:04:25.031Z" }, + { url = "https://files.pythonhosted.org/packages/58/80/c7c8244fc3e5bc483dc71a09560f43b619fab29301a0f0a8f936e42865c7/yarl-1.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dbf507e9ef5688bada447a24d68b4b58dd389ba93b7afc065a2ba892bea54769", size = 98883, upload-time = "2026-03-01T22:04:27.281Z" }, + { url = "https://files.pythonhosted.org/packages/86/e7/71ca9cc9ca79c0b7d491216177d1aed559d632947b8ffb0ee60f7d8b23e3/yarl-1.23.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:85e9beda1f591bc73e77ea1c51965c68e98dafd0fec72cdd745f77d727466716", size = 94172, upload-time = "2026-03-01T22:04:28.554Z" }, + { url = "https://files.pythonhosted.org/packages/6a/3f/6c6c8a0fe29c26fb2db2e8d32195bb84ec1bfb8f1d32e7f73b787fcf349b/yarl-1.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0e1fdaa14ef51366d7757b45bde294e95f6c8c049194e793eedb8387c86d5993", size = 107010, upload-time = "2026-03-01T22:04:30.385Z" }, + { url = "https://files.pythonhosted.org/packages/56/38/12730c05e5ad40a76374d440ed8b0899729a96c250516d91c620a6e38fc2/yarl-1.23.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:75e3026ab649bf48f9a10c0134512638725b521340293f202a69b567518d94e0", size = 100285, upload-time = "2026-03-01T22:04:31.752Z" }, + { url = "https://files.pythonhosted.org/packages/34/92/6a7be9239f2347234e027284e7a5f74b1140cc86575e7b469d13fba1ebfe/yarl-1.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:80e6d33a3d42a7549b409f199857b4fb54e2103fc44fb87605b6663b7a7ff750", size = 108230, upload-time = "2026-03-01T22:04:33.844Z" }, + { url = "https://files.pythonhosted.org/packages/5e/81/4aebccfa9376bd98b9d8bfad20621a57d3e8cfc5b8631c1fa5f62cdd03f4/yarl-1.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5ec2f42d41ccbd5df0270d7df31618a8ee267bfa50997f5d720ddba86c4a83a6", size = 103008, upload-time = "2026-03-01T22:04:35.856Z" }, + { url = "https://files.pythonhosted.org/packages/38/0f/0b4e3edcec794a86b853b0c6396c0a888d72dfce19b2d88c02ac289fb6c1/yarl-1.23.0-cp310-cp310-win32.whl", hash = "sha256:debe9c4f41c32990771be5c22b56f810659f9ddf3d63f67abfdcaa2c6c9c5c1d", size = 83073, upload-time = "2026-03-01T22:04:38.268Z" }, + { url = "https://files.pythonhosted.org/packages/a0/71/ad95c33da18897e4c636528bbc24a1dd23fe16797de8bc4ec667b8db0ba4/yarl-1.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:ab5f043cb8a2d71c981c09c510da013bc79fd661f5c60139f00dd3c3cc4f2ffb", size = 87328, upload-time = "2026-03-01T22:04:39.558Z" }, + { url = "https://files.pythonhosted.org/packages/e2/14/dfa369523c79bccf9c9c746b0a63eb31f65db9418ac01275f7950962e504/yarl-1.23.0-cp310-cp310-win_arm64.whl", hash = "sha256:263cd4f47159c09b8b685890af949195b51d1aa82ba451c5847ca9bc6413c220", size = 82463, upload-time = "2026-03-01T22:04:41.454Z" }, + { url = "https://files.pythonhosted.org/packages/69/68/c8739671f5699c7dc470580a4f821ef37c32c4cb0b047ce223a7f115757f/yarl-1.23.0-py3-none-any.whl", hash = "sha256:a2df6afe50dea8ae15fa34c9f824a3ee958d785fd5d089063d960bae1daa0a3f", size = 48288, upload-time = "2026-03-01T22:07:51.388Z" }, ] From 03796ac52be3d00fcb310d0d4269f757ff6b2d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Mon, 20 Apr 2026 14:30:32 -0300 Subject: [PATCH 092/104] Feature/pdf layout anonymization (#76) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ feat(extractors): use pymupdf layout for pdf text extraction * ✨ feat(normalization): enhance document normalization to preserve paragraph structure * 📝 docs: document default values for extractor and normalization helpers * 🩹 fix(extractors): use pymupdf4llm.to_text with page_chunks for pdf paragraphs * ♻️ Add DOCX and PDF anonymizer modules - Implemented DocxAnonymizer class to handle anonymization of DOCX documents by replacing sensitive data with label tokens. This includes functionality for unzipping documents, parsing XML, editing content, and adding watermarks. - Developed PdfAnonymizer class for anonymizing PDF documents, utilizing pymupdf for document manipulation. This includes layout parsing, font caching, redaction operations, and watermarking. * 🔧 Enhance PDF and DOCX handling in anonymization process * 📝 Update backend module references for document rendering in README * ✅ Update tests to use DOCX format for document anonymization and enhance mock behavior * ✨ Add end-to-end PDF anonymization notebook with PyMuPDF and AymurAI API * ♻️ Rework PDF anonymization for precise spans and widget handling * 🔧 Update model_dump calls to exclude None values for improved data handling * 📝 Add docstrings to label replacement functions * ♻️ Refactor watermark handling and optimize PDF token aliasing * ✅ Add integration tests for merging fragmented numeric labels and excluding null alt attributes in PDF anonymization * ➖ Remove opencv-python-headless dependency from project requirements * ♻️ Implement paragraph splitting function to enhance document text extraction * 🔧 Update dependency installation command to prevent Python downloads * 🔥 Remove redundant tests for merging fragmented numeric labels and PDF anonymization * ♻️ Refactor anonymizer tests to use DOCX format and enhance mock functionality * 🔧 Add xfail marker for PDF extraction test on Windows due to tensor type issue * ✨ Enhance PDF anonymization by adding cleanup rects, removing overlapping links, and scrubbing metadata * 🔧 Remove redundant return statement in _label_replacement_text function * ♻️ Refactor anonymization module: split pdf and docx internals by format * ✅ Add integration tests for PDF and DOCX anonymizers, including metadata scrubbing and link preservation * ✨ Add watermark layout adjustments to avoid footer content overlap in PDF anonymization * ✅ Add integration test to ensure watermark is positioned away from footer content in PDF anonymization * 🩹 Fix: read docx xml as utf-8 across platforms * ✅ Add Windows-specific xfail marker for PDF tests and implement UTF-8 XML reading test --- .github/workflows/pytest.yml | 2 +- .../routers/anonymizer/anonymizer.py | 102 ++- .../routers/misc/document_extract.py | 21 +- .../database/crud/anonymization/paragraph.py | 8 +- aymurai/settings.py | 4 + aymurai/text/anonymization/__init__.py | 18 +- aymurai/text/anonymization/alignment.py | 81 +- aymurai/text/anonymization/base.py | 79 ++ aymurai/text/anonymization/doc_anonymizer.py | 88 -- aymurai/text/anonymization/docx/__init__.py | 3 + aymurai/text/anonymization/docx/anonymizer.py | 122 +++ .../{watermarks.py => docx/watermark.py} | 0 .../{xml_docx.py => docx/xml.py} | 0 aymurai/text/anonymization/pdf/__init__.py | 3 + aymurai/text/anonymization/pdf/anonymizer.py | 100 +++ aymurai/text/anonymization/pdf/common.py | 620 +++++++++++++ aymurai/text/anonymization/pdf/layout.py | 510 +++++++++++ aymurai/text/anonymization/pdf/ops.py | 828 ++++++++++++++++++ aymurai/text/anonymization/pdf/sanitize.py | 294 +++++++ aymurai/text/anonymization/pdf/watermark.py | 522 +++++++++++ aymurai/text/anonymization/pdf/widgets.py | 323 +++++++ aymurai/text/extractors/pdf.py | 20 +- aymurai/text/extractors/utils.py | 146 ++- aymurai/text/normalize.py | 67 +- docs/es/pipelines/anonymizer/README.md | 2 +- docs/pipelines/anonymizer/README.md | 2 +- .../pdf-support/06-pymupdf-layout.ipynb | 253 ++++++ .../api/routers/anonymizer/test_anonymizer.py | 423 ++++++++- .../api/routers/misc/test_document_extract.py | 6 + tests/api/routers/test_pipeline_flows.py | 35 +- 30 files changed, 4392 insertions(+), 290 deletions(-) create mode 100644 aymurai/text/anonymization/base.py delete mode 100644 aymurai/text/anonymization/doc_anonymizer.py create mode 100644 aymurai/text/anonymization/docx/__init__.py create mode 100644 aymurai/text/anonymization/docx/anonymizer.py rename aymurai/text/anonymization/{watermarks.py => docx/watermark.py} (100%) rename aymurai/text/anonymization/{xml_docx.py => docx/xml.py} (100%) create mode 100644 aymurai/text/anonymization/pdf/__init__.py create mode 100644 aymurai/text/anonymization/pdf/anonymizer.py create mode 100644 aymurai/text/anonymization/pdf/common.py create mode 100644 aymurai/text/anonymization/pdf/layout.py create mode 100644 aymurai/text/anonymization/pdf/ops.py create mode 100644 aymurai/text/anonymization/pdf/sanitize.py create mode 100644 aymurai/text/anonymization/pdf/watermark.py create mode 100644 aymurai/text/anonymization/pdf/widgets.py create mode 100644 notebooks/experiments/pdf-support/06-pymupdf-layout.ipynb diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 4636bc5c..319cd7f0 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -64,7 +64,7 @@ jobs: - name: Install dependencies run: | - uv sync --frozen --python python --no-dev --no-managed-python --group tests + uv sync --frozen --python python --no-dev --no-python-downloads --group tests - name: Run api tests env: diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 65a36131..6a48c33b 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -5,7 +5,7 @@ from threading import Lock import torch -from fastapi import Body, Depends, Form, Query, UploadFile +from fastapi import Body, Depends, Form, HTTPException, Query, UploadFile from fastapi.responses import FileResponse from fastapi.routing import APIRouter from sqlmodel import Session @@ -31,7 +31,10 @@ TextRequest, ) from aymurai.settings import settings -from aymurai.text.anonymization import DocAnonymizer, replace_labels_in_text +from aymurai.text.anonymization import ( + InvalidDocumentAnonymizer, + get_anonymizer, +) from aymurai.text.extraction import MIMETYPE_EXTENSION_MAPPER from aymurai.utils.entity_disambiguation import ( build_canonical_entities, @@ -514,11 +517,21 @@ async def anonymizer_compile_document( """ logger.info(f"receiving => {file.filename}") extension = MIMETYPE_EXTENSION_MAPPER.get(file.content_type) - logger.info(f"detection extension: {extension} ({file.content_type})") + file_suffix = os.path.splitext(file.filename or "")[1].lower() + + if extension is None and file_suffix: + extension = file_suffix.lstrip(".") + + if extension not in {"docx", "pdf"}: + raise HTTPException( + status_code=400, + detail=f"Unsupported format for anonymization: {extension or 'unknown'}", + ) + + logger.info(f"detected extension: {extension} ({file.content_type})") # Create a temporary file - _, suffix = os.path.splitext(file.filename) - suffix = suffix if suffix == ".docx" else ".txt" + suffix = f".{extension}" tmp_dir = tempfile.gettempdir() # Use delete=False to avoid the file being deleted when the NamedTemporaryFile object is closed @@ -537,7 +550,7 @@ async def anonymizer_compile_document( annots_json = json.loads(annotations) annots = DocumentAnnotations.model_validate(annots_json) - logger.info(f"processing annotations => {annots}") + effective_label_policies = _merge_label_policies(annots.label_policies) effective_render_policy = _merge_render_policy(annots.render_policy) @@ -562,9 +575,6 @@ async def anonymizer_compile_document( override=False, ) - # Anonymize the document - doc_anonymizer = DocAnonymizer() - filtered_annotations = [] for paragraph in annots.data: filtered_labels = [ @@ -583,39 +593,36 @@ async def anonymizer_compile_document( filtered_annotations, effective_render_policy, effective_label_policies ) - if suffix == ".docx": - item = {"path": tmp_filename} - doc_anonymizer.render_context = render_context - doc_anonymizer( - item, - [ - document_information.model_dump() - for document_information in filtered_annotations - ], + preds = [ + document_information.model_dump(mode="json", exclude_none=True) + for document_information in filtered_annotations + ] + + try: + anonymizer = get_anonymizer(extension) + anonymized_path = anonymizer( + {"path": tmp_filename}, + preds, tmp_dir, + render_context=render_context, + ) + except (ValueError, InvalidDocumentAnonymizer) as exc: + if os.path.exists(tmp_filename): + os.remove(tmp_filename) + raise HTTPException(status_code=400, detail=str(exc)) from exc + + if extension == "pdf": + if os.path.exists(tmp_filename): + os.remove(tmp_filename) + + return FileResponse( + anonymized_path, + background=BackgroundTask(os.remove, anonymized_path), + media_type="application/pdf", + filename=f"{os.path.splitext(file.filename)[0]}.pdf", ) - logger.info(f"saved temp file on local storage => {tmp_filename}") - - else: - # Export as raw document - anonymized_doc = [ - replace_labels_in_text( - document_information.model_dump(), - render_context=render_context, - ) - .replace("<", "<") - .replace(">", ">") - for document_information in filtered_annotations - ] - with open(tmp_filename, "w") as f: - f.write("\n".join(anonymized_doc)) - - # Add watermark to the end of the document - f.write( - "\n\nDocumento anonimizado por AymurAI\n\nhttps://www.aymurai.info/" - ) - # Convert to ODT + # DOCX flow keeps ODT output cmd = [ settings.LIBREOFFICE_BIN, "--headless", @@ -623,9 +630,8 @@ async def anonymizer_compile_document( "odt", "--outdir", tmp_dir, - tmp_filename, + anonymized_path, ] - logger.info(f"Executing: {' '.join(cmd)}") try: @@ -633,20 +639,20 @@ async def anonymizer_compile_document( cmd, shell=False, encoding="utf-8", errors="ignore" ) logger.info(f"LibreOffice output: {output}") - except subprocess.CalledProcessError as e: + except subprocess.CalledProcessError as exc: raise RuntimeError( - f"LibreOffice conversion failed: {e.output.decode('utf-8', errors='ignore')}" - ) + f"LibreOffice conversion failed: {exc.output.decode('utf-8', errors='ignore')}" + ) from exc + finally: + if os.path.exists(tmp_filename): + os.remove(tmp_filename) - odt = tmp_filename.replace(suffix, ".odt") + odt = f"{os.path.splitext(anonymized_path)[0]}.odt" logger.info(f"Expected output file path: {odt}") if not os.path.exists(odt): raise RuntimeError(f"File at path {odt} does not exist.") - # Ensure the temporary file is deleted - os.remove(tmp_filename) - return FileResponse( odt, background=BackgroundTask(os.remove, odt), diff --git a/aymurai/api/endpoints/routers/misc/document_extract.py b/aymurai/api/endpoints/routers/misc/document_extract.py index 37b7d0a4..ba315b74 100644 --- a/aymurai/api/endpoints/routers/misc/document_extract.py +++ b/aymurai/api/endpoints/routers/misc/document_extract.py @@ -31,7 +31,7 @@ def extraction(path: str) -> str: str: Extracted text from the document. """ text = extract_document(path) - return document_normalize(text) if text else "" + return document_normalize(text, preserve_paragraphs=True) if text else "" def run_safe_text_extraction( @@ -63,6 +63,20 @@ def run_safe_text_extraction( raise +def _split_document_paragraphs(document: str) -> list[str]: + if re.search(r"\n\s*\n+", document): + raw_paragraphs = re.split(r"\n\s*\n+", document) + else: + raw_paragraphs = document.splitlines() + + paragraphs = [ + re.sub(r"[ \t]{2,}", " ", paragraph.strip()) + for paragraph in raw_paragraphs + if paragraph.strip() + ] + return list(unique_justseen(paragraphs)) + + @router.post("/document-extract", response_model=Document) def plain_text_extractor(file: UploadFile) -> Document: """ @@ -111,9 +125,6 @@ def plain_text_extractor(file: UploadFile) -> Document: logger.info(f"removed temp file from local storage => {tmp_filename}") document_id = data_to_uuid(data) - - paragraphs = [line.strip() for line in document.split("\n") if line.strip()] - paragraphs = [re.sub(r"\s{2,}", " ", line) for line in paragraphs] - paragraphs = list(unique_justseen(paragraphs)) + paragraphs = _split_document_paragraphs(document) return Document(document=paragraphs, document_id=document_id) diff --git a/aymurai/database/crud/anonymization/paragraph.py b/aymurai/database/crud/anonymization/paragraph.py index 1d169036..17f826b8 100644 --- a/aymurai/database/crud/anonymization/paragraph.py +++ b/aymurai/database/crud/anonymization/paragraph.py @@ -27,7 +27,7 @@ def _serialize_doclabels(value: list[DocLabel] | None): """ if value is None: return None - return _DOC_LABELS_ADAPTER.dump_python(value, mode="json") + return _DOC_LABELS_ADAPTER.dump_python(value, mode="json", exclude_none=True) def _normalize_paragraph_payload(payload: dict) -> dict: @@ -63,7 +63,7 @@ def anonymization_paragraph_create( Returns: AnonymizationParagraph: The persisted paragraph record. """ - payload = _normalize_paragraph_payload(paragraph_in.model_dump()) + payload = _normalize_paragraph_payload(paragraph_in.model_dump(exclude_none=True)) new_paragraph = AnonymizationParagraph(**payload) if override: @@ -171,14 +171,14 @@ def anonymization_paragraph_batch_create_update( paragraph = session.get(AnonymizationParagraph, paragraph_id) if paragraph: - payload = _normalize_paragraph_payload(p_in.model_dump()) + payload = _normalize_paragraph_payload(p_in.model_dump(exclude_none=True)) payload.pop("id", None) for field, value in payload.items(): if value is not None: setattr(paragraph, field, value) else: - payload = _normalize_paragraph_payload(p_in.model_dump()) + payload = _normalize_paragraph_payload(p_in.model_dump(exclude_none=True)) paragraph = AnonymizationParagraph(**payload) session.add(paragraph) diff --git a/aymurai/settings.py b/aymurai/settings.py index 3844d767..2079f561 100644 --- a/aymurai/settings.py +++ b/aymurai/settings.py @@ -65,6 +65,10 @@ def assemble_cors_origins(cls, v) -> list[str]: MEMORY_CACHE_TTL: int = 60 LIBREOFFICE_BIN: str = "libreoffice" + PDF_WATERMARK_FONT_REGULAR: str | None = None + PDF_WATERMARK_FONT_BOLD: str | None = None + ANONYMIZATION_METADATA_CREATOR: str = "AymurAI" + ANONYMIZATION_METADATA_PRODUCER: str = "AymurAI" # Disambiguation Config diff --git a/aymurai/text/anonymization/__init__.py b/aymurai/text/anonymization/__init__.py index 7f839a95..51f3a65b 100644 --- a/aymurai/text/anonymization/__init__.py +++ b/aymurai/text/anonymization/__init__.py @@ -1,7 +1,21 @@ from aymurai.text.anonymization.alignment import replace_labels_in_text -from aymurai.text.anonymization.doc_anonymizer import DocAnonymizer +from aymurai.text.anonymization.base import ( + BaseAnonymizer, + InvalidDocumentAnonymizer, + get_anonymizer, + register_anonymizer, + supported_extensions, +) +from aymurai.text.anonymization.docx import DocxAnonymizer +from aymurai.text.anonymization.pdf import PdfAnonymizer __all__ = [ - "DocAnonymizer", + "BaseAnonymizer", + "DocxAnonymizer", + "PdfAnonymizer", + "InvalidDocumentAnonymizer", + "get_anonymizer", + "register_anonymizer", + "supported_extensions", "replace_labels_in_text", ] diff --git a/aymurai/text/anonymization/alignment.py b/aymurai/text/anonymization/alignment.py index 3a6386b3..e4f2547e 100644 --- a/aymurai/text/anonymization/alignment.py +++ b/aymurai/text/anonymization/alignment.py @@ -9,9 +9,9 @@ from joblib import hash from more_itertools import flatten +from aymurai.meta.api_interfaces import LabelPolicy from aymurai.models.flair.utils import FlairTextNormalize from aymurai.utils.alignment.core import align_text, tokenize -from aymurai.meta.api_interfaces import LabelPolicy REGEX_PARAGRAPH = r"((?.*?)(\/w:p\b)" REGEX_FRAGMENT = r"(?(?P.*?)(<.*?\/w:t)" @@ -61,6 +61,71 @@ def resolve_render_token(label: dict, render_context: dict | None = None) -> str return f"{base}_{index}" +def _label_replacement_start(label: dict) -> int: + """ + Determines the start character index for a label, considering possible alternative attributes. + + Args: + label (dict): Label dictionary which may contain alternative start character attributes. + + Returns: + int: The start character index for the label. + """ + attrs = label.get("attrs") or {} + alt_start = attrs.get("aymurai_alt_start_char") + start_char = label.get("start_char") + return int(alt_start if alt_start is not None else (start_char or 0)) + + +def _label_replacement_end(label: dict) -> int: + """ + Determines the end character index for a label, considering possible alternative attributes. + + Args: + label (dict): Label dictionary which may contain alternative end character attributes. + + Returns: + int: The end character index for the label. + """ + attrs = label.get("attrs") or {} + alt_end = attrs.get("aymurai_alt_end_char") + end_char = label.get("end_char") + return int(alt_end if alt_end is not None else (end_char or 0)) + + +def _label_replacement_text(label: dict, document: str) -> str: + """ + Determines the replacement text for a label, considering possible alternative attributes. + + Args: + label (dict): Label dictionary which may contain alternative text attributes. + document (str): The document text from which to extract the label text. + + Returns: + str: The text for the label, considering possible alternative attributes. + """ + attrs = label.get("attrs") or {} + + alt_text = attrs.get("aymurai_alt_text") + if alt_text is not None: + return str(alt_text) if alt_text else "" + + alt_start = attrs.get("aymurai_alt_start_char") + alt_end = attrs.get("aymurai_alt_end_char") + if alt_start is not None and alt_end is not None: + start_char, end_char = int(alt_start), int(alt_end) + if 0 <= start_char < end_char <= len(document): + return document[start_char:end_char] + + start_char = int(label.get("start_char") or 0) + end_char = int(label.get("end_char") or 0) + if 0 <= start_char < end_char <= len(document): + return document[start_char:end_char] + + text = label.get("text") + return str(text) if text else "" + + def unify_consecutive_labels( sample: dict, text_key: str = "document", @@ -93,9 +158,11 @@ def unify_consecutive_labels( # Iterate over labels for label in labels: # Get attributes - text = label["attrs"]["aymurai_alt_text"] or label["text"] - start_char = label["attrs"]["aymurai_alt_start_char"] or label["start_char"] - end_char = label["attrs"]["aymurai_alt_end_char"] or label["end_char"] + text = _label_replacement_text(label, document) + start_char = _label_replacement_start(label) + end_char = _label_replacement_end(label) + if not text or end_char <= start_char: + continue aymurai_label = resolve_render_token(label, render_context) if current_group is None: @@ -115,7 +182,7 @@ def unify_consecutive_labels( else: # Finish the current group and start a new one current_group["text"] = document[ - current_group["start_char"] : current_group["end_char"] + 1 + current_group["start_char"] : current_group["end_char"] ] unified_labels.append(current_group) current_group = { @@ -128,7 +195,7 @@ def unify_consecutive_labels( # Finish the last group if current_group is not None: current_group["text"] = document[ - current_group["start_char"] : current_group["end_char"] + 1 + current_group["start_char"] : current_group["end_char"] ] unified_labels.append(current_group) @@ -271,7 +338,7 @@ def index_paragraphs(file: str) -> list[dict]: list[dict]: A list of dictionaries representing the indexed paragraphs. """ # Read the XML file - with open(file) as f: + with open(file, encoding="utf-8-sig") as f: xml = f.read() paragraphs = [] diff --git a/aymurai/text/anonymization/base.py b/aymurai/text/anonymization/base.py new file mode 100644 index 00000000..a1631159 --- /dev/null +++ b/aymurai/text/anonymization/base.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from pathlib import Path +from typing import Any + + +class InvalidDocumentAnonymizer(Exception): + """Raised when an anonymizer receives an invalid or unsupported document.""" + + +class BaseAnonymizer(ABC): + """Common interface shared by all document anonymizers.""" + + extension: str + + @property + def __name__(self) -> str: + return self.__class__.__name__ + + def ensure_file(self, path: Path) -> Path: + if not path.exists(): + raise InvalidDocumentAnonymizer(f"Invalid path: {path}") + return path + + def __call__( + self, + item: dict, + preds: list[dict], + output_dir: str = ".", + render_context: dict[str, Any] | None = None, + ) -> str: + return self.anonymize(item, preds, output_dir, render_context=render_context) + + @abstractmethod + def anonymize( + self, + item: dict, + preds: list[dict], + output_dir: str = ".", + render_context: dict[str, Any] | None = None, + ) -> str: + """Anonymize a document and return the output path.""" + + +_REGISTRY: dict[str, type[BaseAnonymizer]] = {} + + +def register_anonymizer(cls: type[BaseAnonymizer]) -> type[BaseAnonymizer]: + extension = getattr(cls, "extension", None) + if not extension: + raise ValueError( + f"Anonymizer {cls.__name__} must define an 'extension' attribute" + ) + + _REGISTRY[extension.lower()] = cls + return cls + + +def get_anonymizer(extension: str) -> BaseAnonymizer: + normalized = extension.lower() + try: + anonymizer_cls = _REGISTRY[normalized] + except KeyError as exc: + raise ValueError(f"Unsupported extension: {extension}") from exc + return anonymizer_cls() + + +def supported_extensions() -> set[str]: + return set(_REGISTRY.keys()) + + +__all__ = [ + "BaseAnonymizer", + "InvalidDocumentAnonymizer", + "get_anonymizer", + "register_anonymizer", + "supported_extensions", +] diff --git a/aymurai/text/anonymization/doc_anonymizer.py b/aymurai/text/anonymization/doc_anonymizer.py deleted file mode 100644 index 7feb6f3a..00000000 --- a/aymurai/text/anonymization/doc_anonymizer.py +++ /dev/null @@ -1,88 +0,0 @@ -import os -import tempfile -from glob import glob - -from more_itertools import flatten - -from aymurai.meta.pipeline_interfaces import Transform -from aymurai.text.anonymization.alignment import ( - index_paragraphs, - match_paragraphs_with_predictions, -) -from aymurai.text.anonymization.watermarks import add_footer_watermark -from aymurai.text.anonymization.xml_docx import ( - create_docx, - replace_text_in_xml, - unzip_document, -) -from aymurai.utils.cache import cache_load, cache_save, get_cache_key - - -class DocAnonymizer(Transform): - """ - Anonymize document by replacing sensitive data with label tokens - """ - - def __init__(self, use_cache: bool = False): - self.use_cache = use_cache - self.render_context = None - - def __call__(self, item: dict, preds: list[dict], output_dir: str = ".") -> None: - """ - Performs the anonymization process on a document. - - Args: - item (dict): The document item to be anonymized. - preds (list[dict]): The list of predictions for the document. - output_dir (str, optional): The directory to save the anonymized document. - Defaults to ".". - - Raises: - ValueError: If the document has an extension other than `.docx`. - """ - item_path = item["path"] - - if not os.path.splitext(item_path)[-1] == ".docx": - raise ValueError("Only `.docx` extension is allowed.") - - if not item.get("data"): - item["data"] = {} - - cache_key = get_cache_key(item_path, self.__name__) - if self.use_cache and (cache_data := cache_load(key=cache_key)): - paragraphs = cache_data - else: - # Unzip document into a temporary directory - with tempfile.TemporaryDirectory() as tempdir: - unzip_document(item_path, tempdir) - - # Parse XML files - xml_files = glob(f"{tempdir}/**/*.xml", recursive=True) - paragraphs = (index_paragraphs(file) for file in xml_files) - paragraphs = list(flatten(paragraphs)) - - # Filter out empty paragraphs - paragraphs = [ - paragraph - for paragraph in paragraphs - if paragraph["plain_text"].strip() - ] - - # Matching - paragraphs = match_paragraphs_with_predictions(paragraphs, preds) - - # Edit XML filess - replace_text_in_xml(paragraphs, tempdir, self.render_context) - - # Recreate anonymized document - os.makedirs(output_dir, exist_ok=True) - create_docx( - tempdir, - f"{output_dir}/{os.path.basename(item_path)}", - ) - - # Add watermark to the footer - add_footer_watermark(f"{output_dir}/{os.path.basename(item_path)}") - - if self.use_cache: - cache_save(paragraphs, key=cache_key) diff --git a/aymurai/text/anonymization/docx/__init__.py b/aymurai/text/anonymization/docx/__init__.py new file mode 100644 index 00000000..5d5d0aca --- /dev/null +++ b/aymurai/text/anonymization/docx/__init__.py @@ -0,0 +1,3 @@ +from aymurai.text.anonymization.docx.anonymizer import DocxAnonymizer + +__all__ = ["DocxAnonymizer"] diff --git a/aymurai/text/anonymization/docx/anonymizer.py b/aymurai/text/anonymization/docx/anonymizer.py new file mode 100644 index 00000000..73c43487 --- /dev/null +++ b/aymurai/text/anonymization/docx/anonymizer.py @@ -0,0 +1,122 @@ +import os +import tempfile +from datetime import datetime, timezone +from glob import glob +from pathlib import Path +from typing import Any + +from docx import Document +from more_itertools import flatten + +from aymurai.text.anonymization.alignment import ( + index_paragraphs, + match_paragraphs_with_predictions, +) +from aymurai.text.anonymization.base import ( + BaseAnonymizer, + InvalidDocumentAnonymizer, + register_anonymizer, +) +from aymurai.text.anonymization.docx.watermark import add_footer_watermark +from aymurai.settings import settings +from aymurai.text.anonymization.docx.xml import ( + create_docx, + replace_text_in_xml, + unzip_document, +) +from aymurai.utils.cache import cache_load, cache_save, get_cache_key + + +def _set_aymurai_core_properties(doc_path: str) -> None: + """ + Applies the configured AymurAI tooling metadata fields to the DOCX core properties. + + Args: + doc_path (str): The path to the DOCX document to update. + """ + document = Document(doc_path) + core_properties = document.core_properties + core_properties.author = "" + core_properties.last_modified_by = settings.ANONYMIZATION_METADATA_CREATOR + core_properties.modified = datetime.now(timezone.utc) + document.save(doc_path) + + +@register_anonymizer +class DocxAnonymizer(BaseAnonymizer): + """ + Anonymize DOCX documents by replacing sensitive data with label tokens. + """ + + extension = "docx" + + def __init__(self, use_cache: bool = False): + self.use_cache = use_cache + + def anonymize( + self, + item: dict, + preds: list[dict], + output_dir: str = ".", + render_context: dict[str, Any] | None = None, + ) -> str: + """ + Anonymizes a DOCX document using the matched paragraph predictions. + + Args: + item (dict): The item dictionary containing the input DOCX path. + preds (list[dict]): The predictions to apply to the document. + output_dir (str, optional): The directory where the anonymized document should be written. Defaults to '.'. + render_context (dict[str, Any] | None, optional): The rendering context used to resolve replacement tokens. + Defaults to None. + + Returns: + str: The path to the anonymized DOCX output file. + """ + item_path = Path(item["path"]) + file_path = self.ensure_file(item_path) + + if file_path.suffix.lower() != ".docx": + raise InvalidDocumentAnonymizer("Only `.docx` extension is allowed.") + + if not item.get("data"): + item["data"] = {} + + cache_key = get_cache_key(str(file_path), self.__name__) + if self.use_cache and (cache_data := cache_load(key=cache_key)): + paragraphs = cache_data + else: + # Unzip document into a temporary directory + with tempfile.TemporaryDirectory() as tempdir: + unzip_document(str(file_path), tempdir) + + # Parse XML files + xml_files = glob(f"{tempdir}/**/*.xml", recursive=True) + paragraphs = (index_paragraphs(file) for file in xml_files) + paragraphs = list(flatten(paragraphs)) + + # Filter out empty paragraphs + paragraphs = [ + paragraph + for paragraph in paragraphs + if paragraph["plain_text"].strip() + ] + # Matching + paragraphs = match_paragraphs_with_predictions(paragraphs, preds) + + # Edit XML files + replace_text_in_xml(paragraphs, tempdir, render_context) + + # Recreate anonymized document + os.makedirs(output_dir, exist_ok=True) + output_path = f"{output_dir}/{os.path.basename(str(file_path))}" + create_docx(tempdir, output_path) + + # Add metadata branding and the footer watermark + _set_aymurai_core_properties(output_path) + add_footer_watermark(output_path) + + if self.use_cache: + cache_save(paragraphs, key=cache_key) + + return f"{output_dir}/{os.path.basename(str(file_path))}" diff --git a/aymurai/text/anonymization/watermarks.py b/aymurai/text/anonymization/docx/watermark.py similarity index 100% rename from aymurai/text/anonymization/watermarks.py rename to aymurai/text/anonymization/docx/watermark.py diff --git a/aymurai/text/anonymization/xml_docx.py b/aymurai/text/anonymization/docx/xml.py similarity index 100% rename from aymurai/text/anonymization/xml_docx.py rename to aymurai/text/anonymization/docx/xml.py diff --git a/aymurai/text/anonymization/pdf/__init__.py b/aymurai/text/anonymization/pdf/__init__.py new file mode 100644 index 00000000..21271aae --- /dev/null +++ b/aymurai/text/anonymization/pdf/__init__.py @@ -0,0 +1,3 @@ +from aymurai.text.anonymization.pdf.anonymizer import PdfAnonymizer + +__all__ = ["PdfAnonymizer"] diff --git a/aymurai/text/anonymization/pdf/anonymizer.py b/aymurai/text/anonymization/pdf/anonymizer.py new file mode 100644 index 00000000..0030c24b --- /dev/null +++ b/aymurai/text/anonymization/pdf/anonymizer.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +import os +from pathlib import Path +from typing import Any + +import pymupdf +import pymupdf.layout # noqa: F401 # activates layout support +from pymupdf4llm.helpers import document_layout as pymupdf4llm_document_layout + +from aymurai.text.anonymization.base import ( + BaseAnonymizer, + InvalidDocumentAnonymizer, + register_anonymizer, +) +from aymurai.text.anonymization.pdf.layout import ( + _apply_minimal_boundary_merge, + _build_layout_paragraphs, + _match_predictions_to_layout, +) +from aymurai.text.anonymization.pdf.ops import ( + _apply_redactions, + _collect_page_redactions, +) +from aymurai.text.anonymization.pdf.sanitize import ( + _collect_link_cleanup_rects, + _sanitize_document, +) +from aymurai.text.anonymization.pdf.watermark import add_pdf_footer_watermark + + +@register_anonymizer +class PdfAnonymizer(BaseAnonymizer): + """ + Anonymize PDF documents by replacing sensitive data with label tokens. + """ + + extension = "pdf" + + def anonymize( + self, + item: dict, + preds: list[dict], + output_dir: str = ".", + render_context: dict[str, Any] | None = None, + ) -> str: + """ + Anonymizes a PDF document using the matched paragraph predictions. + + Args: + item (dict): The item dictionary containing the input PDF path. + preds (list[dict]): The predictions to apply to the document. + output_dir (str, optional): The directory where the anonymized document should be written. Defaults to '.'. + render_context (dict[str, Any] | None, optional): The rendering context used to resolve replacement tokens. Defaults to None. + + Returns: + str: The path to the anonymized PDF output file. + """ + item_path = Path(item["path"]) + file_path = self.ensure_file(item_path) + + if file_path.suffix.lower() != ".pdf": + raise InvalidDocumentAnonymizer("Only `.pdf` extension is allowed.") + + with pymupdf.open(str(file_path)) as doc: + parsed_doc = pymupdf4llm_document_layout.parse_document( + doc, + filename=str(file_path), + show_progress=False, + force_text=True, + use_ocr=False, + force_ocr=False, + ) + + layout_paragraphs = _build_layout_paragraphs(parsed_doc) + matched_paragraphs = _match_predictions_to_layout( + layout_paragraphs, + preds, + ) + + _apply_minimal_boundary_merge(matched_paragraphs, render_context) + page_ops, widget_ops, signature_widget_ops = _collect_page_redactions( + doc, + matched_paragraphs, + render_context, + ) + _apply_redactions(doc, page_ops, widget_ops, signature_widget_ops) + cleanup_rects = _collect_link_cleanup_rects( + page_ops, + widget_ops, + signature_widget_ops, + ) + _sanitize_document(doc, cleanup_rects) + add_pdf_footer_watermark(doc) + + os.makedirs(output_dir, exist_ok=True) + output_path = Path(output_dir) / f"{file_path.stem}.anonymized.pdf" + doc.save(str(output_path), garbage=4, clean=1, deflate=1) + + return str(output_path) diff --git a/aymurai/text/anonymization/pdf/common.py b/aymurai/text/anonymization/pdf/common.py new file mode 100644 index 00000000..91f42927 --- /dev/null +++ b/aymurai/text/anonymization/pdf/common.py @@ -0,0 +1,620 @@ +from __future__ import annotations + +import re +from functools import lru_cache +from typing import Any +from unicodedata import normalize + +import pymupdf + +TEXT_FLAG_ITALIC = 2 +TEXT_FLAG_SERIF = 4 +TEXT_FLAG_MONOSPACED = 8 +TEXT_FLAG_BOLD = 16 +PDF_TAG_MIN_FONT_SIZE = 7.0 +PDF_TAG_FONT_STEP = 0.5 +PDF_TAG_MAX_ABBREVIATION = 3 +PDF_TOKEN_ALIAS_MAP: dict[str, tuple[str, str]] = { + "CORREO_ELECTRONICO": ("CORREO", "MAIL"), + "CUIT_CUIL": ("CUIT", "CUIL"), + "DIRECCION": ("DIREC", "DIR"), + "ESTUDIOS": ("ESTUD", "EDU"), + "MARCA_AUTOMOVIL": ("MARCA_AUTO", "AUTO"), + "NACIONALIDAD": ("NACIONAL", "NAC"), + "NOMBRE_ARCHIVO": ("NOM_ARCH", "ARCH"), + "NUM_ACTUACION": ("NUM_ACT", "ACT"), + "NUM_CAJA_AHORRO": ("NUM_CAJA", "CAJA"), + "NUM_EXPEDIENTE": ("NUM_EXP", "EXPTE"), + "NUM_MATRICULA": ("NUM_MAT", "MAT"), + "PATENTE_DOMINIO": ("PAT_DOM", "PAT"), + "TELEFONO": ("TELEF", "TEL"), + "TEXTO_ANONIMIZAR": ("TEXTO_ANON", "ANON"), + "USUARIX": ("USUAR", "USR"), +} +PDF_TAG_RECT_X_PADDING = 0.5 +PDF_TAG_RECT_Y_PADDING = 0.0 +PDF_TAG_RECT_INSET = 0.5 +PDF_TAG_RECT_GAP_FACTOR = 0.5 +PDF_TAG_RECT_GAP_MIN = 3.0 +PDF_TAG_RECT_GAP_MAX = 8.0 + + +def _line_text(line: dict) -> str: + """ + Builds the plain text content for a parsed PDF line. + + Args: + line (dict): The parsed line metadata being processed. + + Returns: + str: The concatenated text content for the line. + """ + return "".join(span.get("text", "") for span in line.get("spans", [])) + + +def _rect_tuple(value: Any) -> tuple[float, float, float, float]: + """ + Normalizes a rectangle-like value into a coordinate tuple. + + Args: + value (Any): The rectangle-like value to normalize. + + Returns: + tuple[float, float, float, float]: The normalized rectangle coordinates. + """ + if isinstance(value, pymupdf.Rect): + return (float(value.x0), float(value.y0), float(value.x1), float(value.y1)) + if isinstance(value, (list, tuple)) and len(value) == 4: + return (float(value[0]), float(value[1]), float(value[2]), float(value[3])) + raise ValueError(f"Invalid rectangle value: {value}") + + +def _default_style(fallback_size: float = 10.0) -> dict[str, Any]: + """ + Builds a default text style dictionary for PDF rendering helpers. + + Args: + fallback_size (float, optional): The fallback font size used when no style data is available. Defaults to 10.0. + + Returns: + dict[str, Any]: The default style dictionary. + """ + return { + "font": "", + "flags": 0, + "color": (0.0, 0.0, 0.0), + "size": fallback_size, + "ascender": 0.8, + "descender": -0.2, + } + + +def _span_text_weight(span: dict) -> tuple[int, float]: + """ + Computes a sorting weight for a span based on text length and size. + + Args: + span (dict): The span metadata being evaluated. + + Returns: + tuple[int, float]: The text-length and size weight for the span. + """ + text = str(span.get("text") or "").strip() + return (len(text), float(span.get("size") or 0.0)) + + +def _pdf_color_from_span(span: dict) -> tuple[float, float, float]: + """ + Converts a span color value into PDF RGB components. + + Args: + span (dict): The span metadata being evaluated. + + Returns: + tuple[float, float, float]: The PDF RGB color components for the span. + """ + try: + return tuple( + float(value) for value in pymupdf.sRGB_to_pdf(int(span.get("color") or 0)) + ) + except Exception: + return (0.0, 0.0, 0.0) + + +def _line_style(line: dict, fallback_size: float = 10.0) -> dict[str, Any]: + """ + Determines the dominant text style for a parsed PDF line. + + Args: + line (dict): The parsed line metadata being processed. + fallback_size (float, optional): The fallback font size used when no style data is available. Defaults to 10.0. + + Returns: + dict[str, Any]: The dominant style dictionary for the line. + """ + spans = [ + span for span in line.get("spans") or [] if str(span.get("text") or "").strip() + ] + if not spans: + return _default_style(fallback_size) + + dominant = max(spans, key=_span_text_weight) + return { + "font": str(dominant.get("font") or ""), + "flags": int(dominant.get("flags") or 0), + "color": _pdf_color_from_span(dominant), + "size": float(dominant.get("size") or fallback_size), + "ascender": float(dominant.get("ascender") or 0.8), + "descender": float(dominant.get("descender") or -0.2), + } + + +def _build_spans_detail(line: dict) -> tuple[list[dict], int]: + """ + Builds per-span style metadata and character offsets for a line. + + Args: + line (dict): The parsed line metadata being processed. + + Returns: + tuple[list[dict], int]: The span detail list and left-strip offset. + """ + raw_text = normalize("NFKC", _line_text(line)) + strip_offset = len(raw_text) - len(raw_text.lstrip()) + + spans_detail: list[dict] = [] + cursor = 0 + for span in line.get("spans", []): + span_text = normalize("NFKC", span.get("text", "")) + span_start = cursor + cursor += len(span_text) + spans_detail.append( + { + "start": span_start, + "end": cursor, + "style": { + "font": str(span.get("font") or ""), + "flags": int(span.get("flags") or 0), + "color": _pdf_color_from_span(span), + "size": float(span.get("size") or 10.0), + "ascender": float(span.get("ascender") or 0.8), + "descender": float(span.get("descender") or -0.2), + }, + } + ) + return spans_detail, strip_offset + + +def _entity_style_from_spans( + line_entry: dict, + offset_in_stripped_text: int, +) -> dict[str, Any]: + """ + Resolves the style for the entity offset inside a line entry. + + Args: + line_entry (dict): The `line_entry` value used by this helper. + offset_in_stripped_text (int): The entity offset inside the stripped line text. + + Returns: + dict[str, Any]: The resolved style dictionary for the entity offset. + """ + spans_detail = line_entry.get("spans_detail") + if not spans_detail: + return line_entry.get("style") or _default_style() + + strip_offset = line_entry.get("strip_offset", 0) + raw_offset = offset_in_stripped_text + strip_offset + + for span_info in spans_detail: + if span_info["start"] <= raw_offset < span_info["end"]: + return span_info["style"] + + return line_entry.get("style") or _default_style() + + +def _font_size(line: dict, fallback: float = 10.0) -> float: + """ + Calculates a representative font size for a parsed line. + + Args: + line (dict): The parsed line metadata being processed. + fallback (float, optional): The fallback font size to use when the line has no span sizes. Defaults to 10.0. + + Returns: + float: The representative font size for the line. + """ + spans = line.get("spans") or [] + sizes = [float(span.get("size")) for span in spans if span.get("size")] + if not sizes: + return fallback + size = sum(sizes) / len(sizes) + return max(size * 0.9, PDF_TAG_MIN_FONT_SIZE) + + +def _style_flags(style: dict[str, Any]) -> tuple[bool, bool, bool, bool]: + """ + Extracts boolean style flags from a style dictionary. + + Args: + style (dict[str, Any]): The style dictionary being analyzed. + + Returns: + tuple[bool, bool, bool, bool]: The bold, italic, monospace, and serif flags. + """ + flags = int(style.get("flags") or 0) + font_label = str(style.get("font") or "").lower() + + is_bold = bool(flags & TEXT_FLAG_BOLD) or "bold" in font_label + is_italic = bool(flags & TEXT_FLAG_ITALIC) or any( + token in font_label for token in ("italic", "oblique") + ) + is_mono = bool(flags & TEXT_FLAG_MONOSPACED) or any( + token in font_label for token in ("courier", "mono", "console") + ) + is_serif = bool(flags & TEXT_FLAG_SERIF) or any( + token in font_label + for token in ("times", "serif", "georgia", "garamond", "mistral") + ) + return is_bold, is_italic, is_mono, is_serif + + +def _base14_fontname_for_style(style: dict[str, Any]) -> str: + """ + Maps a style dictionary to the closest Base-14 font name. + + Args: + style (dict[str, Any]): The style dictionary being analyzed. + + Returns: + str: The Base-14 font name that best matches the style. + """ + is_bold, is_italic, is_mono, is_serif = _style_flags(style) + + if is_mono: + family = "Courier" + elif is_serif: + family = "Times" + else: + family = "Helvetica" + + variants = { + ("Helvetica", False, False): "Helvetica", + ("Helvetica", True, False): "Helvetica-Bold", + ("Helvetica", False, True): "Helvetica-Oblique", + ("Helvetica", True, True): "Helvetica-BoldOblique", + ("Times", False, False): "Times-Roman", + ("Times", True, False): "Times-Bold", + ("Times", False, True): "Times-Italic", + ("Times", True, True): "Times-BoldItalic", + ("Courier", False, False): "Courier", + ("Courier", True, False): "Courier-Bold", + ("Courier", False, True): "Courier-Oblique", + ("Courier", True, True): "Courier-BoldOblique", + } + return variants[(family, is_bold, is_italic)] + + +def _build_flexible_pattern(text: str) -> str: + """ + Builds a whitespace-tolerant regex pattern for the given text. + + Args: + text (str): The text value being normalized or searched. + + Returns: + str: The whitespace-tolerant regex pattern. + """ + tokens = [re.escape(tok) for tok in re.split(r"\s+", text.strip()) if tok] + return r"\s+".join(tokens) + + +def _find_flexible( + haystack: str, + needle: str, + start: int = 0, +) -> tuple[int, int] | None: + """ + Finds a text span using exact and whitespace-tolerant matching. + + Args: + haystack (str): The source text to search within. + needle (str): The target text to search for. + start (int, optional): The preferred start offset for the search. Defaults to 0. + + Returns: + tuple[int, int] | None: The start and end offsets of the match, if found. + """ + if not needle: + return None + + idx = haystack.find(needle, start) + if idx >= 0: + return idx, idx + len(needle) + + pattern = _build_flexible_pattern(needle) + if not pattern: + return None + + match = re.search(pattern, haystack[start:]) + if match: + return start + match.start(), start + match.end() + + if start > 0: + match = re.search(pattern, haystack) + if match: + return match.start(), match.end() + + return None + + +def _token_parts(token: str) -> tuple[str, str | None]: + """ + Splits a logical token into its base label and numeric suffix. + + Args: + token (str): The logical replacement token being processed. + + Returns: + tuple[str, str | None]: The token base and optional numeric suffix. + """ + match = re.match(r"^(.*?)(?:_(\d+))?$", token) + if not match: + normalized = token.strip() or "ENT" + return normalized, None + + base = match.group(1).strip() or "ENT" + suffix = match.group(2) + return base, suffix + + +def _abbreviate_token(base: str, length: int) -> str: + """ + Builds an abbreviated token label with the requested length. + + Args: + base (str): The token base label to abbreviate or alias. + length (int): The target abbreviation length. + + Returns: + str: The abbreviated token label. + """ + normalized = "".join(char for char in base.upper() if char.isalnum()) + if not normalized: + normalized = "ENT" + return normalized[:length] or normalized[:1] or "E" + + +def _token_aliases(base: str) -> tuple[str, ...]: + """ + Returns configured alias labels for a token base. + + Args: + base (str): The token base label to abbreviate or alias. + + Returns: + tuple[str, ...]: The configured aliases for the token base. + """ + aliases = PDF_TOKEN_ALIAS_MAP.get(base.upper(), ()) + normalized_aliases: list[str] = [] + + for alias in aliases: + normalized = re.sub(r"[^A-Z0-9_]", "", str(alias).upper()) + if ( + normalized + and normalized != base.upper() + and normalized not in normalized_aliases + ): + normalized_aliases.append(normalized) + + return tuple(normalized_aliases) + + +def _build_display_token_candidates(token: str) -> list[str]: + """ + Builds the list of token display candidates to try when rendering. + + Args: + token (str): The logical replacement token being processed. + + Returns: + list[str]: The candidate display tokens to try when rendering. + """ + base, suffix = _token_parts(token.upper()) + candidates: list[str] = [] + + def add(value: str) -> None: + """ + Appends a token display candidate when it has not been added yet. + + Args: + value (str): The rectangle-like value to normalize. + """ + if value and value not in candidates: + candidates.append(value) + + def add_base_variants(label: str) -> None: + """ + Appends the base token variants for the current label candidate. + + Args: + label (str): The label metadata being processed. + """ + if suffix: + add(f"<{label}_{suffix}>") + add(f"<{label}>") + + add_base_variants(base) + + for alias in _token_aliases(base): + add_base_variants(alias) + + abbreviated = _abbreviate_token(base, PDF_TAG_MAX_ABBREVIATION) + add_base_variants(abbreviated) + + return candidates + + +def _iter_font_sizes(start_size: float) -> list[float]: + """ + Builds the descending font sizes to try when fitting a token. + + Args: + start_size (float): The `start_size` value used by this helper. + + Returns: + list[float]: The font sizes to try in descending order. + """ + if start_size <= 0: + return [] + + sizes: list[float] = [start_size] + current = start_size + while current - PDF_TAG_FONT_STEP >= PDF_TAG_MIN_FONT_SIZE - 1e-6: + current = round(current - PDF_TAG_FONT_STEP, 2) + if current not in sizes: + sizes.append(current) + + return sizes + + +def _fit_display_token( + token: str, + rect: pymupdf.Rect, + fontname: str, + base_font_size: float, + font_obj: pymupdf.Font | None = None, +) -> tuple[str | None, float | None]: + """ + Finds a token rendering variant and font size that fit inside a rectangle. + + Args: + token (str): The logical replacement token being processed. + rect (pymupdf.Rect): The rectangle used by the helper. + fontname (str): The font name to use for measurement or rendering. + base_font_size (float): The initial font size to try when fitting text. + font_obj (pymupdf.Font | None, optional): The font object used for measurement. Defaults to None. + + Returns: + tuple[str | None, float | None]: The fitted token text and font size. + """ + if rect.width <= 0 or rect.height <= 0: + return None, None + + available_width = max(rect.width - (2 * PDF_TAG_RECT_INSET), 1.0) + start_size = min(base_font_size, max(rect.height - 1.0, 1.0)) + if start_size < 1.0: + return None, None + + def _measure(text: str, size: float) -> float: + """ + Measures the width of a candidate token at the given font size. + + Args: + text (str): The text value being normalized or searched. + size (float): The font size used for the current measurement. + + Returns: + float: The measured width of the candidate text. + """ + if font_obj is not None: + try: + return font_obj.text_length(text, fontsize=size) + except Exception: + pass + return pymupdf.get_text_length(text, fontname=fontname, fontsize=size) + + for size in _iter_font_sizes(start_size): + for candidate in _build_display_token_candidates(token): + if _measure(candidate, size) <= available_width + 0.1: + return candidate, size + + return None, None + + +_BASE14_FONT_CACHE: dict[str, pymupdf.Font] = {} + + +@lru_cache(maxsize=None) +def _cached_base14_font(name: str) -> pymupdf.Font: + """ + Loads and caches a Base-14 font by name. + + Args: + name (str): The Base-14 font name to load. + + Returns: + pymupdf.Font: The cached Base-14 font object. + """ + return pymupdf.Font(name) + + +def _get_base14_font(style: dict[str, Any]) -> pymupdf.Font: + """ + Returns the cached Base-14 font object for a style dictionary. + + Args: + style (dict[str, Any]): The style dictionary being analyzed. + + Returns: + pymupdf.Font: The cached Base-14 font for the style. + """ + name = _base14_fontname_for_style(style) + font = _BASE14_FONT_CACHE.get(name) + if font is None: + font = _cached_base14_font(name) + _BASE14_FONT_CACHE[name] = font + return font + + +def _rect_vertical_overlap(left: pymupdf.Rect, right: pymupdf.Rect) -> float: + """ + Calculates the vertical overlap ratio between two rectangles. + + Args: + left (pymupdf.Rect): The left rectangle or label to compare. + right (pymupdf.Rect): The right rectangle or label to compare. + + Returns: + float: The vertical overlap ratio between the rectangles. + """ + overlap = max(0.0, min(left.y1, right.y1) - max(left.y0, right.y0)) + min_height = max(min(left.height, right.height), 1e-6) + return overlap / min_height + + +def _group_adjacent_rects( + rects: list[pymupdf.Rect], max_gap: float +) -> list[pymupdf.Rect]: + """ + Merges horizontally adjacent rectangles that belong to the same segment. + + Args: + rects (list[pymupdf.Rect]): The `rects` value used by this helper. + max_gap (float): The `max_gap` value used by this helper. + + Returns: + list[pymupdf.Rect]: The merged rectangle groups. + """ + if not rects: + return [] + + ordered = sorted(rects, key=lambda rect: (rect.y0, rect.x0, rect.x1)) + groups: list[list[pymupdf.Rect]] = [[ordered[0]]] + + for rect in ordered[1:]: + previous = groups[-1][-1] + gap = rect.x0 - previous.x1 + if _rect_vertical_overlap(previous, rect) >= 0.5 and gap <= max_gap: + groups[-1].append(rect) + else: + groups.append([rect]) + + merged_rects: list[pymupdf.Rect] = [] + for group in groups: + merged = pymupdf.Rect(group[0]) + for rect in group[1:]: + merged.include_rect(rect) + merged_rects.append(merged) + + return merged_rects diff --git a/aymurai/text/anonymization/pdf/layout.py b/aymurai/text/anonymization/pdf/layout.py new file mode 100644 index 00000000..50ce529a --- /dev/null +++ b/aymurai/text/anonymization/pdf/layout.py @@ -0,0 +1,510 @@ +from __future__ import annotations + +import re +from copy import deepcopy +from typing import Any +from unicodedata import normalize + +import pymupdf +from jiwer import cer + +from aymurai.logger import get_logger +from aymurai.text.anonymization.alignment import ( + _label_replacement_end as _label_end, +) +from aymurai.text.anonymization.alignment import ( + _label_replacement_start as _label_start, +) +from aymurai.text.anonymization.alignment import ( + resolve_render_token, +) +from aymurai.text.anonymization.pdf.common import ( + PDF_TAG_RECT_GAP_FACTOR, + PDF_TAG_RECT_GAP_MAX, + PDF_TAG_RECT_GAP_MIN, + _build_flexible_pattern, + _build_spans_detail, + _font_size, + _group_adjacent_rects, + _line_style, + _line_text, + _rect_tuple, + _rect_vertical_overlap, +) + +logger = get_logger(__name__) + + +def _same_boundary_candidate(left: dict, right: dict) -> bool: + """ + Checks whether two labels can share a merged boundary token. + + Args: + left (dict): The left rectangle or label to compare. + right (dict): The right rectangle or label to compare. + + Returns: + bool: Whether the labels can share a boundary token. + """ + left_attrs = left.get("attrs") or {} + right_attrs = right.get("attrs") or {} + + if left_attrs.get("aymurai_label") != right_attrs.get("aymurai_label"): + return False + + left_cid = left_attrs.get("canonical_entity_id") + right_cid = right_attrs.get("canonical_entity_id") + if left_cid and right_cid and str(left_cid) != str(right_cid): + return False + + left_text = str(left.get("text") or "").strip() + right_text = str(right.get("text") or "").strip() + return bool(left_text and right_text) + + +def _resolve_token(label: dict, render_context: dict[str, Any] | None) -> str: + """ + Resolves the logical replacement token for a label. + + Args: + label (dict): The label metadata being processed. + render_context (dict[str, Any] | None): The rendering context used to resolve replacement tokens. + + Returns: + str: The logical token that should replace the label. + """ + boundary_token = label.get("_boundary_token") + if boundary_token: + return boundary_token + + token = resolve_render_token(label, render_context) + return token or "ENT" + + +def _apply_minimal_boundary_merge( + paragraphs: list[dict], + render_context: dict[str, Any] | None, +) -> None: + """ + Propagates a shared token across paragraph-boundary label pairs. + + Args: + paragraphs (list[dict]): The paragraph collection being processed. + render_context (dict[str, Any] | None): The rendering context used to resolve replacement tokens. + """ + for left_par, right_par in zip(paragraphs, paragraphs[1:]): + left_doc = left_par.get("document") or "" + right_doc = right_par.get("document") or "" + left_labels = left_par.get("labels") or [] + right_labels = right_par.get("labels") or [] + + if not left_doc or not right_doc or not left_labels or not right_labels: + continue + + left_candidates = [ + label + for label in left_labels + if _label_end(label) >= max(0, len(left_doc) - 2) + ] + right_candidates = [label for label in right_labels if _label_start(label) <= 2] + + if not left_candidates or not right_candidates: + continue + + for left_label in left_candidates: + for right_label in right_candidates: + if not _same_boundary_candidate(left_label, right_label): + continue + + shared_token = _resolve_token(left_label, render_context) + if not shared_token: + shared_token = _resolve_token(right_label, render_context) + if shared_token: + left_label["_boundary_token"] = shared_token + right_label["_boundary_token"] = shared_token + break + + +def _build_layout_paragraphs(parsed_doc: Any) -> list[dict]: + """ + Builds normalized paragraph metadata from the parsed PDF layout. + + Args: + parsed_doc (Any): The parsed PDF layout document. + + Returns: + list[dict]: The normalized layout paragraphs extracted from the parsed document. + """ + chunks = parsed_doc.to_text( + page_chunks=True, + header=True, + footer=True, + show_progress=False, + ) + + paragraphs: list[dict] = [] + layout_index = 0 + for page_idx, (page, chunk) in enumerate(zip(parsed_doc.pages, chunks)): + page_text = chunk.get("text") or "" + page_boxes = chunk.get("page_boxes") or [] + + for box_meta in page_boxes: + box_idx = int(box_meta["index"]) + if box_idx >= len(page.boxes): + continue + + start, stop = box_meta.get("pos", (0, 0)) + box_text = normalize("NFKC", page_text[start:stop]).strip() + if not box_text: + continue + + box = page.boxes[box_idx] + line_entries: list[dict] = [] + line_text_chunks: list[str] = [] + line_cursor = 0 + + for line_idx, line in enumerate(box.textlines or []): + text = normalize("NFKC", _line_text(line)).strip() + if not text: + continue + + if line_text_chunks: + line_text_chunks.append("\n") + line_cursor += 1 + + line_start = line_cursor + line_text_chunks.append(text) + line_cursor += len(text) + line_end = line_cursor + style = _line_style(line) + spans_detail, strip_offset = _build_spans_detail(line) + + line_entries.append( + { + "page_index": page_idx, + "box_index": box_idx, + "line_index": line_idx, + "bbox": _rect_tuple(line["bbox"]), + "font_size": _font_size(line, float(style.get("size") or 10.0)), + "start": line_start, + "end": line_end, + "text": text, + "style": style, + "spans_detail": spans_detail, + "strip_offset": strip_offset, + } + ) + + line_text = "".join(line_text_chunks) + if not line_text: + continue + + paragraphs.append( + { + "plain_text": box_text, + "metadata": { + "layout_index": layout_index, + "page_index": page_idx, + "page_number": page.page_number, + "box_index": box_idx, + "boxclass": box.boxclass, + "box_bbox": ( + float(box.x0), + float(box.y0), + float(box.x1), + float(box.y1), + ), + "line_text": line_text, + "lines": line_entries, + }, + } + ) + layout_index += 1 + + return paragraphs + + +def _match_predictions_to_layout( + layout_paragraphs: list[dict], + preds: list[dict], +) -> list[dict]: + """ + Matches model predictions to the closest layout paragraphs. + + Args: + layout_paragraphs (list[dict]): The `layout_paragraphs` value used by this helper. + preds (list[dict]): The predictions to apply to the document. + + Returns: + list[dict]: The predictions annotated with their matched layout metadata. + """ + if not layout_paragraphs or not preds: + return [] + + available_indices = list(range(len(layout_paragraphs))) + all_indices = list(range(len(layout_paragraphs))) + matched: list[dict] = [] + + normalized_layout_texts = [ + normalize("NFKC", paragraph["plain_text"]).strip() + for paragraph in layout_paragraphs + ] + + for pred_idx, pred in enumerate(preds): + pred_text = normalize("NFKC", str(pred.get("document") or "")).strip() + if not pred_text: + continue + + candidate_pool = available_indices if available_indices else all_indices + exact_idx = next( + ( + idx + for idx in candidate_pool + if normalized_layout_texts[idx] == pred_text + ), + None, + ) + + if exact_idx is None: + exact_idx = min( + candidate_pool, + key=lambda idx: cer(pred_text, normalized_layout_texts[idx]), + ) + + paragraph = deepcopy(layout_paragraphs[exact_idx]) + paragraph["document"] = pred.get("document") or "" + paragraph["labels"] = pred.get("labels") or [] + paragraph["pred_index"] = pred_idx + matched.append(paragraph) + + if exact_idx in available_indices: + available_indices.remove(exact_idx) + + matched.sort(key=lambda paragraph: paragraph["metadata"]["layout_index"]) + return matched + + +def _pick_rect_group_for_segment( + page: pymupdf.Page, + line: dict, + text: str, + line_x_cursor: dict[tuple[int, int, int], float], +) -> pymupdf.Rect: + """ + Chooses the best rectangle group for a text segment on the page. + + Args: + page (pymupdf.Page): The PDF page being processed. + line (dict): The parsed line metadata being processed. + text (str): The text value being normalized or searched. + line_x_cursor (dict[tuple[int, int, int], float]): The per-line cursor used to keep page searches stable. + + Returns: + pymupdf.Rect | None: The chosen rectangle group for the segment, if found. + """ + clip = pymupdf.Rect(line["bbox"]) + rects = [rect for rect in page.search_for(text, clip=clip) if rect.intersects(clip)] + if not rects: + return clip + + max_gap = min( + max(clip.height * PDF_TAG_RECT_GAP_FACTOR, PDF_TAG_RECT_GAP_MIN), + PDF_TAG_RECT_GAP_MAX, + ) + grouped_rects = _group_adjacent_rects(rects, max_gap=max_gap) + + line_key = (line["page_index"], line["box_index"], line["line_index"]) + min_x = line_x_cursor.get(line_key, clip.x0 - 1) + + for rect in grouped_rects: + if rect.x0 >= min_x - 0.5: + line_x_cursor[line_key] = rect.x1 + return rect + + chosen = grouped_rects[0] + line_x_cursor[line_key] = chosen.x1 + return chosen + + +def _normalize_line_chars(spans: list[dict]) -> list[dict[str, Any]]: + """ + Normalizes per-character span data into searchable character entries. + + Args: + spans (list[dict]): The span collection to normalize into character entries. + + Returns: + list[dict[str, Any]]: The normalized character entries for the line. + """ + chars: list[dict[str, Any]] = [] + for span in spans: + for char in span.get("chars") or []: + norm_text = normalize("NFKC", str(char.get("c") or "")) + if not norm_text: + continue + bbox = pymupdf.Rect(char["bbox"]) + for norm_char in norm_text: + chars.append({"char": norm_char, "bbox": bbox}) + return chars + + +def _line_chars_from_page(page: pymupdf.Page, line: dict) -> list[dict[str, Any]]: + """ + Extracts character-level geometry for a parsed line from the page text. + + Args: + page (pymupdf.Page): The PDF page being processed. + line (dict): The parsed line metadata being processed. + + Returns: + list[dict[str, Any]]: The character entries extracted from the page. + """ + clip = pymupdf.Rect(line["bbox"]) + raw = page.get_text("rawdict", clip=clip) + target_text = normalize("NFKC", str(line.get("text") or "")).strip() + + best_chars: list[dict[str, Any]] = [] + best_score: tuple[float, float, float] | None = None + + for block in raw.get("blocks") or []: + if block.get("type", 0) != 0: + continue + for raw_line in block.get("lines") or []: + chars = _normalize_line_chars(raw_line.get("spans") or []) + if not chars: + continue + + candidate_rect = pymupdf.Rect(raw_line["bbox"]) + candidate_text = "".join(entry["char"] for entry in chars).strip() + overlap = ( + _rect_vertical_overlap(candidate_rect, clip) + if candidate_rect.intersects(clip) + else 0.0 + ) + text_score = 0.0 + if target_text or candidate_text: + text_score = ( + 0.0 + if target_text == candidate_text + else cer(target_text, candidate_text) + ) + bbox_score = ( + abs(candidate_rect.x0 - clip.x0) + + abs(candidate_rect.y0 - clip.y0) + + abs(candidate_rect.x1 - clip.x1) + + abs(candidate_rect.y1 - clip.y1) + ) / 100.0 + score = (1.0 - overlap, text_score, bbox_score) + if best_score is None or score < best_score: + best_score = score + best_chars = chars + + return best_chars + + +def _line_chars_text(chars: list[dict[str, Any]]) -> str: + """ + Builds the searchable text for a character entry list. + + Args: + chars (list[dict[str, Any]]): The character entry list being processed. + + Returns: + str: The concatenated character text. + """ + return "".join(str(entry.get("char") or "") for entry in chars) + + +def _find_line_char_span( + chars: list[dict[str, Any]], + text: str, + *, + start: int = 0, + raw_text: str | None = None, +) -> tuple[int, int] | None: + """ + Finds the character span for a text fragment inside a line. + + Args: + chars (list[dict[str, Any]]): The character entry list being processed. + text (str): The text value being normalized or searched. + start (int, optional): The preferred start offset for the search. Defaults to 0. + raw_text (str | None, optional): The raw line text used as a fallback search surface. Defaults to None. + + Returns: + tuple[int, int] | None: The start and end character offsets, if found. + """ + if not chars or not text: + return None + + haystack = raw_text if raw_text is not None else _line_chars_text(chars) + pattern = _build_flexible_pattern(text) + + def _search(offset: int) -> tuple[int, int] | None: + """ + Searches for the candidate span from the provided offset. + + Args: + offset (int): The search offset used by the nested helper. + + Returns: + tuple[int, int] | None: The matching span for the current offset, if found. + """ + exact_idx = haystack.find(text, offset) + flexible_span = None + if pattern: + match = re.search(pattern, haystack[offset:]) + if match is not None: + flexible_span = (offset + match.start(), offset + match.end()) + + if exact_idx < 0: + return flexible_span + exact_span = (exact_idx, exact_idx + len(text)) + if flexible_span is None: + return exact_span + return min(exact_span, flexible_span, key=lambda span: span[0]) + + span = _search(start) + if span is None and start > 0: + span = _search(0) + return span + + +def _rect_from_char_slice( + chars: list[dict[str, Any]], + start: int, + end: int, +) -> pymupdf.Rect | None: + """ + Builds a rectangle covering the requested character slice. + + Args: + chars (list[dict[str, Any]]): The character entry list being processed. + start (int): The preferred start offset for the search. + end (int): The `end` value used by this helper. + + Returns: + pymupdf.Rect | None: The rectangle covering the requested character slice. + """ + if not chars: + return None + + slice_start = max(int(start), 0) + slice_end = min(int(end), len(chars)) + if slice_end <= slice_start: + return None + + segment = chars[slice_start:slice_end] + if not segment: + return None + + boxes = [entry["bbox"] for entry in segment if str(entry["char"]).strip()] + if not boxes: + boxes = [entry["bbox"] for entry in segment] + if not boxes: + return None + + rect = pymupdf.Rect(boxes[0]) + for bbox in boxes[1:]: + rect.include_rect(bbox) + return rect diff --git a/aymurai/text/anonymization/pdf/ops.py b/aymurai/text/anonymization/pdf/ops.py new file mode 100644 index 00000000..bdad1d0a --- /dev/null +++ b/aymurai/text/anonymization/pdf/ops.py @@ -0,0 +1,828 @@ +from __future__ import annotations + +from typing import Any + +import pymupdf + +from aymurai.logger import get_logger +from aymurai.text.anonymization.alignment import ( + _label_replacement_start as _label_start, +) +from aymurai.text.anonymization.alignment import ( + _label_replacement_text as _label_surface_text, +) +from aymurai.text.anonymization.pdf.common import ( + PDF_TAG_RECT_GAP_MAX, + PDF_TAG_RECT_INSET, + PDF_TAG_RECT_X_PADDING, + PDF_TAG_RECT_Y_PADDING, + _base14_fontname_for_style, + _default_style, + _entity_style_from_spans, + _find_flexible, + _fit_display_token, + _get_base14_font, + _group_adjacent_rects, + _rect_vertical_overlap, +) +from aymurai.text.anonymization.pdf.layout import ( + _find_line_char_span, + _line_chars_from_page, + _line_chars_text, + _pick_rect_group_for_segment, + _rect_from_char_slice, + _resolve_token, +) +from aymurai.text.anonymization.pdf.widgets import ( + _apply_widget_ops, + _entity_overlaps_widget, + _page_widget_infos, + _prepare_signature_widget_ops, +) + +logger = get_logger(__name__) + +_IMAGE_OVERLAP_THRESHOLD = 0.3 + + +def _padded_rect(rect: pymupdf.Rect, clip: pymupdf.Rect) -> pymupdf.Rect: + """ + Pads a rectangle within the provided clipping bounds. + + Args: + rect (pymupdf.Rect): The rectangle used by the helper. + clip (pymupdf.Rect): The clipping rectangle to constrain the operation. + + Returns: + pymupdf.Rect: The padded rectangle clipped to the provided bounds. + """ + padded = pymupdf.Rect(rect) + padded.x0 = max(clip.x0, padded.x0 - PDF_TAG_RECT_X_PADDING) + padded.y0 = max(clip.y0, padded.y0 - PDF_TAG_RECT_Y_PADDING) + padded.x1 = min(clip.x1, padded.x1 + PDF_TAG_RECT_X_PADDING) + padded.y1 = min(clip.y1, padded.y1 + PDF_TAG_RECT_Y_PADDING) + return padded + + +def _render_rect(rect: pymupdf.Rect) -> pymupdf.Rect: + """ + Builds the token rendering rectangle from the padded canvas rectangle. + + Args: + rect (pymupdf.Rect): The rectangle used by the helper. + + Returns: + pymupdf.Rect: The rectangle used to render the replacement token. + """ + render_rect = pymupdf.Rect(rect) + inset = min(PDF_TAG_RECT_INSET, max(render_rect.height * 0.1, 0.0)) + render_rect.x0 += inset + render_rect.x1 -= inset + if render_rect.x1 <= render_rect.x0: + render_rect = pymupdf.Rect(rect) + return render_rect + + +def _text_redact_rect(rect: pymupdf.Rect) -> pymupdf.Rect: + """ + Builds the redaction rectangle used to remove original text. + + Args: + rect (pymupdf.Rect): The rectangle used by the helper. + + Returns: + pymupdf.Rect: The rectangle used for text redaction. + """ + redact_rect = pymupdf.Rect(rect) + edge_inset = min(0.25, max(redact_rect.width * 0.01, 0.05)) + if redact_rect.width > (2 * edge_inset): + redact_rect.x0 += edge_inset + redact_rect.x1 -= edge_inset + return redact_rect + + +def _build_page_op( + rect: pymupdf.Rect, + line: dict | None, + token: str, + is_image: bool = False, + entity_style: dict[str, Any] | None = None, +) -> dict[str, Any]: + """ + Builds the rendering operation metadata for a matched page segment. + + Args: + rect (pymupdf.Rect): The rectangle used by the helper. + line (dict | None): The parsed line metadata being processed. + token (str): The logical replacement token being processed. + is_image (bool, optional): Whether the operation is intended for image-backed content. Defaults to False. + entity_style (dict[str, Any] | None, optional): The resolved style dictionary for the entity text. Defaults to None. + + Returns: + dict[str, Any]: The rendering operation metadata for the segment. + """ + line_clip = pymupdf.Rect(line["bbox"]) if line else pymupdf.Rect(rect) + canvas_rect = _padded_rect(rect, line_clip) + render_rect = _render_rect(canvas_rect) + style = entity_style or (line or {}).get("style") or _default_style() + base_font_size = float((line or {}).get("font_size") or style.get("size") or 10.0) + + # Always use Base-14 fonts: they carry correct bold/italic weight and + # contain all glyphs needed for tags (<, >, _, digits, letters). + # Subset font buffers extracted from the PDF lack many of these glyphs. + fontname = _base14_fontname_for_style(style) + font_obj = _get_base14_font(style) + + display_token, fitted_size = _fit_display_token( + token, + render_rect, + fontname, + base_font_size, + font_obj=font_obj, + ) + + if not display_token or fitted_size is None: + logger.warning( + "Could not fit PDF token '%s' inside rect=%s", + token, + tuple(round(value, 2) for value in canvas_rect), + ) + + return { + "redact_rect": _text_redact_rect(rect), + "background_rect": canvas_rect, + "canvas_rect": canvas_rect, + "render_rect": render_rect, + "line_rect": line_clip, + "text": display_token, + "logical_token": token, + "fontname": fontname, + "fontsize": fitted_size, + "text_align": pymupdf.TEXT_ALIGN_LEFT, + "text_color": style.get("color") or (0.0, 0.0, 0.0), + "style": style, + } + + +def _image_rects_for_clip( + page: pymupdf.Page, + clip: pymupdf.Rect, +) -> list[pymupdf.Rect]: + """ + Collects image rectangles that overlap the given page region. + + Args: + page (pymupdf.Page): The PDF page being processed. + clip (pymupdf.Rect): The clipping rectangle to constrain the operation. + + Returns: + list[pymupdf.Rect]: The image rectangles that overlap the clip region. + """ + rects: list[pymupdf.Rect] = [] + for img_info in page.get_image_info(): + bbox = img_info.get("bbox") + if bbox is None: + continue + img_rect = pymupdf.Rect(bbox) + if img_rect.intersects(clip) and img_rect.get_area() > 0: + rects.append(img_rect) + return rects + + +def _entity_overlaps_image( + page: pymupdf.Page, + entity_rect: pymupdf.Rect, + image_rects: list[pymupdf.Rect], +) -> pymupdf.Rect | None: + """ + Checks whether an entity rectangle overlaps a detected image. + + Args: + page (pymupdf.Page): The PDF page being processed. + entity_rect (pymupdf.Rect): The rectangle representing the entity on the page. + image_rects (list[pymupdf.Rect]): The image rectangles available for overlap checks. + + Returns: + pymupdf.Rect | None: The overlapping image rectangle, if one exists. + """ + for img_rect in image_rects: + overlap = _rect_vertical_overlap(entity_rect, img_rect) + if overlap >= _IMAGE_OVERLAP_THRESHOLD and entity_rect.intersects(img_rect): + return img_rect + return None + + +def _collect_page_redactions( + doc: pymupdf.Document, + paragraphs: list[dict], + render_context: dict[str, Any] | None, +) -> dict[int, list[dict]]: + """ + Collects text, widget, and signature redaction operations for a document. + + Args: + doc (pymupdf.Document): The PDF document being processed. + paragraphs (list[dict]): The paragraph collection being processed. + render_context (dict[str, Any] | None): The rendering context used to resolve replacement tokens. + + Returns: + tuple[dict[int, list[dict]], dict[int, list[dict]], dict[int, list[dict]]]: The page, text-widget, and signature-widget operations. + """ + page_ops: dict[int, list[dict]] = {} + widget_ops: dict[int, list[dict]] = {} + signature_widget_ops: dict[int, list[dict]] = {} + line_x_cursor: dict[tuple[int, int, int], float] = {} + line_char_cache: dict[tuple[int, int, int], list[dict[str, Any]]] = {} + line_char_text_cache: dict[tuple[int, int, int], str] = {} + line_char_cursor: dict[tuple[int, int, int], int] = {} + + # Pre-compute image rects and widgets per page + page_image_rects: dict[int, list[pymupdf.Rect]] = {} + page_widgets: dict[int, list[dict[str, Any]]] = {} + + for paragraph in paragraphs: + metadata = paragraph.get("metadata") or {} + lines = metadata.get("lines") or [] + if not lines: + continue + + page_index = int(metadata["page_index"]) + page = doc[page_index] + line_text = metadata.get("line_text") or "" + box_clip = pymupdf.Rect(metadata.get("box_bbox") or page.rect) + document = paragraph.get("document") or "" + labels = sorted(paragraph.get("labels") or [], key=_label_start) + search_cursor = 0 + + # Lazy-load image rects and widget infos for this page + if page_index not in page_image_rects: + page_image_rects[page_index] = _image_rects_for_clip(page, page.rect) + if page_index not in page_widgets: + page_widgets[page_index] = _page_widget_infos(page) + + for label in labels: + entity_text = _label_surface_text(label, document).strip() + if not entity_text: + continue + + token = _resolve_token(label, render_context) + + span = _find_flexible(line_text, entity_text, start=search_cursor) + if span is None: + span = _find_flexible(line_text, entity_text, start=0) + if span is None: + # -- Fallback: direct page search -- + fallback_rects = [ + rect + for rect in page.search_for(entity_text, clip=box_clip) + if rect.intersects(box_clip) + ] + + # Check if this is a widget-backed entity before falling back to images + if fallback_rects: + fallback_widget = _entity_overlaps_widget( + fallback_rects[0], + page_widgets[page_index], + ) + if fallback_widget is not None: + if ( + fallback_widget["field_type"] + == pymupdf.PDF_WIDGET_TYPE_TEXT + ): + widget_ops.setdefault(page_index, []).append( + { + "widget_xref": fallback_widget["xref"], + "field_name": fallback_widget["field_name"], + "widget_info": fallback_widget, + "entity_text": entity_text, + "logical_token": token, + } + ) + continue + if ( + fallback_widget["field_type"] + == pymupdf.PDF_WIDGET_TYPE_SIGNATURE + ): + op = _build_page_op( + fallback_rects[0], + lines[0] if lines else None, + token, + entity_style=fallback_widget.get("style") or None, + ) + op["widget_xref"] = fallback_widget["xref"] + op["widget_rect"] = fallback_widget["rect"] + signature_widget_ops.setdefault(page_index, []).append(op) + continue + + # Check if this is an image-based entity + if not fallback_rects: + img_match = _try_image_entity( + page, + entity_text, + box_clip, + page_image_rects[page_index], + ) + if img_match is not None: + op = _build_page_op( + img_match, + lines[0] if lines else None, + token, + is_image=True, + ) + op["image_rect"] = img_match + page_ops.setdefault(page_index, []).append(op) + continue + + if fallback_rects: + grouped_rects = _group_adjacent_rects( + fallback_rects, max_gap=PDF_TAG_RECT_GAP_MAX + ) + fallback_line = lines[0] if lines else None + + # Check if any of these rects overlap an image + for rect in grouped_rects: + img_rect = _entity_overlaps_image( + page, + rect, + page_image_rects[page_index], + ) + op = _build_page_op( + rect, + fallback_line, + token, + is_image=(img_rect is not None), + ) + if img_rect is not None: + op["image_rect"] = img_rect + page_ops.setdefault(page_index, []).append(op) + continue + + logger.warning( + "Could not map label '%s' on page=%s box=%s", + entity_text, + metadata.get("page_number"), + metadata.get("box_index"), + ) + continue + + search_cursor = span[1] + + # Collect line segments this entity spans + segments: list[ + tuple[ + dict, + str, + pymupdf.Rect, + pymupdf.Rect | None, + dict, + dict[str, Any] | None, + ] + ] = [] + for line in lines: + overlap_start = max(span[0], line["start"]) + overlap_end = min(span[1], line["end"]) + if overlap_end <= overlap_start: + continue + + segment_text = line_text[overlap_start:overlap_end].strip() + if not segment_text: + continue + + line_key = ( + line["page_index"], + line["box_index"], + line["line_index"], + ) + line_chars = line_char_cache.get(line_key) + if line_chars is None: + line_chars = _line_chars_from_page(page, line) + line_char_cache[line_key] = line_chars + + line_char_text = line_char_text_cache.get(line_key) + if line_char_text is None: + line_char_text = _line_chars_text(line_chars) + line_char_text_cache[line_key] = line_char_text + + raw_span = _find_line_char_span( + line_chars, + segment_text, + start=line_char_cursor.get(line_key, 0), + raw_text=line_char_text, + ) + rect = None + if raw_span is not None: + line_char_cursor[line_key] = raw_span[1] + rect = _rect_from_char_slice(line_chars, raw_span[0], raw_span[1]) + + if rect is None: + raw_start = ( + overlap_start - line["start"] + int(line.get("strip_offset", 0)) + ) + raw_end = ( + overlap_end - line["start"] + int(line.get("strip_offset", 0)) + ) + rect = _rect_from_char_slice(line_chars, raw_start, raw_end) + if rect is None: + rect = _pick_rect_group_for_segment( + page, + line, + segment_text, + line_x_cursor, + ) + + widget_info = _entity_overlaps_widget( + rect, + page_widgets[page_index], + ) + + # Check for image overlap + img_rect = _entity_overlaps_image( + page, + rect, + page_image_rects[page_index], + ) + + # Determine entity-specific style from the span that + # actually contains this text (not the line's dominant style) + offset_in_line = overlap_start - line["start"] + ent_style = _entity_style_from_spans(line, offset_in_line) + + segments.append( + (line, segment_text, rect, img_rect, ent_style, widget_info) + ) + + if not segments: + continue + + if len(segments) == 1: + # Single-line entity: route widget-backed content through the widget path. + line, _seg_text, rect, img_rect, ent_style, widget_info = segments[0] + if widget_info is not None: + if widget_info["field_type"] == pymupdf.PDF_WIDGET_TYPE_TEXT: + widget_ops.setdefault(page_index, []).append( + { + "widget_xref": widget_info["xref"], + "field_name": widget_info["field_name"], + "widget_info": widget_info, + "entity_text": entity_text, + "logical_token": token, + } + ) + continue + if widget_info["field_type"] == pymupdf.PDF_WIDGET_TYPE_SIGNATURE: + op = _build_page_op( + rect, + line, + token, + entity_style=ent_style, + ) + op["widget_xref"] = widget_info["xref"] + op["widget_rect"] = widget_info["rect"] + signature_widget_ops.setdefault(page_index, []).append(op) + continue + + op = _build_page_op( + rect, + line, + token, + is_image=(img_rect is not None), + entity_style=ent_style, + ) + if img_rect is not None: + op["image_rect"] = img_rect + page_ops.setdefault(page_index, []).append(op) + else: + # Multi-line entity: write the token on the widest segment only; blank the others. + widest_idx = max( + range(len(segments)), + key=lambda i: segments[i][2].width, + ) + any_image = any(seg[3] is not None for seg in segments) + shared_image_rect = next( + (seg[3] for seg in segments if seg[3] is not None), + None, + ) + + signature_widget = None + if all(seg[5] is not None for seg in segments): + widget_xrefs = {int(seg[5]["xref"]) for seg in segments} + widget_types = {int(seg[5]["field_type"]) for seg in segments} + if len(widget_xrefs) == 1 and widget_types == { + pymupdf.PDF_WIDGET_TYPE_SIGNATURE + }: + signature_widget = segments[0][5] + + for seg_idx, ( + seg_line, + _seg_text, + seg_rect, + seg_img, + seg_style, + seg_widget, + ) in enumerate(segments): + if seg_idx == widest_idx: + op = _build_page_op( + seg_rect, + seg_line, + token, + is_image=(any_image and signature_widget is None), + entity_style=seg_style, + ) + if signature_widget is None and shared_image_rect is not None: + op["image_rect"] = shared_image_rect + else: + op = _build_page_op( + seg_rect, + seg_line, + token, + is_image=( + (seg_img is not None) and signature_widget is None + ), + entity_style=seg_style, + ) + op["text"] = None + op["fontsize"] = None + if seg_img is not None and signature_widget is None: + op["image_rect"] = seg_img + + if signature_widget is not None: + op["widget_xref"] = signature_widget["xref"] + op["widget_rect"] = signature_widget["rect"] + signature_widget_ops.setdefault(page_index, []).append(op) + else: + page_ops.setdefault(page_index, []).append(op) + + return page_ops, widget_ops, signature_widget_ops + + +def _try_image_entity( + page: pymupdf.Page, + entity_text: str, + clip: pymupdf.Rect, + image_rects: list[pymupdf.Rect], +) -> pymupdf.Rect | None: + """ + Finds the best image rectangle for an entity when text search fails. + + Args: + page (pymupdf.Page): The PDF page being processed. + entity_text (str): The entity text being mapped. + clip (pymupdf.Rect): The clipping rectangle to constrain the operation. + image_rects (list[pymupdf.Rect]): The image rectangles available for overlap checks. + + Returns: + pymupdf.Rect | None: The best image rectangle for the entity, if found. + """ + if not image_rects: + return None + + # Try unclipped text search — the entity might be rendered as real text + # on top of (or near) an image. + text_hits = page.search_for(entity_text) + if text_hits: + for hit_rect in text_hits: + for img_rect in image_rects: + if hit_rect.intersects(img_rect): + return img_rect + + # Fallback: pick the image whose intersection with *clip* is largest + best: pymupdf.Rect | None = None + best_area = 0.0 + for img_rect in image_rects: + if not img_rect.intersects(clip) or img_rect.get_area() <= 0: + continue + intersection = img_rect & clip + area = intersection.get_area() + if area > best_area: + best_area = area + best = img_rect + + return best + + +def _render_text_op(page: pymupdf.Page, op: dict) -> None: + """ + Renders a single anonymization token back onto a page. + + Args: + page (pymupdf.Page): The PDF page being processed. + op (dict): The operation dictionary being processed. + """ + canvas = pymupdf.Rect(op.get("background_rect") or op["canvas_rect"]) + if not op.get("skip_background_fill"): + page.draw_rect( + canvas, + color=(1, 1, 1), + fill=(1, 1, 1), + width=0, + overlay=True, + ) + + if not op.get("text") or not op.get("fontsize"): + return + + render = op["render_rect"] + line_rect = pymupdf.Rect(op.get("line_rect") or render) + style = op.get("style") or {} + base14_name = _base14_fontname_for_style(style) + font_obj = _get_base14_font(style) + + fontsize = float(op["fontsize"]) + descender = float(style.get("descender") or -0.2) + baseline_y = line_rect.y1 + (descender * fontsize) + baseline_y = min( + max(baseline_y, line_rect.y0 + (fontsize * 0.65)), + line_rect.y1 - 0.1, + ) + + text_width = font_obj.text_length(op["text"], fontsize=fontsize) + x_start = render.x0 + max((render.width - text_width) / 2.0, 0.0) + + try: + page.insert_text( + (x_start, baseline_y), + op["text"], + fontname=base14_name, + fontsize=fontsize, + color=op["text_color"], + overlay=True, + ) + return + except Exception as exc: + logger.debug("insert_text failed for '%s': %s", op["text"], exc) + + try: + tw = pymupdf.TextWriter(page.rect, color=op["text_color"]) + tw.fill_textbox( + render, + op["text"], + font=font_obj, + fontsize=fontsize, + align=op.get("text_align", pymupdf.TEXT_ALIGN_CENTER), + ) + tw.write_text(page, overlay=True) + return + except Exception as exc: + logger.debug("TextWriter failed for '%s': %s", op["text"], exc) + + try: + page.insert_textbox( + render, + op["text"], + fontname=base14_name, + fontsize=fontsize, + color=op["text_color"], + align=op.get("text_align", pymupdf.TEXT_ALIGN_CENTER), + overlay=True, + ) + except Exception as exc: + logger.warning( + "All text insertion methods failed for '%s': %s", + op["text"], + exc, + ) + + +def _page_asset_rect(op: dict[str, Any]) -> pymupdf.Rect | None: + """ + Resolves the asset rectangle associated with a page operation. + + Args: + op (dict[str, Any]): The operation dictionary being processed. + + Returns: + pymupdf.Rect | None: The asset rectangle associated with the operation, if any. + """ + asset_rect = op.get("asset_rect") or op.get("image_rect") + if asset_rect is None: + return None + return pymupdf.Rect(asset_rect) + + +def _partition_page_ops( + page_ops: dict[int, list[dict]], +) -> tuple[dict[int, list[dict]], dict[int, list[dict]]]: + """ + Splits page operations into text-only and asset-backed groups. + + Args: + page_ops (dict[int, list[dict]]): The collected page operations grouped by page index. + + Returns: + tuple[dict[int, list[dict]], dict[int, list[dict]]]: The text-only and asset-backed operations. + """ + text_ops: dict[int, list[dict]] = {} + asset_ops: dict[int, list[dict]] = {} + + for page_idx, ops in page_ops.items(): + for op in ops: + if _page_asset_rect(op) is None: + text_ops.setdefault(page_idx, []).append(op) + else: + asset_ops.setdefault(page_idx, []).append(op) + + return text_ops, asset_ops + + +def _apply_text_redactions( + doc: pymupdf.Document, + text_page_ops: dict[int, list[dict]], +) -> None: + """ + Applies text-only redactions and re-renders replacement tokens. + + Args: + doc (pymupdf.Document): The PDF document being processed. + text_page_ops (dict[int, list[dict]]): The text-only page operations grouped by page index. + """ + for page_idx, ops in text_page_ops.items(): + if not ops: + continue + + page = doc[page_idx] + for op in ops: + page.add_redact_annot( + op["redact_rect"], + text=None, + fill=(1, 1, 1), + cross_out=False, + ) + + page.apply_redactions( + images=pymupdf.PDF_REDACT_IMAGE_NONE, + graphics=pymupdf.PDF_REDACT_LINE_ART_NONE, + text=pymupdf.PDF_REDACT_TEXT_REMOVE, + ) + + for op in ops: + _render_text_op(page, op) + + +def _apply_asset_redactions( + doc: pymupdf.Document, + asset_page_ops: dict[int, list[dict]], +) -> None: + """ + Applies asset-backed redactions and re-renders replacement tokens. + + Args: + doc (pymupdf.Document): The PDF document being processed. + asset_page_ops (dict[int, list[dict]]): The asset-backed page operations grouped by page index. + """ + for page_idx, ops in asset_page_ops.items(): + if not ops: + continue + + page = doc[page_idx] + graphics_mode = pymupdf.PDF_REDACT_LINE_ART_NONE + + for op in ops: + asset_rect = _page_asset_rect(op) + if asset_rect is None: + continue + + page.add_redact_annot( + asset_rect, + text=None, + fill=(1, 1, 1), + cross_out=False, + ) + graphics_mode = max( + graphics_mode, + int(op.get("graphics_mode") or pymupdf.PDF_REDACT_LINE_ART_NONE), + ) + + page.apply_redactions( + images=pymupdf.PDF_REDACT_IMAGE_REMOVE, + graphics=graphics_mode, + text=pymupdf.PDF_REDACT_TEXT_REMOVE, + ) + + for op in ops: + _render_text_op(page, op) + + +def _apply_redactions( + doc: pymupdf.Document, + page_ops: dict[int, list[dict]], + widget_ops: dict[int, list[dict]], + signature_widget_ops: dict[int, list[dict]], +) -> None: + """ + Applies all collected PDF redactions in the correct order. + + Args: + doc (pymupdf.Document): The PDF document being processed. + page_ops (dict[int, list[dict]]): The collected page operations grouped by page index. + widget_ops (dict[int, list[dict]]): The collected text widget operations grouped by page index. + signature_widget_ops (dict[int, list[dict]]): The collected signature widget operations grouped by page index. + """ + _apply_widget_ops(doc, widget_ops) + _prepare_signature_widget_ops(doc, signature_widget_ops) + + text_page_ops, asset_page_ops = _partition_page_ops(page_ops) + for page_idx, ops in signature_widget_ops.items(): + asset_page_ops.setdefault(page_idx, []).extend(ops) + + _apply_text_redactions(doc, text_page_ops) + _apply_asset_redactions(doc, asset_page_ops) diff --git a/aymurai/text/anonymization/pdf/sanitize.py b/aymurai/text/anonymization/pdf/sanitize.py new file mode 100644 index 00000000..408f32bf --- /dev/null +++ b/aymurai/text/anonymization/pdf/sanitize.py @@ -0,0 +1,294 @@ +from __future__ import annotations + +from datetime import datetime, timezone +from typing import Any + +import pymupdf + +from aymurai.logger import get_logger +from aymurai.settings import settings + +logger = get_logger(__name__) + + +def _pdf_metadata_mod_date() -> str: + """ + Builds the PDF metadata modification timestamp in UTC. + + Returns: + str: The PDF-formatted UTC modification timestamp. + """ + timestamp = datetime.now(timezone.utc) + return timestamp.strftime("D:%Y%m%d%H%M%S+00'00'") + + +def _append_cleanup_rect( + cleanup_rects: dict[int, list[pymupdf.Rect]], + page_idx: int, + rect: pymupdf.Rect | tuple[float, float, float, float] | None, +) -> None: + """ + Appends a cleanup rectangle for later document sanitization. + + Args: + cleanup_rects (dict[int, list[pymupdf.Rect]]): The cleanup rectangles grouped by page index. + page_idx (int): The page index associated with the operation. + rect (pymupdf.Rect | tuple[float, float, float, float] | None): The rectangle used by the helper. + """ + if rect is None: + return + + cleanup_rect = pymupdf.Rect(rect) + if cleanup_rect.get_area() <= 0: + return + cleanup_rects.setdefault(page_idx, []).append(cleanup_rect) + + +def _cleanup_rect_for_page_op(op: dict[str, Any]) -> pymupdf.Rect | None: + """ + Builds the cleanup rectangle for a standard page operation. + + Args: + op (dict[str, Any]): The operation dictionary being processed. + + Returns: + pymupdf.Rect | None: The cleanup rectangle for the page operation, if available. + """ + if op.get("image_rect") is not None: + cleanup_rect = pymupdf.Rect(op["image_rect"]) + redact_rect = op.get("redact_rect") + if redact_rect is not None: + cleanup_rect.include_rect(pymupdf.Rect(redact_rect)) + return cleanup_rect + + cleanup_source = ( + op.get("redact_rect") or op.get("background_rect") or op.get("canvas_rect") + ) + if cleanup_source is None: + return None + return pymupdf.Rect(cleanup_source) + + +def _cleanup_rect_for_widget_op(op: dict[str, Any]) -> pymupdf.Rect | None: + """ + Builds the cleanup rectangle for a text widget operation. + + Args: + op (dict[str, Any]): The operation dictionary being processed. + + Returns: + pymupdf.Rect | None: The cleanup rectangle for the widget operation, if available. + """ + widget_info = op.get("widget_info") or {} + widget_rect = widget_info.get("rect") + if widget_rect is None: + return None + return pymupdf.Rect(widget_rect) + + +def _cleanup_rect_for_signature_widget_op(op: dict[str, Any]) -> pymupdf.Rect | None: + """ + Builds the cleanup rectangle for a signature widget operation. + + Args: + op (dict[str, Any]): The operation dictionary being processed. + + Returns: + pymupdf.Rect | None: The cleanup rectangle for the signature widget operation, if available. + """ + widget_rect = op.get("widget_rect") + if widget_rect is not None: + return pymupdf.Rect(widget_rect) + + background_rect = op.get("background_rect") or op.get("canvas_rect") + if background_rect is None: + return None + return pymupdf.Rect(background_rect) + + +def _collect_link_cleanup_rects( + page_ops: dict[int, list[dict]], + widget_ops: dict[int, list[dict]], + signature_widget_ops: dict[int, list[dict]], +) -> dict[int, list[pymupdf.Rect]]: + """ + Collects cleanup rectangles used to prune overlapping links. + + Args: + page_ops (dict[int, list[dict]]): The collected page operations grouped by page index. + widget_ops (dict[int, list[dict]]): The collected text widget operations grouped by page index. + signature_widget_ops (dict[int, list[dict]]): The collected signature widget operations grouped by page index. + + Returns: + dict[int, list[pymupdf.Rect]]: The cleanup rectangles grouped by page index. + """ + cleanup_rects: dict[int, list[pymupdf.Rect]] = {} + + for page_idx, ops in page_ops.items(): + for op in ops: + _append_cleanup_rect(cleanup_rects, page_idx, _cleanup_rect_for_page_op(op)) + + for page_idx, ops in widget_ops.items(): + for op in ops: + _append_cleanup_rect( + cleanup_rects, + page_idx, + _cleanup_rect_for_widget_op(op), + ) + + for page_idx, ops in signature_widget_ops.items(): + for op in ops: + _append_cleanup_rect( + cleanup_rects, + page_idx, + _cleanup_rect_for_signature_widget_op(op), + ) + + return cleanup_rects + + +def _remove_overlapping_page_links( + doc: pymupdf.Document, + cleanup_rects: dict[int, list[pymupdf.Rect]], +) -> None: + """ + Deletes page links that overlap anonymized regions. + + Args: + doc (pymupdf.Document): The PDF document being processed. + cleanup_rects (dict[int, list[pymupdf.Rect]]): The cleanup rectangles grouped by page index. + """ + for page_idx, page_rects in cleanup_rects.items(): + if not page_rects: + continue + + page = doc[page_idx] + for link in list(page.get_links()): + link_rect = link.get("from") + if link_rect is None: + continue + link_rect = pymupdf.Rect(link_rect) + if not any(link_rect.intersects(rect) for rect in page_rects): + continue + try: + page.delete_link(link) + except Exception as exc: + logger.warning( + "Failed to delete PDF link on page=%s rect=%s: %s", + page_idx, + tuple(round(value, 2) for value in link_rect), + exc, + ) + + +def _remove_remaining_annotations(doc: pymupdf.Document) -> None: + """ + Deletes residual page annotations after sanitization. + + Args: + doc (pymupdf.Document): The PDF document being processed. + """ + for page_idx, page in enumerate(doc): + for annot in list(page.annots() or []): + try: + page.delete_annot(annot) + except Exception as exc: + logger.warning( + "Failed to delete residual PDF annotation on page=%s: %s", + page_idx, + exc, + ) + + +def _clear_standard_metadata(doc: pymupdf.Document) -> None: + """ + Clears the standard PDF metadata fields on a document. + + Args: + doc (pymupdf.Document): The PDF document being processed. + """ + doc.set_metadata( + { + "title": "", + "author": "", + "subject": "", + "keywords": "", + "creator": "", + "producer": "", + "creationDate": "", + "modDate": "", + "trapped": "", + } + ) + + +def _apply_aymurai_metadata(doc: pymupdf.Document) -> None: + """ + Applies the configured AymurAI tooling metadata fields to the PDF document. + + Args: + doc (pymupdf.Document): The PDF document being processed. + """ + metadata = dict(doc.metadata or {}) + metadata.update( + { + "title": metadata.get("title") or "", + "author": "", + "subject": metadata.get("subject") or "", + "keywords": metadata.get("keywords") or "", + "creator": settings.ANONYMIZATION_METADATA_CREATOR, + "producer": settings.ANONYMIZATION_METADATA_PRODUCER, + "creationDate": metadata.get("creationDate") or "", + "modDate": _pdf_metadata_mod_date(), + "trapped": metadata.get("trapped") or "", + } + ) + doc.set_metadata(metadata) + + +def _sanitize_document( + doc: pymupdf.Document, + cleanup_rects: dict[int, list[pymupdf.Rect]], +) -> None: + """ + Sanitizes document-level PDF metadata, attachments, and annotations. + + Args: + doc (pymupdf.Document): The PDF document being processed. + cleanup_rects (dict[int, list[pymupdf.Rect]]): The cleanup rectangles grouped by page index. + """ + _remove_overlapping_page_links(doc, cleanup_rects) + doc.scrub( + metadata=True, + xml_metadata=True, + javascript=True, + attached_files=True, + embedded_files=True, + thumbnails=True, + reset_responses=True, + hidden_text=True, + clean_pages=True, + remove_links=False, + reset_fields=False, + redactions=False, + ) + _remove_remaining_annotations(doc) + _clear_standard_metadata(doc) + _apply_aymurai_metadata(doc) + + get_xml_metadata = getattr(doc, "get_xml_metadata", None) + del_xml_metadata = getattr(doc, "del_xml_metadata", None) + if callable(get_xml_metadata) and callable(del_xml_metadata): + try: + xml_metadata = get_xml_metadata() + except Exception as exc: + logger.warning("Failed to read PDF XML metadata after scrub: %s", exc) + else: + if xml_metadata: + try: + del_xml_metadata() + except Exception as exc: + logger.warning( + "Failed to delete residual PDF XML metadata: %s", + exc, + ) diff --git a/aymurai/text/anonymization/pdf/watermark.py b/aymurai/text/anonymization/pdf/watermark.py new file mode 100644 index 00000000..c15d9aef --- /dev/null +++ b/aymurai/text/anonymization/pdf/watermark.py @@ -0,0 +1,522 @@ +from __future__ import annotations + +import os +from functools import lru_cache +from pathlib import Path +from typing import Any + +import pymupdf + +from aymurai.logger import get_logger +from aymurai.settings import settings + +logger = get_logger(__name__) + +WATERMARK_PREFIX_TEXT = "Documento anonimizado por " +WATERMARK_LINK_TEXT = "AymurAI" +WATERMARK_TEXT = f"{WATERMARK_PREFIX_TEXT}{WATERMARK_LINK_TEXT}" +WATERMARK_URL = "https://www.aymurai.info/" +WATERMARK_FONT_SIZE = 10.0 +WATERMARK_MARGIN_X = 24.0 +WATERMARK_BASELINE_MARGIN = 12.0 +WATERMARK_TOP_BASELINE = 22.0 +WATERMARK_RECT_PADDING_X = 4.0 +WATERMARK_RECT_PADDING_Y = 4.0 +WATERMARK_COLLISION_PADDING = 12.0 +WATERMARK_TEXT_COLOR = tuple(channel / 255 for channel in (192, 192, 192)) +WATERMARK_LINK_COLOR = tuple(channel / 255 for channel in (115, 190, 250)) + + +def _candidate_font_paths() -> tuple[list[Path], list[Path]]: + """ + Builds the ordered list of candidate font paths for the PDF watermark. + + Returns: + tuple[list[Path], list[Path]]: The regular and bold watermark font candidates. + """ + override_regular = ( + os.getenv("PDF_WATERMARK_FONT_REGULAR") or settings.PDF_WATERMARK_FONT_REGULAR + ) + override_bold = ( + os.getenv("PDF_WATERMARK_FONT_BOLD") or settings.PDF_WATERMARK_FONT_BOLD + ) + + regular_candidates: list[Path] = [] + bold_candidates: list[Path] = [] + + if override_regular: + regular_candidates.append(Path(override_regular).expanduser()) + if override_bold: + bold_candidates.append(Path(override_bold).expanduser()) + + resource_roots: list[Path] = [] + resources_base = Path(settings.RESOURCES_BASEPATH) + if resources_base.is_absolute(): + resource_roots.append(resources_base) + else: + resource_roots.append((Path("/workspace") / resources_base).resolve()) + resource_roots.append(resources_base) + + font_roots: list[Path] = [] + for root in resource_roots: + font_roots.extend([root / "fonts", root / "fonts" / "archivo"]) + + for root in font_roots: + regular_candidates.extend( + [ + root / "Archivo-Regular.ttf", + root / "Archivo-Regular.otf", + root / "Archivo[wdth,wght].ttf", + root / "Archivo-VariableFont_wdth,wght.ttf", + ] + ) + bold_candidates.extend( + [ + root / "Archivo-Bold.ttf", + root / "Archivo-Bold.otf", + root / "Archivo-BoldItalic.ttf", + root / "Archivo-VariableFont_wdth,wght.ttf", + root / "Archivo[wdth,wght].ttf", + ] + ) + + system_roots = [ + Path("/usr/share/fonts/truetype/archivo"), + Path("/usr/share/fonts/opentype/archivo"), + Path("/usr/local/share/fonts/archivo"), + Path.home() / ".local/share/fonts", + Path.home() / ".local/share/fonts/archivo", + ] + for root in system_roots: + regular_candidates.extend( + [ + root / "Archivo-Regular.ttf", + root / "Archivo-Regular.otf", + root / "Archivo[wdth,wght].ttf", + root / "Archivo-VariableFont_wdth,wght.ttf", + ] + ) + bold_candidates.extend( + [ + root / "Archivo-Bold.ttf", + root / "Archivo-Bold.otf", + root / "Archivo-BoldItalic.ttf", + root / "Archivo-VariableFont_wdth,wght.ttf", + root / "Archivo[wdth,wght].ttf", + ] + ) + + return regular_candidates, bold_candidates + + +def _first_existing_path(paths: list[Path]) -> str | None: + """ + Returns the first existing file path from the provided candidates. + + Args: + paths (list[Path]): The candidate paths to inspect. + + Returns: + str | None: The first existing file path, if one is found. + """ + seen: set[str] = set() + for path in paths: + expanded = path.expanduser() + resolved = str(expanded) + if resolved in seen: + continue + seen.add(resolved) + if expanded.exists() and expanded.is_file(): + return str(expanded) + return None + + +@lru_cache(maxsize=1) +def _watermark_font_paths() -> tuple[str | None, str | None]: + """ + Resolves the font paths used by the PDF watermark. + + Returns: + tuple[str | None, str | None]: The resolved regular and bold watermark font paths. + """ + regular_candidates, bold_candidates = _candidate_font_paths() + regular_path = _first_existing_path(regular_candidates) + bold_path = _first_existing_path(bold_candidates) + if regular_path is None and bold_path is not None: + regular_path = bold_path + if bold_path is None: + bold_path = regular_path + return regular_path, bold_path + + +@lru_cache(maxsize=1) +def _watermark_font_config() -> dict[str, Any]: + """ + Builds the font configuration used to render the PDF watermark. + + Returns: + dict[str, Any]: The watermark font configuration dictionary. + """ + regular_path, bold_path = _watermark_font_paths() + if regular_path: + try: + return { + "text_fontname": "archivo-watermark", + "text_fontfile": regular_path, + "text_font": pymupdf.Font(fontfile=regular_path), + "link_fontname": "archivo-watermark-bold", + "link_fontfile": bold_path or regular_path, + "link_font": pymupdf.Font(fontfile=bold_path or regular_path), + } + except Exception as exc: + logger.warning( + "Could not load Archivo font for PDF watermark, falling back to Base-14 fonts: %s", + exc, + ) + + return { + "text_fontname": "Helvetica", + "text_fontfile": None, + "text_font": pymupdf.Font("Helvetica"), + "link_fontname": "Helvetica-Bold", + "link_fontfile": None, + "link_font": pymupdf.Font("Helvetica-Bold"), + } + + +def _watermark_text_length( + text: str, + *, + font_obj: pymupdf.Font, + fontname: str, + fontsize: float, +) -> float: + """ + Measures the rendered width of watermark text. + + Args: + text (str): The text value being normalized or searched. + font_obj (pymupdf.Font): The font object used for measurement. + fontname (str): The font name to use for measurement or rendering. + fontsize (float): The font size used for measurement or rendering. + + Returns: + float: The rendered width of the watermark text. + """ + try: + return float(font_obj.text_length(text, fontsize=fontsize)) + except Exception: + return float( + pymupdf.get_text_length(text, fontname=fontname, fontsize=fontsize) + ) + + +def _insert_watermark_text( + page: pymupdf.Page, + point: tuple[float, float], + text: str, + *, + fontname: str, + fontsize: float, + color: tuple[float, float, float], + fontfile: str | None = None, +) -> None: + """ + Inserts watermark text onto a page using the resolved font settings. + + Args: + page (pymupdf.Page): The PDF page being processed. + point (tuple[float, float]): The insertion point on the page. + text (str): The text value being normalized or searched. + fontname (str): The font name to use for measurement or rendering. + fontsize (float): The font size used for measurement or rendering. + color (tuple[float, float, float]): The PDF RGB color used to render the text. + fontfile (str | None, optional): The optional font file path to embed for rendering. Defaults to None. + """ + kwargs: dict[str, Any] = { + "fontsize": fontsize, + "fontname": fontname, + "color": color, + "overlay": True, + } + if fontfile: + kwargs["fontfile"] = fontfile + page.insert_text(point, text, **kwargs) + + +def _expanded_rect(rect: pymupdf.Rect, padding: float) -> pymupdf.Rect: + """ + Expands a rectangle by a uniform padding in every direction. + + Args: + rect (pymupdf.Rect): The rectangle to expand. + padding (float): The amount of padding to apply on every side. + + Returns: + pymupdf.Rect: The expanded rectangle. + """ + return pymupdf.Rect( + rect.x0 - padding, + rect.y0 - padding, + rect.x1 + padding, + rect.y1 + padding, + ) + + +def _watermark_corner_order(page_index: int) -> list[str]: + """ + Builds the preferred watermark corner order for a page. + + Args: + page_index (int): The page index being processed. + + Returns: + list[str]: The ordered watermark corner candidates for the page. + """ + if page_index % 2 == 0: + return ["bottom-right", "bottom-left", "top-left", "top-right"] + return ["bottom-left", "top-left", "top-right", "bottom-right"] + + +def _watermark_layout_for_corner( + page: pymupdf.Page, + corner: str, + *, + prefix_width: float, + link_width: float, + total_width: float, +) -> dict[str, Any]: + """ + Builds the watermark geometry for a specific page corner. + + Args: + page (pymupdf.Page): The PDF page being processed. + corner (str): The corner identifier used to position the watermark. + prefix_width (float): The rendered width of the watermark prefix text. + link_width (float): The rendered width of the watermark link text. + total_width (float): The total rendered width of the watermark text. + + Returns: + dict[str, Any]: The watermark layout data for the corner. + """ + if corner.endswith("right"): + x_start = max( + WATERMARK_MARGIN_X, + page.rect.width - total_width - WATERMARK_MARGIN_X, + ) + else: + x_start = WATERMARK_MARGIN_X + + if corner.startswith("bottom"): + baseline_y = page.rect.height - WATERMARK_BASELINE_MARGIN + else: + baseline_y = WATERMARK_TOP_BASELINE + + link_x = x_start + prefix_width + text_top = baseline_y - WATERMARK_FONT_SIZE + banner_rect = pymupdf.Rect( + x_start - WATERMARK_RECT_PADDING_X, + text_top - WATERMARK_RECT_PADDING_Y, + x_start + total_width + WATERMARK_RECT_PADDING_X, + baseline_y + WATERMARK_RECT_PADDING_Y, + ) + link_rect = pymupdf.Rect( + link_x, + text_top, + link_x + link_width, + baseline_y + 2.0, + ) + + return { + "corner": corner, + "x_start": x_start, + "baseline_y": baseline_y, + "link_x": link_x, + "banner_rect": banner_rect, + "link_rect": link_rect, + } + + +def _occupied_page_rects(page: pymupdf.Page) -> list[pymupdf.Rect]: + """ + Collects page rectangles already occupied by visible content. + + Args: + page (pymupdf.Page): The PDF page being processed. + + Returns: + list[pymupdf.Rect]: The occupied rectangles found on the page. + """ + occupied: list[pymupdf.Rect] = [] + + text_data = page.get_text("dict") + for block in text_data.get("blocks", []): + bbox = block.get("bbox") + if bbox is None: + continue + rect = pymupdf.Rect(bbox) + if rect.get_area() <= 0: + continue + occupied.append(_expanded_rect(rect, WATERMARK_COLLISION_PADDING)) + + for drawing in page.get_drawings(): + rect = drawing.get("rect") + if rect is None: + continue + rect = pymupdf.Rect(rect) + if rect.get_area() <= 0: + continue + occupied.append(_expanded_rect(rect, WATERMARK_COLLISION_PADDING)) + + return occupied + + +def _watermark_overlap_score( + banner_rect: pymupdf.Rect, + occupied_rects: list[pymupdf.Rect], +) -> tuple[float, float, int]: + """ + Scores a watermark placement by the amount of page content it overlaps. + + Args: + banner_rect (pymupdf.Rect): The watermark banner rectangle being scored. + occupied_rects (list[pymupdf.Rect]): The occupied page rectangles used for overlap checks. + + Returns: + tuple[float, float, int]: The overlap ratio, overlap area, and overlap count for the placement. + """ + overlap_area = 0.0 + overlap_count = 0 + banner_area = max(banner_rect.get_area(), 1.0) + + for rect in occupied_rects: + if not banner_rect.intersects(rect): + continue + intersection = banner_rect & rect + area = intersection.get_area() + if area <= 0: + continue + overlap_area += area + overlap_count += 1 + + return overlap_area / banner_area, overlap_area, overlap_count + + +def _choose_watermark_layout( + page: pymupdf.Page, + page_index: int, + *, + prefix_width: float, + link_width: float, + total_width: float, +) -> dict[str, Any]: + """ + Selects the watermark placement with the least overlap on a page. + + Args: + page (pymupdf.Page): The PDF page being processed. + page_index (int): The page index being processed. + prefix_width (float): The rendered width of the watermark prefix text. + link_width (float): The rendered width of the watermark link text. + total_width (float): The total rendered width of the watermark text. + + Returns: + dict[str, Any]: The chosen watermark layout data. + """ + occupied_rects = _occupied_page_rects(page) + candidate_layouts = [ + _watermark_layout_for_corner( + page, + corner, + prefix_width=prefix_width, + link_width=link_width, + total_width=total_width, + ) + for corner in _watermark_corner_order(page_index) + ] + + best_layout = candidate_layouts[0] + best_score: tuple[float, float, int] | None = None + + for layout in candidate_layouts: + score = _watermark_overlap_score(layout["banner_rect"], occupied_rects) + if score[0] == 0.0 and score[1] == 0.0: + return layout + if best_score is None or score < best_score: + best_layout = layout + best_score = score + + return best_layout + + +def add_pdf_footer_watermark(doc: pymupdf.Document) -> None: + """ + Adds the anonymization watermark to the least crowded corner of each PDF page. + + Args: + doc (pymupdf.Document): The PDF document being processed. + """ + font_config = _watermark_font_config() + prefix_width = _watermark_text_length( + WATERMARK_PREFIX_TEXT, + font_obj=font_config["text_font"], + fontname=font_config["text_fontname"], + fontsize=WATERMARK_FONT_SIZE, + ) + link_width = _watermark_text_length( + WATERMARK_LINK_TEXT, + font_obj=font_config["link_font"], + fontname=font_config["link_fontname"], + fontsize=WATERMARK_FONT_SIZE, + ) + total_width = prefix_width + link_width + + for page_index, page in enumerate(doc): + layout = _choose_watermark_layout( + page, + page_index, + prefix_width=prefix_width, + link_width=link_width, + total_width=total_width, + ) + baseline_y = layout["baseline_y"] + x_start = layout["x_start"] + link_x = layout["link_x"] + + _insert_watermark_text( + page, + (x_start, baseline_y), + WATERMARK_PREFIX_TEXT, + fontname=font_config["text_fontname"], + fontsize=WATERMARK_FONT_SIZE, + color=WATERMARK_TEXT_COLOR, + fontfile=font_config["text_fontfile"], + ) + _insert_watermark_text( + page, + (link_x, baseline_y), + WATERMARK_LINK_TEXT, + fontname=font_config["link_fontname"], + fontsize=WATERMARK_FONT_SIZE, + color=WATERMARK_LINK_COLOR, + fontfile=font_config["link_fontfile"], + ) + + if layout["corner"].startswith("bottom"): + underline_y = min(page.rect.height - 1.0, baseline_y + 1.0) + else: + underline_y = baseline_y + 1.0 + page.draw_line( + (link_x, underline_y), + (link_x + link_width, underline_y), + color=WATERMARK_LINK_COLOR, + width=0.8, + overlay=True, + ) + page.insert_link( + { + "kind": pymupdf.LINK_URI, + "from": layout["link_rect"], + "uri": WATERMARK_URL, + } + ) diff --git a/aymurai/text/anonymization/pdf/widgets.py b/aymurai/text/anonymization/pdf/widgets.py new file mode 100644 index 00000000..3ea97d7e --- /dev/null +++ b/aymurai/text/anonymization/pdf/widgets.py @@ -0,0 +1,323 @@ +from __future__ import annotations + +from typing import Any + +import pymupdf + +from aymurai.logger import get_logger +from aymurai.text.anonymization.pdf.common import ( + _build_display_token_candidates, + _default_style, + _find_flexible, + _get_base14_font, +) + +logger = get_logger(__name__) + + +def _signature_background_rect( + op: dict[str, Any], + widget_rect: pymupdf.Rect, +) -> pymupdf.Rect: + """ + Builds the background rectangle used for a signature replacement. + + Args: + op (dict[str, Any]): The operation dictionary being processed. + widget_rect (pymupdf.Rect): The rectangle occupied by the widget. + + Returns: + pymupdf.Rect: The background rectangle for the signature replacement. + """ + background = pymupdf.Rect( + op.get("line_rect") or op.get("canvas_rect") or widget_rect + ) + canvas_rect = op.get("canvas_rect") + if canvas_rect is not None: + background.include_rect(pymupdf.Rect(canvas_rect)) + + pad_x = max(background.height * 0.75, 2.0) + pad_y = max(background.height * 0.25, 0.75) + widget_clip = pymupdf.Rect(widget_rect) + + background.x0 = max(widget_clip.x0, background.x0 - pad_x) + background.y0 = max(widget_clip.y0, background.y0 - pad_y) + background.x1 = min(widget_clip.x1, background.x1 + pad_x) + background.y1 = min(widget_clip.y1, background.y1 + pad_y) + return background + + +def _widget_text_color(widget: pymupdf.Widget) -> tuple[float, float, float]: + """ + Extracts the text color configured on a PDF widget. + + Args: + widget (pymupdf.Widget): The widget being processed. + + Returns: + tuple[float, float, float]: The widget text color in PDF RGB components. + """ + values = list(widget.text_color or []) + if not values: + return (0.0, 0.0, 0.0) + if len(values) == 1: + shade = float(values[0]) + return (shade, shade, shade) + if len(values) >= 3: + return tuple(float(value) for value in values[:3]) + return (0.0, 0.0, 0.0) + + +def _style_from_widget(widget: pymupdf.Widget) -> dict[str, Any]: + """ + Builds a text style dictionary from a widget definition. + + Args: + widget (pymupdf.Widget): The widget being processed. + + Returns: + dict[str, Any]: The style dictionary derived from the widget. + """ + return { + "font": str(widget.text_font or ""), + "flags": 0, + "color": _widget_text_color(widget), + "size": float(widget.text_fontsize or 10.0), + "ascender": 0.8, + "descender": -0.2, + } + + +def _page_widget_infos(page: pymupdf.Page) -> list[dict[str, Any]]: + """ + Collects text and signature widget metadata for a page. + + Args: + page (pymupdf.Page): The PDF page being processed. + + Returns: + list[dict[str, Any]]: The widget metadata collected for the page. + """ + infos: list[dict[str, Any]] = [] + for widget in page.widgets() or []: + if widget.field_type not in ( + pymupdf.PDF_WIDGET_TYPE_TEXT, + pymupdf.PDF_WIDGET_TYPE_SIGNATURE, + ): + continue + infos.append( + { + "xref": int(widget.xref), + "field_type": int(widget.field_type), + "field_name": str(widget.field_name or ""), + "field_value": str(widget.field_value or ""), + "rect": pymupdf.Rect(widget.rect), + "style": _style_from_widget(widget), + } + ) + return infos + + +def _entity_overlaps_widget( + entity_rect: pymupdf.Rect, + widget_infos: list[dict[str, Any]], +) -> dict[str, Any] | None: + """ + Finds the widget that most overlaps the given entity rectangle. + + Args: + entity_rect (pymupdf.Rect): The rectangle representing the entity on the page. + widget_infos (list[dict[str, Any]]): The widget metadata available for overlap checks. + + Returns: + dict[str, Any] | None: The best overlapping widget info, if one exists. + """ + best_widget: dict[str, Any] | None = None + best_area = 0.0 + for widget_info in widget_infos: + widget_rect = widget_info["rect"] + if not entity_rect.intersects(widget_rect): + continue + area = (entity_rect & widget_rect).get_area() + if area > best_area: + best_area = area + best_widget = widget_info + return best_widget + + +def _fit_widget_token( + widget_info: dict[str, Any], + current_text: str, + entity_span: tuple[int, int], + token: str, +) -> str: + """ + Finds a token variant that fits inside a widget value. + + Args: + widget_info (dict[str, Any]): The widget metadata being processed. + current_text (str): The current widget text value. + entity_span (tuple[int, int]): The span of the entity inside the widget text. + token (str): The logical replacement token being processed. + + Returns: + str: The token variant that fits in the widget value. + """ + style = widget_info.get("style") or _default_style() + rect = pymupdf.Rect(widget_info["rect"]) + font_obj = _get_base14_font(style) + max_width = max(rect.width - 1.0, 1.0) + + prefix = current_text[: entity_span[0]] + suffix = current_text[entity_span[1] :] + + for candidate in _build_display_token_candidates(token): + candidate_text = f"{prefix}{candidate}{suffix}" + if ( + font_obj.text_length( + candidate_text, fontsize=float(style.get("size") or 10.0) + ) + <= max_width + 0.1 + ): + return candidate + + candidates = _build_display_token_candidates(token) + return candidates[0] if candidates else f"<{token}>" + + +def _apply_widget_ops( + doc: pymupdf.Document, + widget_ops: dict[int, list[dict]], +) -> None: + """ + Applies collected replacements to editable text widgets. + + Args: + doc (pymupdf.Document): The PDF document being processed. + widget_ops (dict[int, list[dict]]): The collected text widget operations grouped by page index. + """ + for page_idx, ops in widget_ops.items(): + if not ops: + continue + + page = doc[page_idx] + widgets = { + int(widget.xref): widget + for widget in (page.widgets() or []) + if widget.field_type == pymupdf.PDF_WIDGET_TYPE_TEXT + } + grouped: dict[int, list[dict]] = {} + for op in ops: + grouped.setdefault(int(op["widget_xref"]), []).append(op) + + for widget_xref, replacements in grouped.items(): + widget = widgets.get(widget_xref) + if widget is None: + logger.warning( + "Could not resolve PDF widget xref=%s on page=%s", + widget_xref, + page_idx, + ) + continue + + current_text = str(widget.field_value or "") + if not current_text: + continue + + search_cursor = 0 + changed = False + for replacement in replacements: + entity_text = replacement["entity_text"] + span = _find_flexible(current_text, entity_text, start=search_cursor) + if span is None: + span = _find_flexible(current_text, entity_text, start=0) + if span is None: + logger.warning( + "Could not map widget label '%s' in widget '%s' on page=%s", + entity_text, + replacement.get("field_name") or widget.field_name, + page_idx, + ) + continue + + token_text = _fit_widget_token( + replacement["widget_info"], + current_text, + span, + replacement["logical_token"], + ) + current_text = ( + f"{current_text[: span[0]]}{token_text}{current_text[span[1] :]}" + ) + search_cursor = span[0] + len(token_text) + changed = True + + if not changed: + continue + + try: + widget.field_value = current_text + widget.update() + except Exception as exc: + logger.warning( + "Failed to update PDF widget '%s' on page=%s: %s", + widget.field_name, + page_idx, + exc, + ) + + +def _prepare_signature_widget_ops( + doc: pymupdf.Document, + signature_widget_ops: dict[int, list[dict]], +) -> None: + """ + Deletes signature widgets and prepares their replacement operations. + + Args: + doc (pymupdf.Document): The PDF document being processed. + signature_widget_ops (dict[int, list[dict]]): The collected signature widget operations grouped by page index. + """ + for page_idx, ops in signature_widget_ops.items(): + if not ops: + continue + + page = doc[page_idx] + widgets = { + int(widget.xref): widget + for widget in (page.widgets() or []) + if widget.field_type == pymupdf.PDF_WIDGET_TYPE_SIGNATURE + } + grouped: dict[int, list[dict]] = {} + for op in ops: + grouped.setdefault(int(op["widget_xref"]), []).append(op) + + for widget_xref, widget_group_ops in grouped.items(): + widget = widgets.get(widget_xref) + widget_rect = pymupdf.Rect( + widget_group_ops[0].get("widget_rect") or (0, 0, 0, 0) + ) + + if widget is not None: + widget_rect = pymupdf.Rect(widget.rect) + try: + page.delete_widget(widget) + except Exception as exc: + logger.warning( + "Failed to delete signature widget xref=%s on page=%s: %s", + widget_xref, + page_idx, + exc, + ) + else: + logger.warning( + "Could not resolve PDF signature widget xref=%s on page=%s", + widget_xref, + page_idx, + ) + + for op in widget_group_ops: + op["widget_rect"] = pymupdf.Rect(widget_rect) + op["asset_rect"] = pymupdf.Rect(widget_rect) + op["graphics_mode"] = pymupdf.PDF_REDACT_LINE_ART_REMOVE_IF_COVERED + op["background_rect"] = _signature_background_rect(op, widget_rect) diff --git a/aymurai/text/extractors/pdf.py b/aymurai/text/extractors/pdf.py index 0e83c30d..c672dfe7 100644 --- a/aymurai/text/extractors/pdf.py +++ b/aymurai/text/extractors/pdf.py @@ -9,27 +9,11 @@ class PdfExtractor(BaseExtractor): extension = "pdf" - def extract(self, path: Path, y_tolerance: float | None = None, **_: Any) -> str: - """ - Extract normalized text from a PDF document. - - Args: - path (Path): Input document path. - y_tolerance (float | None, optional): Maximum vertical gap used to - merge nearby text blocks. If None, it is estimated from the - document. Defaults to None. - **_ (Any): Ignored extra keyword arguments for backward compatibility. - - Returns: - str: Cleaned textual content. - - Raises: - InvalidFile: If the file is unreadable or extraction fails. - """ + def extract(self, path: Path, **_: Any) -> str: file_path = self.ensure_file(path) try: - return pdf_to_text(file_path, y_tolerance=y_tolerance) + return pdf_to_text(file_path) except (OSError, ValueError) as exc: raise InvalidFile(str(exc)) from exc except Exception as exc: diff --git a/aymurai/text/extractors/utils.py b/aymurai/text/extractors/utils.py index 009b562d..8db4c661 100644 --- a/aymurai/text/extractors/utils.py +++ b/aymurai/text/extractors/utils.py @@ -1,12 +1,13 @@ -import statistics +import re import unicodedata import xml.etree.ElementTree as ET import zipfile from pathlib import Path -from typing import Any +from typing import AbstractSet, Any -import numpy as np import pymupdf +import pymupdf.layout # noqa: F401 # activates layout support +import pymupdf4llm import xmltodict from lxml import etree from more_itertools import flatten @@ -18,6 +19,7 @@ ODT_NS = {"text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0"} +PDF_SKIP_BOX_CLASSES = frozenset({"picture", "formula", "table"}) def normalize_text(text: str) -> str: @@ -33,109 +35,83 @@ def normalize_text(text: str) -> str: return unicodedata.normalize("NFKC", text) -def _compute_median_margin_between_blocks(pdf_path: str) -> float: +def _clean_pdf_box_text(text: str, box_class: str) -> str: """ - Computes the median vertical margin between text blocks in a PDF. + Clean box-level PDF text while preserving the original layout content. + Args: - pdf_path (str): Path to the PDF file. + text (str): Raw text sliced from a page box. + box_class (str): Box class emitted by ``pymupdf4llm``. + Returns: - float: Median margin between text blocks (in points). + str: Cleaned, normalized box text. """ - margins = [] - - with pymupdf.open(pdf_path) as doc: - for page in doc: - # Extract all text blocks from the page - blocks = page.get_text("blocks") - - # Sort blocks by their top y-coordinate (y0) - blocks_sorted = sorted(blocks, key=lambda b: b[1]) - - # Compute vertical margins between consecutive blocks - for i in range(1, len(blocks_sorted)): - previous_block = blocks_sorted[i - 1] - current_block = blocks_sorted[i] - - # Calculate the vertical margin - previous_y1 = previous_block[3] # Bottom of the previous block - current_y0 = current_block[1] # Top of the current block - margin = current_y0 - previous_y1 + text = normalize_text(text).strip() + if box_class == "footnote": + text = re.sub(r"(?m)^>\s?", "", text) + return text - if margin > 0: # Ignore overlapping blocks - margins.append(margin) - # Compute and return the median margin - if margins: - return statistics.median(margins) - else: - return 0.0 # Return 0 if no margins were found - - -def _extract_and_merge_paragraphs(pdf_path: str, y_tolerance: float = 5) -> list[str]: +def pdf_to_paragraphs( + file_path: Path | str, + *, + include_headers: bool = True, + include_footers: bool = True, + skip_box_classes: AbstractSet[str] = PDF_SKIP_BOX_CLASSES, +) -> list[str]: """ - Extracts and merges paragraphs from a PDF by grouping close text blocks. + Extract paragraph-like layout units from a PDF using PyMuPDF layout parsing. + Args: - pdf_path (str): Path to the PDF file. - y_tolerance (float, optional): Maximum vertical gap (in points) to consider blocks part of the same paragraph. - Defaults to 5. + file_path (Path | str): Path to the PDF document. + include_headers (bool): Whether to keep header boxes. Defaults to True. + include_footers (bool): Whether to keep footer boxes. Defaults to True. + skip_box_classes (AbstractSet[str]): Layout box classes to ignore. Defaults to PDF_SKIP_BOX_CLASSES. + Returns: - list[str]: A list of merged paragraphs as strings. + list[str]: Normalized paragraph strings extracted from the PDF. """ - paragraphs = [] - current_paragraph = [] - last_y1 = None - - with pymupdf.open(pdf_path) as doc: - for page in doc: - # Extract all text blocks from the page - blocks = page.get_text("blocks") - - # Sort blocks by their top y-coordinate (y0) - blocks_sorted = sorted(blocks, key=lambda b: b[1]) - - for block in blocks_sorted: - x0, y0, x1, y1, text, *_ = block - - if last_y1 is not None and (y0 - last_y1) > y_tolerance: - # If the gap between blocks is too large, start a new paragraph - if current_paragraph: - paragraphs.append(" ".join(current_paragraph)) - current_paragraph = [] - - current_paragraph.append(text) - last_y1 = y1 - - if current_paragraph: - paragraphs.append(" ".join(current_paragraph)) - current_paragraph = [] + logger.debug("Extracting layout paragraphs from PDF: %s", file_path) + + with pymupdf.open(str(file_path)) as doc: + chunks = pymupdf4llm.to_text( + doc, + filename=str(file_path), + page_chunks=True, + header=include_headers, + footer=include_footers, + show_progress=False, + force_text=True, + use_ocr=False, + force_ocr=False, + ) + + paragraphs: list[str] = [] + for chunk in chunks: + page_text = chunk.get("text") or "" + for box in chunk.get("page_boxes") or []: + if box.get("class") in skip_box_classes: + continue + + start, stop = box.get("pos", (0, 0)) + text = _clean_pdf_box_text(page_text[start:stop], box.get("class") or "") + if text: + paragraphs.append(text) return paragraphs -def pdf_to_text( - file_path: Path | str, - y_tolerance: float | None = None, -) -> str: +def pdf_to_text(file_path: Path | str) -> str: """ - Extract text from a PDF file and return normalized plain text. + Extract normalized plain text from a PDF using filtered layout boxes. Args: - file_path (Path): Path to the PDF document. - y_tolerance (float, optional): Maximum vertical gap (in points) to consider blocks part of the same paragraph. - If None, it will be computed as the median margin between blocks. Defaults to None. + file_path (Path | str): Path to the PDF document. Returns: str: Cleaned textual content extracted from the PDF. """ - logger.info("Extracting text from PDF: %s", file_path) - - if y_tolerance is None: - y_tolerance = _compute_median_margin_between_blocks(file_path) - - paragraphs = _extract_and_merge_paragraphs(file_path, np.ceil(y_tolerance)) - docu = "\n\n".join(paragraphs) - - return normalize_text(docu) + return "\n\n".join(pdf_to_paragraphs(file_path)) def load_xml_from_docx(path: Path, xmlfile: str = "word/footnotes.xml") -> Any | None: diff --git a/aymurai/text/normalize.py b/aymurai/text/normalize.py index 9027a0d8..4154533b 100644 --- a/aymurai/text/normalize.py +++ b/aymurai/text/normalize.py @@ -2,45 +2,72 @@ import unicodedata -def document_normalize(text: str) -> str: - """Normalize extracted text from documents - * join invalid newlines - * remove continous whitespaces +def _normalize_document_characters(text: str) -> str: + """ + Apply character-level normalization without changing document structure. Args: - text (str): document + text (str): Raw extracted document text. Returns: - str: normalized + str: Character-normalized text. """ - - # normalize character encodings - # text = unicodedata.normalize("NFKD", text) + text = text.replace("\r\n", "\n").replace("\r", "\n") text = unicodedata.normalize("NFKC", text) + text = re.sub(r"(“|”)", '"', text) + text = text.replace("\\/", "/") + text = re.sub(r"[ \t]{2,}", " ", text) + return text + - # remove continous whitespace - text = re.sub(r" {2,}", r" ", text) +def _normalize_paragraph_text(text: str) -> str: + """ + Normalize text inside a single paragraph while preserving paragraph borders. + + Args: + text (str): Paragraph text. + + Returns: + str: Normalized paragraph content. + """ + text = re.sub(r"[ \t]*\n[ \t]*", "\n", text.strip()) # delete newline if NEXT char is: # - lower character or a number - # - punctuanion + # - punctuation text = re.sub(r"\n([a-z0-9;:,\.])", r" \g<1>", text) # delete newline if PREVIOUS char is: # - quote mark - # - punctuanions (except '.' because possible ambiguity) + # - punctuations (except '.' because possible ambiguity) text = re.sub(r"([\w,\"-])\n", r"\g<1> ", text) # cleanup some junk - # - multiple newlines, hyphens - text = re.sub(r"\n{2,}", "\n", text) text = re.sub(r"[-]{2,}", "-", text) text = re.sub(r"\.-", ".", text) + text = re.sub(r" {2,}", " ", text) + return text.strip() - # quotation marks - text = re.sub(r"(“|”)", '"', text) - # scaped slashes - text = text.replace("\/", "/") +def document_normalize(text: str, *, preserve_paragraphs: bool = False) -> str: + """Normalize extracted text from documents. - return text + Args: + text (str): Document text. + preserve_paragraphs (bool): Preserve blank-line paragraph boundaries. Defaults to False. + + Returns: + str: Normalized document text. + """ + text = _normalize_document_characters(text) + + if preserve_paragraphs: + paragraphs = [ + _normalize_paragraph_text(paragraph) + for paragraph in re.split(r"\n\s*\n+", text) + if paragraph.strip() + ] + return "\n\n".join(paragraphs) + + text = _normalize_paragraph_text(text) + return re.sub(r"\n{2,}", "\n", text) diff --git a/docs/es/pipelines/anonymizer/README.md b/docs/es/pipelines/anonymizer/README.md index 2d241616..f7f71857 100644 --- a/docs/es/pipelines/anonymizer/README.md +++ b/docs/es/pipelines/anonymizer/README.md @@ -47,7 +47,7 @@ Fuente editable: [../../../pipelines/anonymizer/pipeline.excalidraw](../../../pi ### Módulos backend relevantes - Router: `aymurai/api/endpoints/routers/anonymizer/anonymizer.py` -- Render/anonymize: `aymurai/text/anonymization/doc_anonymizer.py` +- Render/anonymize: `aymurai/text/anonymization/docx.py` and `aymurai/text/anonymization/pdf.py` - Desambiguación canónica: `aymurai/utils/entity_disambiguation/` ## Persistencia (DB) diff --git a/docs/pipelines/anonymizer/README.md b/docs/pipelines/anonymizer/README.md index 11e864e7..67880ba0 100644 --- a/docs/pipelines/anonymizer/README.md +++ b/docs/pipelines/anonymizer/README.md @@ -47,7 +47,7 @@ Editable source: [pipeline.excalidraw](pipeline.excalidraw) ### Core backend modules - Router: `aymurai/api/endpoints/routers/anonymizer/anonymizer.py` -- Rendering: `aymurai/text/anonymization/doc_anonymizer.py` +- Rendering: `aymurai/text/anonymization/docx.py` and `aymurai/text/anonymization/pdf.py` - Canonical entity mapping: `aymurai/utils/entity_disambiguation/` ## Persistence (DB) diff --git a/notebooks/experiments/pdf-support/06-pymupdf-layout.ipynb b/notebooks/experiments/pdf-support/06-pymupdf-layout.ipynb new file mode 100644 index 00000000..803c8d22 --- /dev/null +++ b/notebooks/experiments/pdf-support/06-pymupdf-layout.ipynb @@ -0,0 +1,253 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "1098eca1", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext rich\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] + }, + { + "cell_type": "markdown", + "id": "7e81fbe5", + "metadata": {}, + "source": [ + "# End-to-End PDF Anonymization (PyMuPDF Layout + AymurAI API)\n", + "This notebook builds layout-based paragraphs from the source PDF, runs `/anonymizer/predict` + `/anonymizer/disambiguate`, and compiles an anonymized PDF.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "258fbd18", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import time\n", + "from pathlib import Path\n", + "\n", + "import pymupdf\n", + "import requests\n", + "from tqdm.auto import tqdm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fcfd985e", + "metadata": {}, + "outputs": [], + "source": [ + "# Change these values to test different documents/environments.\n", + "API_URL = \"http://localhost:8999\"\n", + "SOURCE_PDF = Path(\"./document.pdf\")\n", + "\n", + "OUTPUT_DIR = Path(\"./output\")\n", + "USE_CACHE = False\n", + "\n", + "# Optional: keep as None to rely on backend default policies.\n", + "LABEL_POLICIES = None\n", + "\n", + "# Keep aligned with current anonymizer defaults.\n", + "RENDER_POLICY = {\"suffix_mode\": \"auto\", \"suffix_threshold\": 1}\n", + "\n", + "SOURCE_PDF" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3860b71", + "metadata": {}, + "outputs": [], + "source": [ + "def extract_document_via_api(pdf_path: Path) -> dict:\n", + " with pdf_path.open(\"rb\") as handle:\n", + " response = requests.post(\n", + " f\"{API_URL}/document-extract\",\n", + " files={\"file\": (pdf_path.name, handle, \"application/pdf\")},\n", + " timeout=600,\n", + " )\n", + "\n", + " response.raise_for_status()\n", + " return response.json()\n", + "\n", + "\n", + "def predict_paragraph(text: str, retries: int = 2) -> dict:\n", + " last_error = None\n", + " for attempt in range(retries + 1):\n", + " try:\n", + " response = requests.post(\n", + " f\"{API_URL}/anonymizer/predict\",\n", + " json={\"text\": text},\n", + " params={\"use_cache\": USE_CACHE},\n", + " timeout=600,\n", + " )\n", + " response.raise_for_status()\n", + " return response.json()\n", + " except Exception as exc:\n", + " last_error = exc\n", + " if attempt < retries:\n", + " time.sleep(2)\n", + " else:\n", + " raise last_error\n", + "\n", + " raise RuntimeError(\"Predict request exhausted retries\")\n", + "\n", + "\n", + "def disambiguate(predictions: list[dict]) -> dict:\n", + " payload = {\"paragraphs\": predictions}\n", + " if LABEL_POLICIES is not None:\n", + " payload[\"label_policies\"] = LABEL_POLICIES\n", + "\n", + " response = requests.post(\n", + " f\"{API_URL}/anonymizer/disambiguate\",\n", + " json=payload,\n", + " timeout=600,\n", + " )\n", + " response.raise_for_status()\n", + " return response.json()\n", + "\n", + "\n", + "def compile_pdf(pdf_path: Path, annotations: dict) -> Path:\n", + " payload = {\n", + " \"data\": annotations[\"data\"],\n", + " \"render_policy\": RENDER_POLICY,\n", + " }\n", + " if annotations.get(\"label_policies\") is not None:\n", + " payload[\"label_policies\"] = annotations[\"label_policies\"]\n", + "\n", + " with pdf_path.open(\"rb\") as handle:\n", + " response = requests.post(\n", + " f\"{API_URL}/anonymizer/anonymize-document\",\n", + " data={\"annotations\": json.dumps(payload, ensure_ascii=False)},\n", + " files={\"file\": (pdf_path.name, handle, \"application/pdf\")},\n", + " timeout=1200,\n", + " )\n", + "\n", + " response.raise_for_status()\n", + "\n", + " OUTPUT_DIR.mkdir(parents=True, exist_ok=True)\n", + " output_path = OUTPUT_DIR / f\"{pdf_path.stem}.anonymized.pdf\"\n", + " output_path.write_bytes(response.content)\n", + " return output_path" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0a54485", + "metadata": {}, + "outputs": [], + "source": [ + "document_extract_payload = extract_document_via_api(SOURCE_PDF)\n", + "paragraphs = document_extract_payload[\"document\"]\n", + "\n", + "print(f\"Document ID: {document_extract_payload['document_id']}\")\n", + "print(f\"Paragraphs extracted: {len(paragraphs)}\")\n", + "\n", + "paragraphs[:5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3beaadee", + "metadata": {}, + "outputs": [], + "source": [ + "predictions = [\n", + " predict_paragraph(paragraph)\n", + " for paragraph in tqdm(paragraphs, desc=\"Predicting paragraphs\")\n", + "]\n", + "total_labels = sum(len(pred.get(\"labels\") or []) for pred in predictions)\n", + "print(f\"Predictions: {len(predictions)} paragraphs, {total_labels} labels\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "682760e0", + "metadata": {}, + "outputs": [], + "source": [ + "disambiguated = disambiguate(predictions)\n", + "total_labels = sum(len(pred.get(\"labels\") or []) for pred in disambiguated[\"data\"])\n", + "print(f\"Disambiguated labels: {total_labels}\")\n", + "disambiguated.keys()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "eae3f2c9", + "metadata": {}, + "outputs": [], + "source": [ + "[data for data in disambiguated[\"data\"] if data[\"labels\"]]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "665dde4a", + "metadata": {}, + "outputs": [], + "source": [ + "output_pdf = compile_pdf(SOURCE_PDF, disambiguated)\n", + "print(output_pdf.resolve())\n", + "output_pdf" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "715a782a", + "metadata": {}, + "outputs": [], + "source": [ + "with pymupdf.open(str(output_pdf)) as doc:\n", + " watermark_hits = sum(\n", + " len(page.search_for(\"Documento anonimizado por AymurAI\")) for page in doc\n", + " )\n", + " print(f\"Pages: {doc.page_count}\")\n", + " print(f\"Watermark hits: {watermark_hits}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a274809", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "aymurai", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.20" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/tests/api/routers/anonymizer/test_anonymizer.py b/tests/api/routers/anonymizer/test_anonymizer.py index 54a627e1..e003ad33 100644 --- a/tests/api/routers/anonymizer/test_anonymizer.py +++ b/tests/api/routers/anonymizer/test_anonymizer.py @@ -1,14 +1,304 @@ +import base64 import json +import re import subprocess -from unittest.mock import patch +import sys +from datetime import datetime, timedelta, timezone +from pathlib import Path +from unittest.mock import MagicMock, patch +import pymupdf import pytest +from docx import Document from aymurai.database.schema import AnonymizationParagraph from aymurai.database.utils import text_to_uuid +from aymurai.text.anonymization import DocxAnonymizer, PdfAnonymizer, get_anonymizer +from aymurai.text.anonymization.alignment import index_paragraphs from tests.api.conftest import build_label from tests.api.routers.conftest import build_mock_pipeline +PNG_1X1 = base64.b64decode( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+a6R8AAAAASUVORK5CYII=" +) +WATERMARK_URL = "https://www.aymurai.info/" + +WINDOWS_PYMUPDF_LAYOUT_XFAIL = pytest.mark.xfail( + sys.platform == "win32", + reason="pymupdf4llm ONNX layout model receives int32 tensors on Windows (expects int64)", + strict=False, +) + + +def _write_pdf(path: Path, configure) -> Path: + doc = pymupdf.open() + page = doc.new_page() + configure(doc, page) + doc.save(path) + doc.close() + return path + + +def _label_dict(text: str, label: str = "PER", **attrs) -> dict: + payload = build_label(label, text).model_dump(mode="json") + payload["attrs"].update(attrs) + return payload + + +def _run_pdf_anonymizer( + tmp_path: Path, + source_path: Path, + document: str, + labels: list[dict], +) -> Path: + output_dir = tmp_path / "out" + output_dir.mkdir(exist_ok=True) + output_path = PdfAnonymizer().anonymize( + {"path": str(source_path)}, + [{"document": document, "labels": labels}], + str(output_dir), + ) + return Path(output_path) + + +@pytest.mark.integration +def test_anonymization_package_exports_and_registry_are_stable(): + assert PdfAnonymizer.__name__ == "PdfAnonymizer" + assert DocxAnonymizer.__name__ == "DocxAnonymizer" + assert isinstance(get_anonymizer("pdf"), PdfAnonymizer) + assert isinstance(get_anonymizer("docx"), DocxAnonymizer) + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_falls_back_from_invalid_alt_offsets(tmp_path): + document = "Ana Perez firmo el escrito" + source_path = _write_pdf( + tmp_path / "invalid-alt.pdf", + lambda _doc, page: page.insert_text((72, 72), document), + ) + labels = [ + _label_dict( + "Ana Perez", + aymurai_alt_start_char=999, + aymurai_alt_end_char=1000, + ) + ] + + output_path = _run_pdf_anonymizer(tmp_path, source_path, document, labels) + + with pymupdf.open(output_path) as output_doc: + page_text = output_doc[0].get_text() + + assert "Ana Perez" not in page_text + assert "" in page_text + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_scrubs_pdf_payloads_and_preserves_safe_links(tmp_path): + document = "Ana Perez presento el escrito" + + def configure(doc: pymupdf.Document, page: pymupdf.Page) -> None: + page.insert_text((72, 72), document) + sensitive_rect = page.search_for("Ana Perez")[0] + page.insert_link( + { + "kind": pymupdf.LINK_URI, + "from": sensitive_rect, + "uri": "https://secret.example", + } + ) + safe_rect = pymupdf.Rect(72, 140, 180, 155) + page.insert_text((72, 150), "Portal publico") + page.insert_link( + { + "kind": pymupdf.LINK_URI, + "from": safe_rect, + "uri": "https://safe.example", + } + ) + page.add_file_annot((220, 72), b"attached secret", "attached.txt") + doc.set_metadata( + { + "title": "Secret title", + "author": "Secret author", + "subject": "Secret subject", + "keywords": "alpha,beta", + "creator": "Secret creator", + "producer": "Secret producer", + } + ) + doc.set_xml_metadata("top-secret") + doc.embfile_add("secret.txt", b"secret bytes", filename="secret.txt") + + source_path = _write_pdf(tmp_path / "metadata.pdf", configure) + labels = [_label_dict("Ana Perez")] + + output_path = _run_pdf_anonymizer(tmp_path, source_path, document, labels) + + with pymupdf.open(output_path) as output_doc: + page = output_doc[0] + link_uris = {link.get("uri") for link in page.get_links()} + + assert output_doc.metadata.get("title") == "" + assert output_doc.metadata.get("subject") == "" + assert output_doc.metadata.get("keywords") == "" + assert output_doc.metadata.get("creationDate") == "" + assert re.fullmatch( + r"D:\d{14}\+00'00'", + output_doc.metadata.get("modDate") or "", + ) + assert output_doc.metadata.get("trapped") == "" + assert output_doc.metadata.get("author") == "" + assert output_doc.metadata.get("creator") == "AymurAI" + assert output_doc.metadata.get("producer") == "AymurAI" + assert not output_doc.get_xml_metadata() + assert output_doc.embfile_names() == [] + assert list(page.annots() or []) == [] + assert "https://secret.example" not in link_uris + assert "https://safe.example" in link_uris + assert WATERMARK_URL in link_uris + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_moves_watermark_away_from_footer_content(tmp_path): + document = "Ana Perez presento el escrito" + footer_rect = pymupdf.Rect(360, 760, 575, 815) + + def configure(_doc: pymupdf.Document, page: pymupdf.Page) -> None: + page.insert_text((72, 72), document) + page.draw_rect(footer_rect, color=(0, 0, 0), fill=(0, 0, 0), overlay=True) + + source_path = _write_pdf(tmp_path / "footer-watermark.pdf", configure) + output_path = _run_pdf_anonymizer( + tmp_path, + source_path, + document, + [_label_dict("Ana Perez")], + ) + + with pymupdf.open(output_path) as output_doc: + page = output_doc[0] + watermark_links = [ + link for link in page.get_links() if link.get("uri") == WATERMARK_URL + ] + + assert len(watermark_links) == 1 + watermark_rect = pymupdf.Rect(watermark_links[0]["from"]) + assert not watermark_rect.intersects(footer_rect) + assert watermark_rect.x1 < footer_rect.x0 + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_removes_image_backed_entities(tmp_path): + source_path = _write_pdf( + tmp_path / "image.pdf", + lambda _doc, page: ( + page.insert_image(pymupdf.Rect(60, 60, 220, 110), stream=PNG_1X1), + page.insert_text((80, 90), "Ana Perez"), + ), + ) + + output_path = _run_pdf_anonymizer( + tmp_path, + source_path, + "Ana Perez", + [_label_dict("Ana Perez")], + ) + + with pymupdf.open(output_path) as output_doc: + page = output_doc[0] + page_text = page.get_text() + + assert page.get_image_info() == [] + assert "Ana Perez" not in page_text + assert "" in page_text + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_removes_signature_widgets_without_restoring_appearance( + tmp_path, +): + def configure(_doc: pymupdf.Document, page: pymupdf.Page) -> None: + page.insert_text((80, 90), "Ana Perez") + widget = pymupdf.Widget() + widget.field_name = "sig_1" + widget.field_type = pymupdf.PDF_WIDGET_TYPE_SIGNATURE + widget.rect = pymupdf.Rect(60, 60, 220, 110) + page.add_widget(widget) + + source_path = _write_pdf(tmp_path / "signature.pdf", configure) + output_path = _run_pdf_anonymizer( + tmp_path, + source_path, + "Ana Perez", + [_label_dict("Ana Perez")], + ) + + with pymupdf.open(output_path) as output_doc: + page = output_doc[0] + page_text = page.get_text() + + assert list(page.widgets() or []) == [] + assert page.get_image_info() == [] + assert "Ana Perez" not in page_text + assert "" in page_text + + +def test_index_paragraphs_reads_docx_xml_as_utf8(tmp_path): + xml_path = tmp_path / "document.xml" + xml_path.write_bytes( + """ + + + Señora — resolución + + +""".encode("utf-8") + ) + + paragraphs = index_paragraphs(str(xml_path)) + + assert len(paragraphs) == 1 + assert paragraphs[0]["plain_text"] == "Señora — resolución" + + +@pytest.mark.integration +def test_docx_anonymizer_sets_aymurai_core_properties(tmp_path): + source_path = tmp_path / "source.docx" + document = Document() + document.add_paragraph("Ana Perez firmo el escrito") + document.core_properties.author = "Sensitive Author" + document.core_properties.last_modified_by = "Sensitive Modifier" + document.save(source_path) + + started_at = datetime.now(timezone.utc).replace(microsecond=0) + + output_path = DocxAnonymizer().anonymize( + {"path": str(source_path)}, + [ + { + "document": "Ana Perez firmo el escrito", + "labels": [_label_dict("Ana Perez")], + } + ], + str(tmp_path / "out"), + ) + + output_document = Document(output_path) + core_properties = output_document.core_properties + assert core_properties.author == "" + assert core_properties.last_modified_by == "AymurAI" + assert core_properties.modified is not None + modified = core_properties.modified + if modified.tzinfo is None: + modified = modified.replace(tzinfo=timezone.utc) + assert started_at <= modified <= datetime.now(timezone.utc) + timedelta(seconds=5) + @pytest.mark.integration @patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") @@ -230,8 +520,8 @@ def test_should_disambiguate_and_persist_paragraphs( ): mock_build_canonical_entities.return_value = [] mock_get_canonical_dates.return_value = [] - mock_map_canonical_entities.side_effect = ( - lambda predictions, canonical_entities: predictions + mock_map_canonical_entities.side_effect = lambda predictions, canonical_entities: ( + predictions ) text = "Ana Pérez denunció en el juzgado." @@ -293,10 +583,53 @@ def test_should_return_validation_when_paragraph_exists(client, db_session): @pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_anonymizer") +def test_should_return_application_pdf_when_pdf_document_is_anonymized( + mock_get_anonymizer, + client, + tmp_path, +): + anonymized_path = _write_pdf( + tmp_path / "output.pdf", + lambda _doc, page: page.insert_text((72, 72), "Anonymized PDF output"), + ) + mock_get_anonymizer.return_value = MagicMock(return_value=str(anonymized_path)) + + annotations = { + "data": [ + { + "document": "Ana Perez presento el escrito", + "labels": [build_label("PER", "Ana Perez").model_dump(mode="json")], + } + ], + "label_policies": {"PER": {"anonymize": True, "disambiguation": "none"}}, + "render_policy": {"suffix_mode": "auto", "suffix_threshold": 1}, + } + + response = client.post( + "/anonymizer/anonymize-document", + data={"annotations": json.dumps(annotations)}, + files={"file": ("sample.pdf", b"%PDF-1.4 fake", "application/pdf")}, + ) + + assert response.status_code == 200 + assert response.headers["content-type"] == "application/pdf" + assert len(response.content) > 0 + + @patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_anonymizer") def test_should_anonymize_document_when_annotations_are_valid( - mock_check_output, client + mock_get_anonymizer, mock_check_output, client, tmp_path ): + # Fake anonymizer that writes a dummy docx output + anonymized_path = str(tmp_path / "output.docx") + with open(anonymized_path, "wb") as f: + f.write(b"fake-docx-content") + + mock_anonymizer = MagicMock(return_value=anonymized_path) + mock_get_anonymizer.return_value = mock_anonymizer + def fake_convert(*args, **kwargs): cmd = args[0] source_path = cmd[-1] @@ -320,7 +653,13 @@ def fake_convert(*args, **kwargs): response = client.post( "/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, - files={"file": ("sample.txt", b"input-document", "text/plain")}, + files={ + "file": ( + "sample.docx", + b"input-document", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + }, ) assert response.status_code == 200 @@ -330,9 +669,73 @@ def fake_convert(*args, **kwargs): @pytest.mark.integration @patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_anonymizer") +def test_should_exclude_null_alt_attrs_from_anonymize_document_preds( + mock_get_anonymizer, mock_check_output, client, tmp_path +): + anonymized_path = str(tmp_path / "output.docx") + with open(anonymized_path, "wb") as f: + f.write(b"fake-docx-content") + + mock_anonymizer = MagicMock(return_value=anonymized_path) + mock_get_anonymizer.return_value = mock_anonymizer + + def fake_convert(*args, **kwargs): + cmd = args[0] + source_path = cmd[-1] + output_path = source_path.rsplit(".", 1)[0] + ".odt" + with open(output_path, "wb") as output_file: + output_file.write(b"odt-content") + return "ok" + + mock_check_output.side_effect = fake_convert + annotations = { + "data": [ + { + "document": "Ana Perez denuncio en el juzgado.", + "labels": [build_label("PER", "Ana Perez").model_dump(mode="json")], + } + ], + "label_policies": {"PER": {"anonymize": True, "disambiguation": "fuzzy"}}, + "render_policy": {"suffix_mode": "auto", "suffix_threshold": 1}, + } + + response = client.post( + "/anonymizer/anonymize-document", + data={"annotations": json.dumps(annotations)}, + files={ + "file": ( + "sample.docx", + b"input-document", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + }, + ) + + assert response.status_code == 200 + preds = mock_anonymizer.call_args[0][1] + assert preds[0]["labels"][0]["text"] == "Ana Perez" + + attrs = preds[0]["labels"][0]["attrs"] + assert "aymurai_alt_text" not in attrs + assert "aymurai_alt_start_char" not in attrs + assert "aymurai_alt_end_char" not in attrs + + +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_anonymizer") def test_should_return_500_when_anonymize_document_conversion_fails( - mock_check_output, client + mock_get_anonymizer, mock_check_output, client, tmp_path ): + # Fake anonymizer that writes a dummy output + anonymized_path = str(tmp_path / "output.docx") + with open(anonymized_path, "wb") as f: + f.write(b"fake-docx-content") + + mock_anonymizer = MagicMock(return_value=anonymized_path) + mock_get_anonymizer.return_value = mock_anonymizer + mock_check_output.side_effect = subprocess.CalledProcessError( 1, ["libreoffice"], @@ -347,7 +750,13 @@ def test_should_return_500_when_anonymize_document_conversion_fails( response = client.post( "/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, - files={"file": ("sample.txt", b"input-document", "text/plain")}, + files={ + "file": ( + "sample.docx", + b"input-document", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + }, ) assert response.status_code == 500 diff --git a/tests/api/routers/misc/test_document_extract.py b/tests/api/routers/misc/test_document_extract.py index 6a67fdd6..124c4b9c 100644 --- a/tests/api/routers/misc/test_document_extract.py +++ b/tests/api/routers/misc/test_document_extract.py @@ -1,5 +1,6 @@ import concurrent.futures import io +import sys from unittest.mock import patch import pytest @@ -74,6 +75,11 @@ def test_should_extract_real_text_from_sample_docx_without_mocking(client): @pytest.mark.integration @pytest.mark.slow +@pytest.mark.xfail( + sys.platform == "win32", + reason="pymupdf4llm ONNX layout model receives int32 tensors on Windows (expects int64)", + strict=False, +) def test_should_extract_real_text_from_pdf_without_mocking(client): """Test that a real PDF upload is extracted without mocking.""" expected_paragraphs = [ diff --git a/tests/api/routers/test_pipeline_flows.py b/tests/api/routers/test_pipeline_flows.py index 3df22aaa..8d53952d 100644 --- a/tests/api/routers/test_pipeline_flows.py +++ b/tests/api/routers/test_pipeline_flows.py @@ -1,9 +1,11 @@ +import io import json import shutil import uuid -from unittest.mock import patch +from unittest.mock import MagicMock, patch import pytest +from docx import Document as DocxDocument from aymurai.database.schema import DataPublicDocumentParagraph from tests.api.routers.conftest import build_mock_pipeline @@ -20,6 +22,7 @@ def _fake_libreoffice_convert(*args, **kwargs): @pytest.mark.integration @patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_anonymizer") @patch( "aymurai.api.endpoints.routers.anonymizer.anonymizer.map_canonical_entities_ner_preds" ) @@ -33,8 +36,10 @@ def test_should_run_anonymizer_flow_end_to_end( mock_build_canonical_entities, mock_get_canonical_dates, mock_map_canonical_entities, + mock_get_anonymizer, mock_check_output, client, + tmp_path, ): mock_extract.return_value = "Ana Pérez denunció.\nJuan Soto declaró." mock_load_pipeline.return_value = build_mock_pipeline() @@ -43,6 +48,12 @@ def test_should_run_anonymizer_flow_end_to_end( mock_map_canonical_entities.side_effect = lambda predictions, canonical_entities: ( predictions ) + + anonymized_path = str(tmp_path / "output.docx") + with open(anonymized_path, "wb") as f: + f.write(b"fake-docx-content") + mock_anonymizer = MagicMock(return_value=anonymized_path) + mock_get_anonymizer.return_value = mock_anonymizer mock_check_output.side_effect = _fake_libreoffice_convert extract_response = client.post( @@ -81,7 +92,13 @@ def test_should_run_anonymizer_flow_end_to_end( compile_response = client.post( "/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, - files={"file": ("sample.txt", b"doc-bytes", "text/plain")}, + files={ + "file": ( + "sample.docx", + b"doc-bytes", + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + }, ) assert compile_response.status_code == 200 assert compile_response.headers["content-type"] == "application/octet-stream" @@ -162,10 +179,22 @@ def test_should_compile_anonymized_document_with_real_libreoffice_when_available "render_policy": {"suffix_mode": "auto", "suffix_threshold": 1}, } + doc = DocxDocument() + doc.add_paragraph("Texto base para anonimizar.") + buf = io.BytesIO() + doc.save(buf) + docx_bytes = buf.getvalue() + response = client.post( "/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, - files={"file": ("sample.txt", b"input-document", "text/plain")}, + files={ + "file": ( + "sample.docx", + docx_bytes, + "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ) + }, ) assert response.status_code == 200 From 3ad788b4cebd5ca4b50ca0d929d0cc6bebf5870d Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 20 Apr 2026 18:49:44 +0000 Subject: [PATCH 093/104] =?UTF-8?q?=F0=9F=90=9B=20Remove=20unnecessary=20-?= =?UTF-8?q?-extra=20runtime=20flag=20from=20uv=20sync=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/api/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 560e1290..bd492f09 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -19,7 +19,7 @@ WORKDIR /app RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - uv sync --frozen --no-install-project --extra runtime + uv sync --frozen --no-install-project # Copy application code COPY aymurai /app/aymurai From 87c78922631392cb3f0abc7e528a36fbfe34a10b Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Mon, 20 Apr 2026 20:41:02 -0300 Subject: [PATCH 094/104] =?UTF-8?q?=F0=9F=90=9B=20Date=20formatter=20bug?= =?UTF-8?q?=20fixed=20for=20canonical=20entities=20generation.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routers/anonymizer/anonymizer.py | 4 + .../entity_disambiguation/date_formatter.py | 16 +++- .../10-anonymize-document-render-policy.ipynb | 87 ++++++++++++++++--- 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 6a48c33b..c6a2f39d 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -422,9 +422,13 @@ async def anonymizer_disambiguate( else [] ) + logger.info("canonical entities detected were: %s", canonical_entities) + if "FECHA" in fuzzy_labels: canonical_entities += get_canonical_dates(labels) + logger.info("canonical entities after adding dates: %s", canonical_entities) + logger.info( "fuzzy clustering produced %d canonical entities", len(canonical_entities) ) diff --git a/aymurai/utils/entity_disambiguation/date_formatter.py b/aymurai/utils/entity_disambiguation/date_formatter.py index 92e38aea..23196409 100644 --- a/aymurai/utils/entity_disambiguation/date_formatter.py +++ b/aymurai/utils/entity_disambiguation/date_formatter.py @@ -1,5 +1,6 @@ from aymurai.meta.api_interfaces import DocLabel from aymurai.meta.entities import CanonicalEntity +import uuid def get_canonical_dates(labels: list[DocLabel]) -> list[CanonicalEntity]: @@ -20,14 +21,23 @@ def get_canonical_dates(labels: list[DocLabel]) -> list[CanonicalEntity]: continue raw_date = label.attrs.aymurai_alt_text or label.text - norm_date = ( max(label.attrs.aymurai_label_subclass) if label.attrs.aymurai_label_subclass else None ) - day_month_key = norm_date[:5] if norm_date is not None else norm_date + if norm_date: + parts = norm_date.split("/") + day = parts[0] + month = parts[1] + year = parts[2] if len(parts) > 2 else "1900" + if year == "1900": + day_month_key = f"{day}/{month}" + else: + day_month_key = f"{day}/{month}/{year}" + else: + day_month_key = uuid.uuid4() if day_month_key not in groups: groups[day_month_key] = CanonicalEntity( @@ -37,7 +47,7 @@ def get_canonical_dates(labels: list[DocLabel]) -> list[CanonicalEntity]: attributes={}, ) - if day_month_key in groups and raw_date not in groups[day_month_key].aliases: + if raw_date not in groups[day_month_key].aliases: groups[day_month_key].aliases.append(raw_date) label.attrs.canonical_entity_id = groups[day_month_key].entity_id diff --git a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb index a9949050..c072066f 100644 --- a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb +++ b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb @@ -64,7 +64,8 @@ "\n", "print(f\"Found {len(documents)} documents\")\n", "\n", - "doc_path = documents[1]" + "doc_path = documents[14]\n", + "print(f\"Processing document: {doc_path}\")" ] }, { @@ -245,7 +246,11 @@ "source": [ "# Function to make inference using the API\n", "def get_predictions(sample: str) -> dict:\n", - " response = requests.post(url=f\"{API_URL}/anonymizer/predict\", json={\"text\": sample}, params={\"use_cache\": False})\n", + " response = requests.post(\n", + " url=f\"{API_URL}/anonymizer/predict\",\n", + " json={\"text\": sample},\n", + " params={\"use_cache\": False},\n", + " )\n", " response.raise_for_status()\n", " return response.json()" ] @@ -295,6 +300,12 @@ " }\n", " )\n", "\n", + " anonymize_labels = []\n", + " for item in disambiguated[\"data\"]:\n", + " for label in item.get(\"labels\", []):\n", + " if label:\n", + " anonymize_labels.append(label)\n", + "\n", " with open(doc_path, \"rb\") as file:\n", " files = {\"file\": file}\n", "\n", @@ -315,7 +326,7 @@ " with open(out_path, \"wb\") as file:\n", " file.write(response.content)\n", "\n", - " return disambiguated, out_path" + " return disambiguated, out_path, anonymize_labels" ] }, { @@ -331,14 +342,34 @@ "\n", "# 1) everything fuzzy\n", "label_policies_all_fuzzy = {\n", - " \"PER\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": True},\n", - " \"DNI\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"LOC\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"DIRECCION\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", - " \"FECHA\": {\"disambiguation\": \"fuzzy\", \"anonymize\": True, \"use_subclass_when_available\": False},\n", + " \"PER\": {\n", + " \"disambiguation\": \"fuzzy\",\n", + " \"anonymize\": True,\n", + " \"use_subclass_when_available\": True,\n", + " },\n", + " \"DNI\": {\n", + " \"disambiguation\": \"fuzzy\",\n", + " \"anonymize\": True,\n", + " \"use_subclass_when_available\": False,\n", + " },\n", + " \"LOC\": {\n", + " \"disambiguation\": \"fuzzy\",\n", + " \"anonymize\": True,\n", + " \"use_subclass_when_available\": False,\n", + " },\n", + " \"DIRECCION\": {\n", + " \"disambiguation\": \"fuzzy\",\n", + " \"anonymize\": True,\n", + " \"use_subclass_when_available\": False,\n", + " },\n", + " \"FECHA\": {\n", + " \"disambiguation\": \"fuzzy\",\n", + " \"anonymize\": True,\n", + " \"use_subclass_when_available\": False,\n", + " },\n", "}\n", - "disambiguated_labels_fuzzy, out_all_fuzzy = disambiguate_and_export(\n", - " \"all-fuzzy\", label_policies_all_fuzzy, render_policy\n", + "disambiguated_labels_fuzzy, out_all_fuzzy, anonymize_labels_fuzzy = (\n", + " disambiguate_and_export(\"all-fuzzy\", label_policies_all_fuzzy, render_policy)\n", ")\n", "\n", "# # 2) FECHAs excluded\n", @@ -363,7 +394,41 @@ "metadata": {}, "outputs": [], "source": [ - "disambiguated_labels_fuzzy" + "anonymize_labels_fuzzy" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from collections import defaultdict\n", + "from typing import Any\n", + "\n", + "\n", + "def group_alt_texts_by_entity(data: list[dict[str, Any]]) -> dict[str, list[str]]:\n", + " grouped_data = defaultdict(list)\n", + "\n", + " for entry in data:\n", + " attrs = entry.get(\"attrs\", {})\n", + " entity_id = attrs.get(\"canonical_entity_id\")\n", + " alt_text = attrs.get(\"aymurai_alt_text\")\n", + " subclass = attrs.get(\"aymurai_label_subclass\")\n", + " if entity_id and alt_text:\n", + " grouped_data[entity_id].append((alt_text, subclass))\n", + "\n", + " return dict(grouped_data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "result = group_alt_texts_by_entity(anonymize_labels_fuzzy)\n", + "print(json.dumps(result, indent=4, ensure_ascii=False))" ] } ], From a485b083b0a69afdc8230cda516b11051aa103c2 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 4 May 2026 13:59:29 +0000 Subject: [PATCH 095/104] =?UTF-8?q?=F0=9F=90=9B=20Fix=20duplicate=20DocLab?= =?UTF-8?q?el=20handling=20in=20anonymization=20and=20serialization=20proc?= =?UTF-8?q?esses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../routers/anonymizer/anonymizer.py | 42 +++++++++++++++++-- aymurai/api/main.py | 17 ++++++++ .../database/crud/anonymization/paragraph.py | 17 +++++++- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index c6a2f39d..6bc7b494 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -2,6 +2,7 @@ import os import subprocess import tempfile +from collections.abc import Iterable from threading import Lock import torch @@ -68,8 +69,10 @@ def _entities_to_doclabels(entities: list[dict]) -> list[DocLabel]: for ent in entities: try: - doclabels.append( - DocLabel.model_validate( + if isinstance(ent, DocLabel): + doclabel = ent + else: + doclabel = DocLabel.model_validate( { "text": ent.get("text", ""), "start_char": ent.get("start_char"), @@ -77,11 +80,41 @@ def _entities_to_doclabels(entities: list[dict]) -> list[DocLabel]: "attrs": ent.get("attrs", {}), } ) - ) + doclabels.append(doclabel) except Exception as exc: # keep going if a single entity is malformed logger.warning(f"Skipping invalid entity for DocLabel: {exc}") - return doclabels + return _dedupe_doclabels(doclabels) + + +def _dedupe_doclabels(labels: Iterable[DocLabel]) -> list[DocLabel]: + """ + Remove exact duplicate labels while preserving first-seen order. + + Args: + labels (Iterable[DocLabel]): An iterable of DocLabel objects, + potentially containing duplicates. + + Returns: + list[DocLabel]: A list of DocLabel objects with duplicates removed, + preserving the order of first occurrence. + """ + deduped: list[DocLabel] = [] + seen: set[str] = set() + + for label in labels: + key = json.dumps( + label.model_dump(mode="json", exclude_none=True), + sort_keys=True, + separators=(",", ":"), + ) + if key in seen: + continue + + seen.add(key) + deduped.append(label) + + return deduped def _merge_label_policies( @@ -444,6 +477,7 @@ async def anonymizer_disambiguate( ) for document in predictions: + document.labels = _dedupe_doclabels(document.labels or []) for label in document.labels or []: label.attrs.aymurai_disambiguation = effective_disambiguation_by_label.get( label.attrs.aymurai_label, "fuzzy" diff --git a/aymurai/api/main.py b/aymurai/api/main.py index b4ef93d6..4bfd9370 100644 --- a/aymurai/api/main.py +++ b/aymurai/api/main.py @@ -8,6 +8,7 @@ from fastapi import FastAPI, Request from fastapi.responses import RedirectResponse from fastapi.middleware.cors import CORSMiddleware +from starlette.formparsers import MultiPartParser from aymurai.api import core from aymurai.logger import get_logger @@ -27,6 +28,22 @@ RESOURCES_BASEPATH = settings.RESOURCES_BASEPATH +MULTIPART_MAX_PART_SIZE = 10 * 1024 * 1024 # 10 MB + + +def _set_kwdefault(func, name: str, value: int) -> None: + kwdefaults = getattr(func, "__kwdefaults__", None) + if kwdefaults and name in kwdefaults: + kwdefaults[name] = value + + +# FastAPI parses Form(...) before endpoint execution. Starlette defaults each +# non-file multipart field to 1MB, which is too small for annotations JSON. +MultiPartParser.max_part_size = MULTIPART_MAX_PART_SIZE +_set_kwdefault(MultiPartParser.__init__, "max_part_size", MULTIPART_MAX_PART_SIZE) +_set_kwdefault(Request.form, "max_part_size", MULTIPART_MAX_PART_SIZE) +_set_kwdefault(Request._get_form, "max_part_size", MULTIPART_MAX_PART_SIZE) + @asynccontextmanager async def lifespan(app: FastAPI): diff --git a/aymurai/database/crud/anonymization/paragraph.py b/aymurai/database/crud/anonymization/paragraph.py index 17f826b8..cf1e30e5 100644 --- a/aymurai/database/crud/anonymization/paragraph.py +++ b/aymurai/database/crud/anonymization/paragraph.py @@ -1,3 +1,4 @@ +import json import uuid from pydantic import TypeAdapter @@ -11,7 +12,6 @@ from aymurai.database.utils import text_to_uuid from aymurai.meta.api_interfaces import DocLabel - _DOC_LABELS_ADAPTER = TypeAdapter(list[DocLabel]) @@ -27,7 +27,20 @@ def _serialize_doclabels(value: list[DocLabel] | None): """ if value is None: return None - return _DOC_LABELS_ADAPTER.dump_python(value, mode="json", exclude_none=True) + + labels = _DOC_LABELS_ADAPTER.dump_python(value, mode="json", exclude_none=True) + deduped = [] + seen = set() + + for label in labels: + key = json.dumps(label, sort_keys=True, separators=(",", ":")) + if key in seen: + continue + + seen.add(key) + deduped.append(label) + + return deduped def _normalize_paragraph_payload(payload: dict) -> dict: From 64aa11519a63b4d01bc7c6a7ac3f258a4bb7b308 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Mon, 4 May 2026 13:59:59 +0000 Subject: [PATCH 096/104] =?UTF-8?q?=E2=9C=85=20Add=20tests=20to=20deduplic?= =?UTF-8?q?ate=20duplicate=20labels=20in=20cached=20predictions=20and=20di?= =?UTF-8?q?sambiguation=20processes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/routers/anonymizer/test_anonymizer.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/api/routers/anonymizer/test_anonymizer.py b/tests/api/routers/anonymizer/test_anonymizer.py index e003ad33..8225e29d 100644 --- a/tests/api/routers/anonymizer/test_anonymizer.py +++ b/tests/api/routers/anonymizer/test_anonymizer.py @@ -505,6 +505,46 @@ def test_should_isolate_cache_when_different_texts( assert data1["labels"] != data2["labels"] +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_dedupe_duplicate_labels_when_returning_cached_prediction( + mock_load_pipeline, client, db_session +): + text = "EL SEÑOR JUEZ, doctor Tarte, señaló :" + label = build_label("PER", "Tarte").model_dump(mode="json") + label.update({"start_char": 22, "end_char": 27}) + label["attrs"].update( + { + "aymurai_alt_text": "Tarte", + "aymurai_alt_start_char": 22, + "aymurai_alt_end_char": 27, + "aymurai_disambiguation": "fuzzy", + "aymurai_anonymize": True, + } + ) + + db_session.add( + AnonymizationParagraph( + id=text_to_uuid(text), + text=text, + prediction=[label, label], + ) + ) + db_session.commit() + + response = client.post( + "/anonymizer/predict", + json={"text": text}, + params={"use_cache": True}, + ) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == text + assert data["labels"] == [label] + mock_load_pipeline.assert_not_called() + + @pytest.mark.integration @patch( "aymurai.api.endpoints.routers.anonymizer.anonymizer.map_canonical_entities_ner_preds" @@ -552,6 +592,66 @@ def test_should_disambiguate_and_persist_paragraphs( assert stored.prediction[0]["text"] == "Ana Pérez" +@pytest.mark.integration +@patch( + "aymurai.api.endpoints.routers.anonymizer.anonymizer.map_canonical_entities_ner_preds" +) +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_canonical_dates") +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.build_canonical_entities") +def test_should_dedupe_duplicate_labels_when_disambiguating_and_persisting( + mock_build_canonical_entities, + mock_get_canonical_dates, + mock_map_canonical_entities, + client, + db_session, +): + mock_build_canonical_entities.return_value = [] + mock_get_canonical_dates.return_value = [] + mock_map_canonical_entities.side_effect = lambda predictions, canonical_entities: ( + predictions + ) + + text = "EL SEÑOR JUEZ, doctor Tarte, señaló :" + label = build_label("PER", "Tarte").model_dump(mode="json") + label.update({"start_char": 22, "end_char": 27}) + label["attrs"].update( + { + "aymurai_alt_text": "Tarte", + "aymurai_alt_start_char": 22, + "aymurai_alt_end_char": 27, + } + ) + body = { + "paragraphs": [{"document": text, "labels": [label, label]}], + "label_policies": { + "PER": {"anonymize": True, "disambiguation": "none"}, + }, + } + + response = client.post("/anonymizer/disambiguate", json=body) + + assert response.status_code == 200 + labels = response.json()["data"][0]["labels"] + assert labels == [ + { + **label, + "attrs": { + **label["attrs"], + "aymurai_disambiguation": "none", + "aymurai_anonymize": True, + }, + } + ] + + stored = db_session.get(AnonymizationParagraph, text_to_uuid(text)) + assert stored is not None + assert stored.prediction is not None + assert len(stored.prediction) == 1 + assert stored.prediction[0]["text"] == "Tarte" + assert stored.prediction[0]["attrs"]["aymurai_disambiguation"] == "none" + assert stored.prediction[0]["attrs"]["aymurai_anonymize"] is True + + @pytest.mark.integration def test_should_return_null_validation_when_paragraph_not_found(client): response = client.post( From 1860a6c382b2ff9f39a7ba7c17e90cf2a2da301c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Mon, 25 May 2026 10:49:12 -0300 Subject: [PATCH 097/104] =?UTF-8?q?=F0=9F=90=9B=20Fix=20handling=20of=20no?= =?UTF-8?q?n-alphanumeric=20entities=20by=20returning=20None=20for=20empty?= =?UTF-8?q?=20cleaned=20text=20(#81)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../transforms/anonymization_postprocess/core.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/aymurai/transforms/anonymization_postprocess/core.py b/aymurai/transforms/anonymization_postprocess/core.py index 977fb109..bd596d29 100644 --- a/aymurai/transforms/anonymization_postprocess/core.py +++ b/aymurai/transforms/anonymization_postprocess/core.py @@ -1,10 +1,9 @@ import re from copy import deepcopy -from string import punctuation +from aymurai.meta.pipeline_interfaces import Transform from aymurai.meta.types import DataItem from aymurai.utils.misc import get_element -from aymurai.meta.pipeline_interfaces import Transform class AnonymizationEntityCleaner(Transform): @@ -45,6 +44,9 @@ def process(self, ent: dict) -> dict: # Clean the text cleaned_text = pattern.sub("", original_text) + if not cleaned_text: + return None + # Update the entity's alt text and indices ent["attrs"]["aymurai_alt_text"] = cleaned_text ent["attrs"]["aymurai_alt_start_char"] = start_char + leading_chars_removed @@ -61,11 +63,11 @@ def __call__(self, item: DataItem) -> DataItem: DataItem: processed item """ item = deepcopy(item) - ents = get_element(item, [self.field, "entities"]) or [] - # Filter out predictions that are punctuation marks only - ents = [ent for ent in ents if ent["text"] not in punctuation] - ents = [self.process(ent) for ent in ents] + # Filter out predictions with empty alt text and update the rest + item[self.field]["entities"] = [ + out for ent in ents if (out := self.process(ent)) is not None + ] return item From 44ce0ad598c4ccd300ac62134954c33f2d7e3eba Mon Sep 17 00:00:00 2001 From: jansaldo Date: Tue, 26 May 2026 16:32:31 +0000 Subject: [PATCH 098/104] =?UTF-8?q?=F0=9F=A9=B9=20Fix=20default=20timeout?= =?UTF-8?q?=20value=20in=20run=5Fsafe=5Ftext=5Fextraction=20function=20fro?= =?UTF-8?q?m=2030=20to=20300=20seconds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/api/endpoints/routers/misc/document_extract.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/aymurai/api/endpoints/routers/misc/document_extract.py b/aymurai/api/endpoints/routers/misc/document_extract.py index ba315b74..ab1c61b3 100644 --- a/aymurai/api/endpoints/routers/misc/document_extract.py +++ b/aymurai/api/endpoints/routers/misc/document_extract.py @@ -34,10 +34,7 @@ def extraction(path: str) -> str: return document_normalize(text, preserve_paragraphs=True) if text else "" -def run_safe_text_extraction( - path: str, - timeout_s: float | None = 30, -) -> str: +def run_safe_text_extraction(path: str, timeout_s: float | None = 300) -> str: """ Runs the text extraction in a separate process to avoid blocking the main thread. This is useful for long-running tasks or when the extraction might hang. @@ -45,7 +42,7 @@ def run_safe_text_extraction( Args: path (str): Path to the file to be processed. timeout_s (float | None): Timeout in seconds for the extraction process. - If None, waits indefinitely. Defaults to 30. + If None, waits indefinitely. Defaults to 300. Returns: str: Extracted text from the document. From d1e81ddf42faf275a97e3da14408c9b1d4fec974 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Tue, 26 May 2026 18:42:25 +0000 Subject: [PATCH 099/104] =?UTF-8?q?=F0=9F=9A=B8=20Update=20PDF=5FTOKEN=5FA?= =?UTF-8?q?LIAS=5FMAP=20with=20clearer=20aliases?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aymurai/text/anonymization/pdf/common.py | 28 ++++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/aymurai/text/anonymization/pdf/common.py b/aymurai/text/anonymization/pdf/common.py index 91f42927..b17c22c2 100644 --- a/aymurai/text/anonymization/pdf/common.py +++ b/aymurai/text/anonymization/pdf/common.py @@ -14,22 +14,22 @@ PDF_TAG_MIN_FONT_SIZE = 7.0 PDF_TAG_FONT_STEP = 0.5 PDF_TAG_MAX_ABBREVIATION = 3 -PDF_TOKEN_ALIAS_MAP: dict[str, tuple[str, str]] = { +PDF_TOKEN_ALIAS_MAP: dict[str, tuple[str, ...]] = { "CORREO_ELECTRONICO": ("CORREO", "MAIL"), "CUIT_CUIL": ("CUIT", "CUIL"), - "DIRECCION": ("DIREC", "DIR"), - "ESTUDIOS": ("ESTUD", "EDU"), - "MARCA_AUTOMOVIL": ("MARCA_AUTO", "AUTO"), - "NACIONALIDAD": ("NACIONAL", "NAC"), - "NOMBRE_ARCHIVO": ("NOM_ARCH", "ARCH"), - "NUM_ACTUACION": ("NUM_ACT", "ACT"), - "NUM_CAJA_AHORRO": ("NUM_CAJA", "CAJA"), - "NUM_EXPEDIENTE": ("NUM_EXP", "EXPTE"), - "NUM_MATRICULA": ("NUM_MAT", "MAT"), - "PATENTE_DOMINIO": ("PAT_DOM", "PAT"), - "TELEFONO": ("TELEF", "TEL"), - "TEXTO_ANONIMIZAR": ("TEXTO_ANON", "ANON"), - "USUARIX": ("USUAR", "USR"), + "DIRECCION": ("DIR",), + "ESTUDIOS": ("EDU",), + "MARCA_AUTOMOVIL": ("VEHICULO", "AUTO"), + "NACIONALIDAD": ("PAIS", "NAC"), + "NOMBRE_ARCHIVO": ("ARCHIVO", "FILE"), + "NUM_ACTUACION": ("ACTUACION", "ACT"), + "NUM_CAJA_AHORRO": ("CAJA_AHORRO", "CAJA"), + "NUM_EXPEDIENTE": ("EXPEDIENTE", "EXPTE"), + "NUM_MATRICULA": ("MATRICULA", "MAT"), + "PATENTE_DOMINIO": ("PATENTE", "DOMINIO"), + "TELEFONO": ("TEL",), + "TEXTO_ANONIMIZAR": ("ANONIMIZAR", "TEXTO"), + "USUARIX": ("USER",), } PDF_TAG_RECT_X_PADDING = 0.5 PDF_TAG_RECT_Y_PADDING = 0.0 From e25ddcfb8f072e3c8d1494518d086356e85ee350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Tue, 26 May 2026 17:18:23 -0300 Subject: [PATCH 100/104] Fix/pdf signature anonymization (#82) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🧪 test(pdf): cover signature anonymization regressions * 🐛 fix(pdf): preserve signature appearance when redacting signer names * ✅ test(pdf): add focused signature geometry tests * ♻️ refactor(pdf): rename distance function for clarity and update references * 📝 docs(pdf): clarify signature widget flattening process in preparation function * ✅ test(pdf): cover signature review edge cases --- aymurai/text/anonymization/pdf/ops.py | 185 +++++++- aymurai/text/anonymization/pdf/sanitize.py | 12 +- aymurai/text/anonymization/pdf/widgets.py | 51 ++- .../api/routers/anonymizer/test_anonymizer.py | 398 +++++++++++++++++- 4 files changed, 591 insertions(+), 55 deletions(-) diff --git a/aymurai/text/anonymization/pdf/ops.py b/aymurai/text/anonymization/pdf/ops.py index bdad1d0a..fb5a324f 100644 --- a/aymurai/text/anonymization/pdf/ops.py +++ b/aymurai/text/anonymization/pdf/ops.py @@ -189,6 +189,104 @@ def _image_rects_for_clip( return rects +def _squared_distance_between_rect_centers( + left: pymupdf.Rect, + right: pymupdf.Rect, +) -> float: + """ + Computes the squared distance between two rectangle centers. + + Args: + left (pymupdf.Rect): The first rectangle. + right (pymupdf.Rect): The second rectangle. + + Returns: + float: The squared distance between rectangle centers. + """ + left_center = ((left.x0 + left.x1) / 2.0, (left.y0 + left.y1) / 2.0) + right_center = ((right.x0 + right.x1) / 2.0, (right.y0 + right.y1) / 2.0) + return (left_center[0] - right_center[0]) ** 2 + ( + left_center[1] - right_center[1] + ) ** 2 + + +def _refine_signature_text_rect( + page: pymupdf.Page, + entity_text: str, + widget_rect: pymupdf.Rect, + current_rect: pymupdf.Rect, +) -> pymupdf.Rect: + """ + Finds a tighter text rectangle for signer names inside signature widgets. + + Args: + page (pymupdf.Page): The PDF page being processed. + entity_text (str): The entity text being mapped. + widget_rect (pymupdf.Rect): The signature widget rectangle. + current_rect (pymupdf.Rect): The currently resolved entity rectangle. + + Returns: + pymupdf.Rect: The refined rectangle when available, otherwise current_rect. + """ + widget_clip = pymupdf.Rect(widget_rect) + hits = [ + pymupdf.Rect(hit) + for hit in page.search_for(entity_text, clip=widget_clip) + if pymupdf.Rect(hit).intersects(widget_clip) + ] + if not hits: + return pymupdf.Rect(current_rect) + + target = pymupdf.Rect(current_rect) + intersecting_hits = [hit for hit in hits if hit.intersects(target)] + candidates = intersecting_hits or hits + return pymupdf.Rect( + min( + candidates, + key=lambda hit: _squared_distance_between_rect_centers(hit, target), + ) + ) + + +def _build_signature_page_op( + page: pymupdf.Page, + entity_text: str, + widget_info: dict[str, Any], + current_rect: pymupdf.Rect, + token: str, + entity_style: dict[str, Any] | None = None, +) -> dict[str, Any]: + """ + Builds a signature-specific operation scoped to the sensitive text only. + + Args: + page (pymupdf.Page): The PDF page being processed. + entity_text (str): The sensitive text being replaced. + widget_info (dict[str, Any]): The signature widget metadata. + current_rect (pymupdf.Rect): The initially resolved text rectangle. + token (str): The logical replacement token. + entity_style (dict[str, Any] | None): The text style to render with. + + Returns: + dict[str, Any]: The signature replacement operation. + """ + refined_rect = _refine_signature_text_rect( + page, + entity_text, + widget_info["rect"], + current_rect, + ) + op = _build_page_op( + refined_rect, + None, + token, + entity_style=entity_style or widget_info.get("style") or None, + ) + op["widget_xref"] = widget_info["xref"] + op["widget_rect"] = widget_info["rect"] + return op + + def _entity_overlaps_image( page: pymupdf.Page, entity_rect: pymupdf.Rect, @@ -303,14 +401,14 @@ def _collect_page_redactions( fallback_widget["field_type"] == pymupdf.PDF_WIDGET_TYPE_SIGNATURE ): - op = _build_page_op( + op = _build_signature_page_op( + page, + entity_text, + fallback_widget, fallback_rects[0], - lines[0] if lines else None, token, entity_style=fallback_widget.get("style") or None, ) - op["widget_xref"] = fallback_widget["xref"] - op["widget_rect"] = fallback_widget["rect"] signature_widget_ops.setdefault(page_index, []).append(op) continue @@ -470,14 +568,14 @@ def _collect_page_redactions( ) continue if widget_info["field_type"] == pymupdf.PDF_WIDGET_TYPE_SIGNATURE: - op = _build_page_op( + op = _build_signature_page_op( + page, + entity_text, + widget_info, rect, - line, token, entity_style=ent_style, ) - op["widget_xref"] = widget_info["xref"] - op["widget_rect"] = widget_info["rect"] signature_widget_ops.setdefault(page_index, []).append(op) continue @@ -514,43 +612,51 @@ def _collect_page_redactions( for seg_idx, ( seg_line, - _seg_text, + seg_text, seg_rect, seg_img, seg_style, seg_widget, ) in enumerate(segments): + if signature_widget is not None: + op = _build_signature_page_op( + page, + seg_text, + signature_widget, + seg_rect, + token, + entity_style=seg_style, + ) + if seg_idx != widest_idx: + op["text"] = None + op["fontsize"] = None + signature_widget_ops.setdefault(page_index, []).append(op) + continue + if seg_idx == widest_idx: op = _build_page_op( seg_rect, seg_line, token, - is_image=(any_image and signature_widget is None), + is_image=any_image, entity_style=seg_style, ) - if signature_widget is None and shared_image_rect is not None: + if shared_image_rect is not None: op["image_rect"] = shared_image_rect else: op = _build_page_op( seg_rect, seg_line, token, - is_image=( - (seg_img is not None) and signature_widget is None - ), + is_image=(seg_img is not None), entity_style=seg_style, ) op["text"] = None op["fontsize"] = None - if seg_img is not None and signature_widget is None: + if seg_img is not None: op["image_rect"] = seg_img - if signature_widget is not None: - op["widget_xref"] = signature_widget["xref"] - op["widget_rect"] = signature_widget["rect"] - signature_widget_ops.setdefault(page_index, []).append(op) - else: - page_ops.setdefault(page_index, []).append(op) + page_ops.setdefault(page_index, []).append(op) return page_ops, widget_ops, signature_widget_ops @@ -802,6 +908,40 @@ def _apply_asset_redactions( _render_text_op(page, op) +def _apply_signature_redactions( + doc: pymupdf.Document, + signature_widget_ops: dict[int, list[dict]], +) -> None: + """ + Applies signer-name redactions without removing the full signature appearance. + + Args: + doc (pymupdf.Document): The PDF document being processed. + signature_widget_ops (dict[int, list[dict]]): The signature operations grouped by page index. + """ + for page_idx, ops in signature_widget_ops.items(): + if not ops: + continue + + page = doc[page_idx] + for op in ops: + page.add_redact_annot( + op["redact_rect"], + text=None, + fill=(1, 1, 1), + cross_out=False, + ) + + page.apply_redactions( + images=pymupdf.PDF_REDACT_IMAGE_PIXELS, + graphics=pymupdf.PDF_REDACT_LINE_ART_NONE, + text=pymupdf.PDF_REDACT_TEXT_REMOVE, + ) + + for op in ops: + _render_text_op(page, op) + + def _apply_redactions( doc: pymupdf.Document, page_ops: dict[int, list[dict]], @@ -821,8 +961,7 @@ def _apply_redactions( _prepare_signature_widget_ops(doc, signature_widget_ops) text_page_ops, asset_page_ops = _partition_page_ops(page_ops) - for page_idx, ops in signature_widget_ops.items(): - asset_page_ops.setdefault(page_idx, []).extend(ops) _apply_text_redactions(doc, text_page_ops) _apply_asset_redactions(doc, asset_page_ops) + _apply_signature_redactions(doc, signature_widget_ops) diff --git a/aymurai/text/anonymization/pdf/sanitize.py b/aymurai/text/anonymization/pdf/sanitize.py index 408f32bf..ab1bf344 100644 --- a/aymurai/text/anonymization/pdf/sanitize.py +++ b/aymurai/text/anonymization/pdf/sanitize.py @@ -96,14 +96,12 @@ def _cleanup_rect_for_signature_widget_op(op: dict[str, Any]) -> pymupdf.Rect | Returns: pymupdf.Rect | None: The cleanup rectangle for the signature widget operation, if available. """ - widget_rect = op.get("widget_rect") - if widget_rect is not None: - return pymupdf.Rect(widget_rect) - - background_rect = op.get("background_rect") or op.get("canvas_rect") - if background_rect is None: + cleanup_source = ( + op.get("redact_rect") or op.get("background_rect") or op.get("canvas_rect") + ) + if cleanup_source is None: return None - return pymupdf.Rect(background_rect) + return pymupdf.Rect(cleanup_source) def _collect_link_cleanup_rects( diff --git a/aymurai/text/anonymization/pdf/widgets.py b/aymurai/text/anonymization/pdf/widgets.py index 3ea97d7e..266a912f 100644 --- a/aymurai/text/anonymization/pdf/widgets.py +++ b/aymurai/text/anonymization/pdf/widgets.py @@ -29,21 +29,24 @@ def _signature_background_rect( Returns: pymupdf.Rect: The background rectangle for the signature replacement. """ - background = pymupdf.Rect( - op.get("line_rect") or op.get("canvas_rect") or widget_rect + background_source = ( + op.get("canvas_rect") or op.get("redact_rect") or op.get("line_rect") ) - canvas_rect = op.get("canvas_rect") - if canvas_rect is not None: - background.include_rect(pymupdf.Rect(canvas_rect)) + background = pymupdf.Rect(background_source or widget_rect) - pad_x = max(background.height * 0.75, 2.0) - pad_y = max(background.height * 0.25, 0.75) + redact_rect = op.get("redact_rect") + if redact_rect is not None: + background.include_rect(pymupdf.Rect(redact_rect)) + + # Keep the repaint area on the sensitive text line so the replacement + # background does not visually cover adjacent non-sensitive content + pad_x = max(background.height * 0.2, 0.5) widget_clip = pymupdf.Rect(widget_rect) background.x0 = max(widget_clip.x0, background.x0 - pad_x) - background.y0 = max(widget_clip.y0, background.y0 - pad_y) + background.y0 = max(widget_clip.y0, background.y0) background.x1 = min(widget_clip.x1, background.x1 + pad_x) - background.y1 = min(widget_clip.y1, background.y1 + pad_y) + background.y1 = min(widget_clip.y1, background.y1) return background @@ -272,12 +275,19 @@ def _prepare_signature_widget_ops( signature_widget_ops: dict[int, list[dict]], ) -> None: """ - Deletes signature widgets and prepares their replacement operations. + Flattens signature widgets and prepares their replacement operations. + + PyMuPDF bakes widgets at document scope, not per widget. When a + signature widget must be flattened, all widgets are intentionally baked + before sanitization so their visible appearances survive in the static + anonymized PDF. Args: doc (pymupdf.Document): The PDF document being processed. signature_widget_ops (dict[int, list[dict]]): The collected signature widget operations grouped by page index. """ + should_bake_widgets = False + for page_idx, ops in signature_widget_ops.items(): if not ops: continue @@ -300,15 +310,7 @@ def _prepare_signature_widget_ops( if widget is not None: widget_rect = pymupdf.Rect(widget.rect) - try: - page.delete_widget(widget) - except Exception as exc: - logger.warning( - "Failed to delete signature widget xref=%s on page=%s: %s", - widget_xref, - page_idx, - exc, - ) + should_bake_widgets = True else: logger.warning( "Could not resolve PDF signature widget xref=%s on page=%s", @@ -318,6 +320,13 @@ def _prepare_signature_widget_ops( for op in widget_group_ops: op["widget_rect"] = pymupdf.Rect(widget_rect) - op["asset_rect"] = pymupdf.Rect(widget_rect) - op["graphics_mode"] = pymupdf.PDF_REDACT_LINE_ART_REMOVE_IF_COVERED + op.pop("asset_rect", None) + op.pop("image_rect", None) + op.pop("graphics_mode", None) op["background_rect"] = _signature_background_rect(op, widget_rect) + + if should_bake_widgets: + try: + doc.bake(annots=False, widgets=True) + except Exception as exc: + logger.warning("Failed to flatten PDF signature widgets: %s", exc) diff --git a/tests/api/routers/anonymizer/test_anonymizer.py b/tests/api/routers/anonymizer/test_anonymizer.py index 8225e29d..0648c625 100644 --- a/tests/api/routers/anonymizer/test_anonymizer.py +++ b/tests/api/routers/anonymizer/test_anonymizer.py @@ -13,14 +13,20 @@ from aymurai.database.schema import AnonymizationParagraph from aymurai.database.utils import text_to_uuid +from aymurai.meta.api_interfaces import LabelPolicy, RenderPolicy from aymurai.text.anonymization import DocxAnonymizer, PdfAnonymizer, get_anonymizer from aymurai.text.anonymization.alignment import index_paragraphs +from aymurai.text.anonymization.pdf.ops import _refine_signature_text_rect +from aymurai.text.anonymization.pdf.widgets import _signature_background_rect from tests.api.conftest import build_label from tests.api.routers.conftest import build_mock_pipeline PNG_1X1 = base64.b64decode( "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+a6R8AAAAASUVORK5CYII=" ) +PNG_BLACK_1X1 = base64.b64decode( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR42mNgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==" +) WATERMARK_URL = "https://www.aymurai.info/" WINDOWS_PYMUPDF_LAYOUT_XFAIL = pytest.mark.xfail( @@ -50,6 +56,7 @@ def _run_pdf_anonymizer( source_path: Path, document: str, labels: list[dict], + render_context: dict | None = None, ) -> Path: output_dir = tmp_path / "out" output_dir.mkdir(exist_ok=True) @@ -57,10 +64,174 @@ def _run_pdf_anonymizer( {"path": str(source_path)}, [{"document": document, "labels": labels}], str(output_dir), + render_context=render_context, ) return Path(output_path) +def _label_for_document_text(document: str, text: str, label: str = "PER") -> dict: + payload = _label_dict(text, label) + start = document.index(text) + payload["start_char"] = start + payload["end_char"] = start + len(text) + return payload + + +def _render_context_for_entities(labels: list[dict]) -> dict: + index_by_entity = {} + next_index_by_base = {} + for label in labels: + attrs = label.get("attrs") or {} + base = attrs.get("aymurai_label") or label.get("label") or "ENT" + entity_id = str(attrs.get("canonical_entity_id") or label.get("text")) + key = (base, entity_id) + if key not in index_by_entity: + next_index_by_base[base] = next_index_by_base.get(base, 0) + 1 + index_by_entity[key] = next_index_by_base[base] + + return { + "render_policy": RenderPolicy(suffix_mode="always", suffix_threshold=0), + "label_policies": {"PER": LabelPolicy()}, + "count_by_base": dict(next_index_by_base), + "index_by_entity": index_by_entity, + } + + +def _dark_pixel_ratio(page: pymupdf.Page, rect: pymupdf.Rect) -> float: + pixmap = page.get_pixmap( + matrix=pymupdf.Matrix(2, 2), + clip=rect, + alpha=False, + ) + samples = pixmap.samples + if not samples: + return 0.0 + + channels = pixmap.n + dark_pixels = 0 + total_pixels = pixmap.width * pixmap.height + for offset in range(0, len(samples), channels): + if all(channel < 96 for channel in samples[offset : offset + 3]): + dark_pixels += 1 + + return dark_pixels / max(total_pixels, 1) + + +def _assert_text_count(page_text: str, text: str, expected: int) -> None: + assert page_text.count(text) == expected, page_text + + +def _assert_rect_close(actual: pymupdf.Rect, expected: pymupdf.Rect) -> None: + assert (actual.x0, actual.y0, actual.x1, actual.y1) == pytest.approx( + (expected.x0, expected.y0, expected.x1, expected.y1) + ) + + +def _write_variable_signature_pdf( + path: Path, +) -> tuple[Path, list[dict], list[str], list[str], list[pymupdf.Rect]]: + blocks = [ + { + "origin": (58, 112), + "lines": [ + "Mesa de Control 42", + "Adriana Morales", + "Area de Validacion", + "Codigo A-17", + ], + "signer": "Adriana Morales", + "qr": "top", + }, + { + "origin": (326, 112), + "lines": [ + "Bernardo Diaz", + "Direccion Legal", + "Organismo Beta Sur", + "Tramite BX-900", + ], + "signer": "Bernardo Diaz", + "qr": "right", + }, + { + "origin": (58, 328), + "lines": [ + "Centro Operativo", + "Carolina Ruiz", + "Secretaria Tecnica", + "2026-05-26 10:15", + ], + "signer": "Carolina Ruiz", + "qr": "left", + }, + { + "origin": (326, 328), + "lines": [ + "Unidad Regional", + "Coordinacion de Revision", + "Daniel Silva", + "Expediente Digital Z-42", + ], + "signer": "Daniel Silva", + "qr": "top", + }, + { + "origin": (58, 544), + "lines": [ + "Responsable: Elena Torres - Acta Final", + "Delegacion Gamma", + "Registro Interno R-204", + ], + "signer": "Elena Torres", + "qr": "right", + }, + ] + + doc = pymupdf.open() + page = doc.new_page() + preds: list[dict] = [] + preserved_texts: list[str] = [] + signers: list[str] = [] + qr_rects: list[pymupdf.Rect] = [] + + for idx, block in enumerate(blocks): + x, y = block["origin"] + if block["qr"] == "right": + qr_rect = pymupdf.Rect(x + 150, y - 4, x + 182, y + 28) + elif block["qr"] == "left": + qr_rect = pymupdf.Rect(x - 2, y - 48, x + 30, y - 16) + else: + qr_rect = pymupdf.Rect(x, y - 52, x + 32, y - 20) + page.insert_image(qr_rect, stream=PNG_BLACK_1X1) + qr_rects.append(qr_rect) + + for line_idx, line in enumerate(block["lines"]): + page.insert_text((x, y + (line_idx * 16)), line, fontsize=11) + if line == block["signer"]: + continue + if block["signer"] in line: + preserved_texts.extend( + part.strip() for part in line.split(block["signer"]) if part.strip() + ) + else: + preserved_texts.append(line) + + widget = pymupdf.Widget() + widget.field_name = f"sig_{idx}" + widget.field_type = pymupdf.PDF_WIDGET_TYPE_SIGNATURE + widget.rect = pymupdf.Rect(x - 12, y - 62, x + 230, y + 64) + page.add_widget(widget) + + document = "\n".join(block["lines"]) + label = _label_for_document_text(document, block["signer"]) + preds.append({"document": document, "labels": [label]}) + signers.append(block["signer"]) + + doc.save(path) + doc.close() + return path, preds, signers, preserved_texts, qr_rects + + @pytest.mark.integration def test_anonymization_package_exports_and_registry_are_stable(): assert PdfAnonymizer.__name__ == "PdfAnonymizer" @@ -218,17 +389,234 @@ def test_pdf_anonymizer_removes_image_backed_entities(tmp_path): assert "" in page_text +def test_signature_background_rect_stays_on_signer_name_line(): + background = _signature_background_rect( + { + "line_rect": pymupdf.Rect(80, 70, 220, 118), + "canvas_rect": pymupdf.Rect(112, 70, 145, 82), + "redact_rect": pymupdf.Rect(112, 70, 145, 82), + }, + pymupdf.Rect(60, 60, 230, 130), + ) + + assert background.y0 >= 70 + assert background.y1 <= 82 + + +def test_signature_text_rect_refinement_does_not_include_role_text(tmp_path): + source_path = _write_pdf( + tmp_path / "signature-role.pdf", + lambda _doc, page: ( + page.insert_text((100, 80), "RUIZ"), + page.insert_text((100, 96), "JUEZ/A"), + ), + ) + + with pymupdf.open(source_path) as doc: + page = doc[0] + signer_rect = page.search_for("RUIZ")[0] + role_rect = page.search_for("JUEZ/A")[0] + loose_rect = pymupdf.Rect(signer_rect) + loose_rect.include_rect(role_rect) + + refined = _refine_signature_text_rect( + page, + "RUIZ", + pymupdf.Rect(80, 60, 200, 115), + loose_rect, + ) + + assert refined.intersects(signer_rect) + assert not refined.intersects(role_rect) + + +def test_signature_text_rect_refinement_returns_current_rect_when_no_hit_in_widget( + tmp_path, +): + source_path = _write_pdf( + tmp_path / "signature-no-hit.pdf", + lambda _doc, page: page.insert_text((260, 80), "RUIZ"), + ) + + with pymupdf.open(source_path) as doc: + page = doc[0] + current_rect = pymupdf.Rect(100, 72, 130, 84) + + refined = _refine_signature_text_rect( + page, + "RUIZ", + pymupdf.Rect(80, 60, 180, 115), + current_rect, + ) + + _assert_rect_close(refined, current_rect) + + +def test_signature_text_rect_refinement_selects_closest_matching_hit(tmp_path): + source_path = _write_pdf( + tmp_path / "signature-multiple-hits.pdf", + lambda _doc, page: ( + page.insert_text((100, 80), "RUIZ"), + page.insert_text((220, 80), "RUIZ"), + ), + ) + + with pymupdf.open(source_path) as doc: + page = doc[0] + left_rect, right_rect = page.search_for("RUIZ") + target = pymupdf.Rect(right_rect) + target.x0 += 2 + target.x1 += 2 + + refined = _refine_signature_text_rect( + page, + "RUIZ", + pymupdf.Rect(80, 60, 280, 115), + target, + ) + + assert refined.intersects(right_rect) + assert not refined.intersects(left_rect) + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_only_redacts_marked_signature_names_in_variable_layouts( + tmp_path, +): + source_path, preds, signers, preserved_texts, qr_rects = ( + _write_variable_signature_pdf(tmp_path / "variable-signatures.pdf") + ) + render_context = _render_context_for_entities([pred["labels"][0] for pred in preds]) + output_dir = tmp_path / "out-variable" + output_dir.mkdir(exist_ok=True) + + output_path = PdfAnonymizer().anonymize( + {"path": str(source_path)}, + preds, + str(output_dir), + render_context=render_context, + ) + + with pymupdf.open(output_path) as output_doc: + page = output_doc[0] + page_text = page.get_text() + + assert list(page.widgets() or []) == [] + assert len(page.get_image_info()) >= len(qr_rects) + + for signer in signers: + assert signer not in page_text + + for index in range(1, len(signers) + 1): + assert f"" in page_text + + for preserved_text in preserved_texts: + _assert_text_count(page_text, preserved_text, 1) + + for qr_rect in qr_rects: + assert _dark_pixel_ratio(page, qr_rect) > 0.25 + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_leaves_unlabeled_signature_names_visible(tmp_path): + source_path, preds, signers, preserved_texts, qr_rects = ( + _write_variable_signature_pdf(tmp_path / "partially-labeled-signatures.pdf") + ) + unlabeled_signer = signers[-1] + filtered_preds = [] + filtered_labels = [] + for pred, signer in zip(preds, signers, strict=True): + labels = [] if signer == unlabeled_signer else pred["labels"] + filtered_preds.append({**pred, "labels": labels}) + filtered_labels.extend(labels) + + render_context = _render_context_for_entities(filtered_labels) + output_dir = tmp_path / "out-partial" + output_dir.mkdir(exist_ok=True) + + output_path = PdfAnonymizer().anonymize( + {"path": str(source_path)}, + filtered_preds, + str(output_dir), + render_context=render_context, + ) + + with pymupdf.open(output_path) as output_doc: + page = output_doc[0] + page_text = page.get_text() + + assert list(page.widgets() or []) == [] + assert unlabeled_signer in page_text + assert "" not in page_text + + for index, signer in enumerate(signers[:-1], start=1): + assert signer not in page_text + assert f"" in page_text + + for preserved_text in preserved_texts: + _assert_text_count(page_text, preserved_text, 1) + + for qr_rect in qr_rects: + assert _dark_pixel_ratio(page, qr_rect) > 0.25 + + +@pytest.mark.integration +@WINDOWS_PYMUPDF_LAYOUT_XFAIL +def test_pdf_anonymizer_preserves_non_signature_widget_appearance_when_baking( + tmp_path, +): + def configure(_doc: pymupdf.Document, page: pymupdf.Page) -> None: + page.insert_text((80, 88), "Ana Perez") + + text_widget = pymupdf.Widget() + text_widget.field_name = "public_field" + text_widget.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT + text_widget.field_value = "Visible Field Value" + text_widget.text_font = "Helv" + text_widget.text_fontsize = 10 + text_widget.rect = pymupdf.Rect(260, 70, 410, 96) + page.add_widget(text_widget) + + signature_widget = pymupdf.Widget() + signature_widget.field_name = "sig_1" + signature_widget.field_type = pymupdf.PDF_WIDGET_TYPE_SIGNATURE + signature_widget.rect = pymupdf.Rect(60, 60, 180, 110) + page.add_widget(signature_widget) + + source_path = _write_pdf(tmp_path / "signature-and-text-widget.pdf", configure) + output_path = _run_pdf_anonymizer( + tmp_path, + source_path, + "Ana Perez", + [_label_dict("Ana Perez")], + ) + + with pymupdf.open(output_path) as output_doc: + page = output_doc[0] + page_text = page.get_text() + + assert list(page.widgets() or []) == [] + assert "Visible Field Value" in page_text + assert "Ana Perez" not in page_text + assert "" in page_text + + @pytest.mark.integration @WINDOWS_PYMUPDF_LAYOUT_XFAIL -def test_pdf_anonymizer_removes_signature_widgets_without_restoring_appearance( +def test_pdf_anonymizer_preserves_signature_appearance_when_redacting_signer_name( tmp_path, ): def configure(_doc: pymupdf.Document, page: pymupdf.Page) -> None: - page.insert_text((80, 90), "Ana Perez") + page.insert_text((80, 76), "FIRMADO DIGITALMENTE") + page.insert_text((80, 92), "05/02/2025 14:17") + page.insert_text((80, 108), "Ana Perez") + page.insert_image(pymupdf.Rect(185, 68, 215, 98), stream=PNG_1X1) widget = pymupdf.Widget() widget.field_name = "sig_1" widget.field_type = pymupdf.PDF_WIDGET_TYPE_SIGNATURE - widget.rect = pymupdf.Rect(60, 60, 220, 110) + widget.rect = pymupdf.Rect(60, 60, 230, 120) page.add_widget(widget) source_path = _write_pdf(tmp_path / "signature.pdf", configure) @@ -244,7 +632,9 @@ def configure(_doc: pymupdf.Document, page: pymupdf.Page) -> None: page_text = page.get_text() assert list(page.widgets() or []) == [] - assert page.get_image_info() == [] + assert page.get_image_info() != [] + assert "FIRMADO DIGITALMENTE" in page_text + assert "05/02/2025 14:17" in page_text assert "Ana Perez" not in page_text assert "" in page_text From f2310e25c997a81a9c992facf4f43938b179a6f9 Mon Sep 17 00:00:00 2001 From: conrabeatriz Date: Wed, 27 May 2026 16:03:47 -0300 Subject: [PATCH 101/104] =?UTF-8?q?=F0=9F=90=9B=20Bug=20fix=20for=20exact?= =?UTF-8?q?=20entities.=20(#80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🐛 Bug fixed for entities who are always the same that have to bypass the fuzzy matching algorithm. * ⚡️ Improved structure following copilot comments. * ⚗️ Experimentation. * 🐛 Merge duplicate labels for the same span and AymurAI label in _dedupe_doclabels function * ✅ Add integration test for merging cached duplicate labels for the same span --------- Co-authored-by: jansaldo --- .../routers/anonymizer/anonymizer.py | 44 ++++++++++++---- .../anonymization_postprocess/core.py | 16 ++++++ .../anonymization_postprocess/exact_labels.py | 10 ++++ aymurai/utils/entity_disambiguation/fuzzy.py | 43 ++++++++++++--- .../10-anonymize-document-render-policy.ipynb | 9 +++- .../api/routers/anonymizer/test_anonymizer.py | 52 +++++++++++++++++++ 6 files changed, 157 insertions(+), 17 deletions(-) create mode 100644 aymurai/transforms/anonymization_postprocess/exact_labels.py diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 6bc7b494..6fde1db7 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -89,30 +89,54 @@ def _entities_to_doclabels(entities: list[dict]) -> list[DocLabel]: def _dedupe_doclabels(labels: Iterable[DocLabel]) -> list[DocLabel]: """ - Remove exact duplicate labels while preserving first-seen order. + Merge duplicate labels for the same span and AymurAI label. Args: labels (Iterable[DocLabel]): An iterable of DocLabel objects, potentially containing duplicates. Returns: - list[DocLabel]: A list of DocLabel objects with duplicates removed, + list[DocLabel]: A list of DocLabel objects with duplicates merged, preserving the order of first occurrence. """ deduped: list[DocLabel] = [] - seen: set[str] = set() + index_by_key: dict[tuple[int, int, str], int] = {} for label in labels: - key = json.dumps( - label.model_dump(mode="json", exclude_none=True), - sort_keys=True, - separators=(",", ":"), + key = ( + label.start_char, + label.end_char, + label.attrs.aymurai_label if label.attrs else "", ) - if key in seen: + existing_index = index_by_key.get(key) + if existing_index is None: + index_by_key[key] = len(deduped) + deduped.append(label) continue - seen.add(key) - deduped.append(label) + existing = deduped[existing_index] + existing_data = existing.model_dump(mode="json") + incoming_data = label.model_dump(mode="json") + existing_attrs = existing_data.get("attrs") or {} + incoming_attrs = incoming_data.get("attrs") or {} + + for attr_key, incoming_value in incoming_attrs.items(): + existing_value = existing_attrs.get(attr_key) + if attr_key == "aymurai_label_subclass": + merged = list(existing_value or []) + for subclass in incoming_value or []: + if subclass not in merged: + merged.append(subclass) + existing_attrs[attr_key] = merged + elif existing_value in (None, [], "") and incoming_value not in ( + None, + [], + "", + ): + existing_attrs[attr_key] = incoming_value + + existing_data["attrs"] = existing_attrs + deduped[existing_index] = DocLabel.model_validate(existing_data) return deduped diff --git a/aymurai/transforms/anonymization_postprocess/core.py b/aymurai/transforms/anonymization_postprocess/core.py index bd596d29..af5185e4 100644 --- a/aymurai/transforms/anonymization_postprocess/core.py +++ b/aymurai/transforms/anonymization_postprocess/core.py @@ -4,6 +4,7 @@ from aymurai.meta.pipeline_interfaces import Transform from aymurai.meta.types import DataItem from aymurai.utils.misc import get_element +from aymurai.transforms.anonymization_postprocess.exact_labels import EXACT_LABELS class AnonymizationEntityCleaner(Transform): @@ -32,6 +33,7 @@ def process(self, ent: dict) -> dict: original_text = ent["text"] start_char = ent["start_char"] end_char = ent["end_char"] + label = ent["attrs"]["aymurai_label"] # Match leading and trailing non-alphanumeric characters leading_match = re.match(r"^\W+", original_text) @@ -47,10 +49,24 @@ def process(self, ent: dict) -> dict: if not cleaned_text: return None + raw_subclass = ent["attrs"]["aymurai_label_subclass"] + if isinstance(raw_subclass, list): + aymurai_label_subclass = raw_subclass.copy() + elif raw_subclass: + aymurai_label_subclass = [raw_subclass] + else: + aymurai_label_subclass = [] + + if label in EXACT_LABELS: + flattened_text = re.sub(r"[^a-zA-Z0-9]", "", cleaned_text) + if flattened_text and flattened_text not in aymurai_label_subclass: + aymurai_label_subclass.append(flattened_text) + # Update the entity's alt text and indices ent["attrs"]["aymurai_alt_text"] = cleaned_text ent["attrs"]["aymurai_alt_start_char"] = start_char + leading_chars_removed ent["attrs"]["aymurai_alt_end_char"] = end_char - trailing_chars_removed + ent["attrs"]["aymurai_label_subclass"] = aymurai_label_subclass return ent diff --git a/aymurai/transforms/anonymization_postprocess/exact_labels.py b/aymurai/transforms/anonymization_postprocess/exact_labels.py new file mode 100644 index 00000000..afe345da --- /dev/null +++ b/aymurai/transforms/anonymization_postprocess/exact_labels.py @@ -0,0 +1,10 @@ +EXACT_LABELS = { + "DNI", + "CUIT_CUIL", + "TELEFONO", + "PATENTE_DOMINIO", + "IP", + "NUM_CAJA_AHORRO", + "CBU", + "NUM_MATRICULA", +} diff --git a/aymurai/utils/entity_disambiguation/fuzzy.py b/aymurai/utils/entity_disambiguation/fuzzy.py index 682810b6..e55850d1 100644 --- a/aymurai/utils/entity_disambiguation/fuzzy.py +++ b/aymurai/utils/entity_disambiguation/fuzzy.py @@ -7,6 +7,8 @@ from aymurai.meta.api_interfaces import DocLabel from aymurai.meta.entities import CanonicalEntity +from aymurai.transforms.anonymization_postprocess.exact_labels import EXACT_LABELS + def _find_parent(parent: list[int], idx: int) -> int: """ @@ -179,16 +181,45 @@ def build_canonical_entities( if target_labels and attrs.aymurai_label not in target_labels: continue alias = attrs.aymurai_alt_text or label.text + + subclass_val = getattr(attrs, "aymurai_label_subclass", None) + + if isinstance(subclass_val, list): + exact_alias = subclass_val[-1] if subclass_val else alias + else: + exact_alias = subclass_val or alias + grouped.setdefault(attrs.aymurai_label, []).append( - {"text": alias, "aymurai_label": attrs.aymurai_label} + { + "text": alias, + "aymurai_label": attrs.aymurai_label, + "exact_alias": exact_alias, + } ) canonical_entities: list[CanonicalEntity] = [] - for items in grouped.values(): - clusters = _cluster_aliases_with_cdist( - items=items, - threshold=threshold, - ) + for label_type, items in grouped.items(): + if label_type in EXACT_LABELS: + exact_groups = {} + for item in items: + exact_groups.setdefault(item["exact_alias"], []).append(item) + clusters = [ + [ + ( + item["text"], + str(item["exact_alias"]).lower().strip(), + item["aymurai_label"], + ) + for item in group_items + ] + for group_items in exact_groups.values() + ] + else: + clusters = _cluster_aliases_with_cdist( + items=items, + threshold=threshold, + ) + canonical_entities.extend(_clusters_to_canonical_entities(clusters)) canonical_entities = sorted(canonical_entities, key=lambda x: x.canonical_text) diff --git a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb index c072066f..92bc8185 100644 --- a/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb +++ b/notebooks/experiments/entity-disambiguation/10-anonymize-document-render-policy.ipynb @@ -64,7 +64,7 @@ "\n", "print(f\"Found {len(documents)} documents\")\n", "\n", - "doc_path = documents[14]\n", + "doc_path = documents[5]\n", "print(f\"Processing document: {doc_path}\")" ] }, @@ -430,6 +430,13 @@ "result = group_alt_texts_by_entity(anonymize_labels_fuzzy)\n", "print(json.dumps(result, indent=4, ensure_ascii=False))" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/tests/api/routers/anonymizer/test_anonymizer.py b/tests/api/routers/anonymizer/test_anonymizer.py index 0648c625..4480e05f 100644 --- a/tests/api/routers/anonymizer/test_anonymizer.py +++ b/tests/api/routers/anonymizer/test_anonymizer.py @@ -935,6 +935,58 @@ def test_should_dedupe_duplicate_labels_when_returning_cached_prediction( mock_load_pipeline.assert_not_called() +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.load_pipeline") +def test_should_merge_cached_duplicate_labels_for_same_span_and_label( + mock_load_pipeline, client, db_session +): + text = ( + "Víctima: María Paula Trucha, DNI 23.456.789, quien se encuentra " + "conectada con su cámara apagada." + ) + dni_label = build_label("DNI", "23.456.789").model_dump(mode="json") + dni_label.update({"start_char": 33, "end_char": 43}) + dni_label["attrs"].update( + { + "aymurai_alt_text": "23.456.789", + "aymurai_alt_start_char": 33, + "aymurai_alt_end_char": 43, + "aymurai_label_instance": 2, + "aymurai_disambiguation": "fuzzy", + "aymurai_anonymize": True, + "canonical_entity_id": "0bba6d15-1b0c-51f0-b2ca-4fdc8a57cb73", + } + ) + enriched_dni_label = { + **dni_label, + "attrs": { + **dni_label["attrs"], + "aymurai_label_subclass": ["23456789"], + }, + } + + db_session.add( + AnonymizationParagraph( + id=text_to_uuid(text), + text=text, + prediction=[dni_label, enriched_dni_label], + ) + ) + db_session.commit() + + response = client.post( + "/anonymizer/predict", + json={"text": text}, + params={"use_cache": True}, + ) + + assert response.status_code == 200 + data = response.json() + assert data["document"] == text + assert data["labels"] == [enriched_dni_label] + mock_load_pipeline.assert_not_called() + + @pytest.mark.integration @patch( "aymurai.api.endpoints.routers.anonymizer.anonymizer.map_canonical_entities_ner_preds" From 4606b2d5dffa9b35a8f1370f52c543e3151f0353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juli=C3=A1n=20Ansaldo?= <48162237+jansaldo@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:34:42 -0300 Subject: [PATCH 102/104] Feature/frontend integration (#83) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Merge dev into main for v1.1.12 (#57) * Update README.md * 🐛 bugfix: Fix XML special character escaping in DocAnonymizer * ➕ build(deps): Add python-docx package * ✨ feat: Add watermark and hyperlink functionality to document anonymization * ✨ feat: Install Archivo font in Dockerfile * 🎨 refactor: Improve Dockerfile structure and comments for clarity * ⏪ revert: Remove Archivo font installation from Dockerfile * 🔖 feat: Update aymurai package version to 1.1.11 in uv.lock * 🐛 Improve get_extension logic to fix document extraction issues on Windows and remove python-magic dependency * 🔧 Update Dockerfile to use 'bullseye' variant for Python images for improved compatibility * 🔧 Update Makefile targets for improved Docker workflow * 🔖 feat: Bump aymurai package version to 1.1.12 * ♻️ Harden get_extension with header scans and zip safeguards * 🔧 Extend document extraction timeout to 30s * 🔧 Refactor Docker workflow to build and push images using docker/build-push-action * 🔧 Fix workflow step order to correctly extract tag name before building Docker images * 🔧 Remove tag extraction step and use github.ref_name directly for Docker image builds * ⏪ Revert Docker workflow to extract tag name and use it for image versioning * Update .github/workflows/build-docker-image.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * ✏️ Remove incomplete comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: jed Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Squashed 'frontend/' content from commit 9123e6f git-subtree-dir: frontend git-subtree-split: 9123e6ff047ddc6da0528d1de827a4af68752d0f * Squashed 'frontend/' changes from 9123e6ff..8add5c45 8add5c45 1.25.0 d7424d94 use base_url when dealing with public assets ae1a47b8 Merge pull request #44 from AymurAI/feat/redesign 9cfc610c fix issue regarding annotation keyboard navigation a723be01 restore useNotify feature in process page b888214a make how it works modal bigger 49c3bc22 fix electron ts issues eb791d07 add missing anonymize value on label attrs 151e2710 make OS taskbar API safe to call in web 8dc38fbb add knip a0f6c687 fix ts clone element issue d975e3fd include label policies and annotations when anonymizing document 70c44a04 more fixes in height to validate dataset a36a7401 make suggestion clickable on uncontrolled text input ea61e4e2 add fixed height to validation dataset page 072d751e remove axios' default api url 6f8a478c adjust typings 528c646f add more canonical id operations on reducers ae09277c add update by cannonical id function de2b641c add random cannonical id on search add event 74d4dac2 add value as undefined on ui/input component 6aa895f4 simplify and remove unused code on fille annotator component d10fe8c7 add useShallow to local storage default getters 9f62ac69 adjust predicting and file parser flows 01aa8a79 fix TS issues 5655eac5 smaller fixes on file annotation components a7e91cec add remove dialog to label manager's entity tab cad8faaa simplify annotation components 52230ee4 add metadata to search and tag annotations 0f08b9c8 add more anonymizer copy locale texts 6c3112ac store label manager config in local storage 63c4d731 move suggestion label and add mark props 77017543 adjust spacing on dataset validation cae3b907 disambiguate hook 6b21903e move createAnnotationData, tag and suffix to context d1649e5d add max width to toast and remove instad of dismiss it ca56bb63 add size variant to suggestion and adjust display 55a67bf8 fix select viewport and add scroll aa2ce6a1 adjust styles on callout 5493cdee finish mark and tag annotation feature 4fb28120 finish major pages and add file protection feature af457c85 improve accessibility on host page c2c21c21 add className to SectionTitle 6edd7101 update tanstack react query version df491c17 add odt to pdf conversion efb04bc5 deprecate usage of useSchemedQuery and useSchemedQueries 046a73e2 deprecate usage of useSchemedMutation 65ceb195 swap replace button icons 12348edd update button icons 2719755f extract tagger popover logic 28ce40ab create search tagger e54adfbe add small version of select component d6c3bd77 improve ui dialog component 63c6bf09 initial mark component update cd0f7d30 add radix's select as dependency 92ceaace remove old tooltip implementation 2499e4c8 add input size variants be48dac9 add custom icons to callout, toast and showToast 32d3441b add retro compatibility features to select 657e2a5a minor styling fixes + new select imports 7a323cd2 kill more unused components c5d7b4ba create better select component d855a93b adjust styling and positioning on preview page 1cfba9c4 adjust callout styling c28fdcd0 fix title in process copy etxt 3a9a5cc6 remove old component implementations 03954d74 create callout from toast, and then apply a11y to toast 93c9457d create toast component 642e760d improve suggestion component 707e844b update suggestion mark component's styles 7c1db956 add checked variant to button 204246c7 fix gaps on finish page 9e81ee12 hide file stepper selector arrows depending on cursor da1377ea update file processing component 12aa1c6b update decision tabs to panda 490a1adb simplify finish dataset and anonymizer ba12dad2 add className prop to footer 4ed68454 drop file queries when resetting the progress 762cf823 add missing built by in features page 2c9d6cf8 make dataset validation file annotator not annotable 59416b8f clear files on features menu 9585726b use translation on droparea 091b2c58 make search bar static and follow scroll 0978aff6 add label manager to file annotator 5b069d68 connect rest of label manager 23fa8407 improve layout header component 3c88d2f3 finish preview page d31ec034 finish onboarding page 7d1a71f3 add disambiguate and predict react query options 4e91d285 feat: add feature icon record bfc9baf7 feat: create initial label manager 0bc48bc9 chore: refactor Searchbar 962961e4 chore: remove stepper component 95e17235 fix: title in anonymizer locale df53488d chore: minor changes 4a9a2557 feat: create switch component d4830e48 feat: create label manager component baa9835c feat: add more copies for the finish page 9d915cab chore: kill unused old hidden input component 2fd61a7f fix: add missing feature param call on route.tsx 617ea974 feat: use a11y on finish page 172b731a Merge branch 'feat/a11y-dataset-header' into feat/redesign 394121d9 feat: add more copies to locale file c34951e8 fix: redo home layout 31078ff5 chore: cleanup cf9def05 chore: restructure HOC to be a regular component 088bed82 feat: add api base url protection and apply it cd15a776 fix(layout): address PR review on header and icon changes 59dc125e feat: add i18n support for the whole app 36d70bbd build: add i18n 244027be refactor(layout): hoist Topbar and Stepper to global wizard route 146905fb feat: improve topbar accessibility with semantic icons and aria labels 5f910470 chore: ignore personal analysis folder b6569f77 chore: rework layout components 331ff8dc fix: update enum import ee17865e feat(ui): create and/or adjust components 6c9daf38 feat: rework onboarding page 347054d5 chore: simplify main app layout cef7f882 chore: adjust button sizes and enum import dc59ad2a feat: make card clickable 051b6bd4 chore: add tutorial seen to local storage store 1e15bb74 fix: typo on anonymizer label 24f6de07 build: add web or electron run modes beb63bc3 chore: migrate hidden input 23442095 chore: use constants and base card element on feature selector 2eba84b3 chore: refactor header so we can correctly position all elements 0a50bb14 fix: adjust stepper styles (sizing and colors) 504840d9 chore: export constants 3b79f391 build: update react and add radix dependencies f6f7fac8 fix: remove fadeIn scaling animation 41a158c3 chore: create modern ui components 5a02a5df chore: flag card as deprecated edb85211 feat: create modern tooltip component a2c2040a fix: replace brand images with correct ones and set proper heights edce7295 feat(components): create brand, layout and ui components 5475a617 feat: add more brand images 9cd982f8 chore(styles): add animation semantic tokens ce991130 fix: extra character in home layout and rename the component 5e41df1a feat: redesign home 0947627c feat: create link card tool for features 0833a987 feat: create components to render in home screen a6198d99 fix: add fixed height to button and auto adjust icon size ab0a4e20 fix: add lineheight to text styles and adjust font weight 047b115a chore: replace custom use mutation hook with base on connect to host hook 59363cd7 chore: change to named export on local store 3a289e1e chore: add changes to router file 2393d18e chore: fix some tokens in panda and move stitches global styles 64048ac7 chore: re-implement button and partially input 51fe0990 feat: add loading screen on boot, timer of 1.5s 60cf7fde chore: configure view transition for all pages ebcf3a66 feat: add loading page and updated branding images 67603f66 chore: flag stitches as deprecated e416ace8 build: install and configure pandacss c2e5eac1 build: add support for environmental variables for both web and electron apps git-subtree-dir: frontend git-subtree-split: 8add5c452478cdbe6a99ad1b05183cd264183c72 * ✨ Add frontend routing and settings for frontend distribution directory * Squashed 'frontend/' changes from 8add5c45..ff882164 ff882164 chore: add .npmrc to configure public hoist pattern for @types 32bfab0a Merge pull request #59 from AymurAI/fix/53-restore-home-button 94e3816d Merge pull request #65 from AymurAI/fix/add-placeholder-to-select-entities 3545775f Merge pull request #66 from AymurAI/fix/remove-doc-extension d24c458b add a "config" button in features menu f427da73 make hover effect in button work for anchor tanstack link wrapper 77077905 remove slot checks on header 82d2c65a add home button to header on all flow's pages 5663da42 make aymurai's logo a link in the header c3c0e8a7 create home button component 51cb537f fix: prevent select caret rotation from leaking ancestor data-state 5d85973f feat: add tooltips to tagger label and suffix inputs 7e0b67b8 Fix text overflow in HowItWorksModal (#58) 3d516636 Restore delete-one and delete-all hover actions on annotations (#57) fa7e0967 create link component c8112e20 add "Entidad" placeholder to tagger select 70710e11 change NINO to NIÑO 6664e631 remove copies and functions referencing .doc files 4a00039b copy change 422affaf Merge pull request #64 from AymurAI/fix/browser-resources-exhaustion ce8a474a prevent semaphores underflow dcf3b6b7 Merge pull request #62 from AymurAI/fix/conversion-endpoint-usage 7729801f add error handling to finish file conversion 2afe00ee Merge pull request #63 from AymurAI/fix/copy-changes 387d6724 Merge pull request #61 from AymurAI/fix/responsiveness 84843877 limit concurrent predict requests to avoid connection exhaustion 8d3e2693 fix: increase spacing between home and features menu buttons 3025e341 fix: use House icon in header instead of BackButton arrow c9bba1a9 feat: add back-to-home button on features page a0b8f55f use extension to check if file conversion is needed 0b83d0b0 create pdf to odt service 78b1a9c9 responsiveness for screens less than 1280px in width fef9a94e copy change on label manager tab b9c6db53 copy changes on label manager config tab git-subtree-dir: frontend git-subtree-split: ff882164be8077dee58b6748886b0d7d3acbe376 * 🔧 Remove commented-out router for anonymizer database * ✨ Add Node.js and npm installation for frontend build in Dockerfile * 📝 Update API documentation URLs to include '/api' prefix * ✨ Add frontend build commands to Makefile * 🙈 Update .dockerignore and .gitignore to include frontend build output directories * ✅ Update API routes to include '/api' prefix in tests and add frontend integration tests * ♻️ Refactor routing and API integration to remove '/app' prefix and streamline feature routes * Squashed 'frontend/' changes from ff882164..d3e14b5e d3e14b5e feat(validation): persist and restore predictions via backend validation endpoint (#68) 6b8a23ba Add drag-and-drop reordering and inline rename to label manager (#60) git-subtree-dir: frontend git-subtree-split: d3e14b5e00af41fded1c113e51e2e8b73bbf1b22 * refactor: update feature routing, migrate to pnpm, and refine dev environment configuration * Squashed 'frontend/' changes from d3e14b5e..879309c8 879309c8 Feat/entity manager mention feedback (#81) 4d2de106 Fix/responsive home layout (#80) 986e68d2 Fix/homogenize file check ui (#77) 046f8ab9 fix(file-annotator): fix upward autoscroll on search previous navigation (#76) 2ecf75dc feat(dependencies): add dnd-kit packages for drag-and-drop functionality git-subtree-dir: frontend git-subtree-split: 879309c841d8072babc4d06f1686d11cf8cbd03f * Squashed 'frontend/' changes from 879309c8..a37adc20 a37adc20 fix(useLocal): stop persisting groupOrder and remove dead categoryAssignments (#78) (#87) 47fb1fb3 fix(disambiguate): match response items by text instead of array index (#78) (#86) c873c8e0 Mover configuración de pnpm de `package.json` a `pnpm-workspace.yml` (#83) f4ce881b fix(useFileParse): use position-based paragraph ID to avoid key collisions (#85) 181e0356 Fix/invalid entity offsets (#82) git-subtree-dir: frontend git-subtree-split: a37adc20f579276b3a0e5979424ba7809fb7e2ff * chore: migrate frontend build process from npm to pnpm in API Dockerfile * 🐛 fix: add support for numpy integer and floating types in EnhancedJSONEncoder * fix: update Stack component to use height instead of minHeight for consistent layout * fix: update imports for Label and Text components in UncontrolledInput to avoid circular dependency * chore: regenerate routeTree.gen.ts after removing $feature parent layout route * feat: add default anonymization policies to settings * chore: bump frontend version to 1.5.0 * fix(api): preserve pipeline cache for configured ttl * refactor: remove torch dependency and configure threads via settings * fix(frontend): replace previous anonymizer file on load * fix(frontend): support dataset export in web mode * fix(tests): add SQLALCHEMY_DATABASE_URI environment variable for api tests * fix(api): improve error logging during startup --------- Co-authored-by: jed Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: dmazzini --- .devcontainer/Dockerfile | 6 +- .dockerignore | 7 +- .github/workflows/pytest.yml | 1 + .gitignore | 6 + Makefile | 16 + README.md | 29 +- aymurai/api/core.py | 7 - .../routers/anonymizer/anonymizer.py | 9 +- .../routers/datapublic/datapublic.py | 2 - .../endpoints/routers/frontend/__init__.py | 1 + .../endpoints/routers/frontend/frontend.py | 114 + aymurai/api/main.py | 37 +- aymurai/api/utils.py | 7 +- aymurai/config/__init__.py | 0 .../default_disambiguation_label_policies.yml | 124 + aymurai/settings.py | 36 +- aymurai/utils/json_encoding.py | 5 + docker/api/Dockerfile | 24 + docs/api/README.md | 74 +- docs/es/api/README.md | 74 +- frontend/.dockerignore | 13 + frontend/.gitignore | 34 + frontend/.gitlab-ci.yml | 18 + frontend/.gitlab/analysis/audit.yml | 13 + frontend/.gitlab/analysis/lint.yml | 12 + frontend/.npmrc | 1 + frontend/.prettierrc | 3 + frontend/.vscode/settings.json | 27 + frontend/CONTRIBUTING.md | 86 + frontend/README.md | 95 + frontend/a.tml | 18 + frontend/biome.json | 54 + frontend/dev-app-update.yml | 3 + frontend/docs/ANONIMIZADO.docx | Bin 0 -> 11604 bytes frontend/docs/SIN_ANONIMIZAR.docx | Bin 0 -> 51604 bytes frontend/docs/ai.md | 14 + frontend/docs/authentication.md | 74 + frontend/docs/aymurai.md | 70 + frontend/docs/excel/filesystem.md | 69 + frontend/docs/excel/spreadsheet-api.md | 30 + frontend/docs/images/auth_flows.png | Bin 0 -> 293014 bytes frontend/docs/images/electron_pkce.png | Bin 0 -> 88023 bytes frontend/docs/images/initial-screen.png | Bin 0 -> 909887 bytes frontend/docs/images/submit-form.png | Bin 0 -> 789557 bytes frontend/docs/images/url-selector.png | Bin 0 -> 988227 bytes frontend/docs/images/validation-form.png | Bin 0 -> 948776 bytes frontend/docs/routing.md | 30 + frontend/docs/url_selector.md | 17 + frontend/docs/validator/README.md | 55 + frontend/electron-builder.yml | 44 + frontend/electron.vite.config.ts | 42 + frontend/forge.config.js | 58 + frontend/knip.json | 6 + frontend/package.json | 100 + frontend/panda.config.ts | 233 + frontend/pnpm-lock.yaml | 11035 ++++++++++++++++ frontend/pnpm-workspace.yaml | 7 + frontend/postcss.config.cjs | 5 + frontend/src/main/createWindow.ts | 73 + frontend/src/main/env.ts | 54 + frontend/src/main/extensions.ts | 17 + frontend/src/main/index.ts | 54 + .../src/main/utils/__tests__/excel.test.ts | 52 + frontend/src/main/utils/excel.ts | 44 + frontend/src/main/utils/feedback.ts | 61 + frontend/src/main/utils/filesystem.ts | 20 + frontend/src/main/utils/index.ts | 7 + frontend/src/main/utils/resolveHTMLPath.ts | 20 + frontend/src/main/utils/subprocess.ts | 31 + frontend/src/main/utils/taskbar.ts | 27 + frontend/src/preload/index.d.ts | 22 + frontend/src/preload/index.ts | 39 + frontend/src/renderer/index.html | 27 + .../renderer/public/audio/notification.mp3 | Bin 0 -> 6587 bytes .../public/brand/aymurai-hor-darkpurple.svg | 25 + .../public/brand/aymurai-iso-darkpurple.svg | 18 + .../public/brand/aymurai-iso-purple.svg | 35 + .../public/brand/aymurai-vert-darkpurple.svg | 25 + .../public/brand/aymurai-vert-purple.png | Bin 0 -> 48246 bytes .../src/renderer/public/brand/datagenero.svg | 15 + .../src/renderer/public/brand/iso-white.png | Bin 0 -> 38733 bytes frontend/src/renderer/public/brand/logo.jpg | Bin 0 -> 80050 bytes .../renderer/public/button-icons/add-all.svg | 6 + .../renderer/public/button-icons/add-one.svg | 3 + .../public/button-icons/delete-all.svg | 6 + .../public/button-icons/delete-one.svg | 3 + .../public/button-icons/replace-all.svg | 6 + .../public/button-icons/replace-one.svg | 3 + frontend/src/renderer/public/favicon.ico | Bin 0 -> 16958 bytes frontend/src/renderer/public/manifest.json | 15 + .../public/onboarding-steps/step1.png | Bin 0 -> 11061 bytes .../public/onboarding-steps/step2.png | Bin 0 -> 5373 bytes .../public/onboarding-steps/step3.png | Bin 0 -> 13743 bytes .../public/onboarding-steps/step4.png | Bin 0 -> 10186 bytes frontend/src/renderer/public/robots.txt | 3 + frontend/src/renderer/src/app.tsx | 49 + .../anonymizer/anonymizer-label-select.tsx | 370 + .../anonymizer/label-manager/config-tab.tsx | 232 + .../anonymizer/label-manager/entity-tab.tsx | 959 ++ .../anonymizer/label-manager/index.tsx | 190 + .../anonymizer/label-manager/label.tsx | 40 + .../anonymizer/label-manager/merge-dialog.tsx | 48 + .../label-manager/remove-dialog.tsx | 36 + .../anonymizer/label-manager/section.tsx | 76 + .../label-manager/sortable-group.tsx | 103 + .../anonymizer/label-manager/tab.tsx | 33 + .../src/components/arrow/LeftArrow.tsx | 13 + .../src/components/arrow/RightArrow.tsx | 16 + .../renderer/src/components/arrow/index.ts | 9 + .../src/components/brand/built-by.tsx | 29 + .../checkbox-group/CheckboxGroup.styles.ts | 30 + .../checkbox/checkbox-group/index.tsx | 39 + .../checkbox/checkbox/Checkbox.styles.ts | 143 + .../components/checkbox/checkbox/index.tsx | 65 + .../renderer/src/components/checkbox/index.ts | 4 + .../decision-tabs/DecisionTabs.styles.ts | 16 + .../src/components/decision-tabs/index.tsx | 52 + .../renderer/src/components/dialog/index.tsx | 109 + .../src/renderer/src/components/drop-area.tsx | 153 + .../renderer/src/components/feature-icon.tsx | 65 + .../renderer/src/components/features-menu.tsx | 64 + .../file-annotator/FileAnnotator.styles.ts | 30 + .../file-annotator/SearchBar/Counter.tsx | 66 + .../SearchBar/SearchBar.styles.ts | 94 + .../file-annotator/SearchBar/index.tsx | 198 + .../components/file-annotator/annotations.ts | 171 + .../file-annotator/generateSplits.ts | 119 + .../src/components/file-annotator/index.tsx | 269 + .../src/components/file-annotator/types.ts | 39 + .../src/components/file-check/ErrorText.ts | 13 + .../components/file-check/FileCheck.styles.ts | 53 + .../src/components/file-check/Icon.tsx | 14 + .../src/components/file-check/index.tsx | 27 + .../file-preview/FilePreview.styles.ts | 70 + .../src/components/file-preview/index.tsx | 89 + .../file-processing/FileProcessing.styles.ts | 52 + .../file-processing/ProgressBar.tsx | 45 + .../file-processing/ProgressLabel.ts | 29 + .../src/components/file-processing/index.tsx | 111 + .../file-stepper/FileStepper.styles.ts | 26 + .../src/components/file-stepper/Icons.tsx | 26 + .../src/components/file-stepper/index.tsx | 67 + .../src/components/file-stepper/utils.ts | 27 + .../file/annotation-popover/index.tsx | 191 + .../file/annotation-popover/tagger-button.tsx | 79 + .../file/annotation-popover/tagger.tsx | 174 + .../file/manual-entity-resolution-dialog.tsx | 227 + .../src/components/file/search-annotation.tsx | 104 + .../src/components/file/suggestion-label.tsx | 86 + .../components/file/tag-annotation/index.tsx | 179 + .../file/tag-annotation/remove-dialog.tsx | 36 + .../file/tag-annotation/replace-dialog.tsx | 39 + .../components/finish/finish-anonymizer.tsx | 145 + .../src/components/finish/finish-dataset.tsx | 90 + .../components/finish/finish-main-content.tsx | 38 + .../src/renderer/src/components/grid/index.ts | 88 + .../renderer/src/components/hidden-input.tsx | 27 + .../src/components/home/choose-host.tsx | 66 + .../src/components/home/connect-to-host.tsx | 108 + .../renderer/src/components/home/stepper.tsx | 109 + .../src/components/how-it-works-modal.tsx | 81 + .../renderer/src/components/how-it-works.tsx | 110 + frontend/src/renderer/src/components/index.ts | 23 + .../renderer/src/components/label/index.ts | 42 + .../renderer/src/components/layout/footer.tsx | 35 + .../renderer/src/components/layout/header.tsx | 68 + .../src/components/layout/home-button.tsx | 16 + .../src/components/layout/main-content.tsx | 48 + .../src/components/onboarding-grid/index.ts | 15 + .../renderer/src/components/radio/index.ts | 4 + .../radio/radio-group/RadioGroup.styles.ts | 30 + .../components/radio/radio-group/index.tsx | 39 + .../components/radio/radio/Radio.styles.ts | 143 + .../src/components/radio/radio/index.tsx | 65 + .../renderer/src/components/spinner/index.tsx | 44 + .../renderer/src/components/stack/index.ts | 66 + .../renderer/src/components/subtitle/index.ts | 39 + .../src/renderer/src/components/tabs/index.ts | 56 + .../src/renderer/src/components/text/index.ts | 40 + .../theme-provider/ThemeProvider.types.ts | 3 + .../src/components/theme-provider/index.tsx | 6 + .../renderer/src/components/title/index.ts | 39 + .../src/components/ui/back-button.tsx | 17 + .../src/renderer/src/components/ui/button.tsx | 150 + .../renderer/src/components/ui/callout.tsx | 106 + .../src/renderer/src/components/ui/card.tsx | 79 + .../src/renderer/src/components/ui/dialog.tsx | 115 + .../src/renderer/src/components/ui/input.tsx | 207 + .../src/renderer/src/components/ui/link.tsx | 33 + .../renderer/src/components/ui/popover.tsx | 53 + .../src/renderer/src/components/ui/select.tsx | 306 + .../renderer/src/components/ui/suggestion.tsx | 25 + .../src/renderer/src/components/ui/switch.tsx | 57 + .../src/renderer/src/components/ui/toast.tsx | 35 + .../renderer/src/components/ui/tooltip.tsx | 50 + .../UncontrolledInput.styles.ts | 43 + .../components/uncontrolled-input/index.tsx | 141 + .../form-group/FormGroup.styles.ts | 9 + .../form-group/FormGroup.types.ts | 17 + .../form-group/forms/DatosAcusado.tsx | 52 + .../form-group/forms/DatosDenunciante.tsx | 47 + .../form-group/forms/Decision.tsx | 98 + .../form-group/forms/InfoGral.tsx | 55 + .../form-group/forms/InfoHecho.tsx | 246 + .../form-group/forms/index.ts | 7 + .../form-group/forms/options.json | 1937 +++ .../validate-dataset/form-group/index.tsx | 97 + .../src/components/validate-dataset/index.tsx | 126 + .../src/components/validate-dataset/utils.ts | 37 + .../validation-form/ValidationForm.styles.ts | 7 + .../src/components/validation-form/index.tsx | 76 + .../src/constants/anonymizer-categories.ts | 82 + frontend/src/renderer/src/constants/config.ts | 6 + .../renderer/src/constants/excluded-tags.ts | 8 + .../src/renderer/src/constants/i18n/index.ts | 27 + .../constants/i18n/locales/es/anonymizer.ts | 73 + .../src/constants/i18n/locales/es/common.ts | 39 + .../src/constants/i18n/locales/es/dataset.ts | 64 + .../src/constants/i18n/locales/es/index.ts | 11 + .../renderer/src/context/Annotation/index.tsx | 792 ++ .../renderer/src/context/Annotation/utils.ts | 136 + frontend/src/renderer/src/context/File.tsx | 35 + .../renderer/src/features/APIProtected.tsx | 12 + .../src/features/ReactQueryProvider.tsx | 55 + .../src/renderer/src/features/RequireFile.tsx | 22 + .../src/renderer/src/features/showToast.tsx | 7 + frontend/src/renderer/src/hooks/index.ts | 8 + .../src/renderer/src/hooks/useDisambiguate.ts | 81 + .../src/renderer/src/hooks/useEntityGroups.ts | 269 + .../src/renderer/src/hooks/useFileParse.ts | 69 + frontend/src/renderer/src/hooks/useFiles.ts | 17 + .../src/renderer/src/hooks/useForm/index.ts | 83 + .../src/renderer/src/hooks/useForm/types.ts | 36 + frontend/src/renderer/src/hooks/usePredict.ts | 171 + frontend/src/renderer/src/index.css | 1 + frontend/src/renderer/src/layout/home.tsx | 50 + frontend/src/renderer/src/layout/loading.tsx | 31 + .../src/renderer/src/layout/section-title.tsx | 13 + frontend/src/renderer/src/main.tsx | 12 + .../src/renderer/src/reducers/file/actions.ts | 454 + .../src/renderer/src/reducers/file/index.ts | 415 + .../src/renderer/src/reducers/file/utils.ts | 101 + frontend/src/renderer/src/routeTree.gen.ts | 231 + .../renderer/src/routes/$feature/finish.tsx | 59 + .../src/routes/$feature/onboarding.tsx | 120 + .../renderer/src/routes/$feature/preview.tsx | 134 + .../renderer/src/routes/$feature/process.tsx | 179 + .../src/routes/$feature/validation.tsx | 79 + frontend/src/renderer/src/routes/__root.tsx | 14 + .../src/renderer/src/routes/home/features.tsx | 87 + .../src/renderer/src/routes/home/host.tsx | 24 + .../src/renderer/src/routes/home/index.tsx | 9 + frontend/src/renderer/src/routes/index.tsx | 22 + .../src/renderer/src/schema/disambiguate.ts | 30 + frontend/src/renderer/src/schema/extract.ts | 24 + frontend/src/renderer/src/schema/predict.ts | 30 + frontend/src/renderer/src/services/api.ts | 25 + .../aymurai/__tests__/validation.test.ts | 225 + .../renderer/src/services/aymurai/index.ts | 7 + .../renderer/src/services/aymurai/predict.ts | 66 + .../renderer/src/services/aymurai/queries.ts | 292 + .../renderer/src/services/aymurai/schema.ts | 5 + .../src/services/aymurai/useConnectToHost.ts | 22 + .../src/services/aymurai/useRunLocalServer.ts | 56 + .../renderer/src/services/aymurai/utils.ts | 6 + .../src/services/aymurai/validation.ts | 109 + .../services/filesystem/browser/download.ts | 13 + .../filesystem/excel/__tests__/write.test.ts | 34 + .../src/services/filesystem/excel/create.ts | 56 + .../src/services/filesystem/excel/index.ts | 12 + .../src/services/filesystem/excel/open.ts | 19 + .../src/services/filesystem/excel/read.ts | 24 + .../src/services/filesystem/excel/write.ts | 24 + .../services/filesystem/feedback/export.ts | 42 + .../src/services/filesystem/feedback/index.ts | 6 + .../src/services/filesystem/feedback/utils.ts | 68 + .../renderer/src/services/filesystem/index.ts | 8 + .../renderer/src/services/filesystem/utils.ts | 13 + .../renderer/src/services/taskbar/index.ts | 16 + .../renderer/src/services/taskbar/utils.ts | 7 + .../src/renderer/src/store/useHoverState.ts | 21 + frontend/src/renderer/src/store/useLocal.ts | 96 + .../src/renderer/src/styles/globalStyles.ts | 87 + frontend/src/renderer/src/styles/index.ts | 4 + .../renderer/src/styles/stitches.config.ts | 124 + frontend/src/renderer/src/styles/tokens.ts | 141 + frontend/src/renderer/src/types/aymurai.ts | 169 + frontend/src/renderer/src/types/component.ts | 11 + frontend/src/renderer/src/types/features.ts | 26 + frontend/src/renderer/src/types/feedback.ts | 11 + frontend/src/renderer/src/types/file.ts | 38 + .../src/renderer/src/types/react-query.d.ts | 10 + .../src/renderer/src/types/spreadsheet.ts | 68 + frontend/src/renderer/src/types/utils.ts | 32 + .../anonymizer/__tests__/predictions.test.ts | 191 + .../src/utils/anonymizer/entity-similarity.ts | 227 + .../src/utils/anonymizer/export-validation.ts | 285 + .../renderer/src/utils/anonymizer/labels.ts | 10 + .../src/utils/anonymizer/occurrences.ts | 74 + .../src/utils/anonymizer/predictions.ts | 73 + frontend/src/renderer/src/utils/config.ts | 13 + .../file/__tests__/preview-files.test.ts | 25 + .../renderer/src/utils/file/excelStructure.ts | 72 + .../src/utils/file/filterEmptyDecisions.ts | 31 + .../renderer/src/utils/file/flatValidation.ts | 43 + .../src/renderer/src/utils/file/getByName.ts | 11 + .../renderer/src/utils/file/getExtension.ts | 8 + .../renderer/src/utils/file/getParagraphId.ts | 27 + frontend/src/renderer/src/utils/file/index.ts | 21 + .../src/renderer/src/utils/file/isAllowed.ts | 11 + .../src/utils/file/isAlreadyLoaded.ts | 11 + .../src/utils/file/isFileValidated.ts | 10 + .../src/utils/file/isValidationCompleted.ts | 13 + .../renderer/src/utils/file/preview-files.ts | 9 + .../__tests__/offline.test.ts | 37 + .../src/utils/file/submitValidations/index.ts | 27 + .../utils/file/submitValidations/offline.ts | 29 + frontend/src/renderer/src/utils/filtering.ts | 9 + .../src/renderer/src/utils/google/index.ts | 4 + .../src/utils/google/spreadsheetURLToId.ts | 17 + .../src/renderer/src/utils/google/utils.ts | 62 + .../src/utils/google/validationToArray.ts | 47 + frontend/src/renderer/src/utils/logger.ts | 38 + frontend/src/renderer/src/utils/nArray.ts | 15 + .../src/utils/predictions/countDecisiones.ts | 19 + .../renderer/src/utils/predictions/index.ts | 4 + .../utils/predictions/suggestions/index.ts | 207 + .../utils/predictions/suggestions/types.ts | 16 + .../renderer/src/utils/process/canContinue.ts | 12 + .../src/utils/process/initProcessState.ts | 13 + frontend/src/renderer/src/utils/regex.ts | 50 + frontend/src/renderer/src/vite-env.d.ts | 9 + frontend/tsconfig.json | 7 + frontend/tsconfig.node.json | 9 + frontend/tsconfig.web.json | 21 + frontend/vite.config.ts | 34 + frontend/vitest.config.ts | 14 + tests/api/conftest.py | 14 +- .../api/routers/anonymizer/test_anonymizer.py | 90 +- .../api/routers/datapublic/test_datapublic.py | 22 +- .../api/routers/misc/test_document_extract.py | 26 +- tests/api/routers/server/test_frontend.py | 96 + tests/api/routers/test_pipeline_flows.py | 22 +- tests/api/test_utils.py | 18 + tests/test_settings.py | 63 + 345 files changed, 33392 insertions(+), 199 deletions(-) create mode 100644 aymurai/api/endpoints/routers/frontend/__init__.py create mode 100644 aymurai/api/endpoints/routers/frontend/frontend.py create mode 100644 aymurai/config/__init__.py create mode 100644 aymurai/config/default_disambiguation_label_policies.yml create mode 100644 frontend/.dockerignore create mode 100644 frontend/.gitignore create mode 100644 frontend/.gitlab-ci.yml create mode 100644 frontend/.gitlab/analysis/audit.yml create mode 100644 frontend/.gitlab/analysis/lint.yml create mode 100644 frontend/.npmrc create mode 100644 frontend/.prettierrc create mode 100644 frontend/.vscode/settings.json create mode 100644 frontend/CONTRIBUTING.md create mode 100644 frontend/README.md create mode 100644 frontend/a.tml create mode 100644 frontend/biome.json create mode 100644 frontend/dev-app-update.yml create mode 100644 frontend/docs/ANONIMIZADO.docx create mode 100644 frontend/docs/SIN_ANONIMIZAR.docx create mode 100644 frontend/docs/ai.md create mode 100644 frontend/docs/authentication.md create mode 100644 frontend/docs/aymurai.md create mode 100644 frontend/docs/excel/filesystem.md create mode 100644 frontend/docs/excel/spreadsheet-api.md create mode 100644 frontend/docs/images/auth_flows.png create mode 100644 frontend/docs/images/electron_pkce.png create mode 100644 frontend/docs/images/initial-screen.png create mode 100644 frontend/docs/images/submit-form.png create mode 100644 frontend/docs/images/url-selector.png create mode 100644 frontend/docs/images/validation-form.png create mode 100644 frontend/docs/routing.md create mode 100644 frontend/docs/url_selector.md create mode 100644 frontend/docs/validator/README.md create mode 100644 frontend/electron-builder.yml create mode 100644 frontend/electron.vite.config.ts create mode 100644 frontend/forge.config.js create mode 100644 frontend/knip.json create mode 100644 frontend/package.json create mode 100644 frontend/panda.config.ts create mode 100644 frontend/pnpm-lock.yaml create mode 100644 frontend/pnpm-workspace.yaml create mode 100644 frontend/postcss.config.cjs create mode 100644 frontend/src/main/createWindow.ts create mode 100644 frontend/src/main/env.ts create mode 100644 frontend/src/main/extensions.ts create mode 100644 frontend/src/main/index.ts create mode 100644 frontend/src/main/utils/__tests__/excel.test.ts create mode 100644 frontend/src/main/utils/excel.ts create mode 100644 frontend/src/main/utils/feedback.ts create mode 100644 frontend/src/main/utils/filesystem.ts create mode 100644 frontend/src/main/utils/index.ts create mode 100644 frontend/src/main/utils/resolveHTMLPath.ts create mode 100644 frontend/src/main/utils/subprocess.ts create mode 100644 frontend/src/main/utils/taskbar.ts create mode 100644 frontend/src/preload/index.d.ts create mode 100644 frontend/src/preload/index.ts create mode 100644 frontend/src/renderer/index.html create mode 100644 frontend/src/renderer/public/audio/notification.mp3 create mode 100644 frontend/src/renderer/public/brand/aymurai-hor-darkpurple.svg create mode 100644 frontend/src/renderer/public/brand/aymurai-iso-darkpurple.svg create mode 100644 frontend/src/renderer/public/brand/aymurai-iso-purple.svg create mode 100644 frontend/src/renderer/public/brand/aymurai-vert-darkpurple.svg create mode 100644 frontend/src/renderer/public/brand/aymurai-vert-purple.png create mode 100644 frontend/src/renderer/public/brand/datagenero.svg create mode 100644 frontend/src/renderer/public/brand/iso-white.png create mode 100644 frontend/src/renderer/public/brand/logo.jpg create mode 100644 frontend/src/renderer/public/button-icons/add-all.svg create mode 100644 frontend/src/renderer/public/button-icons/add-one.svg create mode 100644 frontend/src/renderer/public/button-icons/delete-all.svg create mode 100644 frontend/src/renderer/public/button-icons/delete-one.svg create mode 100644 frontend/src/renderer/public/button-icons/replace-all.svg create mode 100644 frontend/src/renderer/public/button-icons/replace-one.svg create mode 100644 frontend/src/renderer/public/favicon.ico create mode 100644 frontend/src/renderer/public/manifest.json create mode 100644 frontend/src/renderer/public/onboarding-steps/step1.png create mode 100644 frontend/src/renderer/public/onboarding-steps/step2.png create mode 100644 frontend/src/renderer/public/onboarding-steps/step3.png create mode 100644 frontend/src/renderer/public/onboarding-steps/step4.png create mode 100644 frontend/src/renderer/public/robots.txt create mode 100644 frontend/src/renderer/src/app.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/anonymizer-label-select.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/index.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/label.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/merge-dialog.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/remove-dialog.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/section.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/sortable-group.tsx create mode 100644 frontend/src/renderer/src/components/anonymizer/label-manager/tab.tsx create mode 100644 frontend/src/renderer/src/components/arrow/LeftArrow.tsx create mode 100644 frontend/src/renderer/src/components/arrow/RightArrow.tsx create mode 100644 frontend/src/renderer/src/components/arrow/index.ts create mode 100644 frontend/src/renderer/src/components/brand/built-by.tsx create mode 100644 frontend/src/renderer/src/components/checkbox/checkbox-group/CheckboxGroup.styles.ts create mode 100644 frontend/src/renderer/src/components/checkbox/checkbox-group/index.tsx create mode 100644 frontend/src/renderer/src/components/checkbox/checkbox/Checkbox.styles.ts create mode 100644 frontend/src/renderer/src/components/checkbox/checkbox/index.tsx create mode 100644 frontend/src/renderer/src/components/checkbox/index.ts create mode 100644 frontend/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts create mode 100644 frontend/src/renderer/src/components/decision-tabs/index.tsx create mode 100644 frontend/src/renderer/src/components/dialog/index.tsx create mode 100644 frontend/src/renderer/src/components/drop-area.tsx create mode 100644 frontend/src/renderer/src/components/feature-icon.tsx create mode 100644 frontend/src/renderer/src/components/features-menu.tsx create mode 100644 frontend/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts create mode 100644 frontend/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx create mode 100644 frontend/src/renderer/src/components/file-annotator/SearchBar/SearchBar.styles.ts create mode 100644 frontend/src/renderer/src/components/file-annotator/SearchBar/index.tsx create mode 100644 frontend/src/renderer/src/components/file-annotator/annotations.ts create mode 100644 frontend/src/renderer/src/components/file-annotator/generateSplits.ts create mode 100644 frontend/src/renderer/src/components/file-annotator/index.tsx create mode 100644 frontend/src/renderer/src/components/file-annotator/types.ts create mode 100644 frontend/src/renderer/src/components/file-check/ErrorText.ts create mode 100644 frontend/src/renderer/src/components/file-check/FileCheck.styles.ts create mode 100644 frontend/src/renderer/src/components/file-check/Icon.tsx create mode 100644 frontend/src/renderer/src/components/file-check/index.tsx create mode 100644 frontend/src/renderer/src/components/file-preview/FilePreview.styles.ts create mode 100644 frontend/src/renderer/src/components/file-preview/index.tsx create mode 100644 frontend/src/renderer/src/components/file-processing/FileProcessing.styles.ts create mode 100644 frontend/src/renderer/src/components/file-processing/ProgressBar.tsx create mode 100644 frontend/src/renderer/src/components/file-processing/ProgressLabel.ts create mode 100644 frontend/src/renderer/src/components/file-processing/index.tsx create mode 100644 frontend/src/renderer/src/components/file-stepper/FileStepper.styles.ts create mode 100644 frontend/src/renderer/src/components/file-stepper/Icons.tsx create mode 100644 frontend/src/renderer/src/components/file-stepper/index.tsx create mode 100644 frontend/src/renderer/src/components/file-stepper/utils.ts create mode 100644 frontend/src/renderer/src/components/file/annotation-popover/index.tsx create mode 100644 frontend/src/renderer/src/components/file/annotation-popover/tagger-button.tsx create mode 100644 frontend/src/renderer/src/components/file/annotation-popover/tagger.tsx create mode 100644 frontend/src/renderer/src/components/file/manual-entity-resolution-dialog.tsx create mode 100644 frontend/src/renderer/src/components/file/search-annotation.tsx create mode 100644 frontend/src/renderer/src/components/file/suggestion-label.tsx create mode 100644 frontend/src/renderer/src/components/file/tag-annotation/index.tsx create mode 100644 frontend/src/renderer/src/components/file/tag-annotation/remove-dialog.tsx create mode 100644 frontend/src/renderer/src/components/file/tag-annotation/replace-dialog.tsx create mode 100644 frontend/src/renderer/src/components/finish/finish-anonymizer.tsx create mode 100644 frontend/src/renderer/src/components/finish/finish-dataset.tsx create mode 100644 frontend/src/renderer/src/components/finish/finish-main-content.tsx create mode 100644 frontend/src/renderer/src/components/grid/index.ts create mode 100644 frontend/src/renderer/src/components/hidden-input.tsx create mode 100644 frontend/src/renderer/src/components/home/choose-host.tsx create mode 100644 frontend/src/renderer/src/components/home/connect-to-host.tsx create mode 100644 frontend/src/renderer/src/components/home/stepper.tsx create mode 100644 frontend/src/renderer/src/components/how-it-works-modal.tsx create mode 100644 frontend/src/renderer/src/components/how-it-works.tsx create mode 100644 frontend/src/renderer/src/components/index.ts create mode 100644 frontend/src/renderer/src/components/label/index.ts create mode 100644 frontend/src/renderer/src/components/layout/footer.tsx create mode 100644 frontend/src/renderer/src/components/layout/header.tsx create mode 100644 frontend/src/renderer/src/components/layout/home-button.tsx create mode 100644 frontend/src/renderer/src/components/layout/main-content.tsx create mode 100644 frontend/src/renderer/src/components/onboarding-grid/index.ts create mode 100644 frontend/src/renderer/src/components/radio/index.ts create mode 100644 frontend/src/renderer/src/components/radio/radio-group/RadioGroup.styles.ts create mode 100644 frontend/src/renderer/src/components/radio/radio-group/index.tsx create mode 100644 frontend/src/renderer/src/components/radio/radio/Radio.styles.ts create mode 100644 frontend/src/renderer/src/components/radio/radio/index.tsx create mode 100644 frontend/src/renderer/src/components/spinner/index.tsx create mode 100644 frontend/src/renderer/src/components/stack/index.ts create mode 100644 frontend/src/renderer/src/components/subtitle/index.ts create mode 100644 frontend/src/renderer/src/components/tabs/index.ts create mode 100644 frontend/src/renderer/src/components/text/index.ts create mode 100644 frontend/src/renderer/src/components/theme-provider/ThemeProvider.types.ts create mode 100644 frontend/src/renderer/src/components/theme-provider/index.tsx create mode 100644 frontend/src/renderer/src/components/title/index.ts create mode 100644 frontend/src/renderer/src/components/ui/back-button.tsx create mode 100644 frontend/src/renderer/src/components/ui/button.tsx create mode 100644 frontend/src/renderer/src/components/ui/callout.tsx create mode 100644 frontend/src/renderer/src/components/ui/card.tsx create mode 100644 frontend/src/renderer/src/components/ui/dialog.tsx create mode 100644 frontend/src/renderer/src/components/ui/input.tsx create mode 100644 frontend/src/renderer/src/components/ui/link.tsx create mode 100644 frontend/src/renderer/src/components/ui/popover.tsx create mode 100644 frontend/src/renderer/src/components/ui/select.tsx create mode 100644 frontend/src/renderer/src/components/ui/suggestion.tsx create mode 100644 frontend/src/renderer/src/components/ui/switch.tsx create mode 100644 frontend/src/renderer/src/components/ui/toast.tsx create mode 100644 frontend/src/renderer/src/components/ui/tooltip.tsx create mode 100644 frontend/src/renderer/src/components/uncontrolled-input/UncontrolledInput.styles.ts create mode 100644 frontend/src/renderer/src/components/uncontrolled-input/index.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.styles.ts create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.types.ts create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/forms/DatosAcusado.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/forms/DatosDenunciante.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/forms/Decision.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoGral.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoHecho.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/forms/index.ts create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/forms/options.json create mode 100644 frontend/src/renderer/src/components/validate-dataset/form-group/index.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/index.tsx create mode 100644 frontend/src/renderer/src/components/validate-dataset/utils.ts create mode 100644 frontend/src/renderer/src/components/validation-form/ValidationForm.styles.ts create mode 100644 frontend/src/renderer/src/components/validation-form/index.tsx create mode 100644 frontend/src/renderer/src/constants/anonymizer-categories.ts create mode 100644 frontend/src/renderer/src/constants/config.ts create mode 100644 frontend/src/renderer/src/constants/excluded-tags.ts create mode 100644 frontend/src/renderer/src/constants/i18n/index.ts create mode 100644 frontend/src/renderer/src/constants/i18n/locales/es/anonymizer.ts create mode 100644 frontend/src/renderer/src/constants/i18n/locales/es/common.ts create mode 100644 frontend/src/renderer/src/constants/i18n/locales/es/dataset.ts create mode 100644 frontend/src/renderer/src/constants/i18n/locales/es/index.ts create mode 100644 frontend/src/renderer/src/context/Annotation/index.tsx create mode 100644 frontend/src/renderer/src/context/Annotation/utils.ts create mode 100644 frontend/src/renderer/src/context/File.tsx create mode 100644 frontend/src/renderer/src/features/APIProtected.tsx create mode 100644 frontend/src/renderer/src/features/ReactQueryProvider.tsx create mode 100644 frontend/src/renderer/src/features/RequireFile.tsx create mode 100644 frontend/src/renderer/src/features/showToast.tsx create mode 100644 frontend/src/renderer/src/hooks/index.ts create mode 100644 frontend/src/renderer/src/hooks/useDisambiguate.ts create mode 100644 frontend/src/renderer/src/hooks/useEntityGroups.ts create mode 100644 frontend/src/renderer/src/hooks/useFileParse.ts create mode 100644 frontend/src/renderer/src/hooks/useFiles.ts create mode 100644 frontend/src/renderer/src/hooks/useForm/index.ts create mode 100644 frontend/src/renderer/src/hooks/useForm/types.ts create mode 100644 frontend/src/renderer/src/hooks/usePredict.ts create mode 100644 frontend/src/renderer/src/index.css create mode 100644 frontend/src/renderer/src/layout/home.tsx create mode 100644 frontend/src/renderer/src/layout/loading.tsx create mode 100644 frontend/src/renderer/src/layout/section-title.tsx create mode 100644 frontend/src/renderer/src/main.tsx create mode 100644 frontend/src/renderer/src/reducers/file/actions.ts create mode 100644 frontend/src/renderer/src/reducers/file/index.ts create mode 100644 frontend/src/renderer/src/reducers/file/utils.ts create mode 100644 frontend/src/renderer/src/routeTree.gen.ts create mode 100644 frontend/src/renderer/src/routes/$feature/finish.tsx create mode 100644 frontend/src/renderer/src/routes/$feature/onboarding.tsx create mode 100644 frontend/src/renderer/src/routes/$feature/preview.tsx create mode 100644 frontend/src/renderer/src/routes/$feature/process.tsx create mode 100644 frontend/src/renderer/src/routes/$feature/validation.tsx create mode 100644 frontend/src/renderer/src/routes/__root.tsx create mode 100644 frontend/src/renderer/src/routes/home/features.tsx create mode 100644 frontend/src/renderer/src/routes/home/host.tsx create mode 100644 frontend/src/renderer/src/routes/home/index.tsx create mode 100644 frontend/src/renderer/src/routes/index.tsx create mode 100644 frontend/src/renderer/src/schema/disambiguate.ts create mode 100644 frontend/src/renderer/src/schema/extract.ts create mode 100644 frontend/src/renderer/src/schema/predict.ts create mode 100644 frontend/src/renderer/src/services/api.ts create mode 100644 frontend/src/renderer/src/services/aymurai/__tests__/validation.test.ts create mode 100644 frontend/src/renderer/src/services/aymurai/index.ts create mode 100644 frontend/src/renderer/src/services/aymurai/predict.ts create mode 100644 frontend/src/renderer/src/services/aymurai/queries.ts create mode 100644 frontend/src/renderer/src/services/aymurai/schema.ts create mode 100644 frontend/src/renderer/src/services/aymurai/useConnectToHost.ts create mode 100644 frontend/src/renderer/src/services/aymurai/useRunLocalServer.ts create mode 100644 frontend/src/renderer/src/services/aymurai/utils.ts create mode 100644 frontend/src/renderer/src/services/aymurai/validation.ts create mode 100644 frontend/src/renderer/src/services/filesystem/browser/download.ts create mode 100644 frontend/src/renderer/src/services/filesystem/excel/__tests__/write.test.ts create mode 100644 frontend/src/renderer/src/services/filesystem/excel/create.ts create mode 100644 frontend/src/renderer/src/services/filesystem/excel/index.ts create mode 100644 frontend/src/renderer/src/services/filesystem/excel/open.ts create mode 100644 frontend/src/renderer/src/services/filesystem/excel/read.ts create mode 100644 frontend/src/renderer/src/services/filesystem/excel/write.ts create mode 100644 frontend/src/renderer/src/services/filesystem/feedback/export.ts create mode 100644 frontend/src/renderer/src/services/filesystem/feedback/index.ts create mode 100644 frontend/src/renderer/src/services/filesystem/feedback/utils.ts create mode 100644 frontend/src/renderer/src/services/filesystem/index.ts create mode 100644 frontend/src/renderer/src/services/filesystem/utils.ts create mode 100644 frontend/src/renderer/src/services/taskbar/index.ts create mode 100644 frontend/src/renderer/src/services/taskbar/utils.ts create mode 100644 frontend/src/renderer/src/store/useHoverState.ts create mode 100644 frontend/src/renderer/src/store/useLocal.ts create mode 100644 frontend/src/renderer/src/styles/globalStyles.ts create mode 100644 frontend/src/renderer/src/styles/index.ts create mode 100644 frontend/src/renderer/src/styles/stitches.config.ts create mode 100644 frontend/src/renderer/src/styles/tokens.ts create mode 100644 frontend/src/renderer/src/types/aymurai.ts create mode 100644 frontend/src/renderer/src/types/component.ts create mode 100644 frontend/src/renderer/src/types/features.ts create mode 100644 frontend/src/renderer/src/types/feedback.ts create mode 100644 frontend/src/renderer/src/types/file.ts create mode 100644 frontend/src/renderer/src/types/react-query.d.ts create mode 100644 frontend/src/renderer/src/types/spreadsheet.ts create mode 100644 frontend/src/renderer/src/types/utils.ts create mode 100644 frontend/src/renderer/src/utils/anonymizer/__tests__/predictions.test.ts create mode 100644 frontend/src/renderer/src/utils/anonymizer/entity-similarity.ts create mode 100644 frontend/src/renderer/src/utils/anonymizer/export-validation.ts create mode 100644 frontend/src/renderer/src/utils/anonymizer/labels.ts create mode 100644 frontend/src/renderer/src/utils/anonymizer/occurrences.ts create mode 100644 frontend/src/renderer/src/utils/anonymizer/predictions.ts create mode 100644 frontend/src/renderer/src/utils/config.ts create mode 100644 frontend/src/renderer/src/utils/file/__tests__/preview-files.test.ts create mode 100644 frontend/src/renderer/src/utils/file/excelStructure.ts create mode 100644 frontend/src/renderer/src/utils/file/filterEmptyDecisions.ts create mode 100644 frontend/src/renderer/src/utils/file/flatValidation.ts create mode 100644 frontend/src/renderer/src/utils/file/getByName.ts create mode 100644 frontend/src/renderer/src/utils/file/getExtension.ts create mode 100644 frontend/src/renderer/src/utils/file/getParagraphId.ts create mode 100644 frontend/src/renderer/src/utils/file/index.ts create mode 100644 frontend/src/renderer/src/utils/file/isAllowed.ts create mode 100644 frontend/src/renderer/src/utils/file/isAlreadyLoaded.ts create mode 100644 frontend/src/renderer/src/utils/file/isFileValidated.ts create mode 100644 frontend/src/renderer/src/utils/file/isValidationCompleted.ts create mode 100644 frontend/src/renderer/src/utils/file/preview-files.ts create mode 100644 frontend/src/renderer/src/utils/file/submitValidations/__tests__/offline.test.ts create mode 100644 frontend/src/renderer/src/utils/file/submitValidations/index.ts create mode 100644 frontend/src/renderer/src/utils/file/submitValidations/offline.ts create mode 100644 frontend/src/renderer/src/utils/filtering.ts create mode 100644 frontend/src/renderer/src/utils/google/index.ts create mode 100644 frontend/src/renderer/src/utils/google/spreadsheetURLToId.ts create mode 100644 frontend/src/renderer/src/utils/google/utils.ts create mode 100644 frontend/src/renderer/src/utils/google/validationToArray.ts create mode 100644 frontend/src/renderer/src/utils/logger.ts create mode 100644 frontend/src/renderer/src/utils/nArray.ts create mode 100644 frontend/src/renderer/src/utils/predictions/countDecisiones.ts create mode 100644 frontend/src/renderer/src/utils/predictions/index.ts create mode 100644 frontend/src/renderer/src/utils/predictions/suggestions/index.ts create mode 100644 frontend/src/renderer/src/utils/predictions/suggestions/types.ts create mode 100644 frontend/src/renderer/src/utils/process/canContinue.ts create mode 100644 frontend/src/renderer/src/utils/process/initProcessState.ts create mode 100644 frontend/src/renderer/src/utils/regex.ts create mode 100644 frontend/src/renderer/src/vite-env.d.ts create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tsconfig.node.json create mode 100644 frontend/tsconfig.web.json create mode 100644 frontend/vite.config.ts create mode 100644 frontend/vitest.config.ts create mode 100644 tests/api/routers/server/test_frontend.py create mode 100644 tests/api/test_utils.py create mode 100644 tests/test_settings.py diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 9c303644..4a38216e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -88,7 +88,11 @@ RUN apt update && apt install -y \ && rm -rf /tmp/* /var/tmp/* \ && rm -rf /var/lib/apt/lists/* - +# Node.js & npm for frontend build +RUN apt-get update && \ + apt-get install -y curl && \ + curl -fsSL https://deb.nodesource.com/setup_24.x | bash - && \ + apt-get install -y nodejs WORKDIR /tmp diff --git a/.dockerignore b/.dockerignore index 9b91c7d3..f5fe77dd 100644 --- a/.dockerignore +++ b/.dockerignore @@ -2,7 +2,10 @@ resources/ !resources/api !resources/pipelines !resources/cache/aymurai -!resources/cache/tfhub_modules notebooks/ -*.egg-info/ \ No newline at end of file +*.egg-info/ + +frontend/node_modules/ +frontend/out/ +frontend-dist/ diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 319cd7f0..a180c827 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -69,6 +69,7 @@ jobs: - name: Run api tests env: DISKCACHE_ROOT: /tmp + SQLALCHEMY_DATABASE_URI: sqlite:////tmp/aymurai-test.db run: uv run --no-sync pytest -q --tb=short --disable-warnings --color=yes --maxfail=5 tests/api - name: Download pipelines data diff --git a/.gitignore b/.gitignore index 2dad2bac..feb0089a 100755 --- a/.gitignore +++ b/.gitignore @@ -135,3 +135,9 @@ aymurai/version.py notebooks/** !notebooks/**/ !notebooks/**/*.ipynb + +# Frontend build output +frontend-dist/ + +# pnpm local package store +.pnpm-store/ diff --git a/Makefile b/Makefile index 816c1c5b..898fc3ae 100644 --- a/Makefile +++ b/Makefile @@ -44,3 +44,19 @@ alembic-regenerate: cd aymurai && \ uv run alembic revision --autogenerate -m "Create database" && \ uv run alembic upgrade head + +# --- Frontend build --- +FRONTEND_DIR=frontend +FRONTEND_DIST_DIR=frontend-dist + +frontend-install: + cd $(FRONTEND_DIR) && pnpm install + +frontend-build: frontend-install + cd $(FRONTEND_DIR) && pnpm run build:web + # Copy build output to frontend-dist + rm -rf $(FRONTEND_DIST_DIR) + cp -r $(FRONTEND_DIR)/out/renderer $(FRONTEND_DIST_DIR) + +frontend-clean: + rm -rf $(FRONTEND_DIST_DIR) diff --git a/README.md b/README.md index fae091de..573196fe 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,13 @@ docker run -d --name aymurai-backend-gpu --gpus all \ Open Swagger UI: ```text -http://localhost:8899/docs +http://localhost:8899/api/docs +``` + +Open the bundled frontend: + +```text +http://localhost:8899/ ``` ## Quick Start (Docker Compose) @@ -80,6 +86,7 @@ make api-logs ## Runtime Overview - Framework: `FastAPI` - Default API port: `8899` +- Bundled frontend path: `GET /` - DB engine: `SQLModel` + Alembic migrations on startup - Default DB URI: `sqlite:////resources/cache/sqlite/database.db` - Production pipeline configs: @@ -87,16 +94,16 @@ make api-logs - `resources/pipelines/production/datapublic/pipeline.json` ## Main Public Endpoints -- `GET /server/healthcheck` -- `GET /server/stats/summary` -- `POST /misc/document-extract` (and deprecated alias `POST /document-extract`) -- `POST /anonymizer/predict` -- `POST /anonymizer/disambiguate` -- `POST /anonymizer/validation` -- `POST /anonymizer/anonymize-document` -- `POST /datapublic/predict/{document_id}` -- `GET /datapublic/validation/document/{document_id}` -- `POST /datapublic/validation/document/{document_id}` +- `GET /api/server/healthcheck` +- `GET /api/server/stats/summary` +- `POST /api/misc/document-extract` (and deprecated alias `POST /api/document-extract`) +- `POST /api/anonymizer/predict` +- `POST /api/anonymizer/disambiguate` +- `POST /api/anonymizer/validation` +- `POST /api/anonymizer/anonymize-document` +- `POST /api/datapublic/predict/{document_id}` +- `GET /api/datapublic/validation/document/{document_id}` +- `POST /api/datapublic/validation/document/{document_id}` For full request/response contracts and examples, see [docs/api/README.md](docs/api/README.md). diff --git a/aymurai/api/core.py b/aymurai/api/core.py index c9223455..185dba4f 100644 --- a/aymurai/api/core.py +++ b/aymurai/api/core.py @@ -1,9 +1,7 @@ from fastapi.routing import APIRouter from .endpoints.routers.anonymizer import anonymizer -from .endpoints.routers.anonymizer import database as anonymizer_database from .endpoints.routers.datapublic import datapublic - from .endpoints.routers.misc import convert, document_extract from .endpoints.routers.server import stats @@ -23,11 +21,6 @@ prefix="/anonymizer", tags=["anonymization/model"], ) -# router.include_router( -# anonymizer_database.router, -# prefix="/anonymizer/database", -# tags=["anonymization/database"], -# ) # Datapublic router.include_router( diff --git a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py index 6fde1db7..1be1a121 100644 --- a/aymurai/api/endpoints/routers/anonymizer/anonymizer.py +++ b/aymurai/api/endpoints/routers/anonymizer/anonymizer.py @@ -5,7 +5,6 @@ from collections.abc import Iterable from threading import Lock -import torch from fastapi import Body, Depends, Form, HTTPException, Query, UploadFile from fastapi.responses import FileResponse from fastapi.routing import APIRouter @@ -31,7 +30,7 @@ RenderPolicy, TextRequest, ) -from aymurai.settings import settings +from aymurai.settings import DEFAULT_RENDER_POLICY, settings from aymurai.text.anonymization import ( InvalidDocumentAnonymizer, get_anonymizer, @@ -48,7 +47,6 @@ RESOURCES_BASEPATH = settings.RESOURCES_BASEPATH -torch.set_num_threads = 100 # FIXME: polemic ? pipeline_lock = Lock() @@ -198,10 +196,7 @@ def _merge_render_policy( Returns: RenderPolicy: Effective render policy. """ - policy = RenderPolicy( - suffix_mode="auto", - suffix_threshold=1, - ) + policy = RenderPolicy.model_validate(DEFAULT_RENDER_POLICY) def apply(incoming: RenderPolicy) -> None: nonlocal policy diff --git a/aymurai/api/endpoints/routers/datapublic/datapublic.py b/aymurai/api/endpoints/routers/datapublic/datapublic.py index 91e1f0d5..4b531390 100644 --- a/aymurai/api/endpoints/routers/datapublic/datapublic.py +++ b/aymurai/api/endpoints/routers/datapublic/datapublic.py @@ -1,7 +1,6 @@ import os from threading import Lock -import torch from fastapi import Body, Depends, HTTPException, Query from fastapi.routing import APIRouter from pydantic import UUID5 @@ -28,7 +27,6 @@ RESOURCES_BASEPATH = settings.RESOURCES_BASEPATH -torch.set_num_threads = 100 # FIXME: polemic ? pipeline_lock = Lock() diff --git a/aymurai/api/endpoints/routers/frontend/__init__.py b/aymurai/api/endpoints/routers/frontend/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/aymurai/api/endpoints/routers/frontend/__init__.py @@ -0,0 +1 @@ + diff --git a/aymurai/api/endpoints/routers/frontend/frontend.py b/aymurai/api/endpoints/routers/frontend/frontend.py new file mode 100644 index 00000000..22ceaf41 --- /dev/null +++ b/aymurai/api/endpoints/routers/frontend/frontend.py @@ -0,0 +1,114 @@ +from pathlib import Path + +from fastapi import APIRouter, HTTPException +from fastapi.responses import FileResponse, RedirectResponse, Response + +from aymurai.settings import settings + +router = APIRouter(include_in_schema=False) + +LEGACY_API_ROUTE_PREFIXES = ( + "anonymizer", + "api", + "convert", + "datapublic", + "database", + "document-extract", + "docs", + "misc", + "openapi.json", + "redoc", + "server", +) +FEATURE_ROUTE_SLUGS = ("anonymizer", "data_set") +FEATURE_ROUTE_STEPS = ("", "finish", "onboarding", "preview", "process", "validation") +LEGACY_FEATURE_ROUTE_SLUGS = { + "ANONYMIZER": "anonymizer", + "DATA_SET": "data_set", +} + + +def _frontend_dist_dir() -> Path: + return Path(settings.FRONTEND_DIST_DIR).expanduser() + + +def _split_asset_path(asset_path: str) -> list[str]: + return [segment for segment in asset_path.lstrip("/").split("/") if segment] + + +def _is_frontend_feature_route(asset_path: str) -> bool: + segments = _split_asset_path(asset_path) + if not segments or segments[0] not in FEATURE_ROUTE_SLUGS: + return False + + return len(segments) == 1 or segments[1] in FEATURE_ROUTE_STEPS + + +def _is_legacy_api_route(asset_path: str) -> bool: + first_segment = asset_path.lstrip("/").split("/", maxsplit=1)[0] + if _is_frontend_feature_route(asset_path): + return False + return first_segment in LEGACY_API_ROUTE_PREFIXES + + +def _canonical_frontend_path(asset_path: str) -> str | None: + segments = _split_asset_path(asset_path) + if not segments: + return None + + if segments[0] == "app": + canonical_segments = segments[1:] + if canonical_segments: + canonical_feature = LEGACY_FEATURE_ROUTE_SLUGS.get(canonical_segments[0]) + if canonical_feature: + canonical_segments = [canonical_feature, *canonical_segments[1:]] + return "/" + "/".join(canonical_segments) + + canonical_feature = LEGACY_FEATURE_ROUTE_SLUGS.get(segments[0]) + if canonical_feature: + return "/" + "/".join([canonical_feature, *segments[1:]]) + + return None + + +def _resolve_frontend_path(asset_path: str) -> Path: + dist_dir = _frontend_dist_dir().resolve() + requested_path = (dist_dir / asset_path.lstrip("/")).resolve() + requested_path.relative_to(dist_dir) + return requested_path + + +def _serve_frontend(asset_path: str = "") -> Response: + canonical_path = _canonical_frontend_path(asset_path) + if canonical_path is not None: + return RedirectResponse(canonical_path or "/") + + if asset_path and _is_legacy_api_route(asset_path): + raise HTTPException(status_code=404, detail="API route not found.") + + dist_dir = _frontend_dist_dir() + index_file = dist_dir / "index.html" + if not dist_dir.is_dir() or not index_file.is_file(): + raise HTTPException(status_code=404, detail="Frontend build not found.") + + if asset_path: + try: + requested_path = _resolve_frontend_path(asset_path) + except ValueError as error: + raise HTTPException( + status_code=404, detail="Frontend asset not found." + ) from error + + if requested_path.is_file(): + return FileResponse(requested_path) + + if Path(asset_path).suffix: + raise HTTPException(status_code=404, detail="Frontend asset not found.") + + return FileResponse(index_file) + + +@router.get("/") +@router.get("/{asset_path:path}") +async def frontend_app(asset_path: str = "") -> Response: + return _serve_frontend(asset_path) diff --git a/aymurai/api/main.py b/aymurai/api/main.py index 4bfd9370..27ab0c70 100644 --- a/aymurai/api/main.py +++ b/aymurai/api/main.py @@ -2,19 +2,19 @@ import time from contextlib import asynccontextmanager -import torch from alembic import command from alembic.config import Config from fastapi import FastAPI, Request -from fastapi.responses import RedirectResponse from fastapi.middleware.cors import CORSMiddleware from starlette.formparsers import MultiPartParser from aymurai.api import core +from aymurai.api.endpoints.routers.frontend import frontend +from aymurai.api.startup.database import check_db_connection +from aymurai.api.utils import configure_torch_threads from aymurai.logger import get_logger -from aymurai.settings import settings from aymurai.pipeline import AymurAIPipeline -from aymurai.api.startup.database import check_db_connection +from aymurai.settings import settings try: from aymurai.version import __version__ @@ -24,7 +24,7 @@ logger = get_logger(__name__) -torch.set_num_threads = 100 # FIXME: polemic ? +configure_torch_threads() RESOURCES_BASEPATH = settings.RESOURCES_BASEPATH @@ -54,8 +54,9 @@ async def lifespan(app: FastAPI): logger.info(">> Running Alembic migrations") alembic_cfg = Config(str(settings.ALEMBIC_INI_PATH)) command.upgrade(alembic_cfg, "head") - except Exception as error: - logger.error("Error while starting up:", error) + except Exception: + logger.exception("Error while starting up") + raise yield @@ -64,6 +65,9 @@ async def lifespan(app: FastAPI): title="AymurAI API", version=__version__, lifespan=lifespan, + docs_url="/api/docs", + redoc_url="/api/redoc", + openapi_url="/api/openapi.json", ) @@ -90,33 +94,20 @@ async def add_process_time_header(request: Request, call_next): return response -@api.get("/", response_class=RedirectResponse, include_in_schema=False) -async def index(): - return "/docs" - - -# @api.get("/docs", include_in_schema=False) -# async def custom_swagger_ui_html(): -# return get_swagger_ui_html( -# openapi_url=api.openapi_url, -# title=f"{api.title} - Swagger UI", -# swagger_css_url="https://cdn.jsdelivr.net/gh/danielperezrubio/swagger-dark-theme@main/assets/swagger-ui.min.css", -# ) - - ################################################################################ # MARK: API ENDPOINTS ################################################################################ # Healthcheck -@api.get("/server/healthcheck", status_code=200, tags=["server"]) +@api.get("/api/server/healthcheck", status_code=200, tags=["server"]) def healthcheck(): return {"status": "ok"} # Api endpoints -api.include_router(core.router) +api.include_router(core.router, prefix="/api") +api.include_router(frontend.router) if __name__ == "__main__": diff --git a/aymurai/api/utils.py b/aymurai/api/utils.py index 0132eaac..1944c9d7 100644 --- a/aymurai/api/utils.py +++ b/aymurai/api/utils.py @@ -1,4 +1,5 @@ import cachetools +import torch from aymurai.logger import get_logger from aymurai.settings import settings @@ -9,7 +10,7 @@ mem_cache = cachetools.TTLCache( maxsize=settings.MEMORY_CACHE_MAXSIZE, - ttl=settings.MEMORY_CACHE_MAXSIZE, + ttl=settings.MEMORY_CACHE_TTL, getsizeof=lambda _: 0, ) @@ -19,3 +20,7 @@ @cachetools.cached(cache=mem_cache) def load_pipeline(path: str): return AymurAIPipeline.load(path) + + +def configure_torch_threads() -> None: + torch.set_num_threads(settings.TORCH_NUM_THREADS) diff --git a/aymurai/config/__init__.py b/aymurai/config/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/aymurai/config/default_disambiguation_label_policies.yml b/aymurai/config/default_disambiguation_label_policies.yml new file mode 100644 index 00000000..4de95df8 --- /dev/null +++ b/aymurai/config/default_disambiguation_label_policies.yml @@ -0,0 +1,124 @@ +PER: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: true + +NUM_EXPEDIENTE: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +CUIJ: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +NUM_ACTUACION: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +DNI: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +LINK: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +TELEFONO: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +FECHA: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +DIRECCION: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +TEXTO_ANONIMIZAR: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +LOC: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +CORREO_ELECTRONICO: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +CUIT_CUIL: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +NACIONALIDAD: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +EDAD: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +NOMBRE_ARCHIVO: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +BANCO: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +NUM_MATRICULA: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +ESTUDIOS: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +IP: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +USUARIX: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +CBU: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +MARCA_AUTOMOVIL: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +PATENTE_DOMINIO: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false + +NUM_CAJA_AHORRO: + disambiguation: fuzzy + anonymize: true + use_subclass_when_available: false diff --git a/aymurai/settings.py b/aymurai/settings.py index 2079f561..259d03ed 100644 --- a/aymurai/settings.py +++ b/aymurai/settings.py @@ -1,5 +1,6 @@ import json import os +from copy import deepcopy from pathlib import Path from dotenv import load_dotenv @@ -7,10 +8,18 @@ from pydantic_settings import BaseSettings import aymurai +from aymurai.utils.yaml_data import load_yaml PARENT = Path(aymurai.__file__).parent +DEFAULT_DISAMBIGUATION_LABEL_POLICIES = load_yaml( + str(PARENT / "config" / "default_disambiguation_label_policies.yml") +) + +DEFAULT_RENDER_POLICY = {"suffix_mode": "auto", "suffix_threshold": 1} + + def load_env(): load_dotenv(".env") @@ -63,6 +72,7 @@ def assemble_cors_origins(cls, v) -> list[str]: # Cachetools settings MEMORY_CACHE_MAXSIZE: int = 1 MEMORY_CACHE_TTL: int = 60 + TORCH_NUM_THREADS: int = 4 LIBREOFFICE_BIN: str = "libreoffice" PDF_WATERMARK_FONT_REGULAR: str | None = None @@ -76,29 +86,29 @@ def assemble_cors_origins(cls, v) -> list[str]: THRESHOLD: int = 70 # Label policies (JSON dict: label -> {disambiguation, anonymize}) - DISAMBIGUATION_LABEL_POLICIES: dict | None = None - - @field_validator("DISAMBIGUATION_LABEL_POLICIES", mode="before") - @classmethod - def parse_label_policies(cls, v): - if v is None or v == "": - return None - if isinstance(v, str): - return json.loads(v) - return v + DISAMBIGUATION_LABEL_POLICIES: dict | None = Field( + default_factory=lambda: deepcopy(DEFAULT_DISAMBIGUATION_LABEL_POLICIES) + ) # Render policy (JSON dict) - RENDER_POLICY: dict | None = None + RENDER_POLICY: dict | None = Field( + default_factory=lambda: deepcopy(DEFAULT_RENDER_POLICY) + ) - @field_validator("RENDER_POLICY", mode="before") + @field_validator("DISAMBIGUATION_LABEL_POLICIES", "RENDER_POLICY", mode="before") @classmethod - def parse_render_policy(cls, v): + def parse_policies(cls, v): if v is None or v == "": return None if isinstance(v, str): return json.loads(v) return v + FRONTEND_DIST_DIR: str = Field( + default="frontend-dist", + validation_alias=AliasChoices("AYMURAI_FRONTEND_DIST_DIR", "FRONTEND_DIST_DIR"), + ) + load_env() settings = Settings() diff --git a/aymurai/utils/json_encoding.py b/aymurai/utils/json_encoding.py index 5ff367a9..b5554812 100644 --- a/aymurai/utils/json_encoding.py +++ b/aymurai/utils/json_encoding.py @@ -5,6 +5,7 @@ import datetime from typing import Any +import numpy as np import pandas as pd from aymurai.logger import get_logger @@ -60,6 +61,10 @@ def default(self, obj: Any) -> Any: str(obj), ], } + elif isinstance(obj, np.integer): + return int(obj) + elif isinstance(obj, np.floating): + return float(obj) elif pd.isna(obj): return "null" else: diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index bd492f09..9d1b4a0d 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -1,3 +1,24 @@ +# syntax=docker/dockerfile:1.7 + +# ------------------- +# Frontend Build Stage +# ------------------- +FROM node:lts-bookworm AS frontend-builder + +WORKDIR /frontend + +RUN npm install --global corepack@latest && \ + corepack enable pnpm && \ + corepack prepare pnpm@latest --activate + +COPY frontend/ ./ + +RUN --mount=type=cache,target=/root/.local/share/pnpm/store \ + pnpm install --frozen-lockfile + +RUN pnpm run build:web + + # ------------------- # Build Stage # ------------------- @@ -74,10 +95,13 @@ COPY --from=builder --chown=app:app /app/.venv /app/.venv # Copy static resources COPY resources/pipelines /resources/pipelines +COPY --from=frontend-builder /frontend/out/renderer /app/frontend-dist # Set working directory WORKDIR /app +ENV FRONTEND_DIST_DIR=/app/frontend-dist + # Define start command CMD uv run fastapi run --port 8899 .venv/lib/python3.10/site-packages/aymurai/api/main.py diff --git a/docs/api/README.md b/docs/api/README.md index 212e215e..4b3957c5 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -5,30 +5,30 @@ This document describes the currently mounted public API in `aymurai/api/main.py ## Base URL and OpenAPI - Local base URL: `http://localhost:8899` -- Swagger UI: `http://localhost:8899/docs` -- OpenAPI JSON: `http://localhost:8899/openapi.json` +- Swagger UI: `http://localhost:8899/api/docs` +- OpenAPI JSON: `http://localhost:8899/api/openapi.json` ## Public Endpoints (Mounted) | Method | Path | Purpose | |---|---|---| -| `GET` | `/server/healthcheck` | Service liveness check | -| `GET` | `/server/stats/summary` | Runtime CPU/memory stats | -| `POST` | `/document-extract` | Deprecated alias of `/misc/document-extract` | -| `POST` | `/misc/document-extract` | Extract normalized paragraphs from uploaded document | -| `POST` | `/anonymizer/predict` | NER prediction for a paragraph | -| `POST` | `/anonymizer/disambiguate` | Canonical entity disambiguation + policy merge | -| `POST` | `/anonymizer/validation` | Fetch paragraph-level manual validation | -| `POST` | `/anonymizer/anonymize-document` | Compile and export anonymized document | -| `POST` | `/datapublic/predict/{document_id}` | Predict entities for data-public flow | -| `GET` | `/datapublic/validation/document/{document_id}` | Read document-level validation | -| `POST` | `/datapublic/validation/document/{document_id}` | Save document-level validation | -| `POST` | `/convert/pdf/odt` | Convert PDF to ODT | -| `POST` | `/convert/pdf/docx` | Convert PDF to DOCX | -| `POST` | `/convert/docx/odt` | Convert DOCX to ODT | -| `POST` | `/convert/docx/pdf` | Convert DOCX to PDF | -| `POST` | `/convert/odt/pdf` | Convert ODT to PDF | -| `POST` | `/convert/odt/docx` | Convert ODT to DOCX | +| `GET` | `/api/server/healthcheck` | Service liveness check | +| `GET` | `/api/server/stats/summary` | Runtime CPU/memory stats | +| `POST` | `/api/document-extract` | Deprecated alias of `/api/misc/document-extract` | +| `POST` | `/api/misc/document-extract` | Extract normalized paragraphs from uploaded document | +| `POST` | `/api/anonymizer/predict` | NER prediction for a paragraph | +| `POST` | `/api/anonymizer/disambiguate` | Canonical entity disambiguation + policy merge | +| `POST` | `/api/anonymizer/validation` | Fetch paragraph-level manual validation | +| `POST` | `/api/anonymizer/anonymize-document` | Compile and export anonymized document | +| `POST` | `/api/datapublic/predict/{document_id}` | Predict entities for data-public flow | +| `GET` | `/api/datapublic/validation/document/{document_id}` | Read document-level validation | +| `POST` | `/api/datapublic/validation/document/{document_id}` | Save document-level validation | +| `POST` | `/api/convert/pdf/odt` | Convert PDF to ODT | +| `POST` | `/api/convert/pdf/docx` | Convert PDF to DOCX | +| `POST` | `/api/convert/docx/odt` | Convert DOCX to ODT | +| `POST` | `/api/convert/docx/pdf` | Convert DOCX to PDF | +| `POST` | `/api/convert/odt/pdf` | Convert ODT to PDF | +| `POST` | `/api/convert/odt/docx` | Convert ODT to DOCX | ## Core Data Contracts @@ -136,7 +136,7 @@ Note: the JSON snippets below are minimal valid examples. Real payloads may incl ``` ```bash -curl -s http://localhost:8899/server/healthcheck +curl -s http://localhost:8899/api/server/healthcheck ``` #### `GET /server/stats/summary` @@ -153,7 +153,7 @@ curl -s http://localhost:8899/server/healthcheck ``` ```bash -curl -s http://localhost:8899/server/stats/summary +curl -s http://localhost:8899/api/server/stats/summary ``` ### Document Extraction @@ -174,7 +174,7 @@ curl -s http://localhost:8899/server/stats/summary ```bash curl -s -X POST \ -F "file=@/resources/data/sample/document-01.docx" \ - http://localhost:8899/misc/document-extract + http://localhost:8899/api/misc/document-extract ``` Common errors: @@ -189,7 +189,7 @@ Common errors: - Response `200`: `DocumentInformation` ```bash -curl -s -X POST "http://localhost:8899/anonymizer/predict?use_cache=true" \ +curl -s -X POST "http://localhost:8899/api/anonymizer/predict?use_cache=true" \ -H "Content-Type: application/json" \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` @@ -218,7 +218,7 @@ curl -s -X POST "http://localhost:8899/anonymizer/predict?use_cache=true" \ - Response `200`: `DocumentAnnotations` (with `data` and effective `label_policies`) ```bash -curl -s -X POST http://localhost:8899/anonymizer/disambiguate \ +curl -s -X POST http://localhost:8899/api/anonymizer/disambiguate \ -H "Content-Type: application/json" \ -d '{"paragraphs":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}}}' ``` @@ -228,7 +228,7 @@ curl -s -X POST http://localhost:8899/anonymizer/disambiguate \ - Response `200`: `list[DocLabel] | null` ```bash -curl -s -X POST http://localhost:8899/anonymizer/validation \ +curl -s -X POST http://localhost:8899/api/anonymizer/validation \ -H "Content-Type: application/json" \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` @@ -240,7 +240,7 @@ curl -s -X POST http://localhost:8899/anonymizer/validation \ - Response `200`: binary anonymized `.odt` file ```bash -curl -X POST http://localhost:8899/anonymizer/anonymize-document \ +curl -X POST http://localhost:8899/api/anonymizer/anonymize-document \ -F "file=@/resources/data/sample/document-01.docx" \ -F 'annotations={"data":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}},"render_policy":{"suffix_mode":"auto","suffix_threshold":1}}' ``` @@ -258,7 +258,7 @@ Common errors: - Response `200`: `DocumentInformation` ```bash -curl -s -X POST "http://localhost:8899/datapublic/predict/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc?use_cache=true" \ +curl -s -X POST "http://localhost:8899/api/datapublic/predict/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc?use_cache=true" \ -H "Content-Type: application/json" \ -d '{"text":"Buenos Aires, 17 de noviembre de 2024"}' ``` @@ -268,7 +268,7 @@ curl -s -X POST "http://localhost:8899/datapublic/predict/7e6b6f35-2f29-58f7-9f8 - Response `404`: document not found ```bash -curl -s http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc +curl -s http://localhost:8899/api/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc ``` #### `POST /datapublic/validation/document/{document_id}` @@ -276,7 +276,7 @@ curl -s http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7- - Response `200`: empty body ```bash -curl -s -X POST http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc \ +curl -s -X POST http://localhost:8899/api/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc \ -H "Content-Type: application/json" \ -d '{"materia":"penal","violencia_de_genero":"si"}' ``` @@ -287,12 +287,12 @@ All conversion endpoints use `multipart/form-data` with a `file` field. | Method | Path | Input | Output | |---|---|---|---| -| `POST` | `/convert/pdf/odt` | `.pdf` | `.odt` | -| `POST` | `/convert/pdf/docx` | `.pdf` | `.docx` | -| `POST` | `/convert/docx/odt` | `.docx` | `.odt` | -| `POST` | `/convert/docx/pdf` | `.docx` | `.pdf` | -| `POST` | `/convert/odt/pdf` | `.odt` | `.pdf` | -| `POST` | `/convert/odt/docx` | `.odt` | `.docx` | +| `POST` | `/api/convert/pdf/odt` | `.pdf` | `.odt` | +| `POST` | `/api/convert/pdf/docx` | `.pdf` | `.docx` | +| `POST` | `/api/convert/docx/odt` | `.docx` | `.odt` | +| `POST` | `/api/convert/docx/pdf` | `.docx` | `.pdf` | +| `POST` | `/api/convert/odt/pdf` | `.odt` | `.pdf` | +| `POST` | `/api/convert/odt/docx` | `.odt` | `.docx` | For PDF input endpoints, optional query param: - `backend=libreoffice|pandoc` (default: `libreoffice`) @@ -312,9 +312,9 @@ Common errors: The following route modules exist in code but are not included in `core.router` at runtime: - `aymurai/api/endpoints/routers/datapublic/dataset.py` - - includes `/datapublic/dataset/*` CRUD/batch routes, but router is not mounted. + - includes `/api/datapublic/dataset/*` CRUD/batch routes, but router is not mounted. - `aymurai/api/endpoints/routers/anonymizer/database.py` - - `/anonymizer/database/*` routes exist, include is commented out. + - `/api/anonymizer/database/*` routes exist, include is commented out. - `aymurai/api/endpoints/routers/database/*` - additional DB admin routes exist, but no mounting in `core.router`. diff --git a/docs/es/api/README.md b/docs/es/api/README.md index adb3db4e..d51ec974 100644 --- a/docs/es/api/README.md +++ b/docs/es/api/README.md @@ -5,30 +5,30 @@ Este documento describe la API pública actualmente montada en `aymurai/api/main ## Base URL y OpenAPI - Base local: `http://localhost:8899` -- Swagger UI: `http://localhost:8899/docs` -- OpenAPI JSON: `http://localhost:8899/openapi.json` +- Swagger UI: `http://localhost:8899/api/docs` +- OpenAPI JSON: `http://localhost:8899/api/openapi.json` ## Endpoints públicos (montados) | Método | Path | Propósito | |---|---|---| -| `GET` | `/server/healthcheck` | Liveness del servicio | -| `GET` | `/server/stats/summary` | Métricas de CPU/memoria | -| `POST` | `/document-extract` | Alias deprecado de `/misc/document-extract` | -| `POST` | `/misc/document-extract` | Extrae párrafos normalizados de un documento | -| `POST` | `/anonymizer/predict` | Predicción NER por párrafo | -| `POST` | `/anonymizer/disambiguate` | Desambiguación canónica + merge de políticas | -| `POST` | `/anonymizer/validation` | Obtiene validación manual por párrafo | -| `POST` | `/anonymizer/anonymize-document` | Compila y exporta documento anonimizado | -| `POST` | `/datapublic/predict/{document_id}` | Predicción para flujo data-public | -| `GET` | `/datapublic/validation/document/{document_id}` | Lee validación a nivel documento | -| `POST` | `/datapublic/validation/document/{document_id}` | Guarda validación a nivel documento | -| `POST` | `/convert/pdf/odt` | Convierte PDF a ODT | -| `POST` | `/convert/pdf/docx` | Convierte PDF a DOCX | -| `POST` | `/convert/docx/odt` | Convierte DOCX a ODT | -| `POST` | `/convert/docx/pdf` | Convierte DOCX a PDF | -| `POST` | `/convert/odt/pdf` | Convierte ODT a PDF | -| `POST` | `/convert/odt/docx` | Convierte ODT a DOCX | +| `GET` | `/api/server/healthcheck` | Liveness del servicio | +| `GET` | `/api/server/stats/summary` | Métricas de CPU/memoria | +| `POST` | `/api/document-extract` | Alias deprecado de `/api/misc/document-extract` | +| `POST` | `/api/misc/document-extract` | Extrae párrafos normalizados de un documento | +| `POST` | `/api/anonymizer/predict` | Predicción NER por párrafo | +| `POST` | `/api/anonymizer/disambiguate` | Desambiguación canónica + merge de políticas | +| `POST` | `/api/anonymizer/validation` | Obtiene validación manual por párrafo | +| `POST` | `/api/anonymizer/anonymize-document` | Compila y exporta documento anonimizado | +| `POST` | `/api/datapublic/predict/{document_id}` | Predicción para flujo data-public | +| `GET` | `/api/datapublic/validation/document/{document_id}` | Lee validación a nivel documento | +| `POST` | `/api/datapublic/validation/document/{document_id}` | Guarda validación a nivel documento | +| `POST` | `/api/convert/pdf/odt` | Convierte PDF a ODT | +| `POST` | `/api/convert/pdf/docx` | Convierte PDF a DOCX | +| `POST` | `/api/convert/docx/odt` | Convierte DOCX a ODT | +| `POST` | `/api/convert/docx/pdf` | Convierte DOCX a PDF | +| `POST` | `/api/convert/odt/pdf` | Convierte ODT a PDF | +| `POST` | `/api/convert/odt/docx` | Convierte ODT a DOCX | ## Contratos de datos principales @@ -136,7 +136,7 @@ Nota: los snippets JSON de abajo son ejemplos mínimos válidos. Los payloads re ``` ```bash -curl -s http://localhost:8899/server/healthcheck +curl -s http://localhost:8899/api/server/healthcheck ``` #### `GET /server/stats/summary` @@ -153,7 +153,7 @@ curl -s http://localhost:8899/server/healthcheck ``` ```bash -curl -s http://localhost:8899/server/stats/summary +curl -s http://localhost:8899/api/server/stats/summary ``` ### Extracción de documentos @@ -174,7 +174,7 @@ curl -s http://localhost:8899/server/stats/summary ```bash curl -s -X POST \ -F "file=@/resources/data/sample/document-01.docx" \ - http://localhost:8899/misc/document-extract + http://localhost:8899/api/misc/document-extract ``` Errores comunes: @@ -189,7 +189,7 @@ Errores comunes: - Respuesta `200`: `DocumentInformation` ```bash -curl -s -X POST "http://localhost:8899/anonymizer/predict?use_cache=true" \ +curl -s -X POST "http://localhost:8899/api/anonymizer/predict?use_cache=true" \ -H "Content-Type: application/json" \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` @@ -218,7 +218,7 @@ curl -s -X POST "http://localhost:8899/anonymizer/predict?use_cache=true" \ - Respuesta `200`: `DocumentAnnotations` (incluye `data` y `label_policies` efectivas) ```bash -curl -s -X POST http://localhost:8899/anonymizer/disambiguate \ +curl -s -X POST http://localhost:8899/api/anonymizer/disambiguate \ -H "Content-Type: application/json" \ -d '{"paragraphs":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}}}' ``` @@ -228,7 +228,7 @@ curl -s -X POST http://localhost:8899/anonymizer/disambiguate \ - Respuesta `200`: `list[DocLabel] | null` ```bash -curl -s -X POST http://localhost:8899/anonymizer/validation \ +curl -s -X POST http://localhost:8899/api/anonymizer/validation \ -H "Content-Type: application/json" \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` @@ -240,7 +240,7 @@ curl -s -X POST http://localhost:8899/anonymizer/validation \ - Respuesta `200`: archivo `.odt` anonimizado (binario) ```bash -curl -X POST http://localhost:8899/anonymizer/anonymize-document \ +curl -X POST http://localhost:8899/api/anonymizer/anonymize-document \ -F "file=@/resources/data/sample/document-01.docx" \ -F 'annotations={"data":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}},"render_policy":{"suffix_mode":"auto","suffix_threshold":1}}' ``` @@ -258,7 +258,7 @@ Errores comunes: - Respuesta `200`: `DocumentInformation` ```bash -curl -s -X POST "http://localhost:8899/datapublic/predict/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc?use_cache=true" \ +curl -s -X POST "http://localhost:8899/api/datapublic/predict/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc?use_cache=true" \ -H "Content-Type: application/json" \ -d '{"text":"Buenos Aires, 17 de noviembre de 2024"}' ``` @@ -268,7 +268,7 @@ curl -s -X POST "http://localhost:8899/datapublic/predict/7e6b6f35-2f29-58f7-9f8 - Respuesta `404`: documento inexistente ```bash -curl -s http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc +curl -s http://localhost:8899/api/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc ``` #### `POST /datapublic/validation/document/{document_id}` @@ -276,7 +276,7 @@ curl -s http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7- - Respuesta `200`: body vacío ```bash -curl -s -X POST http://localhost:8899/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc \ +curl -s -X POST http://localhost:8899/api/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc \ -H "Content-Type: application/json" \ -d '{"materia":"penal","violencia_de_genero":"si"}' ``` @@ -287,12 +287,12 @@ Todos los endpoints de conversión usan `multipart/form-data` con campo `file`. | Método | Path | Input | Output | |---|---|---|---| -| `POST` | `/convert/pdf/odt` | `.pdf` | `.odt` | -| `POST` | `/convert/pdf/docx` | `.pdf` | `.docx` | -| `POST` | `/convert/docx/odt` | `.docx` | `.odt` | -| `POST` | `/convert/docx/pdf` | `.docx` | `.pdf` | -| `POST` | `/convert/odt/pdf` | `.odt` | `.pdf` | -| `POST` | `/convert/odt/docx` | `.odt` | `.docx` | +| `POST` | `/api/convert/pdf/odt` | `.pdf` | `.odt` | +| `POST` | `/api/convert/pdf/docx` | `.pdf` | `.docx` | +| `POST` | `/api/convert/docx/odt` | `.docx` | `.odt` | +| `POST` | `/api/convert/docx/pdf` | `.docx` | `.pdf` | +| `POST` | `/api/convert/odt/pdf` | `.odt` | `.pdf` | +| `POST` | `/api/convert/odt/docx` | `.odt` | `.docx` | Para endpoints con input PDF, query param opcional: - `backend=libreoffice|pandoc` (default: `libreoffice`) @@ -312,9 +312,9 @@ Errores comunes: Las siguientes rutas existen en código pero no están incluidas en `core.router` en runtime: - `aymurai/api/endpoints/routers/datapublic/dataset.py` - - define `/datapublic/dataset/*`, pero ese router no está montado. + - define `/api/datapublic/dataset/*`, pero ese router no está montado. - `aymurai/api/endpoints/routers/anonymizer/database.py` - - define `/anonymizer/database/*`, pero su include está comentado. + - define `/api/anonymizer/database/*`, pero su include está comentado. - `aymurai/api/endpoints/routers/database/*` - rutas administrativas de DB, sin montaje en `core.router`. diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 00000000..ff549f0e --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,13 @@ +node_modules +build +tmp +.nvmrc +.gitignore +.editorconfig +.tmp +.next +.DS_Store +*.log +README.md +CONTRIBUTING.md +out diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 00000000..e31ba0eb --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +node_modules/* +/.pnp +.pnp.js + +# testing +/coverage +.husky + +# production +/build +/dist +/out + +# misc +.DS_Store +.env +.env.development +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Panda CSS generated files +src/renderer/src/styled + +/me/ \ No newline at end of file diff --git a/frontend/.gitlab-ci.yml b/frontend/.gitlab-ci.yml new file mode 100644 index 00000000..942f2495 --- /dev/null +++ b/frontend/.gitlab-ci.yml @@ -0,0 +1,18 @@ +--- +image: alpine:latest + +stages: + - analysis + +# This creates a temporary cache folder that prevents from +# the node_modules, and .npm (also apply for .yarn) +# to be recreated each CI run +cache: + key: ${CI_COMMIT_REF_SLUG} + paths: + - node_modules + - .npm + +include: + - local: /.gitlab/analysis/lint.yml + - local: /.gitlab/analysis/audit.yml diff --git a/frontend/.gitlab/analysis/audit.yml b/frontend/.gitlab/analysis/audit.yml new file mode 100644 index 00000000..a66d3a44 --- /dev/null +++ b/frontend/.gitlab/analysis/audit.yml @@ -0,0 +1,13 @@ +--- +audit: + stage: analysis + image: node:14 + cache: + paths: + - node_modules + - .npm + before_script: + - npm ci + script: + - npm audit + allow_failure: true diff --git a/frontend/.gitlab/analysis/lint.yml b/frontend/.gitlab/analysis/lint.yml new file mode 100644 index 00000000..bcb728c6 --- /dev/null +++ b/frontend/.gitlab/analysis/lint.yml @@ -0,0 +1,12 @@ +--- +lint: + stage: analysis + image: node:14 + cache: + paths: + - node_modules + - .npm + before_script: + - npm ci + script: + - npm run lint diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 00000000..dd854dc4 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +public-hoist-pattern[]=@types/* diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 00000000..544138be --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json new file mode 100644 index 00000000..14cfdc59 --- /dev/null +++ b/frontend/.vscode/settings.json @@ -0,0 +1,27 @@ +{ + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.organizeImports": "explicit" + }, + "editor.defaultFormatter": "biomejs.biome", + "[typescript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascript]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[json]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "[jsonc]": { + "editor.defaultFormatter": "biomejs.biome" + }, + "editor.rulers": [80, 120], + "[typescriptreact]": { + "editor.defaultFormatter": "biomejs.biome" + } +} diff --git a/frontend/CONTRIBUTING.md b/frontend/CONTRIBUTING.md new file mode 100644 index 00000000..7f08ddba --- /dev/null +++ b/frontend/CONTRIBUTING.md @@ -0,0 +1,86 @@ +# Best Practices + +## Linter + +This project uses _Create React App_ ESLint configuration as a base. You won't +be able to commit files with linting errors, and if you do a `--force` +you'll break CI. + +We also use [Markdownlint](https://github.com/DavidAnson/markdownlint) for +Markdown files. + +If you are using **VS Code**, you should install ESLint and Markdownlint +extensions. Not only it will show you linting errors but also you can set it to +fix some of them on save. To do so, edit your `settings.json` config file and +add the following: + +```json + "eslint.autoFixOnSave": true, + "eslint.alwaysShowStatus": true, + "eslint.validate": [ + "javascript", + "javascriptreact" + ] +``` + +## Branches + +- `main` is our main branch for nightly builds +- Try to not develop directly on `main` branch +- merges to `main` should be through `pull request` practice. + +### Branch naming + +- `poc/branch-name` for proof of concepts +- `feat/branch-name` for new features like, components, services, +validations, flows, etc. +- `test/branch-name` for unit/integration tests +- `fix/branch-name` for bugfixing code +- `hotfix/branch-name` for bugfixing in prod +- `docs/branch-name` for documentation + +### Pull Requests + +- Define a reviewer from the team. +- Close the branch after PR merge (except when it has the `WIP` prefix). +Otherwise this'll keep a ton unnecessary of UAT environments. +- Focus on one task at time +- Make atomic/little commits +- Push before leaving the office +- Be sure all of your tests passed + +## Commits + +We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) +specification. This will allow us to create automatized changelogs and semantic +versioning. Because of this, _you won't be able to commit messages that do not +follow this specification_. + +```text +feat: added hat wobble +^--^ ^---------------^ +| | +| +-> Summary in past simple tense. +| ++-------> Type: chore, docs, feat, fix, refactor, style, or test. +``` + +### Commit Types + +- `feat`: (new feature for the user, not a new feature for build script) +- `fix`: (bug fix for the user, not a fix to a build script) +- `docs`: (changes to the documentation) +- `style`: (formatting, missing semicolons, etc; no production code change) +- `refactor`: (refactoring production code, eg. renaming a variable) +- `test`: (adding missing tests, refactoring tests; no production code change) +- `chore`: (updating grunt tasks etc; no production code change) + +## Testing + +We use **[Jest](https://jestjs.io/)** for testing and. Tests are automatically +run during the Validate stage of the CI Pipeline. + +The pipeline enforces a 40% minimum coverage as an incentive to write tests. +It's strongly recommended that you raised this threshold over time. + +Jest can be configured via [jest.config.js](jest.config.js). diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 00000000..559f844f --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,95 @@ +# AymurAI Desktop App + +## Technologies + +### Main technologies + +- ⚛️ **React** + 🆎 **TypeScript** as the _main framework_ with _type checking_ +tools +- ⚡ **Electron** as the _deployment and packaging tool_. It also serves the +purpose of communicating the webapp with the _NodeJS_ process. +- 🪡 **Stitches** as the _styling library_ +- 🛣️ **Tanstack React Router** as the _routing library_ to navigate across the webapp +- 📄 **Mammoth** + **ExcelJS** as the _libraries_ to read and write `.docx` and +datasheet files + +### Other technologies + +- **pnpm** as _package manager_ +- **biome** as code _linter and formatter_ + +##  Getting started + +1. Clone the repository + +1. Navigate to the repository folder and install dependencies with + + ```bash + pnpm install + ``` + +1. Start the app in development mode with + + ```bash + pnpm run dev + ``` + +## Run Aymurai API + +1. First download the image + + ```sh + docker pull registry.gitlab.com/collective.ai/datagenero-public/aymurai-api-prod + ``` + +2. And then create the corresponding container + + ```sh + docker run -p 8899:8899 -h -d registry.gitlab.com/collective.ai/datagenero-public/aymurai-api-prod:latest + ``` + +## Scripts + +### Development + +- `dev:web`: starts the frontend locally to be viewed in a conventional browser +- `dev`: starts the frontend locally and creates an _Electron_ instance to view it +- `start`: previews the production build with Electron +- `start:web`: previews the production web build in a browser + +### Build + +- `build:web`: builds the React Vite project +- `build`: builds both React and Electron projects (without packaging the application) + +### Validation + +- `lint`: runs the linter (_Biome_) across the entire project +- `lint:fix`: fixes linter errors automatically +- `format`: checks code formatting with _Biome_ +- `format:fix`: fixes code formatting automatically +- `typecheck`: runs type checking on both _Node_ and _Web_ applications +- `typecheck:node`: runs type checking on the _Electron_ application +- `typecheck:web`: runs type checking on the _React_ application +- `validate`: runs linting and type checking on both React and renderer +- `pre-commit`: runs _LintStaged_ + +### Deployment + +- `build:unpack`: builds and creates an unpacked distribution directory +- `build:[win|mac|linux]`: builds and packages the application for the desired target +- `package`: cleans build directory, builds, and packages the app with Electron Forge +- `make`: cleans build directory, builds, and creates distributables with Electron Forge +- `postinstall`: installs app dependencies for Electron Builder + +##  Colaborators + +- Melina Gatto (_Project Manager_) +- Luciana Vega (_Project Manager_) +- Andy Orlandi (_Product Designer_) +- Luciano Lapenna (_Developer_) +- Ender Puentes (_Developer_) + +## Special thanks + +- Lucia Wainfeld diff --git a/frontend/a.tml b/frontend/a.tml new file mode 100644 index 00000000..ffba6f07 --- /dev/null +++ b/frontend/a.tml @@ -0,0 +1,18 @@ +// import path from "node:path"; +// import react from "@vitejs/plugin-react"; +// import { defineConfig } from "vite"; + +// export default defineConfig({ +// plugins: [react()], +// build: { +// outDir: "out", // CRA's default build output +// }, +// resolve: { +// alias: [ +// { +// find: "@", +// replacement: path.resolve(__dirname, "src"), +// }, +// ], +// }, +// }); diff --git a/frontend/biome.json b/frontend/biome.json new file mode 100644 index 00000000..676bcd39 --- /dev/null +++ b/frontend/biome.json @@ -0,0 +1,54 @@ +{ + "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", + "vcs": { + "enabled": false, + "clientKind": "git", + "useIgnoreFile": false + }, + "files": { + "ignoreUnknown": false, + "ignore": ["node_modules", "build", ".husky", "out", "routeTree.gen.ts"] + }, + "formatter": { + "enabled": true, + "indentStyle": "space" + }, + "organizeImports": { + "enabled": true + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "performance": { + "noAccumulatingSpread": "warn", + "noDelete": "warn" + }, + "correctness": { + "useExhaustiveDependencies": "warn" + }, + "complexity": { + "noUselessSwitchCase": "off", + "noForEach": "off", + "noUselessFragments": "off", + "noBannedTypes": "warn" + }, + "style": { + "noNonNullAssertion": "warn", + "useSelfClosingElements": { + "fix": "safe", + "level": "error" + } + }, + "a11y": { + "noSvgWithoutTitle": "off", + "useKeyWithClickEvents": "off" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "double" + } + } +} diff --git a/frontend/dev-app-update.yml b/frontend/dev-app-update.yml new file mode 100644 index 00000000..199fb557 --- /dev/null +++ b/frontend/dev-app-update.yml @@ -0,0 +1,3 @@ +provider: generic +url: https://example.com/auto-updates +updaterCacheDirName: vite-electron-test-updater diff --git a/frontend/docs/ANONIMIZADO.docx b/frontend/docs/ANONIMIZADO.docx new file mode 100644 index 0000000000000000000000000000000000000000..a96d78e184dc67867e4ab72d2582da69ec73e490 GIT binary patch literal 11604 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 z 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 literal 0 HcmV?d00001 diff --git a/frontend/docs/ai.md b/frontend/docs/ai.md new file mode 100644 index 00000000..cd3f6d84 --- /dev/null +++ b/frontend/docs/ai.md @@ -0,0 +1,14 @@ +# AymurAI + +La AI está documentada en su swagger accediendo directamente a `{{AYMURAI_URL}}/api/docs` una vez que el servidor está corriendo. + +> 💡 Si la AI está corriendo en la red LAN o bajo un ngrok, se debe cambiar la ruta. + +## Uso + +Para usar la AI en la aplicación se ponen a disposición cuatro funciones en la carpeta `/src/services/aymurai`: + +- `document-extract.ts`: obtiene cada párrafo del documento en texto plano para poder renderizarlo en la aplicación. +- `predict.ts`: genera predicciones sobre los párrafos previamente extraídos. +- `anonymize.ts`: permite generar un archivo `.odt` con las anotaciones hechas por el usuario y la AI. +- `health-check.ts`: se utiliza para verificar si la api está funcionando de manera correcta. Se utiliza en la pantalla de inicio. diff --git a/frontend/docs/authentication.md b/frontend/docs/authentication.md new file mode 100644 index 00000000..b1932b0c --- /dev/null +++ b/frontend/docs/authentication.md @@ -0,0 +1,74 @@ +# Authentication + +La autenticación en la app _AymurAI_ se utiliza únicamente para el guardado de la información de la spreadsheet en el set de datos. Hay dos opciones: + +- [_Google OAuth2_](#google-oauth2) + (cargando la información en _Google Drive_) +- [_offline local_](#local) + (escribiendo en el _filesystem_). + +Actualmente la autenticación con Google se puede realizar en el paso de guardar documento. Anteriormente, esta opción se seleccionaba en la pantalla de inicio, pero fue removida ya que generaba confusión a los usuarios por dar a entender que la aplicación operaba online cuando en realidad la única instancia en la cual lo puede hacer es a la hora de guardar la spreadsheet de Drive. + +Para facilitar el proceso se creó el hook [`useLogin`](../src/hooks/useLogin.ts). + +```ts +const { logout, login } = useLogin({ + onLogout: () => ..., +}); +``` + +## Google OAuth2 + +Utiliza el _social login_ de _Google_ para poder interactuar con la +[_Spreadsheet Google API_](https://developers.google.com/sheets/api/reference/rest). +Esto permite leer/escribir en una hoja de cálculo de _Google Drive_. + +El funcionamiento es el siguiente: + +1. Una vez se presiona el botón Google la app de React se comunica con el + proceso de Node para abrir una nueva ventana que cargaría la _consent screen_. + El proceso sería: + + 1. Se genera un _challenge code_. + 2. Junto al código mencionado se añaden otros datos como el + `client_id`, `redirect_uri`, etc. + 3. Se genera una URL con los datos anteriores para acceder a + `'https://accounts.google.com/o/oauth2/...`. + 4. Se abre una nueva ventana con la URL previamente generada. + +2. Una vez abierta la _consent screen_ al comunicarse con el proceso de + Electron, se añade un _event listener_ para poder tener los datos del usuario y + guardarlos en la sesión. + +3. Esta comunicación genera un código de autorización que se utiliza para + obtener el _access token_ y el _refresh token_. Para actualizar el _access token_ + se utiliza el _refresh token_ y un timer cada 45min. + +> 💡 Para pasar la información devuelta a la app de _React_ se utiliza un +> [deep link](https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app). +> Suele suceder que en modo _development_ no quede definido el _protocol_ para el +> _deep link_, por lo que se debe usar la versión productiva. + +![Electron PKCE para OAuth2](./images/electron_pkce.png) + +> 💡 [Más información](./excel/spreadsheet-api.md) en cómo se utiliza la +> _Google Spreadsheet API_ para generar los archivos. + +## Local + +La app simplemente funciona de manera _local_ y _offline_, leyendo/escribiendo +sobre un archivo de datasheet en el filesystem. No requiere ninguna acción extra +por parte del usuario. + +Esta opción simplemente inicializa el state de la app con la siguiente +información: + +```ts +const loginOffline = (funcType: FunctionType) => { + setUser({ online: false, function: funcType, token: "" }); + // ... +}; +``` + +> 💡 [Más información](./excel/filesystem.md) en cómo y dónde se genera el +> archivo `.xlsx`. diff --git a/frontend/docs/aymurai.md b/frontend/docs/aymurai.md new file mode 100644 index 00000000..183ed62c --- /dev/null +++ b/frontend/docs/aymurai.md @@ -0,0 +1,70 @@ +# AymurAI + +## Tecnologías principales + +AymurAI es una aplicación de escritorio basada en +[NodeJS](https://nodejs.org/en/) que utiliza tres principales tecnologías: + +- **[Electron.JS](https://www.electronjs.org/)**: elegido por su capacidad de + poder crear aplicaciones multiplataforma, Electron nos permite crear + aplicaciones web que pueden ser distribuidas sin la necesidad de tener un + browser preinstalado +- **[React](https://reactjs.org/)**: elegido por su versatilidad, ReactJS es un + web framework que nos permite crear todo tipo de web apps +- **[TypeScript](https://www.typescriptlang.org/)**: un _superset_ (es + decir, que añade features al original, pero sin modificar sus principios) de + _JavaScript_ que permite crear aplicaciones con la seguridad de que el flujo de + datos respeta un orden particular y definido + +Esta combinación de frameworks y lenguajes resulta muy eficiente ya que se puede +crear una web app desde cero, distribuible facilmente y multiplataforma, y con +herramientas incluidas para poder realizar un desarrollo confiable y +con la menor cantidad de _bugs_ posibles. + +Además, el uso de _Electron_ nos permite combinar las ventajas de usar _NodeJS_ +y todos sus paquetes como proceso principal y luego usar un browser levantado +por el mismo _Electron_ basado en +[Chromium](https://www.chromium.org/chromium-projects/) para utilizar las +[Web APIs](https://developer.mozilla.org/en-US/docs/Web/API) que podemos +encontrar en cualquier browser. + +## Otras tecnologías + +Además de las tecnologías principales anteriormente mencionadas se usaron: + +- **[Stitches](https://stitches.dev/)**: elegida como librería de estilos, nos + permite configurar toda una lista de _tokens_ que pueden ser utilizados a lo + largo de toda la aplicación manteniendo una alta consistencia entre los estilos. + Esto nos permite configurar y estandarizar colores, espaciados, sombras, etc además + de darnos la posibilidad de trabajar con _styled components_ para un + ágil desarrollo +- **[Google OAuth2](https://developers.google.com/identity/protocols/oauth2)**: + sistema de autenticación de usuarios basado en [OAuth](https://oauth.net/) que + nos permite tener un acceso total a las APIs de _Google_, permitiéndonos editar + en tiempo real documentos _Spreadsheet_. Sin este sistema de autenticación no se + podría obtener el token que nos permite interaccionar con las APIs + +## Estructura + +Se dividió la aplicación en 6 páginas, que se presentan en el siguiente orden: + +1. **Login**: página en la que se selecciona cómo conectarse a la API de AyMurai y cuál funcionalidad se desea utilizar (anonimizador o set de datos) +1. **Onboarding**: se nos muestra una guía sobre el funcionamiento de la + aplicación y los pasos a seguir para poder realizar la validación de nuestros + archivos. Es en este paso donde podremos cargar nuestros documentos +1. **Preview**: obtendremos una vista previa de los escritos cargados en la + página anterior con la oportunidad de cargar nuevos documentos si es necesario. + Es aquí donde podemos decidir cuáles son los archivos finales que serán + procesados por la inteligencia artificial +1. **Process**: página de procesamiento. En este paso se realiza la consulta + a la inteligencia artificial para obtener las predicciones correspondientes + a cada archivo. Esto puede tardar un poco. Podemos detener el procesamiento + de los documentos o reemplazarlos en cualquier momento si es necesario +1. **Validation**: es en esta instancia donde validaremos lo que nos ha devuelto + la inteligencia artificial. Tendremos un form donde podremos ir seleccionando + las sugerencias hechas por la IA o completar con lo que corresponda en ese momento. + Cada vez que se valida un documento, se crea una conexión con la + _Spreadsheet API_ de _Google_ para poder enviar los datos finales +1. **Finish**: podremos ver una vista preview de los documentos que validamos y + enviamos, con la posibilidad de revisar el set de datos o de realizar una nueva + carga, reiniciando el flujo de trabajo diff --git a/frontend/docs/excel/filesystem.md b/frontend/docs/excel/filesystem.md new file mode 100644 index 00000000..28ae5b55 --- /dev/null +++ b/frontend/docs/excel/filesystem.md @@ -0,0 +1,69 @@ +# Filesystem + +Las funcionalidades de _NodeJS_ sobre el _filesystem_ se aprovechan para poder +leer y escribir sobre el set de datos de forma local y offline en la +computadora. Además, también se generan reportes que ayudan a reentrenar el +modelo de inteligencia artificial. + +## Ubicación + +Las ubicaciones para los archivos de exportación se encuentran en la carpeta: + +```ts +// Ejemplo windows: C:\Users\[Usuario]\Documents\AymurAI +const EXPORTS_FOLDER = path.resolve(homedir(), 'Documents/AymurAI'); +``` + +## API + +Para poder formar un canal de comunicación entre la aplicación de _React_ +y _Electron_, se utilizan los [_preload scripts_](https://www.electronjs.org/docs/latest/tutorial/tutorial-preload) +para exponer una _API_ que permita la lectura y escritura de archivos. + +De esta forma el _frontend_ podría acceder a las funcionalidades de _NodeJS_ +utilizando `window.filesystem.excel.read` y `window.filesystem.excel.write` por ejemplo. +Estas funciones fueron definidas dentro de los archivos de _Electron_. + +Para el caso de los reportes se utiliza `window.filesystem.feedback.export`. + +> 📚 Se pueden encontrar estos scripts y más yendo al +[script preloader del proyecto.](../../renderer/preload.ts) + +## Tipo de archivo + +### Set de datos + +El set de datos se exporta en formato _Excel_ con extensión `.xlsx`. + +```ts +const FILENAME = 'set_de_datos.xlsx'; +// Ejemplo windows: C:/Users/[Usuario]/Documents/AymurAI/set_de_datos.xlsx +const PATH = `${EXPORTS_FOLDER}/${FILENAME}`; +``` + +Desde el frontend se utiliza la librería [_ExcelJS_](https://www.npmjs.com/package/exceljs) +que permite leer un archivo `.xlsx`, modificarlo en memoria y luego escribir los +cambios en el filesystem, apoyándose en las funcionalidades de _NodeJS_. + +```ts +import { Workbook } from 'exceljs'; + +// Ejemplo de escritura de archivo +async function writeXLSX(workbook: Workbook) { + const buffer = (await workbook.xlsx.writeBuffer()) as Buffer; + + return window.filesystem.excel.write(buffer); +} +``` + +### Reportes / Feedback + +El reporte se exporta en formato _JSON_ con extensión `.json`. Utiliza el nombre +del archivo procesado y la fecha para generar el nombre del archivo. + +```ts +const FEEDBACK_FOLDER = `${EXPORTS_FOLDER}/feedback`; +const FILENAME = `${FEEDBACK_FOLDER}/{name}-{date}.json` +``` + +Se escribe en el filesystem de forma tradicional. diff --git a/frontend/docs/excel/spreadsheet-api.md b/frontend/docs/excel/spreadsheet-api.md new file mode 100644 index 00000000..a2087b40 --- /dev/null +++ b/frontend/docs/excel/spreadsheet-api.md @@ -0,0 +1,30 @@ +# Google Spreadsheet API + +Para leer y escribir de forma remota en una hoja de cálculo de _Google Sheets_ se +utiliza la [REST API](https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets) +provista por _Google_. + +## Ubicación + +La ubicación del dataset está definida de forma __estática__ dentro del +[código](../../src/utils/config.ts). Esto significa que para poder acceder a +este archivo se necesita tener accesos de lectura/escritura sobre el archivo. + +## Implementación + +Dentro del proyecto se crearon una serie de funciones que ayudan a interactuar +con la API de _Google Sheets_. En general lo que hacen es _envolver_ las +llamadas a la _REST API_ utilizando el _access token_ provisto por el +[proceso de autenticación](../authentication.md). + +> Estas funciones se pueden encontrar dentro de la carpeta de +[servicios de google](../../src/services/google/). + +Por ejemplo, para obtener el contenido de una hoja de cálculo se utiliza la +función: + +```ts +import google from 'services/google'; + +await google(authToken).spreadsheet(id).range('A1:B2'); +``` diff --git a/frontend/docs/images/auth_flows.png b/frontend/docs/images/auth_flows.png new file mode 100644 index 0000000000000000000000000000000000000000..8a98cee5dc635fc38c4776555b7c3f30e68dda51 GIT binary patch literal 293014 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 literal 0 HcmV?d00001 diff --git a/frontend/docs/images/electron_pkce.png b/frontend/docs/images/electron_pkce.png new file mode 100644 index 0000000000000000000000000000000000000000..37c5097216ce6b726887f6613a485194bfa20b5a GIT binary patch literal 88023 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 literal 0 HcmV?d00001 diff --git a/frontend/docs/images/initial-screen.png b/frontend/docs/images/initial-screen.png new file mode 100644 index 0000000000000000000000000000000000000000..c339bdc9c943a5d986580c4d94f92c19a4e4ba45 GIT binary patch literal 909887 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%0D6&<8qO@ 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

  • X`H~7TE3tX8y2DUL_c{l|$FgZxZ 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
    tF1e>` zd#F*Cz4>12J+)0F+Un$f?8RH`a2moNv=8|59YuZW6pa76pno$Nj?EEmXQUaOIa`}> zTTKiQhNVfWb*e#j{|KWJK5D6i4*~S%F5F^^Xd-EZc%fJVa@g&{%9#p~chjK=4RsRo zm5D+Ua4e->AiJ-eEjF0{237cnNP#~ z?8a(?u#c5LSXujnwrlL|YF2aWPTeHpJKZ?f1myv)NIi<=`Z^HUbPlD>w|BtXBoBd= z=ZN;5?NaD$W%pQ7@w4FZsgAoNjd!=4Bo~(or9buvu5)pgctSLUWl|`*3HLhh63$)k z8%cLAqvOBYf_m1LoXQ5Nd9YK_LHTVELMz(hg*uE&+K{Y(P3QM+iCezcOGzMiU|-hQ zEqCxY8g)IUlS4E!DMvx3qFET&gIa5x83TsftV$kE7lW^3F^1U}bKLoNueh;bW6!HO z3cEMZ$gh041&eKtR_%@rZ2h=xb4XBvBlR)e8-VlN5~6mtW3m37a}|0*S~spFzRcm^ z41C=fi@XoAGGc>g&brO6E+;jz2i)fryM{B0n#EX(kUb9td?<6iPPY21r!Qo&t11Bg zooX3K`6yZm3cT7QyZBpd@6soD=Axv0lLD{4LkS-9$@s+~_I}$Y=?i)HUCM~`par|? zB)_TO5mjX-&THiJ;B2z@1uDgBt8%N8Rm+6;x|vPm>_nFSx_54JZ8_;NAN5+mPTqf^ zY|1N^Ij4lBDHHYgZw=L;Erhm%s1TLOB270BlJ21ZEtw_iwM=V>zks%C5i0Z?gjH0} z&A@d}O=~rrxBOLZ30nJv;mNXKpX#ly-SWg4B*hynM04)AG?n@@A<6aSI!9F5B3SLa zkd6#dspSLfSq;C}BbJ&W&_>t%eEfs6`3&=dcQa<2g7_qD%PUG+`0&n2gl<@x zT*PKXI%G(q6J6mVeSO>#WOjUwi}U2N>s$=8!xN3`h;p-FlmpdVF-qteU`-0Ee+e!{ z-pJf?Y6jOjaZ`3lR_5^{?X&N-{NY85OH@~VuIiE6qyN~xclJ?$43@6NX@K))!byvj z@i?7}=|s@?-YHtZQ*^hW#mghuYmyRF=w2x}#ilgZdt_5^1TLhvL}3UKk9BwKU>`pm z=YBNS55_v6lDc>&f3k-X6IyiQa>d)}-@o4P&a03dDkoMx?~H4_q{N3;a}VDHRtS_8 zdx2)+3b5T10E5?sN%l5vEv4WIXg24hGz@BZ;+oKttucjxv4^epIHAWcC~hR(TS^jl zbD6b%)x9m4q<;ejH1eR98sEA+KwO7;HqG32p$lH&Jw6BA_HZ4~t=m>;x%~Hd$uGi75#DA<1IDh zV#zXm;nN$Dhu;a*L$8r;fLk+_^Z_2~`+1^jQ5%(*2p%{H2RFzdOL3X?+44y+O9pt> zWaxHQ=;S=&jr#QFWPdnQ-`2)oZjz^@c5R(=%v}9-4ogo)eTHabQofrv*@AvMuvw_4Vg*^~KT=!((aqSN_Q2ORrBURLQ z|A;W}WC^v@@WE{^%cYcYiWJE8U-^Z)rDpi9is&V>At#>~%Rr&6E^C9NFxSR^$fcka9)IEy-;aM{YS!z^| zVg1s6`0AI(l@shzzp*~#Ri*+MWql!S3mu2V*yQ5~u-q-lvJbngFQ8+)Io|dY%Id1N z@X07}{Ew1{Jd2+UlBeP*E3@nCUGw>^$i83bB&0V8e1{MG-yHu=p1FTYZQMfzNVGItrw7Bw*dWt*&+jNvJ_i z^2ss_Jf2C)Cy2`n@*S%^r?_VQEjduOZt5B1WhlHe=mqtDd*;7*+Zp2MUYKuvYyK&t zmD&KpP;K9*x4z-%T4pzF<)6hEvk<3$VCtb*_`=FLxEXK*+-z>R{@rRAlA*@tm zT;??n|WZru1+>qo8&E^B6h!kXEh-*)@P)4eY- z@b-cnbbALk*U-9Vwl!G=K~5tnU@H2Ht^lSNoXo#fdm=+IU3>l$nA$|?Fca%$n=wGh z-9TM9JY55C@p*^!LAtNA7vhpfJ!MmWa!0=F2a~qWRvAinYAkR#=F^1awK z9))OmrRBm>Cn92nXiOnWIsE{`I|NeAFzwA~t;PT~y5B7o+??{&Pw%ugoa>~{)CI?e zBZhRjb4Rv0n?C3vOO}*|KkmJ0a_|_sa4gN+bSs15%9mXJnb5w@eL?G{tea2rlNi)Z$FYALBYI@$sg>37I}f59O)^b~15SGV z?cuIHZty>y-{qxP*Ibg@BmK|*f*O8RONknPi1C&d^YCLFiw!sY+dZ|Ds+4dUNM73e zMk>#!-{>!o79z=glgn-9@|QL7XSy*))T@}^y$%S#JizDvIF-#22(meL_t+dt!H|AH z>I4wl67=d5p=k1(nmPar+ZnPaf0qFLE(lbEstZtCPSSumDVoqW*P8QvkKoZ(4n_0b zg`6WwNEi)q4Gqq^T2ijSaBn3)S1-Mjcp4HY+Oyeo?`{_c{SAEIzz9;4GNF|4xapMN zP1_ag$RP4j7VSV*_UMs5c-!OfTj6MARcK8*##aU#4dNrtZCp+)e`mjDL3W(U>fbR1 z2h@_M;1@8OoVGSs?c7U_zxc^~|6Nf#2r2-;;C@B%ktGD@BfMsV3Yx8&pS|T$V)_0| zxm2#VziXJ`ldpG03S5$;^RuM%cJ=+)eSs|-UoTb^gO$yc8Crh#-m#NOb^1nAO#4w)Xb$NfKcKRNnx;dFnVY zSX1NE+Lr^n-7i|G{Na~1I;EIv%wTtAR3fXz-^#ZJb#>F*_6GkHpL0@^#$`Tdr7_jm zx`Q8H?sB00D^U$ZV>0!>D_#b9u(3kOLVsFaGThOQ^=xDzq2qqR@5LmDM}CTl9bDur zd;lYgho2nSjkR)mt;`-Q2k4x4M*B1vpOG#%TDx_g%<<+3!J9{fB4{P1WDUFm$s8Xd zL(mEXi09D@-oLeG>Gi=qOFtHvkh0!i&D~L@Bz)S0TZ$!|90i=7>I6sX?IJ~ZMgiGl zvZ5h6dP&*O&$`BJ!g<)WsOHQZ5>okWd%ByUC+PWz6$4*@Neo z`^efCldpl(41{X`d=}IxmCGe5PP2^}$nB5iTtsPaVhor{~8=u2lY)@{&~ZA*-sW(cMTfmO^R`Xr_nn@QTOk}^^Mf}bgc$4kLFkHDmH+W^_lFiPqe$Ln_ z6HjMIFgH#4yj0?2(ft-U!N{7j?wz8>kdR<%I1(^iDLVHP!T2=7kWgWmPHWKqDceic zYy5=YjQ!KbrflNaIpm|P88g$b{0hsA)$7GtQ;w$OJMozM-urpy$5{9R>1+uW8LK7d zDPP-s9d0WRytxw*Q}eipn13y3_zf`jTe;**s>jc-O)a(;Eyy=S)VzKo?yR4*v^J7= z9dkq%y%(ii;1E!lK`8{Yh>7QbU-$pL%e=9!7P1;SmC|R6s9%_quL5|WE(q_P$GdQE z1R=8zmx9Rw-9~huF>1R|w-Hqz5?sCA1VL0)efy>sM*2?QU^wyfq_Hr?@`qsA)nV~T z19Su0R-$Ew{oZF||0BP=y*u-ZmSc>3Oa_XPEzMruR2;`wrh@ciApBusdlY?9yUDZ{ zmoh=vJ`=hzRdlLSZg-a8%n^rygL9m9xWOggOtpzmpe_ za?>Z%=rfw&n*mA}l4YL9c*c@4!6<28@2Ss?DIE!~WK&g|FTMV^ZqA4Q*X#y2 zF$9kQSGurAFGFFg))V0Jg1hjo_&PmnBp$Ub_*1y3_&Qk*{(E5THVeLujIj_ z?mF$j!+=sbiBG&ms@dTUjj->*6uF1zB_dX9K5NG)du98~4@^++5qw{pV+7U_3LWC%JKi&6=`IV5kiC)mvlS#r;bh-Gz=KTbr zDiB02_iyj=U6)8 zS84ipYNjE3X-lsEl3!w+2w`oZ8?0C{W;kt}6GU-8V5$eJ+SWkr4G(YIktoxZo9VDM z3TbY`*qd0LPMj`-j(`=75@;GvwJ*BuD5EH)n|cl%+!Yo%#oW#MaShTnz|HTfdfr9G z3MO{Pj~Xlc7M;dyVaX)~ zu6y%ktG6@fgT{Q+l`o0sM9dg8+CLbQ#&U|xXCOcG_FO?!51aGJH-qc1syBfF`z5Ff zFy=^u;9KH)QFw#u$J|HuPz8!qrQ+x^n`1IxbHaP-1g8Ql?9Ftjua5+lGse=w$(Gvt z(Rj6+swx0K7w5lH_kaJgl7^Cvy^6EULP0lnTUocZ;v(R%cwQ zfqo6GmZcvY)ALj3yB|E15|BS+wZ?NXoHwl1)36rl7w7HyfsO*A!+dT!)GAF-Rx=6Z z{NhMd8qfG)UBWqP_?2>imxUXy9rn+nb~eaJG(HnW+N)-9Uz9vq>;z^v2yy~DJh@3LMgN%Z^Q}%z#*6oAZr_s9dVEuc z|DLwQa>nb#QQ{4OtV^vhF;R~g1%Muq17K707C;?bje zmtGoV)875jtZue`{7^;8GkT#jKhE|YRQx?Ha3T1}<1s_+aJJ*WU(Y|}yYIvL_S>O` zrRPkXxv2blc5__&tmL1|`Ez&vjGaGE*8leJopPz| ztiM?R|5vX>$B@1fGVW!FG<0GIwC1JEMx@(1#{O3{8&bYJ+T-H^TlPVCgv2^ zefG?LFxD@KNi;2H81SwNky?wye$uO~tW&ZbJ8M?A#Z!D?GwKuh$W*7pq10-7KRi=$ z!!FA#K%5cUbyLg%l`?eZloz;sLIsL+W+tf;Uy$&Li{{~YnsUr#<#Tt{^IaF79yldW zaXciW)B0#M#Js(q>7b@SS1gD6|4C~R9C$XTbj=3oksNaRz@=u26b;V@wC0_^x?^>> zAiF=0r7i#KY-U7Op_ivsSo#Octh4P7A6UN^F!QH_|H*rBKUrO}B;6|aY-&2)SwKsn5#Z^enHcOSKUu)*Z7N@c zcsp>IZTJ*#G1FqGK={u-l@un?R7?b!y`EKIuRj|7&yaFo7El*cPY}!+klYImW3?TVgWluwt*k#XlP*q|c zbY9&1!``N(I1De}Pe`SxS-t0+`>DB#~X&O6<8dc5`5q z{uOu?=YsD2Ott06a8yamI}G-fVPXDW!w$(50W55RJdiDo?GNevW?3_5M`pmv+pK^_NU;La5)mZSJHn0CPUl;HS(tb7apQF`7n>Pp0zb3vc$ z>Y`R2>hPwvV=5#6Z|)J4ztCfJ_()ERoL6)=tx~K{yGqs6y&9yemJYInETCt^lAr_mDxYfAT8-)a`8_Gf9}DbaUk_y>sdIwu3b~VkjS)BOM=a5v;xf} zeMo`ZeFu1DlXM|4w411bYVQF2U4esZ>+2is0IUhj(T&!{BUU%o{ni-3*IAZw9n7mD zcqye7_3rs;NneMWAYLxhr91h0tcVzwy2`D0WxEw6OesE*1JW9>$UY(d)7MjE#U68|+% zGQnJ5@g{1b`2%UF@dGJv@GA0k|1(2O93=r0r_T!W#!gTB4M~>N>Fq~sYHNma6k!`J z^IR075U8}au{lBBw5oZvGXk$$d+QTIJi`=WYv6w(-|ev_)Xw_#l-Skf1SWgSfb$B2 zTst+oaPj@J;+`7~Vk0D)d=v#o zu>*6{Cf%*Z4wK7r+H@)nDO(bY!QMtIq-oIV#48SaSG97BPc_bjU6GfQW6HXd z560#y`jQQ!F_$#wYtv{YU$kGByC$Xh3@wpGcWT*Sv^)_;bg{Z6ZJ!@u2IOjit#sP>#I3xuGI@v}JU^JP4JqBCX5^_-EbS8?91cowKZ{#5 z3TKt62@t=tdJ9xC-X`@hp0|9+6+I?N*bKd^3EVq5C z%yX!hK5k#&R`~KUT~GtJ#%I-|8b20C%fB>$jsm#pi+*%CXeaeQeF_w?h2NTMSh=Ho zGj+KZ&1ESLSq$mK-lH7HAE1clV}ngOIPD>Lyn8 z#2hI9mGoh+I>QVo;MkspLJP0yeCiUc8+MP-O3MI6i77eoOD_{nW>fzORMA}ATbd*(*ar|`m7ZLdCg|NG z2X_&nwUf!K4;0tJ>HsTyzc)(-rkjO{U@E;fxb^0Cqqq(f=6T0(5)NRTD`4QAjYI-rUR&dd*xnNWFRXmJH(u6i_tLtez1=&Pi(xQOD24-8d-OMJ z@7*p3+Je5V71HK7sy#ZN5$Dj1Lr;xkkgQ?$(}e|~A{B#=_}1o^sgSWQDfr8?Lo*+0 z>Au{zqb+dyLcSU4;y!|*^PPv6mPZ>`v#=j_XtC~R2UtIh1J~xkCiMAHHI3`r+55hz zNbEj^!jD|yprb|wP4$@@sd@(AP0APAHQy(u>|Fe zejd?W*xc-l(ExpG)J=W;LKsy9i;J)@*vB{sZ5~lEpu#YMTS^3WP*5QbQi0K38-gA3BkK_QK~a6&3Wk7&f~+vkm6>^AGQBy9VjsVoX!pu)mW&zmwoOe}uMyy~ zq;%GdfJMg|I9u|@_T_h<%m0Vy7U`vE3q{HUTI|Y>MSY+oxOy258Nu*s+RTgm?ltE;T$j|kxR(3Psvg8rPy_O+3qJql=@xDCIo{tO zY^xGfH8pW|c6MjucVsPqZr0U2gBK$WY9Rc3WY9fOx-F3uMGrghDvt9V&ywm8+TLUbfGRczlkh z$%9(2&lPo0)Lr6x)rQJJ&(`1LZ7rjXB4JYv)jT$P$iiaDVrwzyw2KA%G>C3;#H!iV z&i6!9u=wzTJmaa$&u%W&s6=ZAT#R?PDg;W$xu1^{FN%=GX-=H_9eX(q;r3imgNnkq zMLMna{9PA{S{Uaf-`^|pP*>)+2Wr6a(mmW5|E%H!M`tQbfhn#sY z61W;Pf6uaNt$DNM9ylF%bz!TR=fiW>$8s)Q*1%!b581dlP!R_IpNC>lo+5y-onL6~ z%Zl)XKkHjKUS`~SAs3cCLmTd}(iVk;``!R1M#Fq?YTV63$trb9Muywmp|aTT30 zPuGvfe(Mgo6Rsq#!Q#}Bp}lPukTTy(Zo?MOiWJ4UKe3Rbpe3O(-u@`CxGfIAgdA?l zXPJyezqAg!uLh8VuwrA6hAx`(t95$6`UUA1hvvOVJ{Xk)=H&Wzu%0;yKdimYNiRWh zEjQQziVQ)4;omivGj~c?t0RkcPMcujny%gGUu!s1qo*c+nx{u1lE@Z3qZN(6JFU$V`D~=Ei zQ6VkZlTS;O*nOun$$t-fgm1i?10$8&s+UJ)5})-)b+__eS3fAC`fX!dy>DBV8~dB@ zGv9-P$~lj`l-`xzqei8donK2Q`i|eBJm3Ps!nmd+D40JEj4bBl^due(yqne3xwhI` zBK$l6&040Y@DV!yUfe6t1J=%lEZi0$Q;U8Jo)vzidHs^P>ltq^A84L{!q!os@YuGM z*we(P#3V2ePc=~*LrUntg1x*Z^XmsMU!r%{J~|H;W&8!AI6;#J%~R8J?3m8QCC)tU zf(Qw1VC<>!4XYU++Iw|!`XE$-2c%s1?c+YvpoJh*!fFpHp}#MASOiBmCN;0E5=pBKtru&yVr?DD<0w3zAjZdu_g3s%te>}5 zlE|0=b)Y}0uNXu(BO+T_+Np&);PS;g8yir4y%7iUMK78$G1$DEgknFRW%%H`!wa#^ ztv@|W;!DW~j1pV!Pj6F8poq=jjSQcl%n4oPe~t0(nTs97*obm7y{4Z#*L(OlN$q** zsoQVv3dWr3L571L>&^f9_|HB0Ga&vGpN8y|z9t6vch>^70_?{@1{%AXIBaDeN7n71O!E?*ZjRp5NTH+mw=4om}+&#UBM!S0;isCv^ zoQ92y(WrsuCzL6Ey?E$bGJpBp;YBJE;xv`zph?I9=ex3#NunQ|t%GP~aKjww?~fxK z9=!{+mILt&YxY7V>}mY*>&U-p5qNjUUPAuRcrrhB)He(~$BXoRs>SG+#V$?zC&^9U zoO_9!kDfEpX@SfT|zm}Mai^=BO-pc)|AWjw#tyW6}LN zH37qExq8j)_xWvVu)VqOu+ux zskF%f^6m!`Xt#ih!35-h>X!4A!&xc>GUNuH2=svDvd~SH{wM=byGP0oDNiIb*`qTGNSIoU>sm9CzL=5u38V%uF`}WfT6_}`1?a}=doFgIn zE!zk4$U(^FF5~5chn8*H7Vc>7W%e1`-3y|Rm0#I|{V{mGHM_#0IsJfoXzpGf-s!JH zl}DCuZf2~sw}S`n`E#tE5kppmudThod={d7qWiM~8inpB)L4FqZk3NC%_)i`eK&LD0<-up0hbS(cJSojK#hPt-BgxWR>IfjU_ zhsfS*!2h1w{@oWXFn97k7?)}ro0C6!;Mv1vTR93bdC$H?6tGx{<~kjCW=0xWgyta< zltuv$?}>w!S~D`?o2cZ!#2}puFUucapm(@L9o=hKg#h+5hc^nxr8?e&IW|_KJAaRA zEZdLT#{tasdyfTZkZu|laYt_1h-Iw5yGSj)da1vkR^zfT%}aW?H~PVx*&^RJrvoxzI3}xoLjtNbYTZGS%{(81$7Q$b-_a*Jm0;ap4R-EWAo#HrHfWjiao)pCoMivy zUsY?pWZY2pYyw|lviG!8eo7jeLU7q!3Br1;j&Hn}MKTrS#3LS+XDP#vE!q^pYdMQ44D>=8Rs68e9gOx zAjMa}Vr17FhlV;UGgYq6^95Q+UJc>jY?GNfiI(-^_PjT4!SVY`RJ}EB zH?WkUlKbhCr69&1`ydARQl*CA(wAqtNw~lFoITLRUnE5|2)fWRPaCQg`;`84j;{=-bL7s}cJ_C+O@|a250ww>p+B$<|PV zC7*STT#Ca5@@Dj!pefF_HaIwh>Rc5gh>^A+;AxdK4bnjD)#6mMKi@F~RUp=ci7A6XH##o!Gl;Lr>yjfsprYWd> zk;JO;Goqvl>AcM z>icO==G-po^vgdEsuRM9`;7%*byWJ@+_Hb3|ztHnBljdTg{loIf5$ zY2OD#fVGGcGNS->;snF(cI;Xk(gp^}^Ty)_KrvWY zX<|Uc`A&efB*ULtGCkp^r-&mY=5gax2ubBswtcc4edbO)6lG|qho40Tn#qG>|SFmM6I(136uQg!cqSr@>7VJGlIOy6Afd5q+H|X{p ziexY%T$g&8@?q1*|0cVg+C1-_dwfO)UwV4pO&AKnAwat(PSPac#@f~?oq%ACm<}`Y z4YLp(HNB-wy!+HOF!a}~aywrLqyj;ogUE=EST@!r1l3}3HPFHoXUQxOt*jbC8Kjm< z*_1ptb|G}GT4b9p5DQ`DT9ii)Iko|Uz-4l!Uh!r!=7@@iE9icFBcBJAJ@>>6n6-S@kQk z-FZUJ=LwlxraD(Z>0w~YlkWCK5DTJKLab4q2*tpj^)${qHs@=F)sAAdJDMn`M3cupaHjkO#-Ez>ob{P&{3aE zKUjKl%@)Vh5(qQttCn*e^F;^HlH$yS7KM_=$e{@eZl+%sV{CAuU{J^YiAl;AvR>yk z(ikU_)*%1W9z%j^SKa{bfY1r^J?KQu|6idKnZ(eIU+l8usmnWb=K95LV9myl#7YWb zGX<)mjtGW@Y`H@PydChNIf*$@pnCv{WZFTIjIo%XkB_|8+*DbdGl-jbMrgVF(~g%_ zVCBBFg#E+#usnkUK&YpkzrVNNXVnx%VT1-BS6MA6&!vn?l!R!FQ&t1fo^cFEj~ZV_ zdIw-Al*L-?JKI*DGu1U0tpzm&dI3GylTz1-*{$d^>}O{56D~c59g3=cfa7%jd8QsM z^kMgRmf(fY=7seAUxONcA1{@W5z6yeS8pH@rS`T!HTli$V`Yur$~G;jJ)g97UsRLlu4sd+#oaQ$|MQgMvhrp=)_4dmbJWRv zTim@pNmj)__masF#P;?jvmr?56(gSCE$Xc>f71MpY4*hqM#PL4kFQ=1%Zc*~JDH+K zBf+0mZRf+sD>1{xMNnJdr`&U^sftu_=dQW_3_)F6z%T2xi7g-}s_gobZ|mgl06qt6 zoJ=n*N=zto?chmMG5eT{jVl6g05;C;Y!35%bh-I<#9V0Cuj|3k#vY9 zWfK(q7R6`xSA%CF5>eS;plN$Mke7EOJ*j(P8v6n1zLEAm~h0c+h zktO!#`e9@3)nT&@n98$4%V$l(6?~7UKjwPhJIRkwp(ICi0au?T3AuiV-bhkDV%)%V z?e+?|KShRBo#G_({p5Le*N?3omxCDX9$pCzBrXsVgXaib@uz1mC5s5DyBRf_uF{x| z)}Sqrhz@NeB8gdA|ECVmy!5}FB!uiL5JGNtd9Hl@+|NsK$?>Zk-wwP5uXF$>iR;Em zp40AlC1au&(vkWk=NDb>m%!HIbRan*9gya6ihUC))9XBYMvYEVGpkk=h9|bGZ4jf{ zj`@DP`sS5@tnk$Npo15dCf4#X_Olrn`~N~;C9HK8q*%zYl+=-wpp^St#q92~v>hv$ zk2TURZ`pygn6jQ=H))5YK zJ41K`92n+HD|n+_35O1w<8c*m1c|7=d!h+0UQ1DWgJj-Vfs%HSQ!5ao*`LSL+wSQlb|JWh01NtDMBHg>sy&>sV!rMt;gPgeqsih>9XS}x(xuTT% zuTM&Ndv=Q_fiw;6IAa!q=gcIqNiN%h=XmC9*<+rTZ^2R9WL#S-q=k%$L4>K1=BAyGU0mb>K(Sw7c zs`Wb?pVInb(jS)%4#w{Wv;Rz)NHDF<)Q!F5{)N9-968O3`f*b zRt@_D0ya>TRJWGrlfcgRHc!>C5X!{v$|SHwuGvD>QZz;!!8KF(B1bedLn*E`QDJV; zbEKi+2We;LB~d__6FAqIv!a5L>*R%0M8^(RwykbL>eaU_@;Cgf|H;dwHdaatSj5P5 zZgZgzN>(;X&_Ogy&&QAHpZX#% zr*_EkbhaUl+@cn%h2^8}!S2;#Po5?z9O*7$Qord)r)8tvq@ciIN6JGdH@M@m@ zV10V*Bo1oom!A9A$;Jr(O$X_ef1a+3a+_X87Za%>zq?uf+iWxT3E(;N7FEJ;5JhJ9v{d*bXetn|IuL@rH|R=A6IOw zze0fjqr)X4-0jpqt~gXB1WEZvhhCWf<_3k5|5I;)tsauLAhDfqMU7?lhBCPN69x)V z|BOx^VwHfBcZVc^tsSTpi<-$$Vm^wrCaUTk;!l`nQmyB0)25%;kvH<+vAIrL-AS9j z<~9(Nl6RX_Sa9ygR#9~~c~!oo$K?CXr-{Wa^EN|O;}KCAXoZuqrzls@&@$Qr4V{w? z_^EYmW-NL8-bvuev&NBc8@@;pOUvAaKsqcZV+9Pq{VKi-nxl2~ND5EVd1=GBfm`=+ zMhXXN&x??PDlzs*Xo_$xxsoG<c&SHWMGZW>CIj&{HyCZ6he$Eb5_s18Z_?8{d@6&5={2T z0|pijvMR`9)4UFZ2x@l}+SigpNFz7r@U28Y`mpdI|cYVj?_NvBc@FU6_ZrL+#Cp zo9P-ji_g|VSTUpK`@t^yJ%L|&10nLUC2ln$QcCq6VL?#E!E*jsymq1D-Aqy3v_n3j z=jrXDB}?p`It(5wKpCMBlv;qTT0jDI*FP48I`O=5(44GJ+O6q&36y`k8XJ;oyEvx3 z98j#uVQyoYB7nf5aFXWWy3$nNzZKUYz(pcP{vYhUc|4SF|L|QZONwZ*Mj=|1?8-8g zLP?|ri6MKoBs()nCE1dM#3UiRvSyi4vXo`WPMPe>U}B8f=e&=h@AtW`>v>+U-*dn2 z-|zlC*ZuT5|6$JaSmv1HJdV%$J__3Xix*HRn#zwu+aC1nVlw8L`UEHt8lnS^MJ+VT zG$UXFp`9Yd^QHt?5F|p{Q{GNzmMmnEH=njGJ43(({e!5?r0YXqokNlca3`g zn(*I0B9L&uDWj;xXL{~LE{eOnSTfk?Nr-)roRWknq4kLRz@z z6W%cO0zL$5r4)a8Ih-y&bz2)7cTnx_-O$aOjly3&R+o4tEcD!zTlnp(jyv4B{$nR2 zylf9V_;dTuu>6@0e_n%s)74?mXXCkbd6EZ%DJ#_@bm5{;R6|IKk;OMRmyH5JZaa@?GaAvBKbNMBd~wX9jBV6;EcTq6R()YPMc5 z`|i_*<`~$DL-yrHscziYJJxc4z~NT3!-|$@vqvh@aO6eSNaBa`ND>22oia{JLhN!^4tuIetfD^Lz?Orq?&q@w z@uWU{5guFEk@opENkgRBW6fmrLm_b~U*xGEe$Dz;0@oUHE|kdT7${h?7GZtgbz@wG zpCVY4KoOreY^&b<6anq;mSOipSg6^9{Vy;=RYYc@Fwb}CxavQCe=q9zH!KdpS|R$u zwaPo+c|`HrS0GpjavBB|yzH76X_lzYScgA!hqdGYEN;PLlS?$$A~<51Tr{x07vAW$ zqML7qVvS&RiWH1d6Jhl+nN^yO)pwJaEa$Ti@{U&O7cxHH2){8#z31qW(H~{@<64GB z-RPlaYca9DqkA0)lMVh7yZ5vrnZUMb#9w^dgzr!tY>ST3jd*%r8}f>-LIu(rfGH} z9d2OUX+xw6yl3~u!&^)*ZXZ7T_}ZQO8`CcpvAq*);o|jbsc)nvPg{6h=luHnN=O$4H)XLuV}*jgcFR00FL^eMGOuiqzt7@VaL|x`R&Rs(bkM< z8@K&Z<79u!SFlI(gn*ar&w=Lq0Us6`1Bv{??(%a=u=?4tMNzczIiX5fmq%JR%%)kc zjYyiDX5GynFa*JDIxs3{jH~SXQdb+cvLmuOw;rd``(!jz(>uP_QrWU#_Lq9J>Kp%+ zjnC$Oh&soj)CS!}T@4oJc=iuet9GnVT+2V#O zI|{DW>&xnMdw@Bc_HYOGJjcGE3eLfH=taRV^)FpdMw8FJvM2PO7^1>UcCusxL`}7n zc~(283H|BJ|NO|r$Lf@NKdwj&_k_jR52K~ltOO~sbK`G!Z(%ONYIOLDY2QVGAvrAD z7_;pCGT^ofAt@Mfu=l?2#sq>y`9Mh+Tb+S1xJ$+P`WdFvtvIJ;B2A z#@Q|V6|IzV4}1A_aH?(U>C$7XQY0FlB)9Y4lM}oTyOZ{b9~rF6$_gAT{Oj$0b84HQ z^T(sXyZl5n`rWS8MupC>m)1U1{+)>VvZ#r|(a3^V|XGjL7OO;%;gM){S+`py@uK1#<5VJtAE1C%v0OwIs*;4n>v1`_0%XxOgP(=~OScg`2I6SYV-jA^^uZ>IdvA^q-Jkw;#kIL9L zyZ*wlN{l9ep6KRnTfwqa1sD@4{B} zcrv!z5VU#Qgb|lz)ce{4;C;{CU_-O>AyJhNZ}|rp^xkMkZXFw2haV#Y2Mf{gFp3vt z>~`fRo&V(CCck$I?drYnQBun)F&hO;KHSTlUi4-~%O{K{jd|w)-3^;{PY4P~i1>z& zo!OI=bIs%mdtn?CoA*liVtb(vY&gqouhZ4dG-{;OO!3T6Fk^} zR&ry&sdJw&|Fevo$HPbx+tqaanuAwT7ZU1XKSyGm#aTeL`hvPoMg#ddKDO=4q3P!*xBL|9P77rj!;ZqQx*6wUkn)rg|mnU3PGbIUbk0 zflQ%E+XeQP)*0vdsVT0z(&*SLXX^8F@cy#sL)2A*+l_U(QEeCheDr4|{>+I#ufm^2 z;s3j9;r5WF&hYdAN(Bh_>t;*(#1x7Z23llHS;iJBsH_ z<=gAVBE=H8%tIJt9ZH>!5MMzrzX;qjc(zVN7+3f5m;U=v`dG`cDV!v07?3oy5mWF! z$w{LN>L29hs6ryYR2^S+OXe$20bN#N@1eYTTG$K-5yNBs%?+cC_WO;zrrh_OKlj}% zc~cc@nUzgO;-#}GtMMWpxZnG^p4YS5)2BZ0_R;wb^~N*Un|f)&rIl+s>hdNx9Pn|5 zZT3vYqC+=(?~iE^R8{Re$9@_s37)QBy1F#_!J9480i1>tnZ*Qx0|OD|gV1pJCau!Pw9Th>{qKaE~O@mO_vl z@?a1=j<^ccV6cH2R%qI+EMGC}CkYj#TRJ%x(3oeY091%GpD>0?02-LTUeR{aC@m$ElzuPUfxee2r! z?-gR=HhZR8bdtQM^8^7F2>pXh zbYn{g9Sp*1)Xi1CN(Y%~rXOha-E(6KR|MzZK_o+u&p=GcgOkOz&>Yi=ZAN#QxN9j3 z#4o*rGLnX*H$hLFf8udSod_@?6T^M)_8=eiLm_=wxDswt|EyIz3Qd~6{o$SDM=WcR z4i3=6-i0xW5agz*ii!&LL?`SVGtbPoxm&bx#F|jgx<1sl@!iE@v$7YSM*36MGUB5$ zvAP(og+vL*S{~eT{ll+*HaZ3j4RrD%ia8{=cnlW;g)K%*O-(uNJ9_rIAa@cP$NWU@ z^Nie8oYPI8+c2NA@2)k+`Yv)c+!;59)ms12F>5(3YU%UF4#Pb*Gz2-1hyw9%>Qg-1 z2}FxXeqAmUaNmCWbRLq|BMkc^J0Z8Eqczq z9q*aw93r59JE1K-wJWtS0TNv1$X_&tM&kj#Vg#*;EmXrQ*)C|s-CS4fc2V5LFK>0O zND@{vEcbM9Ix5%YrkQo+SBv7+?4{Oxl6x(3!x)lEFdnrh1hIpTn)Jy8vA!?l#GM=y zSp^rp_idHfu*I@1i+?)>QoU>CeC*`?spxwGgEVeF%jhllbk28-=_@_?(2mK}ogyV2 z46iwAn`Ai5_t7?Qh8n(nG<(-HNoc_4Cijy!wtbXd{agJv16g~u4cuW+Ad?-*YA0gj zvgbscuy3?y$j0yjJs&yU*b9^iXGx%2AvrN+sd{QzgZtG`vOJ)pm9mM^yH$y}7%MCPw%<4$&D^8~WafFYoUO*0a=96gz&=?G89 zVRTs2>We-SXeK4$_+PGG$*g&O1aJ^CKjL8(k_%zYO+DF2%2&j4MPjzG{yX9Ad*Suk z*4?x2^K&_Uf~f84zT}F$$=wRxq=+z!jg5A`6a8L@=&9>rw`x;uNWT5@A#H4v0Q?3B z7z5#r`tPD*)jY<=ex)4X+5)n(Y_hht?ch7bL1C4g-Lv0DsLDBzL6qO*{c2wal|aSe zArtH3Q#Sk@yyrb$UlD2zeSU(iJlC>%9qP;W9h$hDamZ^YiB>Y)ol(vbA5hX)^ynGDAzTPH8X)_;#P9V zd(#W5wU8#(l>PbIuXU{8F#A(0WP8aDb|2P8`hsg@{3ZX2&Y`0V<;u=vNnM zO3U!0xHHckCiQ9`3b<1tsoA*QHX#Y^aP%A%tM5s{JgDwp-%DWITcb*{ecPA)kiiJo zzKNMcwd4?;u~L_phjv4=?W5L~%wIVU3Nnc5vP%VKeS4Np;G=y;-&cyCM%9NerqAIf zuMa^>lstj%K%^|?1+e-JG%e;x(8bKXs7{lKM{8&u?vE}V7_vvQn9L-?$~8@k5Vhli zP23IJliscxV(=vO$a}8y%Z=DBk)-6=*7S0UhC^U&WEM)jA!CB^!BIKtp-i9XS?!$Z3EPWZj`YO zE4pByWnu&({xzR*fi2j_)<C%BWw2d zw4g5QgKhO#mqwUNbj_Z?I{M?V!pWs*>2%^2WQcgDDGU|5S7MunUrLfobd zD=2wb%9p56NiC8(;i|)M?N@(94~;FxtQV-i$(ziL3(D2RQqPc~m7McNu4@|Ly+sS3thMp1U%)2tr?&gg=Bw7Bw z=bP`HW^%RI?P!#bsfFGL069QWn#T5y_t1@>H*Kh6eS36Y@Rs8DVg!C|mmi=TAKF+8 z*{@>`e9q>eifb36lge{Mt*$OK0q zO;cQ&3}qn=6IHeioCrxo#Y)i3YO5IbHKD4tT!595H#7wfvxl>qk}mcp!<&t4#2WZh z8%H?Np{n*1yUzYNT~nmRsksx+|MRx{L7^BtUKAQY0r@xNU6W++-Sqld%097#{qC$A zTp=INajD9roruHnzg94x$$a>E`~D^R$>mLlYP+BKbDTlI9-(bA6Ga7$Uo{iBI)(C= zO?5|kc2JpnX!jDVZyIQYN?{~V!;8NeZjF#L87GHL^Ii?i*}J&$F$1v;RIc!+@;}4! zXSV#WzC?F|0)WQrW$uFxz4CcOdso6wrO}WOODueJ-9ltL5>0&=B1Dfpi=fpLtPsCw zurnnZpJ~-For)@iX zD<0Y#xgr{FtNpWv>6Ho}sL)eNdu>mQp&&gNPN*+HtVkqnw-qm;Jn0sB6nhYr_~b6m zQ?FdwpeR>-#AtugBi^$H9b=ZSk2?L5emM|Vy4|DS=q=Gx+~yDHHzWRUaxdhYT;9Y-cks$m(;lI}S@9k=eUGC?#&5d+FrmW1mt?V*hIOIP^Tr z8uDpt8&K>uQxx;v{#aH(=;;%nHDZB;qsBG)_-&b3fv@3`U=lhP=5U32bW z9Gkf=PH=mk(ndS%S(5s)S7w@F`2vl{L-G7bJHkLsl~(YS6(aE^1braJ4mZ6#&>XLK zm76(uA$>A&F{tKF&+sQv zu8SEd;3V~gegUF_wgS1ZVBWp_!Y7;%Ue2s#f;kv!#v7DU6a;?r5b-e#`D4-OC90DK z;!_k5CN0sXUYFB_Uo%*Uy1t^?*G=SQXOFwK(g8y$2Y2Xxr;`?~s3m%!3olPwM~8+8I>FTIqg>=fTrWWqu2?k? z4C#K~Ft@iKv)tIrsRe24DD_ie`51%f$%YLtPa1rO+Ybz$U{6>pWO4AFRIh|qQscJu zqO3E|3%0I#()iiHjHB20)v|uoIGy8uQi*APUlz*t(O0o-*szR;d2fI?B$=|I{G7%< z?xS8Tsg_<&cC_U@EpkHns-AG6ptS13wTX_EiNls+)2og?$=;Yk<-(^QhJ~e0)UQ^! z=ABywcYq4}B-6;}dDaV(g)GX|I#z{NNqN*erBAmKR&_7$x~n|d8`sOWul9e<@&7Kk z@hf-zl^bswt@6YN(KQaPt5zElt$wi6r}4@sk{Yg#X1tKu<8^#$;B5gK z$X^N`0Fuyfabo%~$R=DFQ=eOhhe{QE-I4O!K@i0ut69vhTk-yVDarp_77vR z`~6jehILzpNK?NUGc?!jAO|V9++*GIZ3lRliGJ-be$ULmpJQ9=8sW!&T^z-Dwx2s_ z8_M-y6OF1|(u+m0MOHapz240^!gp=y>X*G=V*Z1znasJ3AK`GZzwzrO#`1ZFa@amUkR)0U6tWsr9W(hLiqjA<+>=v!pW48=-ZM^}Bnj##N*Ri={q zk+0Q?kaRjkSfSBAP7t%P%0HRHQ`uI`JNYP&==wJji7j2b7{`5`wWj6lnPoZ0d`3NN zgMQ$-s~aJT%?cJUJ*KsmRijZ{<_bc{4XzfGRl4tuKUh~ced>-PJRoq5Zquu~RQzl} z0+*%N%4uKJuZ!NLHua;`v*VWS#FY1R5fKNpSF@`L$HPglW%_msU3-7aHV04hYj#>w zl+InbI8|)@%-+g29r#a0P8_!pnWhCL8LvgC9KLcTwLb9TQ=bP9WGyO-yM36)#!J|` zWg#px_pP_N!nyZ_#T|E;i(B^WF5Ys7sok2*j$El`J6v^Mt*uUz@7KWBFxk@vAe@=@njH9+H> zgR|njkx%mv$*bU~G$PxR>Ph;Q+O%lJpksi6+dZxcy?h3QiPzfV$RER6j9DX|&-Fn+pVy7*l{|9i-b$jd zQz5T%&wcX|SpQ*n<-X#|PNf@Sr*zl!c|2)qlP><=vos4smC8p#e&qw(L{~GR*$a+> z@HL^*ZnqC-YAQRm*k%5*%#;);n%*yE13flz4ZmeK^OrgtYbIF026`O7WoYA-aq+X- z{fBEthb~eR@59~)`NxTf)y~!bQz@Y>pw!a;dMWf_($tqGposC=jsha88u5w-^4PHD zO}HF3jK=?vT0sz2P*Pp!OzBHxYhln>6Ru)IK1L;>q8MT>#A3&yX1bhw1yxN11Co61 zOyH;LqT^c4VT!pGH6NlkzB)P4=pTW5i+UJOSu{{qlI?A zY^uBu4kjpAsdBcG6+nNa7w47~K^%lkUsJEUVB`#wyl${k|ALSU1hnIgQ?TPA?^!C%3xf(2M}(#}}U6cdQ)E&G66 zh=KNz$Y7$!g!}-DPKi~tQ(vL&4Sr`zwLeP<(-?^b#NcV#ZEtUH>I@8R3#^+Ga2%!x z8(dDcTaq*w?b)%hKjitPa+RP97k}TI7fgfRI4co;s@DyZ_nu-KLUo6tGd^Q1%dZTk7>-VgwY&Z1v0}`^jnp|y#)aGHX z0X`H}^>$u3D6OkzbpAlK4>S3gKsU(=J&}p`l;4%In@Km8kK2F13s2L$sn>@)|M}%k zRcUFXuFp^3Tf&fz7dDbsQ(wtN*K~uumWk@;PVX47aM`EKBr7NyDyhfiEmfQ7jV=gI z(WugAlZ*e(l6^0A`khKY7T2t=WjzXd7o-2M@EOB$Kvd+t%Z+m&KoX-Ych7o~N*~XN zbz}XomOv9Vx}0a0OGmGyqpjyj>AUK&Qf9X(xKUyv%Zo{e4}EXOqG1rVx4!QP{70}4 zRTB1TeXlEh#p^DqF*e6q2f30!dX{>xZO>I4NYRySSSweqP%LaV#dR zsIXkI5fk*~!po9F3A*^h!CEjG`qn6DuEZEvIVCB;LVY`5@~93m(j)V%SIlAlQm%2h zX>_Ud$tFIvxNlBgF{2xPjQO#GSX8N~!EO-67`1=0iS{n?*$dN`8MG6AtH!scUFZ5F zpK~aHD8iTqqKxUyn_e+n`BdVEiLp7qN=XdO3u*BN$(I_AscCea55&TEz{qgGx05 zbg0w1^%d-p)w~R|afSoq34E08+C%#WAn1&xE=dGo$*%~y{c>+D`Z{xkj6~O>(dgjC z)~pNS*P{=p2u}4Y7!Gjb2G0(-c7-m=nvMP9Q5kq>#6cOdB)-in>1=Ly8@6Up+{9Z~ zhCq&+5O@RSK97-+syZu_*CQjAU&$4fc(2UB($1`Hm1UF>y1qhMQ*wga>r{=Eyr!n_ z-{$-sze#o`+zEy6A~5jhbzcXvT&`+ZRDRMnMzDj~%+_ca=S1;5Esy8c?IQeNIE;aN z|NC(mW^7qv4I0w^T+!*ytV!JKe_)0v{WmZ}LWp2<3&%vnE;i!O&k-jp_cvbCJ^IZDb{M^}Dle{s2dt`(s0Ay{y2sv?tYf5ul7m&;Njp&#=I#4NO`;~$Co6Zr)XsvJd7=J5sv*RB)8&fc12Q~Kp1OmptAIt-D z3miGD526}}VoR8}$qS=Q)Otr~0g-}Tb+%MU3`Aa%ybi+KaqwzJ-EiHD#MIr)WqvTL z^6(mUqG!uC(uZ8)!d)*7H}YJKXQGCWy(s4#S~7_sJi*Q>l9`R zM=Q5WR`h;taI223sRGW96VWSfPTJdI)jvfdyG2IS{_@?qwod}NBv$+UVl}n=g4;bN zqoIiOJ1jB~dUxQd#ES<@`+o~NARvORNOeiP%Eoq##p_BO`t9L2?z=$1wDTIWefVaiaG9gBWpP?CGaxcmM{PE7nTTum;++Mz7Yv9PrHlBaE&>C7+F7X4KVv-g! zbUU~2iWfC}eMc!d=U=wH2M3#pgF=_WT3no%f%17 z2#ZeE<*+w^hI7QQeg?A*-V2?detBc4`}hx{XO?Tqn>3_0s!Crh2**qomZ1-Rpl}%euYEHsQ(;-gDAUGlVVgmqm24MN&{n;-ghBj->R^0C2{1 zwF-CA`B54H?%Bp{9oTmJY7lF&OR<6g`v(k%ohmN@A7v*iz9viRcr6WHK(PZ@>SY`K zoT0^t+Rz@S`FbF6KBfSS2ivFsj(yv$uY_Ex$AAQHs6}Z+-*SE(J{!sKekmV9Yh^5M zP_<92ec!`}8ust?|8Z?Qq4|Zs?a_9q{uQa}y>A7;c<8hSKX8|@t6gdgDD6G|Cx(1)4%8$S#Dp>g~nl>DK#{DIK?0rUJ9!io-` zTFrno30`ie{{^I*PM2)0`M{Wy#CQU$f{O;<6YD}23FtE+^ME);#Lg$>q^Xs)Qb)SQ zV9laAUFvUX$FMs+_u~_dXyQ7_VF_26UBW$#|0dJ6)m){BV@xEj5!xiITDKl zoCTJ^ls?fIQ)_zrh}Lf`#!#Gc(o^q|-w=%X#eaoj?7p;o-Tya}BZ%>TBVM5Xe~!%f z@27@1ENj&TeyCY&AG5JeAcBLFSj0|g&9nfJAT)+Sx&yGrr7X7R4FEfI%@P&R#T)YD zwCpb zp{+|rDlBCHe$oBB{;K2=*yrMfqOsTx6O9zJVE?e!P`wW3BIY}AGNrn#PDfNhwHOySjrDtFvC+yC`#9+!lhd|G`pAZ5J%7mx;C;n0SI zXGk|yJ_N{#-5uUhoO^6)RdH1ls$$(baEJNjt4SW0R)2Rso0Ji;MX_QPJZa~hj^|H2 z1(L!33B%DrmuzWx`ynoYZ7O$9y~9jx`ILCysw}WB%&098G?3Q3%^SZ;(^L}*WO^M~ zX36~*wjW#%OpE~6Q3?{EgB;NM(Jz(8muevq$;mfkB?v6$Q%8CEc< zFO>D6+^(R4n%2kmnnF`!!q5*gO9bxb8jHg@09;4bKjJz_PyS&mz6chodjKX=*S8V1T$A7p<>cD%<*|7@*6H|WtH>sPgswCAbgNeR3?5b7O@=( zXWar}NPYwylb9$3lcos*r-aUO?JPU9HqaRiC47<+aIxhRfkpZ5CjwrGsSnAdR}O=Q z?UbEzf>YLlp*4R~JJfLeXjuc7azClDbVXsSfx|)P#6|=t$ANivAf6&lsD<(vHY^c} zZDY96C;QcHOnt$ zdmZfoC%`QIERY);{f^gqaMMY9?C#Cr`(8vMDs4tf-~}@|5~6jwXxq!j7}qO}qW1*xiw>XWlqwsQf+V)uSG2>fj=#ur zDCDo2LQT20X0T0U3?BNoz9jW5e)|e`ut>Y3N&E9-PQfn{%-ObUE2MQ5?FQ-AZeTu} ziropw4fK7N(^Pd$Z~P9eS&4KKYwH=i%tmlv*o@Zl$V^tDvJ6N_A}P%p{EoH>S?t$q zs!}}i4OU0D4g2>LsE(#wn=gCkwROAciidU7ROk9njJ{ZC4!6AS5Z6R82c!OH zmyFs6WUcc)qcHgj&9fID$2{57R7$7tI1~mk+A-LO<3{!ujsY}90YFon%9cpW6u5LM z@Vvj=ft#HIg3FZW>)Z6ERtJejU1MW(|HZ~&6E4_+;J|abMz~-{9ehs~|MGmbD(kiI zfohhXQOBn}JNJ#GzIl5_-=Krkr1WZF`k&btvcK6FfbFsN3s$jCua?Th$2$FNA2%pJ zt#7dHIB6~PXNaVJ^WHAboc%lmnKOrvpSlNv`aw7Uxjoh2?SWG0b{Y{F&`7Rfbb`2-v>ux3YNBI@{VyG7t8EjK-{J@ic-1m%n3qcPUaz6*7fAq;~agAvZgh_ zMwk`=Y%D5HCLPy-rQf}rYu&uzde4X_o1c+hAD3FKT5@GJ>v+eV1Km$0aJHX1&UeCr}Tw};*|I-6rNTlJJLdNyZxQc(|WvpQTU^o5^7$Eb0FbJ#!9egHi zk2F&Q-C8iBVd%p1i1^eue-;E0u%SC>YBRbZq*D^A$2X}L(}a+;Ov$6fdWWT+>3b2X_16!#Uau*0CzW0-0zqW8tmR)w7z8Md2Xyj8oxF+;0gOiP<^KqBQOmM_ zuuX9Kp5ng&se_)?hm(_J4rYz@OpItE?)D%gRtOmQ17f0itj5F`8p;cS#|9kp4hbNp zpP56UmbT_+Gyqj%YA6rSm57BQb(VX-Lr^m_R`R^nk;qYDvn@(HDcp9Hy?4CbziNyJ zx_8xK%L9SI|N3CYrr_2huV8VT5C#Gr>VwFc@Qyal%R2ar8UFgo)*N4x_6dudF&GC<@2N4#wBN zWJmP%$$|(}cB&}mwl-NkKtCs{m7ElqaAG5(co9MBMDZpW0_^Be#u8j zwZhKuddl3neAVCKIPWaQ|MorgAfZ0wnl}mW7&ze6wa>&0G)*V4m>EcD8V9p(!@+>B zUVYJQyJ!FUtBfcz32R};IWsvF%z7%hBY`;%@}NC+iZRvI9~k4|xN1g4AJXI4FMdf6GB(zxTqv^f%65DRRbe@Hu!E6(CDa4?E-)C^Y@L<!dB>(|0r1vhd=%)93VHSIMUf1ID|vDkj=N!pd9 z$2$cMDd)YGmM#f;`l7D(><2UD~^yzY>@cXve6?n?Co z|6jE=Nj;a8a;>(^hXPUUlI@W|F5&20+` z&JRIYeUlI?Pd>VcLImgaPQ3i$a)zvi4UQ2h>XB?!B?mA=(F&^2Hk~$D8>W1^;r^Ey zJ@S1!C91gcTdMkKoob^U`^>wRWA7TSAx(5jSa}8WwPF2Ml`x8*dIw+>y<&@Sgtz^2km6uXi`g|Vw=-i@*anepxY~r@v*(Q`LwXZgUHpV%?#&Z zrBDY;x|eg%ko`291cII*@`H1m_|=*xW|~-=u1Z2Xk0EE?A>vkJCA4Xl-W5HJ>*%m%_q5D*}Z^qRX%z0r$A$Ms^H#V)U& z;a0{nZ|i4>rjyL@MZLJBU1j#Wz!wFzn3wO)^w{s#!P2GkuYG-8deJpS&JNZky74@$ z3@W{CV%f+sh}7S|U&57oADv!&lI}T=DT8`hLysS@SmBS4y;(tl6I!7hW_Ci@pwi9` zmNL8IT&En+d?~~zB%@+S*Wnvx(!gYtX{0F7sV!eCIP(J!PZ{HCkjJeoHlyj0l0!n~ zP)Kn>J933e#N+XKU0vBL%pP7%`=Dm$U&ujTpfQ{qMp{Q;RwzQ?&y z3KKb=?T#0I5}=YJ3oE{v$KQ5bO}x1hiaCG9zd>+9UsZXAG=_`YJ2LyB-s;99ruF*xn~b-5UGYkl#TZAX1D^h`#J#(u~#ZQV(!QRsVPXDqFQ!fub5o)$j?0F`F3O!sO3t))eOCs@`IOhn=6Z7vIC zUPy&|_#?L{>|SWI`|Z<Wj9`@S(W^c6#Yp<5{{ao0tZ9S;whv%X>44&>a zqZjgxJ+X2Ix3~*>k!|3J=^n|*6A2GF_6zD3u2}7E+*|z$Ffs(5AqBRa_F(PV0qqLi zyzO?=n-!e$X#vTNF3m?&pluSTjp&j+;Cv`Wv70w{)X9k4E+fo>E%$kKn~t7+czwS5c$BVhIxXzip3+>{+O;e6;MPq5>hb&L$*@<(()%GPVU!kQKO(h~ z+#9BK?!$egsKDjV?LO6rSAg%i%$Q=*19X;CDI9phQtBLH5iE!UV%DfMEfIw|0{(h6 zRp_#=&yV)Bz#{|D1+#jtM&}z6d;D9+69Ll)1<&&?9Jz&NQ#{P&e~dE}_1+dD4M8ly zD9nz*MF8tVlf9y@)tJ|8+t-upUi$MRDXE7v;x&Zr>*xyZAMalOo_+y$`jCQ_n7W7x z8o~Ms`3!c~WGCNl?qtAXO#Rh7l-9;fym!}&1L5L5sImPIoW^9sR!`i;+PbHMM=vsu z{r5gfRl^$t*h9txG6=lO1H9xjSmZD!W$GY~+7NpI7R0PrQNHz~JsAO(N!RKN#^`d% zIOy5;kp}tpgyRS1(}oa~?$?R#(SGjP=M;{NG)rfjHTqq<&i5LduIr!Z`-1e1^+o#q zt$90Ee_o za08s0O;wNNNC)VSz>5_z1)0s;h0m@YQ?5^P+O_GFtAGXRwa0Et!#KI4Pk$d|jFsPf zA0Rzu&-^%E{#?q~Muz=5fD2`@gS+62eNSYSkK5rhX>|sF&AgKR+W_h#SI7t7f9 z+0<(~&J*=!^(bWGQa7pz6>RUla;J(6lc-^ngTTa1@uXRFcFpubOUBtKaF`lB-XTaGQ1Bhj&o7*O=D41)=Qr5M-ziQ1lEAR#+pQKB&H|kHp z#XRXuuH5>ort8lda60L3ol*a51Lr@qaS(ZV6{vBMuF%3e57X0|Ccp=gE|A59*M?$@ zivB4j4UwA$7#H@g&ECGR?d@Qdd|f4dtnKCMviDbTgGg5>dZ0L=AD$w&SLEeZ)i=0O zu<={6C4ho$&XCoF;%2*DP4!H2M!4jr`QafDse1$x%keZ8tf>Li=_8+AzX!93ENx^@ zWLMD`Z$74E7s86RzSpS_i-M=3S@h<&%cVaXT|zVmwuOt$^5%ybNZmU}d*rd4&}1WL z$6WvN$b5F3>-FWksOUquNwBp8ocer&L@>oR=r%A?wW9h97Yv3z_$_Zb%e=GQWn%vq^@)VCZL~YFU~!HV6@ze*KUukRI-#>yB5= z8Q=FhKe{*4X^%ugT7^w$AjV~2cW9u)r|rJCcgeq6JZ#b|!r*qgvwv=rUyY`0 z15Rq2SNhK#@~;>rM-M=OZ7Bm6<74V#{F-)b{dA%I-lk_r_G;Y{dQAFwR)qQ<sn25b?)BY%?LitJZ z3#343>XY-Ul~fu>j$+@LunGkFBidumQk?`IRhrz|ysHC@f(ta@y3iWqv+w~u_CxVZ z3%jn+S@&zc`meZb*+Z#3#U{xCKQ)C5mZpijr)<3vd|8E`R0at~Zey z4_+vYktx%;A$V2vTS9IB1G6aO8;Sc)xU7VljdjXdGK1c+MEZOKFhbde%1BAJ)EF-e zG5L{jY;DLXhK;~>1mxmcbY-*D1ZU%(aXNiH9J3-KimR`GxBg+&&-vk`kHYp1xGB_< z0?`(xs{*M&my!M+>vUhg@Yts;9F{}NqvetGf%XiKtwTKM2KsVrnppF8gZwPZFIyUI zZZdnoeKR}&b}%=mg9l@KCDX*}o|qd|JQa!h*u8oa6fVF>gfchhux%6C>QChU^*%12 zi@x&|yKn(aOa1QNcfVU-)7yu7aZM=T=Sa~Z;}F}nb1BaNipR{A9wJmuM3D&tQzi;W z=6UmBRlWC00y*{?&HC|w^+h=WX+8` zB}A53wODTWFGQDRncC0AKFXt4qu|V70nwO9v4dgTDm`WL%D`NkM9uPN@ncI~?DIw^ zjSFI5Zn~dXl_< z=a1Wy!PiKdU#^*en>ki}X z;$LP=M5aMC$UdEifj%LDWHY~+b$Jg)x?nJ3Y+)KYaMbg0OY^SXIy-}177l63;&GRw zA&a_i1bt)X#`!BR-$YB)9DD$6&Ze= zW`*KW5k>@K3Z5uZ`7?0oR`8O$9K7@cf;Z z71!zJvfO%sj%g@f04pnBSa&}CcJfI)p;fd1$ed*?N1x_vCwFc*`i4Di7v;jQonw&O zEY5y8f2;mzST9OMwE)HzP3=Ga^%$76*N`;N>ZCoTKaZ?F1PV4w|1Flro+#W|dSl(g zZk8ckVIEWLal65w2HCXZV39~EFw^k{ykRD;05R1|HS;l#u<4pbs;=sza@NW&&2^XF zUU#JEkR^eu6bm0l(rYOX>=0$@Q{T|Zd&~e{i-~C-6n$sm^pV5W0+qf)$ z%!xyNTqRI+Q6VSR2-isoxJ$aTq)=S$(yl2J^p!Mdxl7imMrfEnCR&7(|D&m+Dmqio ze#7g&aarp~b)rY3`gfDPGgBoq#*1c*1f=`bckh!G=JErsY(HFUvNtlDRuPfCsvjBW z9n5!|bdsg9c^JossZ8T?f%68>$K9oZJ z)Si3jit}Zp76&(%y~t&xI`s{Ep`s1t9{l_6H{PA^{c~X{{%baa(%es99nr-lv*&h- z_DIIA`?TJIvj=CSle79(mFIr_>+Xx?QxD|RX0ftqYnoX>Zt?1us4{&pnOOvjl|=0D z^dZc1EgoU9*vBcQjK5Q;od-66>J_x#!b=2G0kQ{cdUQh_mUA$o4a;JDZ-1-<3t^Hn zAACms^hSw=&`+9fK+rUdnW9eP53ogeFTFC;hL0N6fwtf9#r)5BriA;7(~CZOd6ITA zk=0{JW}?0TFN?!9nt;8ba7%GB&(PwoCt|o8=H1S_%6D_6sGvuS7{nWAeD;`Q1%A@9W#)8&hYAD)SRZad^v{FnCH#LL;Y>7aJW^J1^P3bSq{ zpwMsqHI`lI`c2;u-hhi40sX$>ZhtA50|kng?^m+99Xw)~51-2ap^TYeA)DJVNZD2Y zS}&t`UZa0a`^=z?Z3@Gmx|$k*TfJ5PueUzsYelG`LBBiqyJ_;N{iWmjfBaeX|0EeS!@P7qht4{&qC%*x5>O)tlPmA-PWscj;v8ng0Q5LDvqgs#F(vXu}EgH zascO0eJ-g)+K`We#VThRrwyL%J~6!WxR@1{F+gcFkd2ba2&~SFJXAepYffk|MlYSb zT4B|hZsO^&ZxA8e-nNKt0b1?o#bAe(k95gN!_O_0OH|ciWLSO2kNS;v<;#9c=MOn? zAhAEXNLp!^ES$7xLyGA}Rda=lJCPH(q@zjdY6>b);Q3RQyqob+0{Zc;9?>rn+^X|f zZgy{IMbvCCxl1DIuGv{Q<9E4&hw1^7 z!(Stw^~(3d@faS3v^&v3x5O?OvY8yd>PA#HlS73i=wP-J$$!c|ajL8N`~>_=rv7KU z?jvn5-f%FB6(-N7?0yG)CMVs%YV8~4@67B0!>EuVIEXx)aFLGvy4hOuu1j=u-GC7W zx@aOh4t=%2Ku1biuk^tA?;)VwmpFIIn%Z3+xs&P8k@e`=`;=L16wlrs6g5Gp2bU!O zd^e3Lmu2wmS!E6@=0!R!B{a#RQ(Ebh${E1!aA77Z?tR0Sh*+$zs-NY;dvW^(F4{X~ zW;Ra~6yo-Yq&&Jpx7rWR<9SRkWto`Bb^|vLTYf_2b6=F-3OqgjpO*yHnJmrcThb0t z%?3O~N)Je7&SjDO8t->R=3`nh1}%0@Ex@fG(9nHMpVW@lQmvH96^<5JfB`HM)6ldrxD zB@6Fe!VWZkyc$0|tUHxBra_r?6SHIBtlw`Z4&KEktIK4K2Fkxz{x|{Y=L-04bRPN`lSvwQb~s?Hm+~01gq5@HmTkjaRDPZ0 ziEm2F?0J^uHXv59w&WP?=s_LaWUY1?S>8ab`*!o@rSh$63!AH!icXE#UShe&Pt|?9 zoqJ%2Q_OFZ71b>LSMdR;{EN4Z%dwtk?qSi@_X-(#CjR};kVE6gic4SK{9698(dwib z>&kvDx33uYC2{j>7gQaFY{m*-9fA(-kWibzsRi)KAI^U9-o4n%tRn%rb2ER+l4pt* z*YoF>j0V*DD-TV7#cX~MZbYpxO50%Al9S~o=JtK(oeB7ZPxV=hAz5r_=EUXy)NYlyfhfbO2!&i#D3 zw8a69r1=WAdjPz3a-YNa5d?lmGi_3xM+VurE!t~eQ0Yk4o=O$^B-8G4>{!$}wUGko6uUb4n|evc~@hd+z}iRTt&?s-Tzv#Q=gN z6DkNQIhKNgiV`Hp0s&D#5kZhx0t%8rB}gg+$vKIViVR99f>0zuKw<$!DvFACPJ!Ro zU-!IuYu20T?$ z!3#T5@%|}q27LNIPxXuR@*d_14OKaVH#bR8TWXz;MZ`bc{k>Hb;_;+t-uA74xk7Xf zc=9w1_oMxqmt=JfsUm{l?7V`2W^ovo#Y$(=O17W}qu5i0nz6q?qxGl2S26s>xSyPgFJ_rrfz=T zS*jl4==2v0U_EbRD`|YN^ce7c&Y;N#&WqW)z zw@T1!EBbiDuO%Yt>`A$QoZV*d@%rU!p(WRjja_muOMGdhVT%jgiamto+#qtoFuG=~1_=dxFBtfAL;_64;9vIb0>yq%1Bc+kIfckr=^wYjw;DH{(iNuAU* zZje;Y&sUSs;9(OtGM;TK+_i2;6$XN8jLIb%p!|as)RFZ(N?VS6zsD!}!9?c#$q?fH z4L{icF1Zv zKaphGrdW9Tw}@d&pAdZ^$=`Oyc`^wmXuIXL_jgnw=TFonZ+Y--Afo&tjMsC;p#fS{ z=Lx2U={-g8k>T?Jev7)8szljO2#a2_cOq&nIzRx;luGyt*cv@#AQKs!djkAztOce` z?k1EjK-K`5cmehK_{Cs4S;GX)^+oPDWpNBLPGRZdT|SU}Fmwtu zi0AQG8uPGIX(hW@?~<%5mPx*F%;hGQe27RnLDz{*^T z0&AhW0Io0eU*NN_xS|#K0jw#S9&c=#`O^vS%N4kEX1QKjiP-P+{a zQE@YwzCt_gM_<21?INF6#OAN_R==LV4>TbD5tqQvL@C#Ww6JyFL4^Lj&6}87>lLu6 zaeym27lRdKeM<}wJgCQ4I`^p1Z@SPW`qHw#+YEJWbAJ*3ih&Q*W^>CnAR`e_Gp(3i zZ71-C0q4rd+{h5lNV!_(uegzMQ$!maq9B{t_2ny_kK%jK&_MxJq@4JV6Ti5ptdMr4 z_33)?!OEXY5R_APOKsCkJs51=pb1xP9BI!WanF!kliOIx>Vw>8SA5yl{K>)qsE<(} zPv!M6gPY-*Oh?k={C1uE#rdM^;BfeL+g*2e`wZPt@;%7*>&@&7uBQ&Hk(G?K3uzx} zL2c8oPBqM5KKtJ?_4(=C(`ojS@r$L*Pe0>frPCr;pHw`2a8c36_%insCE>*nZ=(4= z{}2=7;J+&Tp5-$?J3-^C>Ve_MoSeboe9^a=hQov0Gk%@k{aBKjS@}k|Y8u1imPUE) z6*k5)`sti%Io-2e^4B=edDlIEPUp|v`Sa}jd9(g+A9wckoCK%>ro%WCwN~)iZ{fx? zlW4vgjyB$$j;y8`!OCOPg&+bFpdkknT7htB@RF9oBb$iT`b<5qa52SZxCY)a@#g2x zHC)r6DuM_;Ow+JVSmhnWqV{(m3%v8fap+>mnM64`^!@dUrzu zjL;G*liD>;g zl%W)#6P3xnVOJ9Gek6*u<(2esNM2u#8Ro6xvNWn9_q196qU7i zb0EzL%GPk!DlwXn#MPdW^t2et+ZeK!t$H_NvmB_|Im#T<_lixZsIkz{x+x(K4{^0o zxAd<3FDUY|cNR zSy^34oiQv+vma^YN-DXTku{}&+Fa$aYa?vVXV5IIW_lSoEuZ$$yH*zKHzuV5C!ocb zB$AfaRs1Fs15+;UxoSGHE%lDiI_zkWrsK);S*R?Ogt|6jx@75`xn4d`C*Rv*`T@j} zYp1$JfaVz1y0aY>yLS+>{7*T4*jh>$EL3CI9qaivzk}HN{M@^ts6*6gsEI1;+yE?- zP)~2XHLzPKgIT4t@6|PK<)3BbUEP|4`&wjzvp$zkGq^Q!I}O$8>jSsp+(fDGIxcq(R7r4FHSa#ou=~Bhxy3jue%x z5!MJUiTsGt%HUA97?b%jrXQ0E47xWSn?Kt0mj?}`Y`R@#`JQy zHibjrKVDEL4o;$~q7btL5h~5LBY#FDWQcXBf~ zH;|}WD8w8A4Uuq2y4vvkLe=ulzML`LQGIlK^$<|OaH zI_4LFn>k%r=va(&T@AO;tYeF0DN})`xBeXP)`lINkE`oHBGaN!RE1S$Y?dv~CW+Yv z%MH)gIIJ1$DQO>rB%tq4WQ2 z$iZHe!T0Wi@04)r6#?7>vwOxZ$vzr?I{0%B{yYbN-i3eX@qm#C>H*^GUlB&!M4Wgh zP!p6C7u}Q61%e&ncd%t{wC-m2h-KVp8MJMAWo0cJ;q?R5u97cxsh;@b_gtwF}`5HMmj4LlVcyfP3ZVM8|%5Vh-(Cquft_~Aok9LR^9ydC#66*N|CfI8R)n#oBCk$&rwc?hWsH#FQ9Rqi#uC*e(7S?(&Ue=ddD$9Z6 z5_;m~w({LK7FiyWa~oB=UGcV`{kBV=xvffR!A~CA9V(P|s)k=0Xik6Jeh_uVZP$>s z#l#MD=4kzfI#dTxD(2&}*wQ`UCs>rJqeaO_#F_6^{Fpg)W*G>!HjZu&-L=kUZozb2 zY%E0W-l2Rm@1KQf%Z_d;x1}x~)@&R-`NZPMS;GcFeZJ>8=b(3p>Pls`C-*dzPgi!` zv>QJ{SHA6jBDSTT(MBYnd19Uv7`vn_P#B$lK4Ahza}_xZrNFqNN8KQ&5T z|K6xWrGG*;H{Pn_N@zG^TDt?JN^B4H+Y~nddBb-`;r-g0hel>jNq{rn&11WzG{}N! z9{PMy<2qdsG0bs1@aXT2V97`SY;C;xJmqaaIQJ{~<`Xqt8dU1y9L@qP1WJ#{!fNKG zS*fFXV-%}X+HFFJ^oiAU`{9ZLLX|=lxs?~`Wdl5G^_7Vs0D=JJ<>e>B!WeQ!4B|u8 z;A;yP>nFQ=BpXW;uHn_f8%E$}9ZQx>xNl5B2x_7{@t7`ee%=Ri@~>0Vo`?d3U>uG8s1_LUd>T)jrGclp`dyrT&KJ%4}z=BpqvXD3}MY zst?IYTuO{!yoGB&{^ZD?ZvMUR4V< zeND_e2=6$mz67g(>g%eOJAj38Kb|C&Nz-~n6auV4!4y^tW38yx=CG9V`vigF?E81T zOEA=yju6>&+un%nAYW4u+E~h-LPowidtF6mq9qShOLYm;#AqX|8Mo3fQ}F)hEo*la z8#BrjRUA@iu^TKcsRdR7_^60}G~1qd(JyRX&6o9Zob!c8OIuRDuKnlqUkC(`ovi5j z>D!iOqRJ%~i=cnRl=dF|xyNFoWl?N{ulOORdso<|8i%(%+-K+WIu3;*S?2%9L%2A& zQI=Sbh6eRil~K24x2woPj*q5=s2bC)9yB)M3#~JGIJzh~(dso7#|=glG>9{G5U}IL zXvo3S!F76VG8$bU?yuecFx`_Oy>xNJ?)XHo@QW(K?UG9rzVgpbNZzMaC1&ISU0gdk zEXZBVcXgP+9RkLfO{HE(v|*yH+=ZZy8ZxW0V=NoasxAr8H#ocMA21S*#(dxT%&!Se z;ks&5d+GXeSmj+1CCQ{c;eYhX=iB1F=`-%9n=n#>!#aaTjv$K$K8n$IGXPfhvZc+T z>#O;7nlF5NpIFnQQS=B?MVWNrtq-FhZejxxVxuE>EWlj3dR;VE(T{@?;^rguH|Ie- z8AYRc%XEG7Klk^Hr@OZVQjBmK*n2t??74sV7>OKBqoo2%4hMH{tUdqg@7WP_ih3>z zI(3x&)c@tHX+ZBNsu}TpQXf^3Rb$N@#Wp$XE;_{v)EAy`dd=Z34J>6KahB&N$nkqtjq*Q&V!8cN;KJ81 ze`l(@8Rl6wCqDiTc)A5s`4NZqzHtR|j?8auE?5COLcOSmJO;yJG z+XT{W*Id*fVupasVW@0f8GPXI(EaYZKp&9Q=Tq?4x1bHdSvTD0=@<=KNW0+-0a|uB zUjwN14OR{ikatkgZTYSlS~eTqPZq29U=eL{3gPnv%=Q>8509Ks`6A+s=q zE2$9S-8)Sbd`jy^oDq3STg{aeQ9~!1ga8%tvhF%A;VrkB=akOk+OJHPSFM+MU^=VP zz37IHg~^(cZiQUK)p{odS**!RQPPTifg6M9fO-vCrW#D|)9m_)QC=prsjfsDVYGTz zV`l8(*95p1L(W0Yq%#k#eVf9Je}!u=9fo4lk05t^L+#$#n6k1-!=T%;^Xkm;Y>^6d zQ*#2X5y`t#8*%dR;jmcAef=8!Nt^QdY<#m#(-h{$RvtuCNyh2o7wfzS_Xai>Eu4J@ zs2g-?$=~Xn-oQ&Q{uKfPur*}q2#i*NHRe~$^d#C%r?{@r8Ud!=#$O73-=b^e9{(Pd z37XP7zALZ#L!*D`2M!e3-QE|}BM+P>H2E)5!^1jb>ZK%jDfJ9Kj4&pAeI}d z{Uk#em`3M=e`@N;L4uyhe0ZjKaDCN?Kh^!A$%@fNb8j=VaQywmbBQGtAg zJbrW=atm?sAb;69{so`tT@Uq5^2P730}=n#(G&l5DH{0mQ==2=3PmYz*we}ORh#w9 zx&Wi58kj4TIU)!c0+&ZCOMw@O2+I=@!Npfox&zfOMf>zkj%}=3aA-e zCpXf^78G0eD5DNs=kWWBap8YZ%!`pBLW^?Yc>MH99SMib7yQwc+;rFkMd|tZwELZu zpatV{( zv$P94j_~~oy-B5AQaZeRHQaArag}xK>h}^z6Qm#^dQdI1q>ky0UZk7mJl6Br5i;KW`%zL~uZ_o_?p@9ndl2 zgSl9PHUSjY6V7DIbo zYIp|Gg#&B=kI&|$zLl9WX;rvX{yLAuuL)F&8ai$J0boOK^Ap{wI0nEQU<;mbQTvD} z1Dy=9Mu1bP?!=*Ik+1)`jn0iBQB_dTECEJ0@uBAiLY2bF*15C!2gLbk= z<2k@*c-_#Z%J0`{Y^zb#NAMz6B65$V_f$d4X2)IK#kUj)lA~+I$>}}$&?Hg~q;ZYz zH)$HBlbv2As8N9c!OezAg}5)1{X>|@N4Fgs&d+C;9n+R2Ic$IJE8?ommzuH3itEO8 zGpiLAar*`r#!oyZPm?(yEJ`kLd170(ysDg`{`{24XUFs0k3;=YepOe8C21GQ?d5Bd z+$FCT)I#i~$G;qj-n@zRcKx@`^X>Wi(=LObng-+oo4L71c8mt4E)|7GgLJ|!dWK6I zQ`~_;M3Ri%=_BDUEuTny5BKWXTJ-=Dm|_xDC9?T!u)*z!1 zxs9yqc-Sg{Cvj5RyxKlAdAY+>l=iCju;B$GZQq8hdj4|O1_9WWz} zG>bPbUcg6+HicZ=Q-U=>w&5lrgR9AV#Mwi<%@?`-p?6U|lAV1W-}js?0oxnS~zZdzgS)`6}Ib*GI=f3Y`I)~-Gk3xtN#iPq8= zt*#55H= z6Ju?9?>-B-E;(}n>)IXSizN>{LSK!el+6TWWY0_@|AJhsqU%0V_42=n%JzMkCeaZc z7wYL`kgPH~U4-W){ffIcj(We|w=>;rd*f)`N8;%8a9ijlRBZq9VodVQtqZ`R_#qwy zCBoBsb=(QJKsX;QN)sUvRT2L0&&8zM1(eDCKuwEoIJq^0$)Om7ux&v{4Z=WT`{=^_ zY(fu4oyw8@?EcmA*IF3^??)$6ve%FFZ6sF{?y>v5{ zqtFroKRhIG?f)`H2Jk{0LkSp;01f3TRyAm3wA$^yccIn!6QXq!*+;!n*Bmnz%kpy# zi$BWbo|ye~H~x713Oto}e;L_8mv;zpnWpYMchAhRciU+91~i=?WAJ$bF2tsRy_IPzx4?qSI{;H)huemDoiy zA#=?2;%9%rf5=nU@Q7jzswBGjh6icdn%33Zqo+=}<8W*sxjx-Tq}|i1*^(NUwG7** zPomCbB9p2D-Q4A@+0w$6o@`kdcocB2>B z4%V5r0V(+OzCP|3=d^`^-z&i&Wh+}ehs8iJgO0WUD^W?>FAdcIs9IX^-1|L`Iqr9o zL{rkXQksQ0{@RV6m;adSY_P#rL z903GejN+uYFFo?cA4X4a2N;dKH0?{~fQwH|$OH0piV869M~@94lA|#H1ZJ#?J%>%L z_T+iV^r@FMncpqzncT!>JQb#0<_b|8ajXW=w1>@QNlA&mS z7AnqT%b0nj6Z!Yn*;jiFBgsx;F#}Rkn@25b~YFok4E# zU5s?B{@QxS?StY`b-eW<_02a7sjH(u(8lhpYm%u5;0*__Nb$8Mkt)6l&~s^fM|E`! z{@VK1G$XuGi#pJtwTZ7u*EzCz5juKVot10&X+Uot&t0sd@{Kf(LZDR4!?$wlsQ`Wj z*f1l64j}6WR@Kb5?1cA}c{F+=uJmn&ccq|{MEMG_c==0vMS&niSXfPuUC$X^UoaAc^qBO` zd0dgK^kHQ9RtfcDeB6X*Gys+~rfhth_a(rB1-?cvr>_Vit%G{HhwEQT40Mlv70r!L z5iG_f=1nihf0LQ$8V%j^sN2eA^N-W?vbM6&^#c)O!8T~9p>G{56>IEh`#r~U$OLcA zbrL=e@MEYujD6BgG8XNq*EMQ4N}#Vv-%Wt4z{Mn`6o}w@X%@w#dkZlvre+*;eunMA z{+oL^N@=7bTg~6R=cza2H|Qju5@^oxM9H(ORtd`w$}PG{aaS`d=-HKq2>0BsO>~t# z@{l3o!VavT&$FhJPO@j#B7`gGoo3_9Fu!p@>(U1Y%ad+X0WgCD3_R8L+3$uHI8Su^ zFM9TFbb5Anc8@ITvpWgcwE=pelC=3%Ys}&X$rf@f)-#lC;oOONT)p8| z_@xAqKd)hPJX*Yr+-?bFr(~VCa41n7m+J{8>;V4wm1YmcW*fi z-HtyN$rBNwt99+h!l#M{zbN&H$z;ILZ5ImSYraF2yqsli)O5xq*qUVZvn`#Hl5{(R z1cL;XdU=sbULgiYwa!oXj(5>cCci5T2oHIED$Sj-<8c=3@VhQa+Xt0XXM{E&bPW0Pe!s^4d60fQ4i(3hYkjn$vHoq+ngqx26@gGJTWy`iSmP zq^N|b^J_K3aUT9skXF3++e>;R=K=NVkJtCi-&)LQnvSQDWN+y82!NfHXiJvaycm;|J7$y$4T=W3xu7<2N2szxG>Na-^SLJSYVa9Us6ofe8uC z>Iq(zr4Nrz=Boo_TX;`@TCuvV$NBHs$({<|?J`0Q1eBodNYq+0p6K$h^c>O?qRhq- zOl9RO+?+`m_{#P^SupGi!qVJGE3=~5bFyDvvrAy53SzyVB2x}>*iSMU-Enhg<@Rt` z>K#~*#5k;rrf>)EsWMrcnh5!Sz-j2Stm>>>pEzcZ+5~F+06-0YOO<|cuQM$YFJz;R z_N3W;%M)-lFge+Nd*qh+~*lGs5y48v&Cb%r?;IAE0Y7-BM<@JwjZ`q{6@a7F1%h*z-^}j>HYUEwHhmg{R;NQ4 zmv`!hH8#$c_B8TBYhl>d)>g3mx)A8_L_AqKS?vSQl&$PJ_lI)NE59~Md4#7Ur&#U8 zmJ7!>i5k@3M2!tr2Ff}}5034w9M+4x9*NnkI|jv zu9?q*$${N^c|&jA-*;~!)&h0^e}u2V!u=Fi?HjJ*tq&W%J_y(~IUiFJlXG;Pro_5Q z^^r%t!B5Svc316;9p|IxSogB3G@pD+D#%k4*syYLhjoZC-dYVyx%)Ml3Od4DgO2p@ zn7ig_wJrN{VPD<^;~86TUANv=Y)hSt+yy#o{i`!f{PX!|>VL60A`!B$~ba9q>kMRx&nS?SbpM@$dg`I#WTI~Pnn3g z>8Y=meu#3pVv5(Aa|eE<4W+`1INbAdQGEoFy5*~NcM**k4FP2ZB)SLH)l4Zk7?n!u zNWiGUy`H@ad*LUVJoz4nbbe<3xg&;U*FM2Zt~9Y1=Y;(W!s--5F4=u_nCYF?J)`^a z@Jg1U7kLw>_`IAjzfG`XtZB)~HthO3`zt!4B4p#*vrDI?LSn>FynjP7n$S|gGs?k+ zNq$5BfLYLvF*U;eOS369(f@EX|DttiL?q>NSL`H+Y&WNZTg#?VG^#QS?}iBMff z72@5dSJqk~;^3@xKGgK|1bl702L?bGBEl2fumuAT7brv$nsj-G#aXp{!*IWRj;UKl z&JWhUt0aGZZ69n3Pq0gpJ2iI-)&0JnWnLn9EY02>Ov9caeTq=+>D>!A$9+S$HLZ>h ztUqv&;G4$r2psPzL_!3auewp^xPKmdU|ZQi-!GN@Zc{f zwpSP#t%CG8zKkNjWwL-KB8PcfXauO=eMnq3@T9Gi%f2SveJpLf9{ZXn)JIUF_Y-{? z6ICU4KNL3KFM)Pv&tHDg@Sb5#VL8Hf64XgRdcb|>b3V4R}nu9Xa$X}mQh$-A=RRH;@p4cz_ z<2{4zBl&Wq9xbB2iRI zX~1Ufw?VOfk%Lsq0@WXO&DmN7hhh=6xQ0V{jQ=W?_1r8M7so-b_vTOUu8SNtg4j4| z>EgTwqEw>FYqWYgd!r|vUckE`U~_Xny~E8GFhzQYu+0u(TOC%DX%mH2fWu}|MXkC2 zE8B7FVJ9|O9sf#c7opXT)R6K|egUid9yBW8ZK`^rVcTUor6ZqC>A)n4n@X-LYvWpC zKX*vMVyaEq`xcuRN4~3fcIfp_UFzFsAFpDY%WzCPi9IwLxX(~tY;Y0?jPKHgYFY`I zAIA81SDZ0(V&se}VmqM1S0XMZ$7s%msZU_j=fT8()%X z)xnx>3IMc+Nays_&*VuZ+V})vgL+E26?+|#%UN!)m^nQT6!Z0(S@Kmq*b-+suNg%E zF84{@*|8j|0rF6lc;0pxbusdd#aNWV$sU0nFMe=K`<|0N`uM&0WzQ4a`gx#>4DXXC zu08twdwtiX>tU~q?uXn)?%wvP8P;|sZAMD-_wVaZ)@VfQz|cdbR(&mN0o%-EA^&47 zhq(o8T5}?14{fjE2_0F5X*tDbTqssfQ)k>ZMEvhMNQC}*xDLpC*X8TY0fU!qElJn5 z75JwRDCmE5=uBf34L>KN_Wk$S%O9_rM*QQ9KCL2Ryl;0oB!6n-e6MhD+x*y!JS6&$ z4iljI{g(eYV^$R$5&4e}7bv{<`TlXn?ow`O=pP;0P5*Z{$es3|dJ9aH(F{51JwM8D zOsiS(C=Z~Z1E_)JwpQ76fcPryp_l13O?Gp2n08tom>wN;?Fs79gM(UBH+U}3^yNEb z^^C@Hc0S_KFFm@e9VM2FitJ^K=s#c>4@nMpX|7FXNgc?xxQVRaHva){=Kb*DiA4U!(k}CZ`B8Snye#j!T)4c~uXivgf=#sLo%KUE@z~+Y zx6D`U_x5KydOf4bLK5t5G>3ByZwewc^;qTl_2uHY2DYtT^N%q?xl!??;xC=pFx3wj zxb80Pz`5QBPgm6>wpE=o({b#`-(1cKJ5k5(&XC?le$ZuoUXW>kvt;NzbnM<^>Kv%V z-aMs<;T3+B2QxUPaV|?QGz@)k9w;3e|Bwlcqu;A z$jZT_zdG&d_{fCJ*M}(`+PFQ{SgX65vahFqdp{TX3akO-;GzXC(a5YcX1E>ZF$&ds z;8pG&sym6`lJH?e^JU#HeISnXa$k4^_dc8Rso;_ur2~Nm<*iK+<)CD8Iug~-)9?I& z!23mfks5s`us?>ZfZvemH#hVh9u2jNVsQh-k0Ba09RXoS5o7{HBZtw*yo(p<-`mIS zzr=gb;tQ(cd;72I9h&-&y6Cl%aU%!EpX!x%nR)K5HYvR&houy8|5Uwkt$s$i^t8?Fw zI+E!wh-Z;Z`WLtqiszYg(3Ri%x%82f^=-aQ8~Gj#T@7;UHKPk{f?(8LDq0|ExHLiY`J)pfD z%5=KvRqEj#yUw2#-upWFWD zf&0JoReQOy1<=s5ui^#O-Ok6O)t8c&8P|7T_utQBp3qx zH050GJtW(1dtm~_`C3?{*h2OhCzIB~qwJ9eSM1l%QUn?G4}%71siasWKhBHRgYWCe zzv5hvp#IX7eZj>m#R#j}pmYA=gy!viloD6gy2qzKy-(2K9vIN$s~98WO3zv_Uk$)- zTsB|7{JH6}I}fvESqDt_S8TRb9&7nDa@w{ng+3Eg_K@o^F_LMlmSyybKlHvvN0hX+ zM{J}%21)_H>FX!9b8KOW@qr0*EWB|s(! zGO@Tqe-0<3)Q#qai=>3Et(MXKK0icwD!K|E2k)~i^8#}m_^u)-6^V*Es$i=USmYBd z(~TabZ*W09pI2@!za$*~gG3ynf43+cI*@ff^-jnC0tnP>Od zpT2%UM$sn^M(+y)ZajTarF^Hej_-*0zjRnmbE3|I71{4rCI~r(vNI}0r$NikObosZ zYfo>gd8p*#jq5jmpPm!7aQ_2|a+))Bfi#4d+&o^!U&o`jO2?|x|Mpw0W=RvrK8s7g zxd1NgrCJsJJm9)iPdj_Fs=`{zwrr#)1t$Y>s9NN_a4qlN5kJH5@_k^mJdI0_-Fakn zYHcy!O9m7>w7vw5t3zbc6ltIsaSvWfR&3`8QKdYRRMkGogFv2R{eS zmO8uqC@sb3^FAsHdW$s2FF$7<6?nxeUg6Vn(wA({34MhxY|DOz07R~?(h4p)#d|9~ z?dY@LS&VzfaAJMoK zZnO}-^DJrhZU%qj;RC1KEBwZJM(>Vcc}q`qI=w&3d@k(;-@uUgVHetkBMFeS(T+RO zhpzwKRvr>MA`ea3?GZCkJN);)1WK{?8YQmybf=TFrr5`r9X^)!7>(go^xdvi`;Mq9 zJ(JhE!td?f{ie!9$pH;hy^coxpWHDeW_lD9fgEE0ENxQt42D*wNhTmDAJBkZxM4qB z{5Hk;;u;281B0Wd$eB-&oCt+E$7^ZrD~86<@ixV^`4_<@&y>@`UNfX8_o!r?Kv;fC z4_8?8td9Le?j5cj3+FDmIdbLOO?H2)&!zQr=`JFWn^CEaHXLHfJlMA5DRD!}8H;Qa z)@AkyUiCVRY0}Y>ceYI0Ts`*qtLMW6_h|-(W;JP6V$nh);wrsZlB{SaePmk$OL5p; z{ylr{f7$JH*oE!5okXr_Q_ULvEyb$q?&kLv=BQV3i1zkvPwQ>vh@lUrZq%=P`A>E3 zwAeVic=<`eK#AKih8}D_@S4L6_+K)Xo9*XqG}*->5vMC+VYcXrgF{yq#!>VBKS#aQd3^M0{;tmtQ+87sRV2Znw z9ewE{{lIwA+aroMlJ+$%X%1WcG%J3Hzq~7r?yfgQ6e;fB<5bI`5LmJQ?~ACA0we|| z)#k?8xks=X8*EnxG~6$(3j0p9P(TFGc^8YDyo+!5UsK6L&l#}pu9UB$E5N=THZ~rS z_9RXgUxMd+NmvYld0l+=#VPsR`iNt4$QaY?RJSw^+x=$2+NesM_hjCnD$kqJm{k#T zkK<-l(A8@1-nZ{~!_7Q8ax?dOKpzA@O4Cf{;njsvKaPAzFKiCmQ+Ms6mS9F;2OO9fpWu@p+%MQwRKyM4Uj)gk|4mar`}Btgm8jU43Xi44j7h#d!f3L@=;^dmT7_K(xu7qZDi+N-q}*+hfGB%53KG9qN7`zJk# zvf2|>Iq%zE6PNNDQgcm5HW7uqKdY;}pLrqF1$q1rjlJ!jQ@Q_S^<;p3!0<1ZCKFE0 z$U^D4YgsJA6WFleS%aP(u-uV>hHcu%;tY^CdcAEAb=z`y8CDesY|pqXp_1_Dt3P+* z&olAoRroU~{Qq_=ytB43*8JfMNd>`RYh(IqHJW&bk~fNQ2a-zn=yWXBn(me(tQBKM zMX6Gbq)Z?b`25)d00NV;cnzP`31iWasuiv;?5Uw+u~!sk+^eD_&ItA8l~kNys^v@uYcmf9$2#7xfw(Y{>39TU zgM8H9YGGLxDyLnve_H-k-W-i;d69pKA(dv9AdSJYuI@H4c!U8-3UuqTsov1WPVvh= z_C^5@TfOn>Z$h2;bONjjGUAnP#7(Qi5KqZ{TehKOV9NYywr?h%M-cj#Pk`BZj+&ku zUxZotV(!f*XcT5_a|SydCX%vgM+!w{WPZ`5@9jmS?;Tb4h8>;YNO!SL$;gxw0FIq5 zKhSIaJ>f6MhgV$#=Mn9`-?j@PTYpSm6c^G2#~4MZ+?=Iiymq-k0V@M^DFVfF5k{kq z@!Bn$CVI`;o8hM+I?Y0`I|xkd*!G~FvQbk&^+HYH_Oc^sL?gsEWTG5C@5un`L7fX9 zY5Tv!MRu)6t=s4*@U~%!i$|`9cSWOo#r=w^bU!seFe0xsA??kmo>Y#F`CuC}FNiqF z|4y!O&()87)_lc&e!aKeo)YVvXiiZERLo~IBFBBN-EOq&=TGs*16IWiu}=CD@e$tX z))NxlG!*q>{z>7RA#r7fdp!9eWOlOa%9b%nCR&JFtlDb-UL5Hk^{`}Hqn*6VPt^a! z?Ig*@ytxpfYbt=8!VPK^Xxdf<%~P#$Fn8$TZ6C z=)*mhAu@Udu})tj>9TybIx$1F{;0T8sI6Yk6|l>cMqAYc%R#`i->wVs--8GiFvM36 zcC&03X#{Dis%Li4ixEd#Nl$kfXU?I`lpz#A{k-<}cKqzDmOC`}iu-b@pTlPixd0aJ zEPB=M@Vrj$l+lXvwCSni-Vz*(jq}(o!Pq7ISXOy~TjZ{2YdNY}E%e4jw7nZ5VZOUoKtBe* zmZ*SLKW*r!D}KgAZ;oYy7C{e`UI96Q@h`#O=I zg{R$KdP6TVBCuS$NaoUaaOI&CPZ)YOoHRdQ686|QL_^LyfI=p-nh^|T4Ll_V*@kvE z9*W7>bhTjdl0iO607jvZYIKk5!}A@7o^ARq!Tk~1>(h6li1hApz@wMrdv1UK%l%k< zcDG?r%bZsE=}!j(1uklCxueTzZOMEO0GdL5HmYCwY+}td`rl)7ru+9j0CD*{vKi@N zX}j)JPC_k)G5F;-5nI{iA>ve=m+qPq3CKR`XA>|~<{aX9k5rADdAb&g^er@TuvXJk zY3};Q1aqb-?V}7SYy|zj>DX=CUpu=PM)Zz5iAUQH?@M4ZzSnwY*D(ue_8%Lpzb3;V zJe;R-1K>*(R6R;w_qU^dc4Rtr#&)ZTV<+b&vEAA&t;xfni-FriE&u7lZ z`Y1fz@v*6)JOZZnf=!}DKd1-GUIlT8CPTDr0=x>cbRFI{FA{R&>~{8gW^CE-8NLcC zQS2nEM{RO5+(EnxC@7|tUsL|E`RiCMmHtk9DlPg8W#~8 z=D|U6p-5h#L!T0!J#g@AP9d%f>A^E)4NXt0&jRj$9+&^SA@wQ(R{h>n6WC-SUU&4aMTl65`fuoP1V~7_+ zjP$fUHF55i1nxET2rMQPM`~osbCA0yVjBHFc3kn$CRV;=q>KAgZfAk-#IpU@OixL_WCTH?JMxfCdt9+^kXj8(#i77m2if0* zCr!iYf*%Q{slW{Vqa!b}Kg~qbi!vohm3x z+@&M**}@l8{o>1HtA=)# zuERphxJp0Z3=y*m49s@#FDK5A-m+KO`ce zyjy}!`G+TAkg1sjWa(7LKw+Ld!KFVzqa^rq_)Et5N6OAB;jGE@TZ!NJYwuP2hor)M zsF@dGi5sYt0;+ullxhcrTA-v5E?Mtg`53`r_4;y9%OsEsjYNjI$xzp$p##7WS9f~| z8B>3Q3)_exFxy*!*dDhd=dLH$C2i;Wgo^Dac4O%HG?ku^DKkhm=5YLbL$R z?+$^mf{f%vb+cu$ABLcH5j{q}Fl`S*6!XmMz5X40DwlX+{@?9DCSs5E=ZA0FUQ{S#lF&r!>$rKR>d=_1m&tDv23?QpT zig6EyWiNo&v3XyS5gF zzLTQ5${cxb=u3Aymj3f&@AzsOh+AFKBjD_<);Yl!jZZ7v43~cUun=VQNrLV~0WrHA zZWC+c(~eb_uD$RZ{aRG&O^?gDQO$|Lkq7;BAndL!1L;Gb>#gT&_J#XwaYdAaXE^N|O#48H2#k>HHy07%_GXRNOX^}l zMmN6stkze=A}JCnJ30M-5NXTpsyL3Qqb3iouzQ4!5^==n?30+l9FCfTDw+hig0MUB zc_@!h^V@{@?;f3*M#qc)_29}_=7tAu=lDc_ltZ9j5n*pOc7o^nP1uD7wi6cK^oO6l zqVKo6&49aD_f{k0{vol&W;VGrZ1lTVy2I&W7(ERLYD2hdzL25diR)a9Xxq3^E;Ud$h< z_=>5Us*EEta|-8B0QG{d;+2QKW!<$dHhuT2d|XlWsIbs86G(zMziC*iXP%$4>kE35 zBPb+B*L~bz5@IkxNUmmXX+Bc3vWg8vZWZMfbe`JB9#x(Pi}P^avbnU6Jd?m)zu9-> zD6n7?w|``a^3FrW5x;NAMegeK4&<<(Hqg_5@aEM%RTB*IjzYzzg{74hC=-WIK84-8 z?+%6+y{&tDD{v;Zd(45C2q;Z5v;IDxuXV3d^RVbM$SvdSoX+)xb~nv8&tAQnQh_5t zEu6E}y}d((iHZ$E*y?-Q5y@yK#PMm7M-k1{Yp!(jwG`(*-7zZ(t+9f%ESGgECGvyw z{S^RRE-p?+tHBYT$F`$)BIc!T%-w5tn8Wn*FX5kwc4QQV_(oLhD>n6)j!`n5U`Wbe z_Kv>~|8MNQ2Urx{*6%5zfS{nFWC0V1NR}j_MHEy(P!JG=Msh|(GIWawNH&vc5G5ly zNNSLziS65fn-fOM@`YoX+_-xYp zrDv%QM$)Oq$J}SWA)L8A$qU7BXEc19)<~5s4u1kU z+V{=m3xbgS`0C~iylV#vU%NCa>Pe~&={&Jtb%rs#qB-y15pe;k zv}gi;ezvVtd7eBE<93@;Rt_yv-tw*^zu>aXj4bYQM}8RD6B59PttS^#_g_iM28g4qjgPN(`+ZICi zAVnZ-BOVVYa^{`Z`@;hG9lu%Za)7&o)hwHIPK6&35N_26W+S(fz7oIW`ev?G<;FP3 zm-ibEB5Y(nur-(|FXz6QWl(;oj8)W^C3hAMT45;t_90}>0AcEXaf;u3X zdpmioP9S#!^7!RrACVGVzRQFi5mJ4C;v9S_c5>U&vUue4$1yI_M}=^t>A*-UlJ~56 zL|cl8m?u$$U;KQ0(ld}i@SHp!2RlE|R+a@<%XfHlgV&`oD6X{i-;N!@ZbR-gzQRJKLG-2RvQzP5Hg6)FbVh~hG*5DU>W@2SrazMd`OJU} zQH=LxDY1X7^O=3EY3|Y{5t4lSN?M6Cfz>8?QJu%QH7NS++hi-_I|HFMwhzMgXZZ}9 zpJb(nEZz5tn2+^}(P_h{`(E2L_Fx)1J21rvh%T?0^X5ihD|B;%+Ub1ISG6}2%JZT6 zXi`I7hbm@+cUCD`DYu)2VS57z>*vQvruS9*ktBK2E^cl@F@sw&C8HQUE758l6!DP@ z2QX~S*fvsUufJJ!We0J$OETL~#@myyJP#)`+QOfYHUP~bDc%Z^7;+4-TqS>{gtzv`-Wbf95^kKYvd9FgNd?YO~iZ&9<5weWVs zFKs^Qj!e$lTZL5z~zKf_ESde_aH)GER3pZ+I zBkzlq677O#6~1(LPujBE&g}~b2XD+{n;wjtB`uX zMs3E!RsB-3X2)FCIc_$_UjARbQ#HWF2EdE)8FD$cYaX{+q4g17poFMH#oFNfKubP& z?$+LS$z+34%1uCJ+B!cO4&qW^DF8~(XsQ@+JPth-T_w~2d(^13Q-80~Fq%F@@;gg_ zP{J<>+mlseqtVI+aiK~s<{L9p4HhV)(lOYJH6%z$lRvuxU&XEEHZUJ!7<*8OtTPDb z?@0=k@TKr#f>s;+sZUmFV_GgPehu@3eB|0X7G*KKYVA49*op|n+0sQ&bv-b_)SNWyQ z-mq_T;Cje2T@;lFKmJp`Su<DPqq_p!*>NiOA z$5_#yp`KxTIYud}zLBS4O#`AcA@|N)e$b6k)&Um)qn!Uvlj^%;TP~D5Cw{Oxp8vx^ zTE9NFBTeyEP$_ZluHxrXqNVn;MsCR!>8-_pY)H5~@sfP~2;6J+Zron-mX0f7_NkLc zA4vPo?<0xlC<_u%>Lh2U*;bnrA!KR2%5^#W2tqradM?|=*(B0J)i=9X1J~wxl}_fd zC*PG}mKr6t07LIru{SzSEhjAkE+e_dmil((8KXMsVHQLCX_GtnTTiUeVNfDw@~*_n zEgJcV6Vqb&AF0n5!=OvT10~E)8u75>@h@i+I!DhSJ@CynKkcVdFIcym)Bn(1<KDW#K{_M={s7vSN{%MdlWV0g3?msG`+<239 zUc~7?&S@`XS!eoM`T1dXY>~qi zWo{&k7X!#Lc-wyPDrS4BE)8UjBC$wlK1d*Ao)0cU5C=vk>YD@4Ra1BZ`R9-< zsi@0TNHpc){u(o^NVl?hfzW4oI9GSy9e^MbnyfFtB;`|2#jIY*_(yC%m+u5?q@OYW z?@<45&0`a1LO@&l@_R*C7J5JI?_T2KL2`bqOHMQc9{#=H{=Oyv=?ZI;qHVEzNFsJ1 z;dnPV$!+sj!x|om3*T@+2O14X1EY>kiclOZ2yj|lqZ8L zfCFa_Tp=O-vfr$X$SEI1_OXoZ?#SsrmiFA&(|hLJB!39aPO2ciNjZ|373SN_GI8PC z$YyA-IVfFCzupfg_2NjnGG%nBa8fQd55aoAl$e0!ya4RB3&{uwfMlG@(^m!w4=3|u z;>fNb3;4*+dyp1Lz~7>BY1&g`JYfWiRG?3_%7LDpjCK~pIIKxbOL#^xW(f_?CSRF#*x%WxlJ(`^XEiB||mT^YDVk>j4G*|Mo zhjMSNbH|Z8FX?PtO%6IN@LJCD+itKd`boAX6>jmV`Y9a7E_t(pMdTt#a3qkUtVEw( z!p34ZnP8!oHVpU_DhfwlpFcjx#>V+F=Xe(n1)ED^0DtCnOB+i!njbe*V-8vN`*D8D zIhdG524m2P*quyx!t7DPWCTRKpcJlX{{Jl^9K0AM31^>sd zN4-~^Ks^UZa6>OM7^dyxl1D#sHJ6ji86&{Fxs88rxx-9aOL4F_EOTCe1 zI1zh^i)S&K-{MstJIeMPV(w#3v5|R|J}ZxUSO*jC$rgsO2fgUp_WcGM7k^I9Gpuy8 zMJ&xcC;0$uU$_(`8jc;|zu55OH*=y)<{6ddvn#{Di4t7JU(wS(BVWCsPr1Pd!cXiaVmEOm= z=26V4QFuDHW^+QG4eicqz2%dQnRztz zR8L07)J&Z10T0cp^qJT_L$Uwy9Jc0bJBF8EF^hB6NHc%*7gYkUXzehTY}tml0G7pL zS_62VXu<=ne~hevhF@V$no-i;TLC(EVq693peJ2=7AP1b#23i}oKtMhf|5f*1CQr0 z4PSw}=HD{DY!@(cr5-r`2j}8avDv+D1c`lnrQfj=xDf%>0^&)4+8XZgJ+L990UDZN zl849oX4v=MpVxvlb7SKN?r)w^d%AHSMPpMGd^n6Uvo~OyOu5k4%gVMX?)d2Lm;);6 z{^sGescWH~1urO3og;{QA@`Yj;!ofR7gBgl#34mzq&MPPyp> zgIevcTDMV?SNV&UxV(Be7C@kr8RU1oy*}+0?xu;tn$Fy9JM!Se82swX@q};yoRG2< zuhH1rAzOO)XO#%^7-rV%K9Lub5K*XR{Hb?k!_g*2KCv zz-9(-`UoX2Ozpi5y{4UPrO#_-E>BYKp^VZi>@b~d(hhR0%(I40n=Cy)ltSCaPjH=A zcRIwv)h*8C+DPiB7~ZL(qAXupBZmgbBG*jf?y`RU2nzPG-`pj6W=9@JYbxnQs*o_t zJbNjZ6Ux(UNY$rn-j?LE)VsSaT?zmAUE;#U-i_>81mua~PU8S-{kjV|VH#~o^-)i3 zMmKOjHahEXyoF_g(;j=vBkVUEh!7hZ81q*;|4pwf6s+ zy~jEN64ouE=k^n6m#B@XU$f?Dh`?zH8xJznXcUfS4j-Azy!g+gBl3Izb_W=wezP_? zUkkp96N`jxhCC7szsj&R)b^iZB+RLG;gT?_PjA&p_|Udy0EIH_M(L)PMHVvF;^SzA zUa$;@jOfv?9%}=Xa1VV#IbN<24b}TNleeo+_N9 zIdUV#kSyYoBY6;R?Xe)fE{6XzMPlCz^@r;4@25zRSTVDJy^5)a^#e*;_(d!N1e(ok zQ{!?v!_=XfOTWQ)nlgtbW3 z%AKF_7Yxg4C2@DYy02l8WEquZ_ta*Jt6lv>SuJUYRhuikZ`J#LX_ffc_KrHynp)TH z4UPfE#bpwfhT34Hz5R8;Z@B8=8R9*YV|=5}rShE0%!}@hXi-NC`msGwrBKK#wz)Lw zHE3DfrK=cZp?)1eBz%}4O=b(9H!~aE*b24KqV@ZgZR859cf4jm3YxI|cj=~SRD)J-30$-cpG1A(^=kQ< zIs*!N3H^r-TOY=d4ShA?suPEzg@3J`q-T!uS5w0j7?ALuWc>n$_w>s**XjKK--br~ zTgeyb07Ez#`;(0N&8&bh$iR01Z>iR!mQQAT8G~@3k5|-U4ZPKrt2li@9OWj`j zmpuDoPxR3I=njfnGeU*A)EF(tjAennu@{Wns1&qg+ZoVCcQw4u*m@UWDlmgrVF5NO znkag5bfy2WmU9!fx*`*1HpYRWj{;4XUYJmp2{nVrWA z07;jhHeLreH2b`XHMvG(p3bConjEOaDY-s2dluP6RwC>PN5>(*WO5l(p^t^_%DVae7#enJO-3%Z;@Q-AFSA;R!9Ro z2w7WPD!jbE;$V(Q$&LpqyD#-^>_bBj_plXCCRhJcY=wEv$C84cCiXqvALVedWKJs@ zZB^&;^qkiNJ;KkU_OJ_U0&ipRttBew(|^+_JiQ2SMdWPs##4G^Vpv{WHW6E7OuP2f z?uN&)8ubiU36TR2>t|B`e)RWB{JkgsJ_>(d3jgcA3j=`ySn8?{Y0kk&ttI0rQ4|?C zhQT?s!7JU->(9LjOMn`;LXKc8Eu}(T{5Lg$X3^2H0ocO|4olJ$vu@BRA43lywOsxt<_i??jdYXSW6ltjsbr0ukgM9WnLzdWhO3 z*NMqQ#>(le+6rbmz!cjincT5M$gC-o@7-A$Z?o&)l(TNS~etI8eWNe1lHmXZ0NnV=D<;9vnsl3kUO|Xcb5m zHtQ>DW^>A_w!THumuZXZ?gw#Z8+Z18{lScf4If;s=2lm<(dT~7HH}p-9J^u)p%D7m z(AUHcuk^ueV^HJyV(CC2Pz+UEujM(kMsT7U-6Gg&SiR#?pp=8jT8m#?cbYVblvS7| zku1=5eV9vOS2|oBCK&Drw?hV<=(?7L<`4}o2#YsW-oK7v=TumHTbx!VS=cXxHdvw= zxxSy%F@0zkSj_J8T$|!F|2b`Q?Ygj#W`UH(6SP6fb#@f&wCtcF9%N|2@vas&m6%2h zfl^+E(54cVE?wdjcVNm%%pq560^4GEPe@Dl2|YNu+*+vBeHC+xWyrZxr^3yK?l1WN zpjw6$kbc+4D(z5U1s6g<<=Pd+#ZCl9ZJx#Fz&#CHpk?LpeTw5M7DP8W6K5K<`undxOymEQM^ zxEWWL()ID{I5l!7&D#g#S`8fY2>2Qvi^VQ%Zl-y|F+b>|^lGGr7rp!8fQ50x_QR59 zRA3BnuY7q&D|H}O!#2>XK_FqX_|>HF2FAA8Yzu+o44iHH znX4D8(Xa^up(24ofhu>TvxfNNaQlm+6q?&*P&NoEVW&-&;^oa($*K%EI_3j0`we^5 zj~r%>9KUexs+mVWwB$g)DNSVQ7~uiYjN=1bO#KD-iA26Ga$i+EidEf&m56mAR02K* z@G}Bw)S@`Im<10=upUfaaYcTBvrOGnS*>vk@M@gurm_(72hOviDVvs zK;hgC&Ex=rAKeQz{}*Yv5us^ly~3{K#vz)MC!$5=mV_Q3uoXR|I)aArkwobmkx{(Y z-@I=BF#iNTanR`fS)&Emw#sgVqXx0%zwlRiLK)5lGoBR@y5~AZSPi`fXAMw=PU2@} z(8Jf{kRBkGH-^np6UAZE+X~w%cW{{L=_~-GH+WR}=*!F!y9b+8WEpf?2xSze_${hd z;=ztx2+IKu&5h>FM|QEGYN7=w*Tn0IhMPi-vLXs**E2?a9`o}?-DL6q$b2nC(IvMl z;KU?<$#g|7Q=BLFLv-W_f*&~ZI#E=RzC$lz-iiO z5*NY`-^B3dB|b1_rvJ4vIT9oYVN4cp#|uO@_Blfa6a= zOF+LkGz~pO`8EbZQ-{2jaPZZzNE%`L=>1x11-3l87RW2=`&~q3@bIcP`$w}K7QW;E zc)5&xiiud?Rqldx$o|IUbNSd|jSGJo6?_xa&tD>)V|hJ{SGYtJ*gM%f1fsa&sWpW+ z{!2GD7$y|D3rP1t*+s_u#AGE3)puugaNp=rZwyk2+_E%Td!>)V7s78P+*PDF75JyI zoqMi}rV&X~Uqg+k&1Q5Rt%y+Oi&#|$#hv@V+xIbS;-{P9N#&lBZ2^^BP$NQC-4FV( zLFcsrL}jjIxjX=081|3#eRtUqO7&kTjg!MX&V#G#)KJ%38gp{HHBUtpOGY4|8BX6O zo>oF$%fyb?R&$xWT9`pwf{aC?atIs^N^Ci+GKqDIb5e&tbfFsWuE}>AA6Gr6&xj&K z6j>hpUZNOR8K`aOCSfmX=>@WCNQ(t&?&@OGZ<2Q59A8&$hfOv1O6p2y3S8BsmrjQ? z+^21;SEJf5ds{PjgS;!&>EFBShCwevs>*tn8x7V7lJmc>>X6~+w{5a)yA1~J+(NFO zesDj`hEP0o2rw_2uMjnVSanJ1EQEHhd|wVw7w}M68!C*uTv77se0aGb>zI|J^lSM5 z`U!(Ut6mixZ}`vXq>@p@3BwK`fAC^acWy&g1vMeQ8~#{L_bohdAe=}H+2YaQV9*@9jHRSfTG{z zt;sBLRqv)YXu*22qz6U$^yLucVLO3YtSMb_Bo_w`cTX|EQeN6^a~)mF|C|EK5AQal zz`YhF*DREsUtoUROMwvz&&U<}CgJ_MgWDUJAIMQ$k}2QZk?z_NW3ic{%VRIkmYTCp zkLg5r9=n&Dcg8m)Hx^}&o5it^1`u3(K#TZ`oB~%|HkgN{KhjG!)Ie)SxmVcXkpy!C zYz+P250{ksVve=pAeA*8q80Ipgzd%CZ(f-`mFRv0(*(C>4>k$YN9%*Gd*JryXVcL^ zk|ii|%{=3)Mzc)DS-b-{3sEU{>)S}H{o>byaNV=*#H2=(Q}tKE2H}qkElDDxH{ist zpbQ-1A*bX4oQl(h3%>6Y{WoK_5c?(HQcfRShGgskFj5IA_*{T1Pm`u4N#c&5-5OS{U#mzCUU zzV_!rxjWi?=jh&f%=2{8oFvG;1|LWK{rK-S`FlhBJD-M9c{z_&D-P{AsL{ps7aPwn zdReVi!cu3291m>Y0&?w2JG3!8YKnjuq5v=aF&DQ!hR@OSU=kZr7+vgo&r6IxalXrA z=f{cUqqpfkAYNAFWEae;9bKf_9)h=S@Z-!?2H$@eEw3RW zfU`AX^Kfs68T?#`$w`JsvXpD7o8^b;x^ZevD>U8wVgc?Ar{Z(o=NnOkI{4gZ9aol0 zQhXv*f*KLwBQp8CraPQsL@|xfDK`ixRZUNKd?3I&aTCY*CiTHX_?yb`NCGD9-EcsFz1!; zm0*lpP2{0{7VPv~loP0*%m||+uU6jTp1e`br+a;^SlEiVEiIXE(wxn+H|)uO8P+kz z!|8#un54OS|F1`X#;u-EEeBm6mRy>;Lhc0A&0Th~H*b)@U31zAXL}VFdzkJL=>t3( z{)y5_>3MmaPjfdum}cpf=^(k2I&ZyG@G!r1htR5f&s|g-A;H&c{a$M3yqE!30oP{e zWZ{zO)P^~O4&&4FC-zOtDZi`<96Z5Hd$0On5Ylhn89@q%5Na#)-5pCe zMguT{Q6$p$jquTi=2NwS0wRsvW~WXx=|~etWaJm-H^Dj%V*$Y$7(om?)&d~Jme%;u zYjU1spv7%6&;nYIUh8;>qs@rPkJ;^9yR$S0Y{l9>m3(nFH`@N97>jS(UgKUFdAWnQ(+_YA%McHHZguW| zZ6|XqUhNlkb+bR9X#9Kh{ne9@9-IqOK$$7wy;A8a#6xf1xwuEMm?Z_bf+^MnL8e#; z?Nco3jg6#HuB3yDUvHtap>W1}{IO@R8d!HeidObpQ{e`!uZpwGKIVV7!e7UZW$D2` z{|FN<*M~GMn0P7^)vwZs(lo$WOek|X0E~qQ(d|oT&Gxdxa3~U9Zv0$K z_H5ACwbSq>3dDInnwz~|L+q|e_%6IAq53GB*!i0+C!O*}zAq^bMMU%rg8K(-Tr>1- z`Oz1hDnF(jV1w~L$~s2A)?m$p4T(DO**tKDs~1OmhvLwR{x560>wDF2skQ^4$_mUq%)jamne zAwOpJQe6cL)T<<6@A_t%`}sFF7#6+#z8pBXon=}mkpR}INm$=`F>|HY(HF@!)F(;_ zmCF}txg9IXhibtef=y)q(ArpAS3z9+*0fon#H!uQ82;cQsleI@A}(}fl=WIj>)l_} z>s*4WkanO@24LD1I~>bG4`$vMI+9G8$rRW|+zf?pZf;^2;hK+?isn|+##Nl410s(| z$<}xq3Kb-m9EPz#r?>vRd4%hz(yJy}4P#UZf)qGVp-3RPI+r z_&Qyt8x{QXnuL|8;?z%WxAmu9>vnU5GfKQNXhc{?S7rN75OO_y#(xH}5Uxhke540T zE*qRLKV#_Qa`eU7LQ?+{aMa}0DqQ?3{)ziRs;YTA(N#%p|2}?nCQniBNxHl(&&lp?;_B}`~3z3EIF7p`O&H~HxLZb1=IIE^-@R=8UT7qKa z6)W}nZSsv@KpMBc3%C_uwzvl2mLwl%UklY`0ha^G8sD1}$Pd=f^ZSk`-weKos#R|s z>WMWBIoRE%GPE}f+)Exg7=zv}1t5!{709K^qFME^3eUyOmidLv>NdDBP_HnX$~b$J z?$mIR+VhUp-wpTOnVy$!_XBJcRQNn!N4*fMuMCYaP?`xgJjkaX-U!i4D%TC!f zOB|#&>U?-ZpT6&Gvd&c)r;%J7o-WfarjGxW+_cBCTJSGcwBNR`iHU!;Vvenoc;#0m zQ_9bMQ#^*jk{kB*lEWHj=V$Zh)z@_JAK`Y|xp`4SOPTHu83igd&IYGoivv^kENS(O z%bB(_bTS#=v=Z+V)@Zmn-k50+MyB2`WP{BiBmEz(cZ9TlPNorUC)4(B(XMn_{+Qh# zt?B#^Ew$jX2WhBHS+(GjyZZ*uQ2OP6w06>+&T~tL#JHssQ^8h{{-e>nGADoG?rF9j zuJ8jtC>~MujH$_|?L9?B>5YF{qc?B(U5Q_4!gG8 zY=!5VAd%?sV^<|+Dp$z6W4EoWc-h-woEDuTEgInDT4OUUXC{d{9@-rndOv4+}u5%;QPtVh+TVC)VU~jejLo zLq(6yCTS#$wA2=U&L4lcmu(DDXE<(r>SPg0fLpS%E+@6)imeR2gq2qvbl1YKN-&=J zNy1QlF$Q?B? zlOe~PJA3aRWsF5}y~c^jXp!Ki3%2+f+M$0w=1z%VbK^Tpl>X6Rw$L9%D5Lj(93{+0 zztKH%p7GvmI#%s0)bj{t=Kh$Au1ZZG8B?Npd0KgJ&JHP0DK@2RyeSVZ6U0)>77O%1KlKiDdyt>TT!IQ&HNjhlufI zDU0s1DS54Ko5dzKVxA8ep!kW6NRcPP4z`AtL`>wXBBoQltmngc`i9xW`3GEd2m|%E ze>=r27<~%s^ICN=lIL<5PcFm7E;;vs3D$Ka>9>I!)5C1j@O<@PjV^g+46eF&w<;CW z7hw?ma{rwo5^+j-zrwi=f-y0R?($-Ya@U#ny<{V~;w4h0q}_(mBy|e1_0%EJXnDImDFW~JD9fYrEUdr5eL9C}QXe#2eFC7O?jLVj!`HkwNaptyD z%MdY1QPGgDliM`0BL$>{1l1i;T(~j=r!LU|u~P0TRAV`@nNztkE95P@i-YRf_Y2mJ zT9WYdGOnZ7yqz#D^H3P52M>EJ2_g`?B0XI?>d4&qy!Uhv-G#VN$_&;^+tQ6kmJnoA z1&>qze6VkJYbA$))Y*{^&i0m$nDE&EQ)B=THtqJGcPrh_h5I;vNFu&i`yf;C{B znv%{bh_!Aks;)Os&>=p&Bx~D&~ zqfYxr_-R^(n01F3S?W)pG}Q(q`b+rd8j-Yq0cyL&YVnjRO=-yhd@+3b`83q;M@=$* zh^GxC*lKAO9g|q0EnUyPG4Vu`X!m}$s`FX;|C6T)z1W7LMzB@Nk8Dw9hK;`2h*(pE z1%k({lF&Q9i`nSHK}dn*n9zw}I+;pOvY9}@k_i{`j^$mf*Iu_BnAvV4l#j z;`R6!r(FpjjbKZqJ87;CC6)9}t%R`wX5}@-q}*`+JvQgtJ>DHNmpX*lF`oxSN3F|` zto=P>@tt7tYh!hsOqIA}BL771qw9hE4C1P)VuBW2>T;C8>rk68!UN#Zv)bFK`O{mm z*lTsS-z_k-T|IOc6OivAEgOr?W$oDz==* z6-_!o==vsjw2!rGbz48DqOIe~l*V#Wj)uumb}J4K%n4Dy&wPW*ec9$9CLkY@f@`PG zndGoPs$RUMYYKnVKUg*yfi!$PAL@Dj2N%Te4q_%kDNA1m-?_s|-R4NAG_0TCKUC}E ze$w!To~I7}0bYzg2!26v>bA;<6P%3HGk4r5td|Ye_M>RGL~n)_++>{)aWsm5#hlPP zdU`*G2mO1%|JYSp6mLS3+=PMR)Kdrn|BhR%jcPrxL3m6!i$Hn}kf+!}hLq7#S;9KJ z+zbRcC^O%l-ZH^2sc#+b4Q`UEVuNVmC~$pNCjy#iLRe9o3!A5tb}U7t&fkArE2)&7 zeNRGz^Q5@`pxC;+q*Z}%oF=h{!>uBo!G?GUL*dz>{)v@X5SG% zJ2BirTrA14B&F?7g4Tcjg2u-?nnn*@CJ+tzaC^fP#QolR3qc%UhOfsAHWt z5>*|#ni*!PQg6_SCDu}R?+B2NGyOcFkZMrM7%>@s`;8Xy*0V<}^bCi{R{pK!egSS1 zlk1v6i3@EZ_4Ye^7QKiTuoZRLmLh0W!k#X9JcMWcSW&L$AYVuBgJpLK1KR144>F8PYM@S2~I ziZ}-K*m9RHWwQNwMTGnV)N~plZ|?0cbhd0D5rmCQo58`n_YBMCHftxR zo~ct8Y3wDB9aFmfMkSfj{%4(>*80gq#WDU==P&%c*hL{ZHOYC|{m9E9HAUYOC#T-c zzhHmn$ndfJQ1xO|OmnKOR=RD5UVTjC?vT zAB&!OswlXU_%7n_>HNJqfA5{YPuBnM-#fx`0Br}mzP94YRdF8>vbONEBQh}I4d8_o zf&ufLBo36D)jh!^Oal^%bY27yJsp?k59%>`Q~0L~4>jbT6Whus-O^78eiOW><3jVX z&AUD&h+vcsJ&TuMp-5SwHXu~ltO5%K;kDZzzl42`2COxVa%}jFI@0svbYux8^HUo0 z!5714q(kpW^VrK}m@W7n;1(x7IV5_s!DrAzyQ!Ow;yPzo*eSXHlh$ttxc{7#hJKrM zl*icvx9dp42U$O(uG{_YjzL+6Xz@CXvheq4T6l)@Z_Zw$@9xdlOE#oAu>SP<^xqEt zZ(f6Eta1!F@%M_y%9!INr+-U(`ob&>N3RhU5TikqnTCh){F%%^1R0tb+|>sKky0AY zb90^9j_F;Dsnuj?~N>?=#ZWS%m~SF)uz#IY0DW<6O* zpc)=#4Rydqb|!cf{_0RTyB)rM8Sl3xl!Gl3Wj-1K3mwXIE;Dd*~jM6=(&Pk0CfD4(%1DSqll$~-VHsG?#q)9J^7iSG-y>0cV$FQ(%#>oxFPEP*H?)x^$R!?@6MfY|^(lvu8V1`~x|LlJ zO=>iIZl=d!D=t?m-1_y5O+}bVR<;)&V7hC_Rt!nop@_N&jlQCL)>8$p4u{XOuD8#a zJ>LUS$ju3Ev*z4*MrV@*;&ju{X3iD}xZY#A^8L?%i?4{y7gwljD2nLq|BQ<~5;CjbC?WoRy_qXdFhKAc(tL-&(qY+qwCK67Z zg_FE?#@_>^BJfY=k5&?Ah16k6n-@V`^Sg;kaGV8xJi>JexVT@4!((!Va^$x!+dz%H zIoV~PKKSOC0FL03pHiQf$YHM;P_@y20aewrHQ1!*m;W%vG2Wwfb6c@nGW7Ggn>t4qtOurqm>R zt|8fqQPkoOg%ujx6`Ud-B)oUMDl8&sdSBs^B6W+wU7vfS9aXg@Z*Cp_rvn*LH<(Vp z5`Er2{Pon_)R|+dA#{(lj{oi8?=|>)AN+k5{%5}rxFO^PYRPJA8JGWx30@}_zS(Mh zf!d{xHP4E0uMLWI6A~kil)0E+z3sVZu?T;21j!^wubjE^Y2 z-Fy3Ch*Et`Hh#k`RF>>b-#AVDn*CO?p21X->=REq+Grakjk4;s-4EId8F-6$T63m> zm|pH=2DS|1H>f9esU>+Y)2%0SpJ zpkSZ@aYeAE@T%uO?a$TH5wYQUy^H#Kk+t>5xc&FlKxeBK)td|*8E=jACFPxM!mtlA zyd@+AS7Y@mVkWm1eqNt@KkP6!<}+C$;u z-FZ2=z8
    z9h8PMn?1p{|X5yE*YC3AwoWXZynY0N@O^zG2g41|=)2eIKDt?K}Nl z@KDWZO<^@qN!2NIB@S$WcDIVU+n;6{4J(HxaqxA`I2)Aq3vLyZl2Eb@J7imGnOFz# zTLsQI#5(HQ7ZBfMh>XBX*e%+v+wEixa@%_pav&^!74Kw;eK278*urNi9cNTUL#q~} zv&JdqPm}b>_2uCExGaF^fHtK=?kt0G@$OBSm#-o*Pb=ySXQvwD!!Bw!gS91izuT!E zIS`0&<+;@v{bD=;9O!vgT_A~#(D zE`hgTC-m;3n3+B)HOpIAca6Xkz`OxlH?r{*E`>Z7zQ)`F+<|HPR%xI8m*o)UM3XxXS~=I@pkQ3{~9>n2Sy<&c)C-bw{FLD4<^mF|#K ziS?>ce0%=%Ztt6u9iZ}$6Yxf_qkg=vQD%*RwSR*3Te2{fW{krhad(3mg_EO_^R9W> zJt9Y?8qmKp0-TOIeG1(=cp99m?i=7^br)Ai^QlvN#8(A<-}GmCKKn!|3#?r#_q_r< zhoThpQ6kfu1%Iz7gk$C8G5{!R+N;#G2M>P|a@=l`DwnuZE@jdawf$)B?L$_`Es7*d ze;Og6wQ_Kn&+ex>lyh~tL1kjXJ={G-*6EW=g}?Qf%$eV1(WLTEyc~?dPmLXb;X0g? z|GheV)DE@GAPZXnP)d^HB;YyXzG0{H97b5fTcG(k zS>cP(j9EGRE0*ni?W#XhWVv6W$nG2#;1;abO1$7Zr@t+nss-@E z!*(<7&zHwn-NdgV7m$wx2J}_#1QSDLHz{(?GSK(aqN-)2)E8q1zM>;`d+poAavMeg z@cKaLTorL9r?wv@5!Y7@=$DGynNEv>P%Rd**@GV>Fy*+ z=6E>5i~+fdQw#;!<^eiFL06SwF5P0La7C^v)w=opx*X*4F&R zV~S>M&9ChZD3%CW#Amw^n>we$Yu)V1g2+M+x1icIE>$$wTnmETE-2hdnlhvtePyqo zzSZ2CU7vPetchZjuzvJ2ni9|f1jl`6ybPU5K;aXmgGN{3p#(&e`-l!Q+q;#H95;~O zsx?=uWBOz7tL^x;g+M8zqt9QBHB(Yvn>j1_Tp#X?5Nssr~$OM!kk)J!g9V(Uf+>1p~M6t zvB-+Kx`IDj;PQBb{d;U(0|gSTnox+cbq{xg6{TINL%H$ERuMqyaKXe|1d4Dwyu;z`{6%3Xyj%mh$n`#qUOtn^;bW^XdDg&5cypg}qT z)L^M9Q}NF8%_6cMBDzussJu*N*QYW|O`|p0>OVIS<%-52tc`3E`~3)@d@enYvL5*I zYMjQqzye(vYv3|)s(-s(Cw-|sMB&DExzln4apOi&`jNjeP`v*ac^)Ijec_-5L^U(fHyn?Zt_1qVT4nLYkBr#2y z1O;#rXzwsn8*TJA-i@@hy8)zcvU#kXma)NU6HNa^4Bl?=&mvXboqug4sCj>9lTiDl zAu`QERLwG*q{MXuX9a+0oMGd%))}dJn8N#;u-J~&;o?%`Mp~Cf4FfYhm&v`I&+p_l>Q0JvtPG!O?V9!+%Jjpr)mUVWRIAQ6PM>TF822|X zb$0dIO^zN8&YuDn`_Y)t879G(-SG&i#xizlY>b$Pqd|%#gDL$NVqxV*Wt}{w&R#Q$ zT_jT{iLXs>9;A|**6a#Aj$hn^YU4vLc?ezHYgCp~=GV6z0@{fGtV%4hdYcAE6ivv( z(9kdCMs)-4)hWJ*)r8viNwcZ{0V(0{;cCZvkU`Q0!Y5CT;VXCI_>r#ke=$CQ0WEB4 zF`)Bh7}#txXgm=Ocv=DLB>P`l@<;{+O{V%|t!@zs!fmwML)(UX-F|5@1{#4*wXacYyRI#6j zL%0xiF_NGIuIA6rYAJ{&t$oIlWJZ+Gi+sn?eVKpTSOPo6`Moh;y9H@Cjm*)+Mz=iT_rsu;jx zs384jG`rsr)f`2RTTq@at7dzJ%7cORm)&o?a*I^VgLejHwi6@-M|+ak>|;{xp2Jl` zcr?$hW2%GDoJZRitc{KWc(I6YYH6s%88bB540Zi33^v>x-3&sGHc^$DE3JPkeyH7+{DzTnar-O5_u; zYXB9rb*V!k9EtZiSFul%Up&l`{zla!yS`gjdw2g_$SYc3U>pDn|B^jaZHPUM0aapn z&Z-5CDVSaUT~7*^#_^^^7=s;^S&&7YE1)AO8s}m$)&ETab2`8Ck)Q78QV>2Q5WV21 z5}2nQ=ImO-=j^v^{0*?HI7#XW>Tt9{>dd&ZCAInU5M2|LEA8FICU139&+ zN$AvbPyF6&U5WTY^K)qJ(5+5kI+G^6f&Ml@&F&XOoyARx>=zU| zxynh86VGEy_4A`8>&RFfsUr~!VR{M`G4`nr0i#`UYUxSdrCsE1GOBJe zdezABeZMU0`A^%2Hu=){8)qr1HVZK^eaMV#?a=p~B7q8I(2Hkx@3h3)JD@&zAg25`ul@c< zj`|O1`2S*P)5Gt|tl-Aj;C@W19mgt;!&!bpp2vUvX~P% zh_Z0rK9$BKH*h)@X7zZGRfdqInhxrqg*cpOm^7SEW&8VsD;A#!%a)k!4#_=P1u*HDu@jd)L65`J}w%-UvAU zAt^PPCy<(f)ag{7u2FmrzMGSUf4wnsk@UyF>`k`kJ2xFy`>Q8_c1VBHZ)YUw{edtk zn6x=Z(wijY0w8;BSa^`}9Cn0X6;_$Q-F?rE$sfiM36q-DwpuCh-1L61@aEi5A>#&< znECA-w;WM~{cpZ=@W?Z?{)ya!H>#z3vn3){Zzd*uE|H;+@AtoY%1{@yHLMzVSn!$-TfHoO%VR# zl#Sas|FiDg_wmMOcFx}D%7waDgRf4S-Wu~J?5kP^G1xy4Bcwe&8PhKVtnJ>(+KD>i zV9BnHt+<2w*U?Kq9+Ch=3@08RFTn|wSy4i>GaedKk0uNwkIqqBPfXBVZxxEr7hB{f zm~$kc=&>T1%BoPY2_Ygf9_pAac=$OUkT>aSp(2Me+g|194|JbYvLR_upnef zuWCDEZGQE8V!YUsPM@8Dbi6ty;f83eNDADUyP}=CW`Ap>$bmxYOZ|fjCqIIXQU2^- z?D-&w@*wywxW{3vbntGk_)podkL{G%_@>(3MCgK3cmz1McWZ}A0X8}L+qJRR7557y z=HYFniirt2|N8XseN+hjxOLlD-Pl-3!qgduak`60(X{s^$onUG_*?QQ>-dujk2P%k zyvBBPpE&TJe1i^80Jj8^4x2Z?zrM7C{mM?5=-?zjs%v`NXz;~V_9T=G4hT#yg*GV8 zaDPq)uQHFhA|V(%47A=w+T`8mxxRBR+8eOelmYyCd+be^=7AEq>$L+y# z=OnbbWYq0vc{8d-zqN$5`UH)a^}GY`C;VVBzzgBzi~Vbg53@I*V9uj3GZprG@$-Sa zkx#~hwf-hnW0!($kZPLWO1WlYkJ3W%=TJZZpBoA(UIK5Uv$5{N{!-+hBOm`@FnpJ; z57R;|o#47vG*MuXlD%zX-=Rz`zB(A=b#be>A*~2RBIyGUe%?x26XeyS4cWp*cmDWf zvoarj%61TUB;&NE!3O|ebo12YW+d^qTL8g`?bl?TY@KwGN^{;zu+H-}icB4Udy9uO z8@}9;w;k>6kJvoUCt%MqE>89V8qsUM8!)tOf-su;hblq7GRJMCBy_~3s#R-gReD>e z<6U{Dzg@ax{i}&D=8_kpUxcfb$PQcLU{BcSSU6{=dsvz zOgfql(?iXre7kEglKbrg_fcj~iPAlbhRFE!$qUbvo|hVVx1%*ro9*E^*jdZ2{WH4l4v~`p z_{dFCsGb@5@DgxSp?$t5nJ6c)#i@dA@>tZbh{&~j?zEYqUnru|5qj_gubPxPSPPIf zZv~vc{#(U>mH_sHBLimA>qD{`u3|I}5KMW@Hc-c4ge_Bon1cuBK_H}U zmvPKBq!6b?UO?uP$vnv%>SPb3bl@lwux<=I+ZCGnu%ojAr?>MwkEPzG#_v!gp0_}g z*;krl88&8Vhg=gQdlM3U6+wWy=?Q19ktf&vwEO3kE&J&poqh+ka`vW6$6cGJuXl44 zhYr~#gNc&Pon*yK8&#zGeD_9mYgoXNzqKwd%B!~8(2E(Dn*pYzkN!X|xbTtkzPp;_ zs;*bAyRv|*qS=w9zS_&#;~`MWe&ZEYYDLTMW`gUAa}b{p+ci3{M7G&ROikG-T1KvfAh$Ta6;h>%*jG=h# zOC=gp&jXL!xPY~eB?#w>j*tJZR#-JG4xU~HS2 zMsaUHGjcX7t2EQp;WlAX(E6vpr||#pDgR@h*r3ICO#y9zHOZMh?6LSKz*{wPJVrF9 zHQRT`)w6!Hf&;Z3c?M zvI3h77akE|DZQ))kutsWw-}%Us{lkJbl z9oWS(>BX2da(G(O?w}7X*CYT?xjpGpU*mQBcNg0fuE=i`J3_saX*8`!_pfuv`iD(c zS?L!&PAQah^5a!*shrXEu5h|xRc~3P)4E1cv&rk?n#4Mxs+kYC%DSXojVh7v!;8(U zPmq!!*u&m0z;6GKT<69`(vI_DUcd>76kPA>k4xXRK<2J-JAcNrSX5kXDsQdJg1lOf z!(1zd{2+L8`GeoD%=@Z6W&+mAhdWD88#t{(NQ~VxEEXd+@A~aqUf7(I-h0z;Xdaf> ze(8(K9QfE|VP^udzudeO{y8K;mjW~!(72Lle=FYJ2&Zw#`P7$x*V+53nev_!LK@(N zGHL>j2$72BP{Y4Lp)jA(&0l{`b=E=FQ$0jE*L+ws#+LN3pWj)#<(Zcpf) zECW)u?t-6AgUu7MeLOsRpd$nybNS{nK}z4OWI(_DY`q;*eza>F6M9d-EfAev|Cy+3 z9Y4NYnn_MX+Qt6LOPG(vXZYwdrUjEq5ASL7dO9~cT6e2F z(f*TX75n)2x_cE}|9i^+oF|q%B72+vw{CfA_=N1HO>0@VR@w4*oG~VQ|CVPy{yM(a znDX2vrR5UPiF{t8a7~h=We^6`v$^ks&JNsWEjDsxVjhhXcjbFONChRt%SyjJ_Ji3B zmA$6N+YP~Xe|j#BEDCxX2Ov|aoo7`yxtzVC|5~ZL%dnVwTXmb*U!tk5Bi`gF07_Pf zjHR-iOqq=MUf8a|~oE zx~ut^_H+Ine6D@cvsFOaUiIn8)tsq)5%{h=gAq-eWZ;%+JcuB#2cr13a|^*0Qtdco z{fu~ottf^Q$m9Ro3^NnHc#P#bTRfSo5^17R@aX&*L@lin_IsK=caWC*N5MpX7w@#| zjAxdeMcS^v7a&UeyFv?UX+QjHbkTFK1R9AdIa&Z}?b?Y*U8R*^Nk|Gn!v(M+C3 z>ibQZYaacT@{Utqydh}PF#QGg;Wrbl_2od@lKl!ly@kt4vdwz`*TjJ@VW1=xea){6 za+Iv!8cnpjmU?+Nz%m3%BioYQ*oQ>-#KmPvD7!8mzE|G6EZhC)PpeR%6<$nl@7@b_ z<8xAs#+rb`T{w$+sH_Cp_L zTWPE#8$hq|gy+Xcm!mT6he;=M@Txo&aDuXMTh#CbHRO^m@`Z_x(70tPC_niO1KoSb%{`4b^fS)y2vK^C zzuL~d!y3YD*M53tap&u0lF!k&5IuI#8U9?h#jTeLD|aq9io{RAKi~>?JA^fmR|(t9 z@yhs9pat)?9|Y|;#ubVRYA)ZAig#MynxR+SGpGHni90WB0TPUWB|!M8Pz^*%hO2%f8GD8=JEu#{NL z8Ra%!U2-`=0{%`p7*FWNrx4KZ4xL)n|9eYECZixM6jy-D@rz4fugNXl#a(dWep9~& z;jPK<>)V;kV*;@3)wzOa7V6CX`F$w_3co6Ux;FqMP5p*>FYSvcFjjq+wK)|>8GmPe zwnW8rtED)M;SfjVYqOAWnN>Iw{4O`jiy&(JIrjw$zktvF`0!aZ{iC6epelv5eyq7! z4`TnaJlJ#nobJx2HcrW_*#)pRWRD5YO2);dEu%7JWjoSfSv^1Zf?nyD-e=%#>@b1- zRXKpJ$x$4pc-#{Ha=QxuX162oXVQ7?Sw4s9x~=CIQmWQ>p{p`@^@|Y8C6}u9=(s2j zLr?tFe!KV+$&FBYNVro-BI`JoQUxFHlanQ@1+yI$0$*Uk(g1zx*Y z8@_lh+WzcBNuZ_J7QF(nD9SkIs#GOUAsHXfCo{IwG&uWOivFbV_CED34%u_FM;O(zT}4&UkTud|MZIr=JjGWR_sge z!_6th&@<#JCs>td=Szm*vq#us#-jdhSRR~1`+Wq#c#G8DZrzq%*soWTsz*R#@9 z{&wHy(YsqRDfg2Hzx2-8jS9T-(~Bf=g}sV93=#b>JoV}O#tX{v{X7!NM_Ae?A(Qk% z;T0pa6+tKdK{~Tqdqd8{VM#_}lIMPY#u4EKbD72I@k` zwS)G%!TfAXG0X_GTpn2Q^>r@_uCujT4*8#hQ=lFGBn=v}yhGw=5g9FCA~*CyIx{9u zX>^rSSLsBaI%mSwjMI6ynXZ$rA2UPtPip0Hbkq4NR81s{MXY&)m$5>99Pd6ZOXgs3 zw7yCgESL|iDeu$UD7BCW?+2K{8{jSwG6u(T>sUXlEQL~%-(>952}Md@;wjUP#F75m zQXch%^rN*U1pE+t2v}~X>yN2!vv6jxAea1cJ;yR1f#aDsP8<=?b~LqE-cQmhe)^m~ zCRkjYWH4W(E^*pM}Mi|qki}U>QQRk81 zQ^+%TJ|=u!KMg7yz{}ykeJ$P*FMIWy6r|(vf~o)K^wsf7RCjB+aOh}8#?IJeg~g~_ z!$R5_2v=+F)W}Ah%+-!>-^co2Qz#2P8R6N*#xFdsCa(Y(lk7rMXPe(v9nkp$;7I!R z_QMOdI~UlH-K+~3qwtU|`qvTlrmDl*K@`pPEQzR=*C>D*?s1_2+3_d=dM!Nl10t3P z9kcyR$+1~ACX(8g2sonXUvlsIoIHslHLkQ50@P)=Kp22N# zq|k7Af0myZMqPrkA)Ras^13d9GQxU^F6+-j<@_GB0aoPGgJ}K%t{Efr=?Q1(XLQ%o`4q;cEa#ukyB>&xLXPL|e8(zR9_zMI z34NPy+nGJlhGYGnzP%ds8Pk<%G9D#-K-YtOvT`BmI}vhOAyYqmsgBhFXQ=7Z>$?<) zlVvz05YMyX*dB)e32cJ{4quWB-spwtA7^PNG#fy7=Y>Mz3OhTyrem)x=r7!1iS6P0M1On|8az-U6?f@~&|f-+mjA3` zUz2S;d~Z{sm9@nd{F4k@NgqOgU+Jjh;_Cv=g;;MUgii_u2kZStytq| zNed7R&XEaXFRwScTgvL4_r2G+8O6Uhy&?$MOXY07!S)_XoFD7PeJh8p=Js6+hT^_W zUh~2SCd}#{e!k17xG4SzH5Lv1V_$LI78?s00Eu(Khg>tqPhScUx}JY2t|y888;&Nq zvh~eagk3YcE>@2h)ojDUFAYb{2_NC&uymN1Uu7@~hVNRu_(!-O>>a|@LNCJTHVvM* zP}2PKV8G(g8Y#nR;qbA!sGShkpmpHPVB;Nq+&s1u8+G!xJp@<5H0pH9T04fC>xrO# z(OpX7?4v6e3I*f-!y4P{@toODe+zRxlyRMnwNmkW zRWJ|i3A6Xx(8}~;dSyVJV#Rz(2Qc(|fLps-w(M%Di^vx&8{_a>%-YAzE~NT3kB}7X zdIeB*7kIQ`7=1qm^K*a#c?SoPwtOa-wfLegFvzlBukg;v>J{Y5k@Mk?)j{(c&L9tb zA^4ZQN@>Bja(4rP&<|(_Xnh8=%BNcoRgcrf+2vR!l(i>I+7Zs!ULO^@U_d7dn@+| zvd;-B0vhJLN?UVlSjqyR$Yek<)L=&%N!eHy*Bqz?wA%ILY@xs(fbdTt8!=D6iRNOo zmP>buumEqT_;SDHZ^cF~sQ@vxa=mNyM&*t^{v_(;Y|ev6x%a^Pm%^p{Z0i%h(YDj? z7Gn=~ZA4=ha@ZiW$A_ZvK1%?=kT2oUej0t|O}1kfYVE7jE#nxB&*X5BasTjSuDZ5j z0B_;ZCbj_dws;b+CG&~94wcF~lTik|nKO;;6x?~xg?A?}0R#V7V?Yi>o+-c~FdQSi zo?ADcKpzOI+f=0|1igFUwiw2{+$!y{W>>g{N`1&nzqYZV40_Raf(qSS zDzTfsZx+AqaCNl;z9bgAXv0PC)PH+ATNuxDsgw9Zub=oA#6{sKzd)?RF%yr?>^WaA zV>(R1#5h=*c>Ob>)}n+(rCAPs{fV#sJJ+~?!QK)B<7hGq{%YKNf6?0{%#Hf|757!v zpa@VJq%pX^|LKeJ+dzK6H4yHPU%mHQqSI0qsx{kB5WA_b2x%8ZLYo01Julnuul)Q7 z`;E7geXd&8bY9-~LR5DofWo%-OR}Y%0}fZz)y}hy3mSJ({MuvdK!+y}taLXW*YyIz zM7cglYuIr^N?eJ#j_u2cuDA%Yu8wl_g`L)sN*I!kqh;L$pGaV#jfrN$u+zaEUw=1@cCgAyW!R;T&zGg+z3Tomjpe7PbRztj% zt>9~`Rl8MY2sXYQ(s!HZ*7&O=JIwuBPm&`;#0gzME;_hPQLdz(L5Nm#(%JMz| z83R-ce&zx%jrv}rP>E#=5VBclpeBX^5#XeQklM+@x~L0^{?nTc-4gZPR|+_~hf_#) zkCY)vc<&ob9?dzg~*jEYvu#`S#_H5{%8~?qob&7mj~iogsCRT3@E&h}$O478&+4 zpTE=oQsxl)XyniN#S=0AiK^dQ7EMmsF{__m-bu!xK^SHUh068>g5!p7m#|$^(drBi zpOV;%X0}TG+^6qcy0^DNO|er_p^m^cZVVDV9Du)v444ByX(p|^N9LX) z(N7)zPT9k&>;OKHexu6nw$wEe=DS_Tf*(P78i!cSb|6mkdigkb$Th$cvRv8nePeSc zyB;T1<<#ek>+l$R{~LE@dpuy;In`Zf;%DPj zCGobn?hBWicoUMz1V3}@>PH!EhC)e97)S1pX^_9u*!ll9Mu*Yh?Rfq41J4nvBRC$* z_IDm<7_~`#vu+(bis%2ZTcYLMiU1KFwrU-x(D#U0n~sBShF*s#TlreObG{pq&)_hH zJiU{iQK*Vxe-Kd!$`Ka1Q)j8}nQNnP;B3#XAk_~wVpV)Aw4_(_ZsBQ3n8)>~cTCxb zf-_8#0`t$Y!Y$hU{zZ3~GkMh&XdswA*s z{U%w*AHC5^z+P!r5ngQ~!=+x~Roe}pYw>)g7wm_Kb`B7?uQv02r6+#nDIP-?cW6Il zvas;{zD#@93j}s7NL5k1aM+85xQU!RKqs!6y@vb`k*}~7NG_^Vcb@bjomWQ)(4ayt zcDAollvS$tgw_EwNNJ{Tp_?XSS3&#wY!0NxoDX}L8t4gj=0^&3EHzjZn0{{*z7!(J zTA6qmdVV=IJj$*9`Hpz>2Z#VO(GsNoGZUK6P^9=BdB=-GCeh-cwteJH#-x+**nE{Pk&s7FuRueOgGl1CWtO;2dTr@qHD z(>Iybn+;5}=^CeA^g;u$LrBOc5Js*a>57o-@bJeyw&Egu$@&Mm)Esxnhm*v+%K50m z;Mmsv9{!yHk#|w*nKhdjyDRm7vdG@7hfII-N$(OkerEo~Vo4%4VR#L_8h%QTg!<#U zj(eYLFj2s=qdSNmn&lY^@!`4era|m|DF(_UOmQK&oHC#9dLA=X8D^E}SD)eIn3z-l zrVC__(7Z&uALuoj2mqGKBvV<((z3y3k1PI2`O>GRtk=}6$C#Dg-}ug0W1Fsh3aPxv z9FbBzDtG_Lo$f}2@OvGM+3>U37SpGh-n;YQ%t&_Sd%JSv;ikS)naqx#P5t4z`Q5Y~ zjbFEzT4Kn8+3I~MIO?AVvM)(n-l8c{?TdpK=cxhC){XGdI2(0Ts&`7@O)0EKA&d%Pqbu6Yas-E^@Q zJdz8tx%Knz@3M;CWnD?U9j+Ifg4XX7QkIC_Pq_~69e!5-<-cy^zi+>(?Em@g17`sQ zKt;4Dnd!5)eH^AG`{%$b9AIP6v~s8<%}jK_kfIS6V>y&X7t}Lct&r#BrpI}Y%Co7( zwJRiX6b!<83{OmUVLtpI_;oPLO#&YdquGi?gga#uvvFWrzX=#2{GGvsUU)E#_uwau zJ144^9fCXYZtO~{!^a68>uwDqjQXDKL#~wzNrrZTHo#_gEoDrZs&TXLKTqo3u|~i5e7ieTkzOmswut~mO2%Wk{(*3y z;WvD|VN*)U*z&*VRV#ku)3n@Q+-9%6sQXf*71DLt+cB1nO#X8~&787|xf}yf4r<8J zl|J}<>|{V1S)8Jb)r5*+JF1pI)huDm7;GlwH~jSrWe#Pp+ih2q3ez{yh5O7Ra2ZtV zOUFR}rS=p3&{LDK#WukEghj~av~LzEmtu#zsvCkIWgrV3weH4v;=0jHFhO|nZLdRI zMoeLHA0ST{*NT{hETf=dl1N zbKU0R=^dL8O%HH;OJUfXn-CsX;+C6;6pNRUuKB{Dd27pj5(-7<9>nTj%*Dx5&R=xm zVTSc@t4?_Kyk%y~PIz3MO=pFNnS@vhU1Kig5H>9@q&6q=06;0#V2bkH9|s(QV#E%-q4OKioVxdzZ!S$^3KcksP0JC;sh4{ z^9#BlX9_SBt+b&0KkU7CP!!#_HY%dvizp&NGLi&DKmkGGs3ge(5+n_Rh~%8ZsEFhw zIcE@&oa2Bbi9^mX5{DrQGcbe+x6$8w&acj?d#k>xTiTw_uPeL56ekjHY7 z`OaY;U>>=I^MF1ELxJ1f$FuGc_VIgFU%y3o5=O|gc^@Kl#QT>xXkY}UR3`eUDtQ>g zqqOCdl@D64q#(;DR4~>|9Sgfol%nv*g7GxHhY^!MI`=Xe!v5{)cr!qNO}kNu16U^F z7sdKo@e(=#=f&_!qPKckH~Vv0xgU@1fVp@;k$_vm_kQ z3ZDwH{j9)ZVRJO7Q(Q-HChhDF~^`pNv&o)J*&$NoD zj&5FY_U6&ef%YT6gaViX{cDPP^WPzsmmgCK%y98(F;r;Ni^vKQ@qA5^UgF*J#{tarfXU3t**ce8l+Mv`*c|_ohtn3AFx;>kD#C>f7Uk{l=032XU{Bdz zg`J2!^7^EoB0j+raE)Z17M%p4CHu>80NUOw+&MZ>q(E(6nh=iHe3s1^z~=pUa&|_|Ii}GporLziqKKI;Q;%^pS58oGe^{x80W_42-oETPc(2 zUpD4COibEw7EUZ7%s0Q1;$JB<+-b06Cez1Q-P2-F;SgleH)3XHRzo0$LugCatCnOyYgax-I#PdTTQ{WOGo`kpXzd@kBxvEji7`qNQ;MWt;!%tpb+*7i{dfu`e8+= zYc&=)6T(m={PKD&8bDm^Au-y9HaJA$|*5N>8 zjg%@|JwQswai}VPfF9%)9-|Zk!77_)u@jEJtnzkD2j9_;l-O_9lX@vQS*m@-xeb^O ziYf0yPY}6gvGVJwEH}Bu&G7Mo3NalYTr!j_WSk6=>n=>2<4%&h9|PZT&EBfO3QDzd zrV4!hFJD(qp})`LU-J!m3+yj0eHKSuj(_6~=zJgGu1TseBqseJx|gY>Ln9g4wAaXo z(*vD(0*SvxxQfTTmt_haYmg3I;7`U|RTyQ~m#oXwADA4${QFU7WmUP@w+{@L5oMZ4 z_3PUBu;=`~2&@+i=88@ZKRjAVaN#jp5K-VkxgX(kE^5t z-y$O-3SAI-&TC>H;wXr&+$K}WFMT2N`DFwzuln88io%cJZ9aK2W0_?$PBa%MJsaUl zO^8jR;rCxuEay2PXC0&yb@?XO3~p-;S=8{&y47sF`j-54MsAYBVP}TkE+JqWC>|tBa{D0>%Jq!pqP`f3i^=x6U0Df8mS9WMUd9zFEr|faM zw^ssYmfu;}%cR=6GdA!EdCuf30AZ>i0@4+PkZPByQV~&hNafu+6k`3fWrfUX3=i`p z=skKZ8@9g?^>8^8@o5kxC5fI_jgtucw`cZ`l$CpSs-PNTmPpQ!n0t_GhZuG~Ora06kgH#u>?9+N-N`)=`k%!C?v zXVxBdV#j*3T=J56xTJ3U=NKhH#IFM`(f{gYesLv3paftMxX=tW^59$Tv4XQMP#A45 z>_vg|PW$`rF+LZ0OpKs5QZU-qd@P0tTydwmZ@*DZ=K*${=Q)UB&~~d)%c8Nn zf0iR1CKY{QX7HQei>Y)qzd_d*>Os!~CVzl@OQQa)>sR6JOhpMPJfwf^V?z)Q=YB1z zbEo89OR9B4}6I}5d4{}D7XCMF8+kjSLsh+>Qd}RB9YZsFBikH z-C|?rV8}h=tIgNtOZIUOdTf6({heI-Y{E5ooilieq`>?y6D*zzN+3^{bju-EFF0Qv z0#TLoYXcF`6&%MRlmvd`lfkBqd^4o`%%d67bB2k2p-I(sn+OV#!fcP7;vd$yL3*J# zmAu&63Fzb(t`(sIxWBp~5?ifVhl$R@-fJgM7jUaKmN+CinSTCtw>>{?z!ALxH&)DE z88VS0D(0!Gs(JSiF76$df#Rjex&Bv=wf02u8}az8WPy^t+Je!7#{P+?BJER>ynqg@ zLc2F5sAAu;=A9eo4q-C(u=287w?q1gE-KzldUSHeTWR6U!}mKKG#NsE)gt8fgsuYC zM#>C7p-&fjSQvKo)sK^@i`q}l7l$d5-c-Rd%cs&wPh%ik5}Vhw&Rdh{VjwFg0anAA z?DxgTN46rcVdQhH$>*l2lkq>}Rssxj61Giwo;)^VK+7n8!r~<*B@@*%C6Z-iuu3VJ zsU9H(sCmsO*9;6O`hmz+)(tZ=GbZ_O!d5*;J68R*c2>AmAQ}pphcn4`a~Hn8|Fwjg zJ4(H7#>hanbB~a@i-46YV1qifeS#$G>*Hp5w&o=1h^6<-_k({!QAE)|GLoEYaQ z6wAjzY^1z9ZUI9pct_#f^ZTziPXFk)H>i;1@wxLn)tyAQk8N2-?4hRL>*x-m6S$*2 z$};}EIQ37+bhW*IX1H0Mb;_P@k6fHgye?pE!Q0wD`?0Tq)UY<^*i}B~P0wBT*YT0V zayO}bYl+@Fb&`OtjJ~-0c8j*QA>2)l0WoS2-99?x4Eb2u1`69p3`rHQ>=9_)P2;cb za?Ve_5MkgQ`6gW%V6VI)LQ?qXnZ3)5@i9awFNmN&y*^Ax3f|! zR|LMIB>p+*9~1l!ngw^>9zSlVu8vEvP}DhjG<#ygvmK9j|u(< z&H|&93|XRLU&*wYgOY!(4lE1S7?H}eK6~EVZH*LDQ6t;MK795>3U5b9Kt^f)=BFz>=Gbh?A8ZUP zU!G`8X}QT>ij!4DP&2DDpePH;61cA#X1^|69Y_@Q67capM}r_}`ZdCJbL${r86K+#W3K-!Do@_-}U+b&@G7 zBK7?5`{cmOazy`oLr^3O3KaC#GmAvpSY_fG<#WJOP`Lf?4cD2a*CGFY@8QS){b2?O zOgT&M8UB9UeO89||K1?(icTVk%XJVx+&~(9wGVzLv?3 zWL!b*wjOLk3kXdeW(o`Qz?hg-Fc7T+ee=aAEbcCPW%$UGE6v+ZlU`6c;2&94#` zHZKC%UE06ye!F|5>1d&+iyXfD_*ET<__NRF>mR!Y^=eLaCAtXJGl=_mCNg~sUw+ex z{^ogHVsxBJf(k6iL9Ya@^*O%dHN!%5bx2(9rJiN5>W$ZA#nvSc&o*b8$yAFkZRz+r zcOEm$1w+*?r{7GX-`UPqD2lcG`P$@ifjEmD`&#hHEfj?d+hitxpgu%g_`Y_vfz4p6 zw`keLvAgY+DaWh9=fMjXwu31Cz#kxS;p&+H28(r9*t(8sO76%Vt;qBB`Tbk$glVl{ zY^*S`uzYdNhArLo69)T3LbI2+?(g#;iS?kyz$;^rJrxBNFVkMATtJw+e8#| z)$)Llg&FRZK<8;y{*680690$pfpZiljjR4-=8d9?*3-b{FH(=$33Jb85I=F zlg6kQ>`A-L6^m0J9ZbBHQz`X3fWkbz_%@F6yG$ za6dI{BYp^!Y}m->0h&Ko4YO@-{mi=H?)GpGb^0<228hRSvpyx*KM-fGZdEz&U)xFA( zKp@;$b>(eXIjMo{hoQ~(Iw?w?s=@ySyk>^SvC%`@o^7)8IF;2H-C z3akLc1{Bi$uOm(@2{_b@WyYwgq_Ml{;K@-x7?PZ)fF|1nLNfbrpGdDPo)tI~6@LW? zUhNjWmDBItUV^t*|Kfb;aMM{P?l`#bdW8+x>V+52v-nU`FW&LGr$h}=^Cqr0dSiwh z^)uT{SC`d^KGcA#bW0_Kl&no5Oe?T-fAt>7vLSpZV6L2`5_i*5Xf4Gvgnj3BJ30T` z`2xDPz0wTHzw;I%uy5bHz;z%u4pmDUlOj)a!NJJ;=;Ur?QEo+ z``Pppt%$ugdG#twgleRU)r*@0!ymfsLfu0*+)c3Tp(Xl z>Avh$hB{sn1Lr7(J3aX#cmI0x_Q{H9*JG94ksqt|aSB}jem6{sqhC1xxd~ug{;|a0 zGxQ%z{9}p#mG8vkURd@!ozSa=VxZE-@cor9khmdRPNGNEpS~GDat;%P7URP~!U2$X zk0erd3A3KFGLg*sv9_LMb78<|mpT$v^<}*)ehZp1ETHJp!y`5E{l#{zL@3F!qQ)<) z1sfLQ(u@2#_w5dV3~bm%UGbyDi<7=JhbdiC(4p6%I8gzH?1;P3XJDiHi&Y#5oLPqRe5KeaY{EpBtrh%daG7A3fzDYaC3 z`~xTy80r`b;3yoX$*rB$lFcLd{{$=b()?5=b^KSs_tMXUU$-a#@Cdpvdi^CM44xv^ zulKGU!aT*=V?9VoBYlqA1`gVT?4LQD2M%*(*rY=-6fYSM)7uvr--hk6UKuW*Sh2k6 z6k*W}={nQLR@F?&ktP)7`J2@AjD>zAi!cRdxz1ubdnjf{BA%3Tr zGDPNywC^oCC2g%XZ<-0Pi4_ik9#>AG%Y26Mvs1mQ?{bMUCeh?&oLBrCL}y%G%scn?!z+KjQbH6rXB0wtJ|2pt1JGlJK z`N7)6WEN4={P%JKI6=rD#d!<)c}RIh@ot4a6>%SmAv50^b$!bGQ=+Rx?FzlfjTMfI zG7OZ2=H`cYWbWH5Sa>QGnoDLp0S-0j1T70j-AbqOH>;c2wTE#k-pk*>Bq!f$UM08(c8+9O)l+s7Nr+?UOS+&zNE-e3K^pNUV*I zkFTz-kL&L49z8yOw7ivLGu);jf_LUG=IcLI)4)GDo8F+aSO3&}u)ikwpyb|4MnVF5 z@eVh4EP7%`)*%nWNzj+c@9L62$w|61sYYH6;2qK-Vf|tCK{^o@EQtZDx;IfeM)2iP zXNF9=e$2B_<*BA8#KsD~1lhO0ql(6CJ3>~v6NN7cT*&%6c0DFrr4awdJ@V@lbqr|T zFu*ohB4u626?hJUJboCLz6X=j1)q!9F+C19gV7)U|B?KUOR=n1eqvieZ3glymvY>{e2KUSzNw)gb=ZS z4x!9bCD=Tvt!@`B{_2 zLpXCnZE^>?UV0u&3D|Z$jUnWH(kTlV$my4Ta^*Ya50~1d$`N$+i+t6+1D@Nq#PLz#?+>DRa^@eZ@3%;*k zDO-BYIp}^YsPmb=0*%hZ#Wgh+#`ed+nao#%K~E|7%c|rxb?kCH zV|x_tN4F%d(}}OMKBYvJ4bjT$)PyYm=g~<(W$gi|gdw%g#GOzvFWXDRz~v)j00Ud~t=ylc49F*y8`YlP7Tbx-{Jv%ZyBalp$(ApH%ArFOAI? zIv&g$%BID6BH-V@KTYX?nnCNUlP1eDRSiWQcwK6lYperSRF;t2Co`_gt0AuY%U!Oh zL9s$4(#mesqBtXBGM{?HM2?mFMy%$xP&sPW*owT8@YW}8d7MKrvLNj0tm0rIEOpI%8<4zi!@0JOzeb>MvZ<^c;R%Z1^fD z&Y@%4;fbU%O_Oe!GNaYC(wn{-^i^UpjTXgz!Go8JMvEP|PBnmR*%)l|AqZc>?PkQ2 zF58{>qdwnkxb1N&Q&8kfo!abyG+orrZ*~lj8xxSF6ZuI+^6P%n@J8-{nj!z(M#yi5 zOr{|l$+hFl#8LwSBBwkqW4isK-hZ%u2;JZ(#QyCUD5|bT$n?!uPgF)^oRf*na1AtO z!|%ZN+d8(N=0*vL+11$Qa!-Q4K?PB#v4W5I`iqg+6Bnzc?;rft7&GZKP^eo#;d26y z-E6h^POH5~iUE|RD|c&beEda9db*m{i^h*1Mv=)8ze+ls>6B1cQC7QHBcK$Dv4NO) z_Ph(?&DdqfeT|WdvkkeFw%r`6Ur~|aNXz<>3QgQ%UA?E~A%L^n+JM;FUc{-I4ivd= zA6KCFvt_O9?FH;)oe(=7^VyQg0)m41RT~g$Rt@g%seI(MF)QSsM@&S4@SN!qZcp`27Qjv1cGLF*m^E&VHB=#D(OgYm?dQvhrg)l)`x09(oheHM zO%E)ktTsk6$%Ol4C}HMZD9r9hCGi*RS5Q)S3~k_q0>3T$BM^v@H!OigF391YAjfO{ zNI+gk)qHy7hxz3kwQRk(CMG$T$4P$L=@X2L`popyY@X`vVd~XdO6#!Pb)q zM##7dJl91#5o~w}_SOmL0I~{6WFu$z_1DVhnY=eCwRXiPyXUE{b2?Oy#gzaO-|xX# zmyo)KAJ8=6IIqp>luY%1r6>JoGeIyA%I6u`F-fC5nf?RTUr027c3efhd#R3YJ%wEx z`w@K%KL=kiNtSQEf7I;j=;U?@BCtK*ux2~Pu5*9Cy>Wr1rk?G<((-!xPR^Q~_9sOb zw$L_&3$W~^?-Gfd)wN;=$Q{A*{qmLNehMp9@7#X#GQ8Wp-=}XaABxWic@hGLA7#Ha zV!L2*Fpaqmx&em2(|U}1to!&0jB}{!zBnG= z^x^wpU|<-MgIYgB#!UepQ)fSy)Afz8e+E~KL39IEKg99|rw?6wj+m`_9!idK2Z7YN zHPS{ujBb@S2^d$ID}FXMjAD^aiDZ^6kW2+Am}Ue3J@8z_TMIX)Eo>mt`05QYnPAVM zh51cqCnxd2TuUxe9v?6vAbVm((5#cG~=0Ey6Q%RQFE zbVbUIY}w4bt2|lpTTS*D`|Wp)FTcaZg_$R(VrUbX zY0nE@&xIPBM7&t&gSBW+Cj2VZTAGaCUBBQ*;XiFwa-(EEn2oQwu5Z(KnzGx?Rf+>d zD~^^kybp3vY*E>v8Sm}=79N0nPs;Mn&ql&!-B!XG{mkI;gYAL{Lo|ME<=2cb0=+2q zv$gJ3&^(|8YW?0O`Bgd`fZ0*~0a6#f4q9JBqx|q2f;5>cD8cTiOakHrPXqYY-~s3{ zo&la2^H&Vn@);i_fGXtOhQn&to3HPe>8SZR{0U)j!ZHSWj4Ml3lv6AShC@XLyHS>Q zFgPO9OF8oekR)GY07{_;>#Z|h$_f^A#^oFHlxkBLbJuUG;}G4~%so9`DpAaH0Mys@ z+ofja6Su%Gjp9L5ZvMJt`t%G%9^JcN>)mG59)gmTO+%yGH|b`c>4l^}cYFq}4Enm; zpAt|cs&w>yb;;1r{dWjQ&=lluT7nULwYE~vZc?NK>3zd=9J668BzltJRoplX}6n_`8k;_J{W7F?X5Cs%ut4O zYAF=&4PXFOCH%ML0M!sri6CRmTNSCuOJuJcnvvbE_<1k>6yvU;B97?=w}nQfZST_w z&cFT{Sa9Fk;Zc|VtezoL!b;)Lv@_{CHMOfeS7$f1CF66dDsenpT;HwD z6PK>anmz1JD_OCKjZf9&kxU0lo&1zcuC<>_*p*X_N`Dk{-S7B`_l{y&At~!@;;#I5 z9^DZYbvug$I%Y9w+n8GbtCM|7rWj2LF@iL3jpa-D*wMA)Z-Z7;(X#5w1P=Zzn%f1eN`%S)$LsuWF( zebhzzjj*cNTW%3G`Xb=Ex;=g-O7QYGAv~3aOh~cCh_z3Q^V&UeowRGsr_QqVx!nTx zbZGolw_sBp?{L&X zUv1Ul>b-}f7`57_Z3H3_w26WRsrJph(&*s;WIS8ix<~ohMlyQP0iQUXeQ4&*+LdBCLU5bf zQIC?s2GdTlbUaiw7n=%fKutTj@frshKSO9vdu?}WZnsK&swgP8K^CBCjG)_%r!wx& z((c=joae2*w<{EDu3$9qXbo4yxDIuk|A%zLKp#H*TtvFQM%EX!-+bcs!CeBo$?540 z`GTvcTL-&ef=9%u8NF53@kN7 zGb{KDFjnyG3Uy0;%!FMcb1jpFQ0(~7N%q*QP??+WCJXF6s$cLV@Hzd8s`Dg-VZf`X z&!f13Uyl|cNixeoWp7BI*@&gG2^W2170PNxbEFNKep?P^h5T3Fs96t(Aj6TSo7MxZFri*1oRw2dw!fU13ezUe+I*{ z+_{dQjR*9&PS)=hLE|PIxehZ^#Uk_a^JxG&i6YUK?C7(V2M42kDwTcZF7I8tWIsE- z)M3zl86eYqSw+RR#Cl6RpFvK@%}^bW0hUl;SWrpob-FB1**_8`07^9N71Z|ubY|6A%Lm4D`bCo=Ni<;0#We zDE!~~$^gnPnLyP7_3V1|a@SR>o=9dZU*CIxlI@wnM_$QnfmfI@z>Q#AXhPu8qVCcy zj!RD)uLq_#l`X`J=0v;EH>J0Rv+MJ+#4AB#j1>soIRGE4+pEvNI9|q!}<*x3~44{1ar@`_dp&W(6N!y+=;Qunog7X^^^b8 z`GB5dX!o%Z2tnt-I|i9@%K%0i^m`LcwH@F7xEb=6$4JU|6YcqK`P%QqKgf6w46`EI zdX}O0|oS>a3H_P&1y$q#puz?X?tOn-^GHyH!1B*BEcl(Nn)M9{Ly0LJ#p5B^SpFiz83y zE8^FZ0pGv%zl{9D2H2Eh%X$6r>j2B1nC&}T%jZdM;{AX46yS7jxw!D>@iQy9PuHS% z$jPb%EPs;=9P#Oo{O`4d87pX*ij6g#ctybCupws?7TfIJa$y{G+4TpUq1?a%9#*#K zujq{{5gYB{acsF?7i|xavZ~$AM6vOCGp?trO53&GWS2{*c>0>z7QA}&#=-e*5B+h4uW(=k9UCXHng6TO=! z5q5E045)Y5)MEemJz^0((i1e=3+PBmkv$SL4bq*trb{LXOOuYh&V2f4P*ua`)dn$7 zPM0I{(P@188wx)(8<|n!sCkss=Y;(U&CnNXXYl2~u;ZWu7i8p|!xa019nWj&un(gh zzo4k0IV&Rhy4dL*S3K61LB73o9u<ZM1ewBG@>yQ$x` zDHnq zK13Y~z7#wF5BbCp=CFbWCTu#NH7$%~!&&F_%{fvFUG?Y40(Wq4ZJ$^f(|_?RZ*jU7 zz5Qokr)9d!oY->)Vh#|0W}U~MS$EFhNrJd#+|U$ys`Dla!zlW=R+wj?F%7^`oikAW zw@p>h&qLb!URk(sYkx_W8Hl z3ir3pM`G!+rI2S`!vooa#{gI zcS6{k{=U?!%-aBe$MnAQAt~j)1G_2F^8EXOO#8|wI8K_G(9CIUs^Z9I@|fiq;K7A3 zOKU87>y8~x?`XT5kLMKW6;`BsR$u?N<4FKm^DvOHrtH)Yt|`X!=vg8k-b$LlmAQ8} z_NU(6cP17OT@rfw0KF+fI};iV>M(y0$OZ%~L2_*cpNP~y|342t_5&85ua`H~6LznX z<^h481#h~7i8_z*+nnAQH|D6-y+CrnoNn9GZMU55mbLdMKZ9gvXjG{041Z4EA`u~9 zYvyPNc|QrSf=T5gExb|qzhS{|qK)=Z(*exD8?-kDR(Z`aah}fq9_2*C>dyAMVwyrn zS=oX$$V_3UsGdu)?B_ihA!RDh;0@kb-Y7f9Qf1bY8!~tG^O?C-kU2;ASZ07XxVLqD zcD|J2dbw)Tk8l=uw_H?IRd0cKe|@3OMH?ji3vWXu|N6Q6{59@wRu-;9^7?c(0Otpq zBs}(BBFkpF-S*s%#?5P!-cb_p56+*avA=sV!H`#0+@H%`sRCc#O!8ra{Euu4vLNCI zC^#6~x+&B(OlKVWTXRVYaHK0~R&^(Iu-N#rw<;?ARz#2^e`R0wqzz=|x82cq58 z)xj5s*F@fb74C2<_h7eMKW#+jqUNvSa&^yYU2mxD3m2cF1Ft zF2|(s{Q2D=$6Jofw;Vyvgzt&|ii+Ki*TmhmeDC6VaT-6NG&mb=7lS-L-v&qs>ar2$ zfUK0FtI2smhbGbLdPmKja8-`$Ga3i<%agSS^Fkrrf3^ z9q6E?RT~dOY21o_579Z^;;#l5$4|hBe$@rb8)tX}9dG=J$nRG6!qoH^l*$R|Z5X<~cJbKEWW0c?1FS-0=G`fBEqrWWko96dY1Hyag2 zTfRJnqNgr5Q9Df3Ga!fy$3xY&8$50T`m)3}lZqxX_2Ex-smq7Vh5CJIgH+#?@X=`1 zs@TV?y*PAuA96{@z?ebu0p<_#gf|94Q=bu0{e5FJb1yxAK&>RWP2Q|{;lrqn<##?R*BlK#xA(e*C)!p&Uk_0ngj{ILg|IP-{@4qNw6B( zb+_1OdSaVd=EG*IWRF9CKM0@;l0wb2c_*gSe*8&KR@V=jcmJW0@{sq@xEj0h!k2)^ zCt)#s7kK|z1Y~?-dHM3^(_TgV4a&{iYiEf}W{G>Ixg5DXn{ukk{%wed$Ip|<&Uiw3 zBEt4uIQj;)$i!Hk5|DqJ(1i3gr6&m3os%0Su?#Gs+_B$UeVbzk9iFJuX8ctjt`WuCQV5 z88rwX^-94|zRkniqU9&W6`%KVzTusn>W%w9P&hFd^u5x7$|~=We*r z>?>rh_B~?I+tKQdA97*U>P!i^Ey^O)2xV#MiVQU39=Ue_i7XCN4qPaAcQe2KFKY%v zI-!GHZr*RT_WQjz@)%sn4UC{40o^8C7lELdIcRhn3L zllE5;3+t2VuMr=dppH%XSPMonK$DacYb(`9Y4T2?(N1yU3ZHLuWwGW?{FQhTNP5|Q z#_5$DDX;loiu1=%m^t=D8(_E^wB4yC2Rj&#-BoRbv8^=)-qc3g-)N6sx#rj zTg5twO5turqkGGgge2f2cu$)ALgHf~*H51{Tptv@R6qazbpzZ{=(9`vc*;Gn7sC&8 zHdar$&NG0-+I=QAMNBK#3=xtfSN1Eb9)GVGDjb~rRayKuBD(twq0w=M5OSAGPff2{ zQ0eK`{8$|LjW-?S!_ri5qB_R-W>jLk`fF45`f7OrhT=q(^K#`?R3+6;=uxp`ekmK_ zUT&tvwgjK#R9_Xf@py z=m5M*_(6yva1c1Cx-p1dhpVS8oUPDxJ%G{q&g0WDz94%;8tJ2R^m>Ebtl+B_ka&(j zoWt8r!sKqiz$#HGbS}xTwo?K*){V%b@r5+7fi*-?TGo z#Ji9{R<9=WNoPrx@5){kH}yLCIl3t%b2|2bM@H8@_Ab*;~Zf%)?)P@_W0!cYN%6nq^;prvY%$7 zzd`I6lPkLB$&ozL+e%H{Wq4$YWad`>R{lfr!6%Af#@FDu(!|MC5mIJ9yJ(<;$v++b z4_gTrnvLbK6F->ZOxp*|AgL^38=H!D+sL4mZ8WX6j-h_4HR%L=9^t1U_84+dVSGm^ zbK`}F)n(eqqh#23P5*{On(b#2ADCaQ5wk_nRQH0P?eD0&gZO0@B6QrJ?qET*7Pnqn zWIxl1JZWe^cc(h!hwN8Wqh@W!)*~3ljyok5G>?9^2OzhTh0l>5YJjf1+L-pKo7UX^ z3jwtF3rbRy+DS76yq zLwok7^781Rbjie_H0dxKAc{Nh7(lz!hvT~iCu@+rceVt3Lgu>mYkxPgtm)T>T%*OS z`L#oZ|IEq%-@LiiDH%TNR=7)s9;R-q7q_O2Pb=k5KMTfU$?lmPI^N*j#-?owq5_Tl zvDdVJ{*>I!@VPT~v>!xdv8Ov91B8oB-F0^h=IPMk<8d0+qjN*%qg<@6`-nDY$38I! z@{b^fPlNypsS{cOc(h;HO<`TQw+~CZVc%oxzD3^x9845HZ&gRkw^!7l6-mrX>_O2Y z;L$>IP2XW+v^!_cqHId+=#Th*=W*~Y1Ucm6LkXFrPU%IK*vg4Nn*8SqeD_H=L*G8o zGmg)A`Az!H;g{bC+L1B8EKNZ}g~;UOY9fM~nnr#sx5iTHyzS@Z0ibX~K7XpH zx#h?;1J%2dA6dk`FYUY;8(nrzNn=t>O|G_^6XkD}^4OKyzU7J;9(?OVWDd)P@b)pu z#;gIbxLNw99FDx1IA%R`NOr4f8L*nuDD*(j`KY z$_hfb+{rgl8`99Y$AyGt=Ewr_Zcd$6>|$LmbMvW9g^nYjwA#uE7JyVb0$ao*H1k=C}6 ztdi%+^*~VkXY*eP4t_9i z_AUevANiF_vG0sOzBBIGa9} zMZ{QaVCKtu^=i|57KbR_<)|xfjf@=08G=uO?gKJ{c0)x~9kl7h=d(iezt0La=PlEnF*CBAOGrd%ot?i9c=@B1b8rc=OBShY| zc^4-vQqBi@zIlL2GV}e{90E#3yb3*pmo`X9_MKYGMb-7>sr@cDfz@A!qclK)exiz_ z=!Bjf%j6zH)dWbH^-x({qgh^&H%}_;QKC%$zGZ>Mc-+x^lYm{O=amQ1%!d0q$6ds? zT+aee#CgrT+}NLSXgP&)h_#b~+qL$|Txus$6TVN__S;pnsps@6TFywf8z^;seNieJ zgbw?lmy|zfDUF{;TDoDmGqANL@kSj#Y2Kt_D78iF#(99k4@&7md3`RN$9Rs@>PG3Y15)$nY9^rBhIX%~ zy@kj>^&$Q^b7!%>_@QjN12l3BIiUwu0;JO?F7`?8HFFrd3=X+&PmiE`xfRPf0BMzL zfjK}bM7@asIa>UvQnpfm(^u!hlPt2^7k0zmT4#R?%#qX5@Sp}Wm%e^A?`8DjfS+9`=X@Ww65{E^vHWHolOx1YC3Bf&x6x*_ zF0K`IG^dri9-xg@dwA^#JFD(Knbf=GD zS}`r>50Gx+wHB`wrnT2_mVv~B&QbuZN^iY`29$tRsb8Sqf>+z)VDeNB)f? zAp4TKn{Wgsbc=m^hHCLxO!mh#!C&qpOX?OyrFrDjNUv|#eV9pvoXshPsZjvHZdo{? zmBy+Sd*HBx+Ji&J^18kn#C?_jqCo&_Xz0}n_FEFx(Rz?Wy@T2b^RXaS-`6nrwZ1hZ z6q`t}zTAL-fzt$(+Yy5Xa^Bcubfioo^}?p%3$Wi|4Kf|5+PJq-Tavl=!*axI+)r!U zx~m*|+=WhY6nN(2$HL!<14@ZoA4g2Vqo2;<#)v6={k)Htf(j$9@%qM#HCR8`2Lksz zuw#dtg<)E8-YD0tee*G~ydOttokxi`eOh*-o&0|V1Qkxfea*dBBBt`Er$Mo_X#cHt z(vs=J21I724CPr2N9veIE6SMfnLh!C*+G>1Sr~?zimf6J{P;fmp$4b&FC2fP*iP|`~HMj&Kc1mu%zLLn2t$_Ue` zPG%Krx!+CReR~S8eWtMka>F0`mZz~<6N+$!N314{ZPC+eh|l!l?cZ>9NAOvQ4FPAi z2QAEuzo@GOPVG^jCY8T)RyhS;KC82tfY{sr*m}OkMTRGtWUX7}rztok(e>kNZ@8-0 z$q=4NJ@Ujf zl-TWd#N?=27gSMv*#K3x4qkOKaH!b6IDR@Odx_oq;$6ZEd=ZW{>`MtbRfTeAulrgh zg?Z;hKc?U-G1qb<%WtGj>saR-bux8|JzsRY|zq3LO0fu!%gj`Xm^UK~u#*GJF0p6;plr-JGVN%OB90B=J=-ADg> z^7%pe!v}+aw+m0d&LZ{N4=7l)GnTHE=DoXpg4BbauAytr_7cBOHWivHMyWY89~Mye zwsHk#v8wEEmyAhc=4~8US{yaQp1@SvkxsluExlx>g2r)m(aLPwT_vak_bI*u(Xm6N ztJ)OLp6n>H`n~R|RJ0doceo9_)3z-Wp(2DHIDvxq!-AOf@eXOBgWt-N6W`P$_ff(g z7?6)9Xh2SG9du6+k9pB=O+im;THFqgD^_T^`Dt6w`}xS}irk~FwXL#NnFS|Ay3jiD z7*6X)Q%e;;47ZCu=od76vT5wGAdS-{vjS$XG(Dl7y3OBOzFJc20@jiOJA>Zfh3bN3i&kHbyVxfWBt~zMaY}hF?Wc7ow3HwLTm@8 zu*HXZCz(QC{o!}mRg^bhH@(q1a(dGu!&Gwl1-=ZWm<}zs_e}4)i`?Q@B^v%E-20Y4 zYZ87~1_j-IUbX0sWP9R)c;4&uTPxxLMBf?Y&3> zQOnzjr;$U0wRd*n*FjGe(jymR;YEZwr5j8{M_=F)WTOa!`}@Mt`C1GD-L_+&`9p z)yACaPPy?O`)V%+duxWO*2%xn>!}X4X48CHS*Hn7b*&>h@PX4gFwR@zZeRuc_!RhY=Q|$t#WRQWGivdi zR{G}DAYo9PS_qur;2_g-(l&UoC)10FGc)ib{w71njgn$_kZgh7JSr}05o+0=WjqR} z_%UY(hTzJ;t&T^&!N?%MATW`hAC31;kejpC( zdRe61Z5!1V1$_GXd-8rBtMfihbHf~qIQu@@UtOw3|49}zHas$n01t3g5W590sQaEVV;0Ev`8;%6#h(F;A z9E3L~;59*n)036?ACjL|)+DvwdUidBLdN%4lN5m-D35fgc&b+SC6Sj1m;?m7grESF zG*0^m&7%yBUqNgtVP%3gxct2@jn9ui!{1m0EMc8pUErK>35_TjR~J6hi6mvBEkToG zR}bUG&yM)zTJ-Qm{-!wHCTq8Ex^)JY^H9@ksV6-Z5rqo4r@8>3MCP!vDQV5EZ15Ws zE;pbTvQq--)*idY0KckVs043IDWKmQKE2RU6PF;7FMTV6A~KntcE0g2{X9Oh99=!ZZM|kV8Sg z)-`lMrT8*&^T|k7Jf3yiE{_8D zGaG4mKr+*j8dM0qRVstXFDXG1j#CK|b}X}L{wMul;LpiFHgt4^-sCG&ty9w64WN*D zj5PAV0t@JR;He%j!SqHpJO$U)6*B8kW_1?VZ{Q z@$lZd=EYG;ozzNbKhp~KuIpUKAxk_KQ+5-dP8k;s=$sAyU+leiI9%P^KN(R=hxl);QKbM}zud7tn5J?C8K zT<>|$`#aakwf~vfd#|7wv!`1_4?pROVPu^RZW7?NPgt z4sW}W1DM-cTEuoYuhqW3Mg{&OGk?vU7c+UV1p>c7=G7zZJzTb0){Zdfok0vT9wR(` zWPPMYn9+Z%;?cE13OX*v1E=ID4dnKIvSn7o#zo4T7GUK3H(6JH#L{AP$Tk zdZ$t|%JLL_bB?-^%aj#Ygt~qC-4%nA@QYc83`w_25ZWtez0hd>O9;Szc!OF0>^edZ zR|}zM-S%8s2c3^HLX@-g+DiEB0h@NwwyAzn8STl$jCyirE^5!z8u^cHO)a(Lh!a~04Xb<=4aZj?^w zcr@pg4$x=TqSRJhg=vv?bSw`|N9w&_z}e#x(fdyrQT(m-2LtS0lyC6tLkl5t^k(_o z%w>cA)L#$;%_)Z>L{~+IkFi56S^Tx}5VDKxQ_C|xV!I`VVBZ!?CcfvnSowjWWUBJ% z3l-Pf9}dg3#Qt{NJ!L=5w16e#K4yd5V-LuThpuYQrg$pOI3k7F=e+@JY4#Dw zdlnsa48RsRfOSmi{`%4yu;bIGnb)T`4XKQ#3re_i>+L-)V?(!WJH<>?LlLtG&OftRCrpDY(;>_!PZjX@lHz94K+b0PWxh9dgBZTzFt*)v_Z@`w#p4^Fm zMBd1?8^|vRCqdL4b*&&DUI_-a9|Atx^5kLGQyFK}(ER|6}T8w-bpXzCFdG?Z7TV0u$OcpFtTbKXN5tBvOaiultrGZhF<7Q zhdln;3YOTffu)?TBUPH)-J|l?pZZ+ZncRYQQ0;2IT*uEdA4=2WupCZy|9V$DvFk=G zL*PrF8d`C5reOBsodOlMT$n~8$eiI?TAyNo%V?u|4StqhHeR=4u& zTTjvOe6sT0+I!57+gw$gRscAon23UEY(`)L+LhnADu|3>k_nP=2~Rz6L?B zK{AT=E!bCUtR=YQ3fsbO#Xsn&&L)*c%3Lu4CGb3Q&aQh4FIy-ls$-OkU9sBS*F<>~ z)*2i{)Y!tIsKG<)MTdf&u46+nugz5r55ZNVK?MfSlZCc$6+@dmC)#PYfK*_Y`?Z6( zWA|5O`DTZJX8LVv4}G%JwF1hXomX+6atk_e@t)ufD6{VKwzPPI>R>^9IWpwWk*=pK z2L7=P2Hu#S0rox{NZrd1T-RFP4obMgaM<<-03|? zj0bZ%DVfAWL|&awyBmrk1Ov8Chl&R$rI@O8JT&DTA~W zkeAD*`zaSB%dJ>@wC$B0!eIKPS9uruW*K;YRrgts@bBwCU6p3cfn-Mp{l~8S>nj70 z`Z}v}(}loZiG>mKM(vY&LY8e9W)y9D0#@VyV27zsJprF$Kpx0pRP=OC9fq1UfQ7Zv z`P(wy)rAq)M(q^_pet>lqO)UE1cO!c>&xEjhZ22oYlWe)Jt+r;?I_rBRFk>Ulrsy$ z`ZCHL(zselGB>hS(NEqRHXz@5b3$KLCKTN%F*`-WyL7>8;m%vgzB`E2;(O`9{`!Cvk0o@q>O*)N#% zfrW?YNcLgs^Q6*=^4u$2kvTSn&8Kv&vl49hP|4~+a<$X^H+L&Hn}df)IpTBkAHV)p zkvAQdSY)*6NU~H`VRMSuEtj%GF?HtZqJ%GrRJ%&UJ{#=wrbXRJ8SAW#$H+fNhzP!#9E@f)5H!~`E>7)f^&O{ z*9kerc6e(``$YLKE&va&)v~d&B`;}i;^}&xfG?U6Rr#+FQWAA9;Z6zlfH=BR)jVH} zKGG$LWH!9S^qjCDPf#VDMyhUMc1&AuJY+Ykypy~34mEwq^SpiRAhMu%pU)hprexLL zjbhWx`1vAPq2)dX(va>AHxGJl*WtQ@w_%(ZnwUBd-C4t`l3IHw9Uw(PPHe)&{0_uu zHY)dY7CuNxMKJ|eT9-avp!mdlh)KC z7i2w6RvK2s{*G7W=b$IBi$;Eyj54@0P#k zr{l3l4+EZoAU8p%fDR|d<{H1hHJnz-X4 zTMrg@+sg@{f;`QGTAqw~YFSo+KW`#t!?ty*R}(NJR!+al zOuK=BLVJ?UDXEv$MlU^dMgR12rmveqmv;8Pk=~*bifLr?ZHpZt;l)Qj=sTsMD}%)sS1be%&&>n9fTwA4Uh>=(a`3R1XGcACN$|#1_NN8G5AW z-KI37GrDQ}rtDH=4T-$McE~O18}OAs*lI2>0(;_`?iY?gSed%!W5I^KUr~Z;$(&s5 z*{oJGX3GUVWPY&>m z?kTc^1TfhZ5+h(Y-9>|^N-iAi`vijS7f(Y#n1e2P?rteIC&ZNdU{!6THiYkn0i?Ol6r_WCZI7a@1MECujNK`0N*}8?l1KwS z%QMY+uTU=KT&IZ4{MCX%XInu(_p?Cbmku&2l6C~$^D%}P7}^2;U9%sboRHb%UYA%t z@O}tEcj77u%ok}ys4Fw(c06Sf2lB&^sbK^>WJOoGDi^)KI(NEf?z^=X8Fck=`RoBX z_jru5og8?#Y021!s3Cy6_|tG&j!9)Gi{^uo?rP1PJSSscg+wTd@J8% zJ=etEG9cGb+8)gR&QuOavKQpNnuZGQKHNN<>X!`!|^g-&n;nFnVhPgTQ% zaJ)Q<9U38z(|JvM&1;Fl#P*W*62r$2eU#tjgVUXmE1WhMudxOCVoUaQ0xZTMZFG%x7!U|S7#x(I9_d_bppbq2 z;JQ~nC>eNAKIr44$8i!EkGmY0QZejj;nYf1^B3W@!|WzyY_W~$-j*PFUwddeV|xv# zPW-RxhN1;3N0P@j#=xCT1j~te^jYfp$Ml?^YvQoN(%^nFqw+`Q7qfDSODaGrL(& zUm;|q@SxZXMJxc*lj9``HQt7K-EMLM1*q;UZ^-8u=^W(l-n%N%#zOr{?X8_78E1FW z3zC?LyfnR**#-68@(wc>W|bI9`hQ&L0fo!Ikg;~!>E0+ zAymnqBLDRk8;yUCKArB+ZSXvJ2S(2ogj?)jg!&P&?_HUv zsh^)6ZS{`gGD4Q-0v_W&fn6AD=aebJ=_w{L$hJdsgLKmF+`QJk#See3wbGYK%u$B5 ztv;WkE6odtm+PSCAuFt}_#zIB?TUUC6!0bkf7egcI>?S4tJs3_(vx-90YxcX0z8DU zkgHn_Hdp-$c-cXJpHvpLa8Olc8Q*cBmcT6yIjPf@cWZ@K_Dd0#Q;(-AXj#VE zr5)eD0=^1`tj3ogus`%fBU{EbPWn3A-=`m%0{Kncz}^x-%r0F6Pv*McGo`2a~Dk88l$sgizJHVwTVjF>{TYV zuG~+w!*>7&S7wKOH$dF8d{_sQ8mzUyRuHrG5EAG`8kqV-L2}<(G=? z4J6_fiH}VDem>J0G<$bZJVWwlAl;M-3-A3GB{{Zy5B%tU+7?k_UdkWiCX7+^HU5&kJ_xvsv?GywFYq zwz??wFb_}oC^W8s5ZCvKxJ1^f-TaiGVHN$Q3*TBzZ{m;+tjqM=OV8YRdx25!qX`K7 z&l8+z&O1Mu3~zm{v@UhMckRMr=YT!h>%A_a-S$mxW73Nk40iv$iv3yHQVI3HMEHQ| zy!84XB`RMYBw*;%hTkT5$t#cI;mGKs^yC}gi_H~{(v5YJ4mtaC!n9UYeA>XHsk?DHB&dJe+Yn(*1pglTVo)hyH< z&T&!_{`!MRcdIA&P(){L-N+!|=Z>*X8Y&nZI4vQN`0dx8PF|f(@((vL+6hM$GMp8N z4T_uHY?uk^s}r5LY=hVPuZoZ*xJ*?g= zK*fRiuK5+U@R`Y))Fz_$=FXh(HJSl4t(^aK8RzqD`|8Dc`z2D}V50O(zu0T! z0R9xc5v8TsIxbhG_Sh0aA;p!@qhBMk z3}4d$oEYKV0iB@Y8yuL|&)UcFXfj+{y9i|ZIqS?8c$8IQQ9&m8R$IcBHd|6j)*v~ zebsH^(5#6wQ*T&b-~Q;z-BN5gRF(dt>Uz%=Be`;(cO^Vl`PJy;QQCXxk)XZ_U_ZXy z@?A@1Gc>Bxk3yh)Xk}uqvK^pZCu}=eUBvoKm2zA4SS{Ez3Gn9@DwXvDFo)cIy`*|B+?P*svDgQ0 zhOq$;1gblG&58gTF_qRk`y1AHSMd^{#$WC!xsW#A|Hcn8v#>^&i{CGUlow=&5KK3&QXP8-$0 zR2DNCg$xM-co`;O&wJ-dcjha7^`-d+x-$(`4uq1^Z%da|WIw80Hj0rPa`aKzXpQ#M z&c8Gwo0@cm;x)sJi5rt&dQu04&lSo*Dt8X`=cj=%m!3K1{I{nTq4jRdfQ9%y8noYN zF?PYRzVp`O)5pi}ITmo4h;K5x-^CH|xQ|!TT6jE)8kAbxXNMU<2d{HV6_WnoDH=lLBq(^(nBI(jj9skc@kr1!ap&aP{cD@Yr!rBYtr_ZT(6S) zfXrmuHJHu|cU0qk<_x3$Do4DhfFPJ4)cH6zoC(gjFpA6C-w;NRNdxvNc1xouLS}D4 z417975|cVBCWcQ0m_?;9nt4LHcbJXB)X1N)`=$4!XY0zo%sW1rpuI!EZzo8PP5{#s ziiBe^(StqvRfQr>@0=7Ju^2OG!hLBYF4gBC(+I{8M*v4=%&WDl!OD z%;$i{l@zHH*uzcFxn^8vRV1ViheLGBS(GYsl zC9C)PXhME31BR)OAzKaoWTa)nRgp-){sBCG)Cg1QY-3$zi%}VDo}IMDhaNuA4r_Pe zH5rNJH=f%2&SaI7Yd-91wxOUEA{Z0UIQ%V($lf?17{J2nF^xYhtXB zWEb|NlG_@Hyf7#!YYYzEEtj6h9ieuWt_#hk;zt?m4vfudSD6l1c89RygtpPV{5(E( z|DHrmZuHo9BI=aZ_)9N@IM8)9+^lre2^v=m*O^6jaS8b7?I|!H>K%DS*j}6Whvp)( z$tvt#+%*J>G`xlm1JMt?jl#X~rHiV>F&cCx!%ENR@rl(D3bz{uzW#+u>bm@e`fmDP zPXdbRpmWZ!N56}4U~DcH(9nILJbzv+m=mK5gfQ&I-;(25-3ZciyPo(O2TvOviIwo| zk`ZF`B`zC5=huITdH&IJP!?y!VgQ)o+dP7xG`SjI;B5`DnwlsFCOJ;DXuH$Qupt)~ z4u&EXjA$J257r;?e}CxI@X&f{b(ho$s#LqOeX!aritYDYxJb$o7}cA~lIoIL2Ye_p zb<3%3HCyYsP^AY;4y}%Ga%{dlS+?f$`$zJfrOKQ^?irENb>^9?4EaxocjxV@RIjky zZJTDyk>go7b#ASHjRnM0WT6 z|D5^%W@|ts5TQft+p4q*YWjTc_(t5B5l|CNJL>w-vl+tUwN|n&{Xx*|?2eO}13df? zh+6y#i7)-AMI3Y^;vF%cy~%y-fhlYnA9e#ej`w6{tW+x*OcCPrSq~Sx5RaI z04r~g_813Zj9tW$T(~cqioTFl+Wk6MjGcTIM*G(wCbfF+izD__8@)#Oorx#+_Ol4p z4jR$CzXpHjH5|MbO(}GOpH$>%6;~|7CjV2xOD0x&G~N+2LiUdS*?`ejZwM}ZfJ^Wb z|IX`JW7}W%JqMwcB+2LLE(2FCQ~Oed{?vJu*+{siQnD=a8oLtY!4)`}%`TYm`RR?v z5-?Bfc7J#>YIW1bAx~tKe{-I`CBfJ`PDb(uHvoDDNFX2ReH7) zxs1c18UVm&dT+G-ASy?FBb-Xh@GcB}n+``z|FX3_7P*5(VN|<{MLyQ32Ywl0BP2>3 zU-#J<()ZYNF%n{9l^vQN@@FyYN3+P&`Z|nEvf`R-j0AWXk%u(~qqNmmc$t-A*)^gh z#wwMXKWof_hmTC*r+PjZSPUJr*3kKVx%=@MeiGo_ryP(pr1SG4m*~tJMzi2krFsk& zczZHH7lo_4xr<z=?-Jb!EpL2gP8{8 zC;eeIUft7{ka+je(UEK-Dwrk&$qG`jnxEGdbwuS0W^dwsi4ZM1Tp0yOYu{xI?HOz0R zOxjMNTja^YemGZ?U?6^#a-9M>j#*{CLhYSrw7n`#_YzX87rlhYF2qeDzuw}XeBpR~ zdjLQV&ZY-nD4H5k*m^%6=o0-R{MjlGf?nmK@9zq~B);RIG*4oGtD;kXeJCw^2M>;3HeIb>CHmhD6Z};OmKE`R9`^aFp6nw zcOqM4Gw|?Y+NT*mtG@6cEr>Mez$&=>8<741HUWPUm7ZSRE?S1j$&7yTjR6<+4(V-> z?qAZlX|=@g81Sgaf+wD-h>tK$cUX6{x!T5WR&{4WR`d-RZ=-Lot-+d z{7^rivfcbuk)h+V;TMXxJt;6_fp?^F?9c{x@6z)-5%8rKrDB5#<5C`vz8{=fuBSBD z_V36nnG)f*+!^V)@a%@jZz$v;L&wb$)AZjhY(!aXMF8MO0{rIr=_DT{X^g3#!+Zd2 z3bvv2HmOO55GB13Y!YF1hQF8qaCbTO?ku%c!7H@uSpT^Mcobn2CFg?)3LUph0{un+ zJ(75TN6S|NYzW9Gdr0gi|Fk&_1Wx{jI|8$ny`m2fdcQv#UyBx)Px6J%q@oYnmxZ?4 z!+#DiDB|SRzI9VDgsRyC-tyY&>S{p;hmI4y(TsL&8bjy8LniRZ66;0DyX|>~a`8W5 zy~0X&AF_l$s2wVxqAFQ`(dzU==-%5k#zQQX@+@+-)Tb9PByxS`(TJ^q?-S&2IXnZh z?~lR@sFEQbHaKgK>yD)Rr7Lh6*!<7VPK+MkQ`ht482ouwh*Ip}sA3 z*%ZPi6Y*X>e)}o-=LNIq#*_`u(Y$5IpDX__wZTT77)BLzQX2E9KqXOu0rNX_9eL*@ zYb$9>7f7Epa~Pd);WeHyHk}ns0`anB<*QSuj`~P^k0C2M);;7CdB*t?F2{8*0esg& zCwH{FGb7p=U~A+}lC+AgRg+?OG7AfOPWIlKakTw@k^D*8Rf}kYen#Osxs-X{@z-_e zyRsIC+}*dF;g4rf!WgN$9&=0_Fm#*voyZ)-O3tNJ0Cv0lhIT7NB2?vBaZzA^`flN| z@_!a#5adrE4vmzeSWvbuEOhULlPLkTEt?>ZePn` zx)Aj+I^9PjsJMg6=Gp=Ky96*L@xuZPBL|utmyEIdRwVqyoiwtA@V=cuh#~kAX`1fJ znYA=#_db*CLP$o(K;75oF-yu=@HP5(W#?H^v0!H0NE%#5B_Z(%DmUuHZa;$i5I`8~ zMwvwqx5LPqJte>9X3d!s}0ZQn^q49~N(t&;w}q*$(Tm zBvmOU;44SBNE=qqjWdoDPWjwwB(zQboJbr4?U!evj@ZQ8uKW1YU#PEJC6K264FCx* ze)7OPKqk;%=E&`#qyO^f$_{nF@&+t<=kXyl8`*#$mDPt>{wkWhz3}hOln({Y=Sp`g z$JE$wQCbLVx0r50m*~{<2IO=h%8!Zt(h15-x5Pg6+^uKu*~lgnx~PpdxW%&HJ!Of7 z0RkBG&Z!5SRxH4e^}C;~mstS}HFgcuU8Xc-=M)EiD0D~(irzdU*FcpBl=nX}=*U5p zNIW`|5vTx2Y>TZ7(CvKG3lYHRWaAo*N)hQd^4e06J1st$YjoIAUGX z8i`V#tbVCN#oH0C2!8Zc1XlG!SAywP(xjm`$H0DB)8urldO`CXe!k?7;2)csW=k|DdOKOzrNI%es#vrf<<`ZH5iF9T&{i{ zmK5qKlpwhr$LP+O0f11kDFvo#SKhTU3#{Ky`hEU9DGhMCD823f^iclZSC_V_>x)<4 z{hh9NkNp}=bo*CAx9v|xep7EF&Km(}H8%VQ7T0gWQ+jW?C`U+M(>!l84$MJ@jLqZQ z>GVUD7LJ!+5#e>qwQqj6LDgF`*lS3Xv7-~ZSX;}aGss}2a5`Y0lrwDh=#I*JyZ$<8zs}I> zh1lJplp8mP2y88K`l<%}#%Mw4%y8B5V_>p^v`8lyEM}2bsK;IvZIfk?O>Wp0tp5yW zHMU!&buh~-X^j_8bLlDoBH)0}NuR_;>GF4`n=vHA88g_%$_IeDrb-t*DP2-+8+rMM z05u9&w3|F5@Bv_`Wl&|t#rX*0&Okd&r{6jcfIJOO>1Bwd=jQi(3EhwH4v_$t-o!dX z0RIOhlHU5lin6m9vwu`-!jRE_EabPp?ptRlD2FD~{a)HF?hhfVu`%>kyHCnr3R@Qb ze#{wHzy^vNc+BkiW1e`RrQP;y(;eudadj&XBsK3PiyiNcm`)fLwN-dxQAg7269?%G zbbyNk{k_Nl@Jw}XA0GC)u0@NaX9(6_qiq)WK$&FdEL-z-*kKC!i0&&$zl^Kjf`$AZ&eA?KjTllEiIk66 z_3~dOit_AW{c-8KkJB}u`s7uRDy_tcmPgpYUJpw4me-1y=P*k4MY?9fYJMy(aNByfpl@S}zKB*pOvz9RInIduw8V1&lHZ z>LqqtXwMT8Ut4&k9M)I-^*EeN|9!7t&NAd-!~BEB%hV|&kasz~rs6AyX3nWUFA}To#`6s$`|Jz)K9Hp&S1Pwlu zwWmG-AlUIVWnP;hp4iz%+oiIa(o&#P{0 z(`O=>T!Lq8)(sc1xVT|tw0OVX!`6L@_HIKk<=cP=SL~a;uW(mxfmmqlJB2npaHV`K zjA6#5q`IQoZ~=y9e(Z+s7BBDn=)9Fv_tTiqK)EDZ(9Cx=--uEng|w;rnF-(U@pYUK zB78P8-w*Zg*1GD@YM}kn8fzDa39-Z1QXzd95EQL(vMPx0Y#tK!Ly=zY`yP-AQ<<8s zItb{HBMd~EK0bygEkqE-t+l$fA93;db`c}cE5q!b(+5Fidgk_hlmvLG zN=N3IdS&Y;=CGH-#uGaer996_Cd065B#^KGq!f2c4>yJLylL3P3w#_NbK@BwK?lT? z$Qy3>?Df<*A@N#%{C2k)v13@_e&PJi{!@>@A=KbfM=?&|ce?~-;O-Kv0*Tdf?lEv# zzwfM%1>*5@FdX9GX;+@ljnv)e@%gjhyD)Co&2QMnx!nbC|Kj!PwI>4p{GYHX`DYRP zWYRdnhre@8?eVDp?K%u&cQH;7Fs;{7kt+ntmziG;R$3BR@L}WsXZ4>+FabuV?|{xI z=04M5DdrwFN+AG>x%Glv1jZ16W76(P48h<_KuVJGp_u#Jhl}!A!E#vv3f3eaT@8bB z-*`;sW*B92aNo`;Q;&K6<=0LH12N2=JMUvY=;kTJJvZ&CbIS#A+Ac`iYoZm5>d0PR z*!Z>P66sji_lEY2QO@8s`m-^~fWHT5gWHg(|9JHHy;%#m49z7(M7T`7bqZZ~wsVIW=UT-XncTTHY4)2;?hKnr zXc_xG=8|vl{%6ZlO7(Mk5iUrXz~k>6WNeeMUDBnsZ*Jz}51kw)uoxkCg4KWVq$Gbei(P#raBJnTYGJhH9QwYy2DA*bfN!iTTfW zdC@@&3u=RgDa9QDE9GozwQYPCR&lFDa)7a~&1n6D^3P zqKZ=osHj#7CBRSVe+TpCpFg@u-hVb205x}$w#Iz^dGUp!cTFsTefy|Xe5fI~(qq&4 zBp|&WHZgh>4@3V@6QXgbTZU&Vh#slvWhJc*1UdHNL+fA94Nk-1K7)vm$se+bt9yeZ zc6#|Ahu3vES(niG_G8_kj}B781zik24!LT#syCR6nskLZ6)>x2d!}9+xw}KI{;fy2 zBep+8i?XbG*_aVA3$RjdS5+?_DF!-0L1G#|rk;^w0paH&jGjup^TMxvX5hyOv>eQ* z-p@{TP*_rrAGzjMWhP@cH#jI0yiy+!6zCYU@cv%vsye@u7{o1()Z6={wGVCB2g~L#lb^ufU{_H1R^WIOI@FC-WE^#z(A@)<9hHow%7PQig%lWX>-l zyskc5Wi-Q|IIb9OttTk}F!`xnvP#?TZ`boLpf2y9JI{r83k=hc23iTH%&t+$!eUiZYF!_J25fI}SbZ|#- z){I))-lhznF!3+rS%I8jB_P>@uIH@ANNkPBv_*(kA7HxPcsfr4HB3b4e64@J!yVhU z>#2U)_z<;pb4xC3ep0GN+QDh(arh}f0+x#ptzu;smB#!i8~$W674=A4c7j5}-uULI z^ARlaVQC$7x_9EEB5&ZZN$FlJk->18tX%5E6X`${UyS6(xvC=&5}GQ4@o%knU5=@> zI{Z$qrljB?wV~|<6?A-uPd-thyp5W9dXU#wsc#H=)h@9>Gkd$}TGR(Dr3v6w1DS2* zKmm@&>^Smzd0Kw%(YBt|q!>PTZ+F`_mF~)P z0Msg2rW7@RDdqR-`o;d-S3Xf>Z^CP(z_MU zV_O+alNm9L%Oh&+T{T|V1-Zrk2=>yzInVSl4Janp(E7*7$+e&-s`fs2jcCit2sRm0 zWlKlr-dqKydBCLh=-R~6qkwI^IJ`Y0krDZi^;1odmpnh`O^?ri+8$AN3`xuafzWYp zk8&L*?}{ig1WN(l%nplm=SH>f{L`^%1G&dq>Jp3fR_gnGtRWY(M<6}dj7(mYc&C?j zf+;_D){9ViJHB{GH#i*^GsS_?RF{CFII~+n(TW%_i^YN+0>}2g87X@?A9ehe?YvNXsQI?+)-%rsQ1I53K09Do+&9~-T! zuvNcz3eXpQqK)IS@*6^1J2k?(@uMK+aIU zO@TO*t>yaG%fWZx3|1H{ore@=yVQB}oztD`*TXu2(1a%VQvznx$|;8Hu3G66u&1R3 z#?@-2^I)tw2q0N279kpe{Y~GI!M0~$NTxd|Bz?#6;|Q`k)WE2YQB zlu=ZOy3Lp!x`(arigJRM(r3|6m3M%gquV!V$`Zi)9VJas%i5aDB+s@ldG^#_3JA~(=Y5d+G!G#Pk>cdCRb|04h5WByEmiai5GK92qZ(A|t23aN zf&THP9Z1RWIQWIO^>X*}Tuj9SIP#(?sesIk79h=SbaXVE$Vk8q`eHas{m$JHtnBZE15PFwrkXbF*Zn+(hW(J&u`ok{VFGu<**3{{zO3>zq#(GJs5TL$EE) z7_>jJFrzHF2--C1JI0Cm^++~_1M@=LyNppJmwhA;>&p}(d9J(KW38MhDCOoimjO^W z{kZnE6GTS=5qKYF_W_Rekg}=ZB~p0qkN;RER!cGy%h@9>6uOwZN2<`0O>CZ?U|x$| zI+O+*o(0T!mz9b)Yq3$Q=AxQ80TvMyz@NeH|C>J}7W_k~$RJe|!tK!eYv^)dG{=94 z)cHRlQXdGQZ(FuKp$_^8+KmM^aGU`)aFj*5j3v?g9Ak4Bhl&U+x3J_L?z45Lg9swY z*O$KvEJZOSpfA9O0R)ypSPo*pXY6=fw#;NPvuGr-tlv=YW)4N|`X%WA=w;YGrTH;= zIFM*#aN-)SjKjJ90`9UGD@`d`K%RY=yPAnp(pCFP?cuS{P5j!#LfTA6odHe>*TQM? z0b5Vgr`zxBQ-(|^YVEwkWkU*D?&9ZG%0c7O*q)pCbSD7K1qd&E`?gusxAfiy4&J zG5y~o^8i9u;p;#^v6B{nQRMp$`*FPTk>s8)a(qjcu2cBRl+Q1mGA#Yn-UwmwH<5?1 znwSq4o1s5I_ct=GC4yd1YX_WGWN|!sKPjxGHm=)_2e$oa-M4eH8w|F5Ues#(3B1q8 zZQ!YowFtP#xmC!Sb19@h%ax$YAK%Is#zg4apV_MA>+c7yKC(c*s6E7-VImPmSILj3 zZNxRY^RXWOpdInwiEryD;n_RgKSV!>r~X!S&b|3g<1%{NsryO(bt8aJAA7Fy<<=0w z-pxGc{O=ie$H=)xWO97ZA~uI1Z~Z77dAiVba?+M#4Jkgw^zV{8oNhQ>uVU&1$B`!% z=nlKhbH;%VhfMpC%0AR5i|G4n9;lLZw5!$?efOm!-@hn4vcLVGQF!RY8FSmH=R0`i z=aj8&AKJ=g`~(9j#H9dUVC{Rf8azDT<~4fr;HTkh`5+j}!fjjcH}iNS$F^uDt_W^F z^%8Bif)AkE_rEPeRCq2oclt$O0l8f6T&xkV_)=I}iuTmPTg{KLlU-!62BQ3s;WI%O z`vcY>amw0QFiSI!f;=4-X6k>5OEn5>oW=%gV6{5|k~po0*!;qN6-(z=KwDW^eg`Gq)!kFrGO*A$bru5!LvoZ?B5|Mlk%u;hI_6uSM(X874>a5N)M-$k)FR=Y7VA!shy^G^4MK z zcqVeFh*6%ld)!mORY7vi(PoX?>=(fr?Tw;uGP?)i;A$;+e9#CuS=#*R@+2A`dANe&TM!YFTWNh%u&byougXo)`@9fosfZyWknwZxMnVingaaG@3xu^B0jrbC z5{@3T-%`8lYvcZC^wgbVOLwTo`qA3!2RIKoPyf9NE6l%?$;2ely!dCCYOSixS)EcN zjlbnM`1j|;pH_c(#c4MqnCU8&dLbBqf=|HUJMn_fZeQ~s6q?4BJxrfkF z2AcM=%8RHxi#x+7NO3O`MX2B+baR0Tk!7?7QfYjQ8^>>`W;T$p+pRioFJm6SYxCTr z9c>9N!r!W&x-tRYzS*P|I;IG(d(&%zcYT9+ZFsCr7Oj9LEMvq(8{J2@-D_UGhZ{2D zk+rfZ%vjt+DO4u42wnu65$%C0DHg#~g731aizC;4PQTO=Fpu1f!N^ectR(0zf|tO> zYK!2LvY&Ac{GQQ4DXYv){hjEi`fwn+neut)x_)DPwF%j&LiC|Q-_U>vDZ~sgZ zQrSqmVzQC7^#pUc7VP5;UpT_};*O}LkPRgyr~AUayx&qlG>q?oopCK186Q8>DYi|P zj_h$DpkR9hyROS%O)GUppPz7L+}!R>CWVW`_=I)?w1}cY1t*!L)6ki}oC(u{Ie~Rx zHmERylx1VRqiSU-@{(7VBr4zR;iTD}Uhq1Wg_wJI7nK+N!Cl1D)<>ffFYZU7Xc`v$l0k4(&WhSB z5rV05nLa+@mfDyZ993m7$fw;0@k9^pXJhX`toK1o!EpEe((nl?{pr~{1U#N|kzN_%jOrWfX)Wuqt!KuK`K0@E3uCG<0NiCNr)WKv1Gp2t!Bh zU5x~LelQ>Ic?O?@(5LvqwL+Ul^$@e}$G95=xB8OP6R7kY!S+pAQ^()$V%bT&9b#q2 z!aw(0yA|>z>Am$+;WTHV3)0D1UP5@wEI5IRY4Izv_-J1e?LpFgW7}2$Ph?@4so)90 zM7Kmo@y@Et&39T*u?qDhls{orKI>RE3jJL!MGG1Ihc$d18Rud4e$*xnfDEFoN@a#dkS#% z>~klaWw4~9L3q+S4GRy36O(tGz5=?3;Q)xaR>{6S=mb@WdiF+m$o3zg@vcn3ymDFa zr`&Q-%82+q-X&A)I=l6Ou@e*nzKdBGkKXG$#?M@Ph+SRpfxkBo<2W3#5X@zuHueys z<)){SGel55QiBH1pmko-e2n+Oi)!Sw|7^bW@!;hv`XKvPgkj#8L8sEZ;eD#)iWIJ4 z$-!+JGZNWqmk7>x(ciKxW*fu?#)ubJo+j4%tW(}Pyr4wXYHhJ~N&4IJri@}=@CE7_ z@i8}wJyVo5x0y<+3nHQ|{l%h_fqdSrUc+85$#}#|Mch`s;`f=r87q0hqgRyMP4Q;9 zQKTf=4vLt%S`{`O{+2YlsY!zhB2&N1)TS*N;5Eox%kwlE`Qp3d48lcv;&Mg-yp0z_ z3(Y6M*kcd0OrC3Tm%gR3HYuR`7t1GK6seFpj0tE=>|rmRDiJuZaqAydV%0|M(aoma zrY`jXMfxwb?$w_k|IgPdx&*Foq0;YT3dM&)eQI)%3X?Prga8l8wIBVoW-2Qcwg@MX zVfxIzH+<0_REn!R+JtPw)ZUv-PBOsZb=g=@9qf7imBV0lH z(&S4=d5b>JZ0qq2-R4Ig9_p+wXz=CWIex)0Bkpp05DXQd5uO4Yq8U9_aU~Gdv_-8W zh2skFUvxSgH~oB+`^)>$&UD|Pf=VTcDfJU2ifuvs#o7}OKhbTg6_Ky$9r{WXs(}}4 z+(BvrqDJde1a3k%IdhsiB7BdwSCpQ01aVYg97^V%t1D<}#A?r3DmHi>?K77gkm@L6 zrVWYLZD<~`=!o6C{%ht`s)OsqpTiRT=k))@Hkq+JIa$sFo8heFDeQP}!y@&xF|Q{9 zhe9X#&11k*{o8JiA-!&gN0L{}RxY8g(srpK0@PF z7iV*%$sL^R6%VS~tMnf7Tx__Eh#&Qvg#-*+pbC5!x$2r$o+^}@`%L;r`N!yTdzoE@ zvm^U;`$h8A?WPoC*H`kUrP8k7zfj&gAF)VbC-dVfoy z=o$*cU)O+~@mI^g9gWn-{5mM#hc8>gyLhd8O!(*kvXG#Foal5K!vOJWT0`<#iSg%S zZIvSGBKAh&Y*u6Zz4LP4Qi?GIiwZa!E8uoQZD-0D?aO0&u7SI}79vF62prrc}GOG>`uS*aJlebp>-`IQ4sHVEEZB#%&MZk_q35qlkVx?{MqI5)h*&recQlzRV0g)!XcY+{Y2uQD?cL)SRNZb4Dzm4gwz0^>; z_m)hGQ<~tz zt;-Ev;PosG&d$44wT>pE`+{SQ6_g}s7r5<1S&q`R7B6hPfcyph^^!B`TAxDcp>!>- zp1KA_gSI5x*U+(}a_yxps$q~0m`Jxf{*uE4b}1S<1Jz=?z2|F*) zp7$E!;Cq@;v(iy;ysHg9a`--ZfG65rJ7^=LM(NGthy>o! z?t=;R3DO@F*sBkPw3ZuI)**AwgZPhBP4^$y=23XJiiee+rD`k-#u8?X$ix-S9x6i% zd2C7_hqnJIZ-1~hz2BVOaA88tPvHPYuXS@rMNiwyJqrb;o7{Q_{Y_dL0t(zb9EmhO z1IVW0L&?Suy{l*d?RoZy@>JN)+w8W!X@y7Si=Mu7x&M07I5q9`&83^rvA4RY-HqVw z!)k~ZatF=o@9k!K#=GLWPyO{|My3PisskFVL~L^4_t2s38@7YeK-9{y{052bX&pRr z?EFD^7Jf=lKm8DV-)3<7%C_(IkHht@W5>T$-fxr|BhRr+;h6)b(e`@6@5roiV0PT( zwn!iYW9N*S{SmfGWTbM1j13Y?&|J*%JS zp3VDG_7d55?uuVId)jRmQTUsN^fM=iQMoemfc&1^K?fxmJ(wwW{su4xW0nGGq?tmo z>V;{YT^x#S7eWnysi6HGiWbUbg~y&mv3+!Zv-pY2YwuRW@uWlA1zBnC8*u{|d)8m* zt^0ZB@FZc{g7X3Gf`o(-cdaEYdEZf)oos?Lp92CqnT92#+DB-Q|>S5`x4|M9K&Oh^Ul)5h(C&p&B zn!b3``l~|G=O~g^vqAsVrTnvspN6FyArcmw+dP5<-y(C0G-uqG8ZSj=Noo;UXO&X+ zKHn=V!%^&PeWc#U7rMA3RItlhjR%k9l<08Fzd>ER7cf5_uQ(ZWeW0BFxpzFdT;`iDV)b|^oFU*zwfy__n(K|&C!pM6uH=I_hudST=?*z zB0oJG!c;98qkRv4EE=-wpph;p0t1TXw6J=-+;Q1G$n{AKyI->!xD~rQRYxpet-?@i~G8F0+({g>2Ba#cjQ9#szNT z&`!m5>JHtW6hRE~8K7Rs#lYu@RsPOIp_PG=uWA=|LVM*<4;EB*B3@iVUybd%8bvSr ziQ(s+9cEJt-QOB^hVT2S+wDt%`H8Qi?wvF|@B3q2VYW6)6AZ#YF-;Ji%hR_|p~bno zr=Z0_xhsT~Gc+?XBP(Zfv#qae&xsy1Cksyq%)fZMQN?qIl3~$fx+^@JhNNL^`Ik`7 z-+*PVf!`Dd8bl#B<+ezJUE9i2$xE|eQps%+aJFi4e>UtdyamtZcNRx}%ZtzeEsCSJ z2HKvM|7UMrJ5EDLnW>#mSA+9@}T>Qlb%^Zgz&AdzL5$E8h}-zN&oBgH#xPjj?v#m!rTh#GP{e5{?6Mqev-+ z$E*#1rO%)M8-0=jw)!|{wgMlEYal27YQx^~Ce^zCRl0WO6Z;gkvdfXbmhW`=V5dnJzTb_Z- z9`-MaA0^{5)UxmknnG9dDg?*>U^dRX8kp==uEhWY@el zrRm5g%R4^(3(}V9O0;*qzrFh8o68@`rXiNIObCN1uTr$*(+++fZ&LjCaiNb}GIuvY zRag9cU4+xfxs+3moYkkczUQ^+O$<}*Y%E%mW+5v5ZZ}%U2%>DBvr^NCu>?A;+k-bQ z{$)7(&m6NOIaxa2sEfyLY3axtVZ+K~E4)rbEoZxGjJWrFHsTiJ=r|ExU7FE;__?=3 z+vW{nt~X!8#DctJxw#(OJp{8MN^lc=IEzV;=@%XQaaO*cd5Puoel68|7B4Tzo!9yl ze#_4Kpsn*Q73()ePXpl8dM6k(eAX_A%^_!BqhM;`W#(r*4N8DD`_J;Ny|w+tyDt)A zIy{GIEc{m~8m<9u#scsB{8g7#GpBC;Yx75UMFKxOE;h`z=}`C<;oI_eRl*=k68*yP z#NK!G1A;t9SUHKQDI(Bq}jaaz;e~4R5u#YQ0<*-@5TrF1ZVw+4+*w zQd;Xju7XB9U1>N`LER-pX^mi4MJ>;TL9aaq4l9C^od-EbhNzl@Tty!k@Zt?E=_1XG z&{!8Nj{Y*QW$lTXv9K8I&W5ayOey=l%rrtoaqA6*q0MYQB%Mn-Qt_g9ns~mi?OY{G zI`{J12Km?%%iJHCcqCT4I?&$>oQkQ9(x-Sos(3759?%)0++flX?WTV3*B*nuP&V_d z=PhSM(#+V;EH?O_(=T`${qcSd>yeF#>Q7Pw=UZ-^HelhRIhg%9Z1ef)slypQ{tWrE z(}6{Q&WG>OtFG}DIO?co{Os6Gb}6$*D4q|c-=*_E{CIshCkMe<55JA!f8XZ6llI@0 z_W#{|^OrIon+-miiezwQ_?P-tmYt`5ttoxjOKp*;u1tlo_W%Pf@O)DPK&hQa3+4Dk zrL(?An@w4mU{H2D7mjyZd{uwxzc=ve>Wq7EcJV-z*+6}e;t?Y~wwP!p8;& z`a)5Y6Jw70ft}x)JQxD&`b^lE$lfD6<*Igq)5hcpktIh{x;NI0wY2K4VWjr6%&)-} zs(C_*F>N~!hIvYywidH})O%OQ<26?$*Qq(g@w1hOrcQnGS>&}0X9TNc8*A8>v7T9% z3A6U;(6o3B$A(YffH23mN<_WHx`IQmZTQr}xt;P^mX5y|a$xPPfTItNtVG;lUT(=Wd_%{hFzJL^P5sjrm03p3ke-??pzK zvHnGM{a~P$OKk;h0PfbS1lFdvM=M{6!H=W`+k8&`S*6Es0y2B$x^HCpS%q#r)Q_RN zAL&1Xe%=k>bLYEJZ?*pSGjp6nNt;T{aU2);6^x-Q7Ioye-D1MD2sqvFi-Q_+bd182 z@pS-5_GOQHwe>(<9w|4V2Yh+hG>#($`KsZJD{RRz-@ooW*be%Ai3CDaij5my5%!~J zO@;e!Y|UU}zv5G!tEFMh{f%6wngTd(Bh?h(_h4MRV@Cy{4Fu5OBHNp;0nn|o>XxAH zd4z&Sab&x0(x=G!Nu#}{BR}Y!8j)p2Ue;(c#-V)<8H{oS^nRc-qWkSECG6i`0NF@` z`oM)Z;XQi(^Jgv(YUrW6!Msd`R3C0nmh=kt5TSO1TpN`EtU ziQS}FML=~iP;{>{_9|K~8%bpiaW?qtb3bGcXGAuJz3Otb!YRyrTG?)SBi)hlw3qkg zKP3UnsD8{~ZJs|f@zn%%RqnSh7`roLGnHy@-wZWxS^v}EJ+>C1d$4^E?U1dx`#t!% zqMek6zn|`^{+9GIe&q#d({*4;^AH(*F7l;quvuqp^!|3H27XQAh*ti=%*G_zy!m#W zzvI=29{f-#|KxbGX?{<66E+iJ(Iu-_cc@?dRveXB^DAvL9TpEAI%C7?P|jo8S8&yF zP(C*Tj`}s-9}GZhO#8l~&_zo2@`Xtl#CK2NxL?%+Vl0XtV*CCgIW6Gw>WwDF`x_Hh z>1X9EM2#)O3$8a>U+%|}z)|6Eg&C2pO0|&ZJy~vb{XHdO6bKJ^SrM68#~GrecS+W3 zWBim>Cu#72%@=3^3di9UOVa|y zi?oIvp$9g7Zm`xX!%EVqS0N2(}sJtyxMk`ZRGP^ynwR{G-GSTm|u+W?+ zs;ta?wJ$lg=J@sOVY2npX0(40u4u67sfKi48nISedCU3+^##m-sFsFD4vgHQZsXJPWz`kdgY^-^0s%3=ibV_>PG=Ca=oOOL8mSgHb+a!jadq+Fb2D^TsWXO!m9jZgcqx&k*UzN?~To@v!rc?F;jF zf*SU=8*OJNuMedvi8%(b3m0iS``X7+IJpcA0XJ#`c7RO-vdktBA@v8lBe3)YzMRL6R9KndD9;@8s8f_mKddJA!5-6#*M%ZygJGHPYBj~&Q*>3+uFzpb<9@Ip|? zF@;_CfBkN~rE-8AJX*s3O27Z42yJOWje2!) zg#UR#lQ?vtGi56d!;L;TeSQ#Gc!6;TRrS^=L2W*dF%_fGpZ zr~kLZ)h@n63`57=#%u?3e)?&R*4VDLb*Z`MlR&Dkwno9tFz8!<1U(xT!sr93|2z|c z`{KZ41oU}McYBLeHp6iEa7A4r%G>tha!k24uv?_KV(~kSH3S$CnwsVlQIIVO$*ZDS znE`Ch?JfLik&Xt2RYlh`lyUi`hK+lCm|ab{;--CGpl34GomQGMot=WCz2EW8@dVln z1Rrs{B(yPYA`6k4ArcCEPOt}=lkEAB>qw3*f7)O3!yRo@u{XOdYd;jV>)Z@SGFrgV zUG`mGkKVleLb|i-V3+!Fn}o#h0%%)i&;CS9WTnu;Z+$(h)vodkzVvU{%Dj}C^(@z} z=JFMrl8z&ar~i$bEjk(wiQo59caiz_s3%k=QTo;W@U3qvl+LSslf*TgFMn|%cAr=( z_xXXV8lwM(yX}weV@DsRU@W{2*6b|wRX3hZJ@rpijZpkB&sR3%@VrOv#BFW)gXAi8 z7OB9q6I>Y?trc9Pn5FV0gOFZ7V*L*=SDhAintB&MlF`;yl&+;R2}3`%WUc<)g7lU3 zKbE&KSXI%VSH7MWv(j~d{!qW1x>evUyU^`iS=S%*NP$ZVZFNHG#o)a|&13c*CC4V6 z+~g#oUJN!j`;RwR7vn5ib@buk&?4}d^_$%CkFRG%O2s4ssA-(Na6^-aQx2+iQbS_K z!gWUpHHJ)vHG0^q?_eL_0FZchZ>(ZupuPcUp=0VlJ5XZ?>cdj3@L`3&kB^8=ycZPh(}G%3)M_l|G{?l@bPRZ zQ5-Xy5r|F9*4Z+~g5)>j$ctz1NSuB+mR!bu@6VX2ycGO*BfguoR(*&k(Sl`xuTQkV zRvJQm2X19s_h-{zNaDlE_84xW{nm?Zod^ z+!J#@l<}b?qtY{F{k#W2+`aDPDp^isOG>VS0%xg0PVlAb1IGfNV`?kmQVx)xJ!7+Z zkq-@Ol|Ms2FsVe#HhZybhTcnR=s}JZT4O4kUO zR?QMSGa>)mtUyiZ(O+80@?Vbt7xn*9-JvV|(`U*M=VBg+)MIx zZOQk(P69#q6eYG47r%GyS9V#A+Sbaxn_zM2ho6#lh+=O2JO1T>Q|%SZxR%Z>&ciU( zk|!7iYnQZpN{uN*J z`hor-n)OuV`@)GoHF^cV(-ei?WUfRF#mf3~n*|`+`dt-X69-J>q@g+-{tF$4g*T3| z;@O90CL1HpN6!ndJ<7K|aOR?APV=E(VUB@O)Q zjNdDJNqCJVfBAmdBJ#nN!X|LKKHu*=b8OB(Wx8{D*!%3=VzgL(98a^E?*ILue0^x7 zJLy1{ze(4|EMg1Li+~b1CV^p|L%_-6Pg4l(uyG{$X7T=ky~?Rc z=Vl+5G2N9IxZMc;hz^PVNa!98?F#m+rPST>*qtz=rFCQ-^piZqvlji_!#0WTNCa^O z*OZ+ES#p(==m!IREF*yh$~7FE>HNDE!>pdEo2*`AXV%YX;xJ44s~#XNI}S^scL^O? zr?+a{5I7>;v0%gHzpjtU>fuxeu4sXxUw; zksQcvbD1v@{CvJ(CT$*?WsB9nIO??RYIa;hcSP`xsg=vj4@XJ`rdl2c(UOcVg2m#QH1oT8~CDV^FN<`=5M9gR_1iSjdYL`h4%t_u-o6$ zSOgi_+nCPgyD*dDUV5~~q3_F5q&~lCzf2}ZN>;7UAmUH|x1C>tN(PCP*}IoYuBOe= z3PGATROoF`v52POSp(@9I(8i4cx?(z7J+o>`gDCTaR#9b8BQn8pp_wfIvEuR{f~I= zw={~^tPsZn5}@S&AyUvU8Er6yu1|sZb)dTJY$HnGx1+ztT{L%0340kqDO9=VbzcP| z9h<130R+#71%p>Qu_^bwMQ&8*{s3s2=8>TjMGHvYC}{JLf2VkCHzzdlgfv1>DU_PQ zYa0O2!K&)A5d#)0gA)*InB-1t{=9olORZPeMLEm99uYadOkL$W_;ty%{Izho-KW32 z#5Wlnj;f8qH;Du_RIX6QsB7O zu!{t!${Vp+dn0iZKQ6tfPSFa=Jz^89GN7_%!*055vQC4t*!WE@?h?oQ;FSj#P5VTo zYt(|W+(EfvRRwqGF->%YJIP=55|d+I*gGerH;bCpvM({#VYaM?&uRuuv8XrbGcedJ zKJkV#@I-^~O#+n4|NJUt#*DuiHF)s&?Q7d*UaR%rmpD0i1+3R;`TwiZOB07aa)dGY zYqcj1B`qUz(QwkX_d6bO5f`89(XE<{sVk$tW|qlb$Kwz+0Ii3un?S!_SbnD}KhVm`53?KDtit_DYSz4hcm9 z#%Gp{nG;7Sj|FJu2GilvLeC-W5gN2Q$X_msU`&zI$wDh!8JAb2@dOO`40}cecvK?# zswaTI_zDsGG%L120aQONUK2LmvB`HKrQ!HQ+pp?`jL{`tWAK8El*J(0MlEbd%pHz; z*7NQ|a+Dcu=hShPET{?(WMa!%`ys{}kO%a`9q6Cv4nSn-|5$ZL?nbBuT3`f?p!`u! z(#dx2P%1gw9m*gRqQxi3tPD_l!mpOfP{X3;$Z`xY6^|y-^1T6lhVMLb)9O5LH%9ov z)u!NiyZgYKB{Mbmq}iW7Ke6pJmr8(4CM^-dNt0T z@oCRJy#+*E)tjo`bPJ}yO z70WAaR72He-F{;I@BmlqzEQhWPh-6DL+o&|W+q1VmCG_T)f-x9#TXW^7=wK_$eRWX z1H%yQE7S-+h4O$?uRM#IYOy=)5ph5PRJbKm&|eA+Nnnu#=+OU?GLA#gVTjN`z-)gu zCebHF15k!1g!$u4E1kiq--^%6;L#=l_v@;t4W#4Lvil5vryvx?f%D|$+jDmas)RHU zucGX$2(x$bQ0@FMC+4cu5|*&auIH)lM55R2E;Og+VGoZFyfRYKjbbz!?>bQb`LRNp zRGb7>r8)4)-y-Wwu1~`Tqq6L-vi1uzMVWY4ia|lzY*iMtLJKwa;v_(03)t9=Y!coM zN}*-ba63{rT~KR?C4eau6a}C_v`u>UX3GB(7ia{M0{>6J7gITz-zxKq)BzoP*AP7m zhP%a$HZPB?=q;o$@MP#&eyKhwwD&NCQ2ze;TXvl1%03ui+_@`=(*cAFPV;ZW^yEK_ z?eAtM@P}@QsUC?obZ8vc9e*xcAD}tSXXu;1(#>*lhu3ALueO)faYE;vZmJXpdv#7` zYiD@4^b%ZZ?LOdtq*p-N-(n~DJt0Cl!-_#3gyz5n5I?**qtNVBhkC258FUCbgDAL| zZ{eTJuNzF%Qask#@n9Ow)N&NehVU))-lr8WaG33)+?x8r;8BmhO2zMk%C684M)sB< zAq@Zt0eEjfXUkV)`io3qF6aQ%L17{L3$qN)`yG~%sRsn^T;RBNjmilA5`WTumLd1x zqh5zi-JywFWuaJXX67hCv6m3LCNqFQHCp0QiKu0Bd)wt?LV>zL8I+Q;IVuw9i=ub> zoiQ`bzN@!DSYg-G+l}%Fv9$a!*{f3-=sa=o+QNp}J4>r{(do9j;ZcqhVe@fOmLmS^ z@;nPO4=AP=c8Le21Y6bxjc^zB>ViEgKi$zi*vcZB9hu5q0g;EnLT|-XS{^h7uh^q$ zhaqV+`~?!$P<2cJrch)OMIY4qM{szpkzz822>p+M+2SMF`2V%|nHymxy-ztE(qTFm zbi5#x$+J)Fr7{Uf<$LmLR5=y<$TxW&8M6>7q&$@6O&)bg=LKKAhO4$8@t)yRQ{P}{ zVRP@Alj!Wb9!B5l;?jK~r*5Z*V5|oY z07VW@p`!jJWJrk=Q?W%r#qF+gYg+$)_GVz64wsmTRl0)@KpfxK>HQ@5|FEw#OW{n= z!2vF-WIknRo}!P#x`W+o*>M1gp3Zcl78n5|z%2X%4K0z;dguH8j?}IJzcoCk)@8a7 zS(T}O?egYq^6O;~g4xKd{y zjH5C7t6HnY{YQ`E-QY<=oe{Av>wu$wUyeUBFFly)_OnMWTn{LJmGX!-`F%#qys#u> zOh8LMC2;r6UynQkp=Q{}g1sy(6L7y`qD{Zz`N96hukhJA0ubCiZaJv+#_{K;utNg% zDO>P)`sN_r9|qcy06zs(8m`8m-ndTc(A{W<%6wE*=xc0;a=f2CYCLb{ z?Hd)lLdlMMzP5CzyZdV4l^F?}XM2{rGfz33CyrubIn6Meh2Q?TDQuVgd;vOI;4H_#!sI%X!EDW;`wZWI>l&H;1Dq-;d|({8cZQR+{v!_CB_}U78g-RDl^Aur!YM6bUN}j^3y>32j zYXmNnIggp<<4wcJ8Q*3PhfjHg%WL>r)a>M2MsSqJf5AT!Ru#P zka2eHo!ly;n21@GISuK9*)xd6-LRno7~rM%@cG^XA_3!AB1R6*auz)QR2~PB=-D&y zV9ih@B={9tWvs$wEb)6g$i+`x%#ZX=po9GDJGG+9Yvc;Oy^mfT>A}CHpU$u8tppqF zFr(Mf2D>$YM=T2sB`4^6PlKKT$Q)bkGWvGu4E?0|&)8qpmeVKBIT;r!4S0P$m}q5k zbY>j?D6i~!f$gk{xWYtgVivlJ4;YD~Q>a!amOL3nx$#QnYD;-&6k~1VZ)CaXes@6v zWCD?X&QNhRi)UYE?Y}nEfOUiI@>&Qnt|5Vjcgb9YvKmnTSY_y)w|S2k1lyou%>Pon zSJ{|K2#GgeWkzLM6uc?OxJJo_yG&r40p*dk4ET2#B8us7MM0;b2cU<`0wxmnNwB4K zJd|mtS5hfM0(5EU{7)@`3!hld)B#l1l?pKunjSN=tjp-1=xnttS2k9rjE>D$a$<@+ z*aba9;Xp%0hX&8bgJT882U*L7h4lVzqQoZQ-jK|*D zkN%2B2;t2j;&7FXe`WGbYwt9t+(3@m)VxP#;H&Nj2K}(K(}2R<(~0FbrL*wPNGDgX zjoxBb7qt?6Y(CI5!*HU-fKP!q@HsSmpB}XZ-aeo|0+Y5=arsQ%^S`nkeK3hVE#8)6 za~!bEh9i-G$h-eG!QT3XH_$`Cxr|cM4^>NdV{$X*ofoiSj>C@`$GRPJJzrkYnLadF z7yg8|?NlD`&bv=;FIp|~C{}4h8XG}VF=>93w^Ov^xgV^ep|%Oq{8Wqd9s|53d&Z&n z$Q*B|Q`6FoL|5yOu-mam`P!S~^5r&hJV`yzVENu2V%=>Br`gvEf4>h^yQqq z*0DU{KDle1z2AIuJ& zIxzVw&8;i835&g6mYW~($xSuoI6$*<#^`(IpKEJ{}RbE>4W1>gSe8pm4R6%jMcaQ;oWpHw6gC%c-BpQACx{sUvlzT zqffZcL*Hjn4-Z~fiozYWulg17_X^0HpK~PmW3AY_q1$waen~lKdm4f;yUqqk0;~58m9+Zwq`Oq`Q>ySu0_QGNbY<8%&@x&9xjPdEEpS}23 znz`9!-XTb8@n=Ww+1IG*$occl~E`n`GH5evW&6D#-{&Yx_WktX5#4Tc4Oi z41J*;DBaOS;HZg}Erp*Eax18My@aX+cA?q0K5mU&r~Xd) zmn++Sm}L-?a2~i&_dF(+ZEG< zI<8c#<)cJK9609Kt)CBhp8j(fM7;T=QmmLI8G1_SBqs4JzhSlnl(#9!_uP?eRcz(S zO~-vftDl#C8GKG_`y@iIham%7!-(;m!}jM8?l14_$1K%~OoVy> z6hyr!+2W0@45$eS)xnu6%m!lOGo0kh9@n~D-YGRt;f&j#HAanth8G%PC#X!6$wzQ~ zD8p?3z|{EL*zhLHI(%Ljn@FEmj+Zqp~XBeF26g= zM4!Z$YIw>H3pZoqIbo*@WsV+l2V1#HJwd)wU)0TNT+$tlQ}XrD#JwyD$iO^qYLm_K zp;T|%LM5FVngv~Os3?-ReF)|*puA@F8LKqFppra#!FY$r5H%phV$%m^CIfYkON3-X zM@H70uiP#6(7dQ}vfB8~xQ_R&-sL^wwZIv1(O5wn*ZBUIx2{KUgDq!cE4~uWQj9(C zZEQ@gosa3&it7Jp)f}Z{zd~)gJ6%*Pk5{7xEH^&W(0v-;zZ}Jz#YVzfF&=o&pY(V1 zrUUF`AjR{K9VhbCsCwRX*;K%pCZ?6l<#$hKxKx73i_%+K{$P1RF*B#x`x$tf)U@SP z*4xfzZl{~2u+RVn6mk9nE49#Zt;M$^OlOlR72^c0Kx_*ZIJcDZ&k|;iyiFru@&dHu zI#{ny@7V$KULsc3OOu5Q^kCoz5~Bm@!Cwt9Q$Ko*fWxfWzrl0IHd+#3{J+a!iqm9} zi;Vb`9S=HG>O+TCElHsbDu9vO(w#nh)DSR|(LKLvK5tn_oyB3%m9)`=>6e~n{ydzM z_jt4aLS)=Y`>s9xg=14P_8brITOGC7+aPSai$kcbPT|jN9>!Bu6{RsV@CJrTAIX8` zA3U4O+$dEX*oVf;IiREGOHy|)o=cneFAAAFhoLInRyhn>Qj3khlF9FAylgL?RUa1c zgcRy2Gt`tT0#)9+v7euQ!(}z8#fSFx?F>J%z%HMKpV?x4yS#(Q+!vPtJPz*6W;|=l z41JgxwK=XuZSW(E`NlM8YF&rVop$sk!WfXiI><6|i03**-0?QA^q5u@VDU}|%p@b+ zp+quzS=dbv{ML4E+@Gjb%r%AS@*9EX8QCLH8S;5)p~9`j;4!k+xI5Usrk}rGj+3Tr zj6)Y)ir+u4PJl=thNnQV8SCgM0TsRKB(aohgTcz*VFVfr$4}gZj(O}NIx1k!qzDYj z_BXS&fdq9RCsC4x3FneG*3+XwkRqo)Z~)h1_S$O!m9S%?p8?LWQp9#Rerk)J)TMo@ zB?_X$c^`p}%A}aD8#yF&C_M*NE@!Z)25*GP%ZN(I17b}dCUbManODp=8+|MoF+igI zcI-?36;=~#%hiVTaUSupZd1*0+B5U=(kmXntGmRf@17h9nLXJ&-gg>Ne5vnk5l-ky zN*Jwsa>DM*vH{j+Tx{8uQlV<{)bPlawg!=2URTp~xa7`G2CqI?kX;1oK#ZE()^R^Q zv9c-qMv$muFSF`M=4Dmj+`K7TgrrRwRk{xO(JQ)knizfGaSEgEwaQ>_jhyg2x7{zv zD>op{t9WQcA6GRveW)L=2I|Acg-Mf2q1~mRVYdejyUZx(%aD`HqcCFj34i~)CL&DV zaT$QkxbZe_uMD@w*MkY+gJeJExgh1G$x=d$h{ zSC_hbUY4{Q~XyONP z_PgIx$&oTeS!x;e8@zw?t0oG3N*mj+}IA4ba$FlJ7ka7ytE zOk`jE`8t$;+Vdq;8P-vH+eTv;3hE6FD)~to3>G%dVoLT5BYgyGx(;JFOr`@<$co-@ z>Pv^-u@;IADUK1*V1OT1wa3q4u~sm}kSVK98E|VHVJN7fGBzE$M|U%w;MF|k;IioQ zC5eh8fBqnNIhhg=s($yem(76*>l950tfgLPoAEEB&&9Wu=~k^iX!9aAd3rMRGfHpe zF9>G6!g#J%zV@63Hjr;W#hHZ6K^#-M^CjNnQRBT%)OY$tMqVF~IaRQlE6*;-Be|f! zgG%F1NDEwudaa(dPR3==#sO|$wLp^`(yN4_yLZ>lWe&=)bS6rRwsakpwvd-cKHT*A zb8MptZ|k-8Qr=CWlhnj(Smk|7(VGF60t93s78V;+7;ABrufaPX7ErRACQy3sG>FKC zo;e20LzfDHOvsrLx{hRMte1hC2g^ogpzI6a%__Xr9R7SsFWg%a3RZSINU>`Shsi#V zxCWr?6?)1HuSXo*14+Q;N!aQeV3WpMhkbW55O4?Wja`$-=pyz)h{p?#H$|X>9hxw8 zDFAL#N!x?PN`Rl(B|(7=+CLOag*(3mnYEg*HG#8eZnxt#7CCd%v#?CI+60xz+p~wd z-~isPu6;@&gvL^72NfG@z!nOMKkNcq^*I14PDq%@Av{%W9>YTZ&UC6wK6F>Rb$%fL zb%8S0Dhue=*dwQG5GCzVZI`9$SSY^?$Wl>Cypt3OXA{uT5O#LpDwh zee!G!aq3Gdv{JaGQeQNduDpOMe*M7Ghczu;HZ>DtlwIUkmpFf;;ZuwtmA+a(i6sJcbBDG6L27wH9T1ObI1J+hQINm}Xh=aENKG68 zL^!zun2go*&Dg;!|8Qf;VR-Czk+8oBv5(3LA4Wh!F{6!%xXVEMaQ_wIIP7QZk@uwH z@CRqa=Xo>RyTa#87Cjk!%K*>V59@);U5H(Jghn#r&?{|*NW<9ZX2}n(DW$~s0+Yq> zZATegT-RfI?6^ux`50r!bzIJ@d+*zTLb-p9z3_Q>blLobpVgeD&Ui zv$Z?kEAxLXlISc{d{Ip|ju;{M$MAcre^LKk%dz9xqhy=o7gz`r#|kdFHa+7T7QV(W zJ(*uPXJ7V^;(f`RJJr3u5K-*?$DFUig7Kupo{=HHk)AteujtA+TjUshAGePCY;STE zdV($R6lUzFMXqXwZT+_V5hu3p6tPx*h#}imoUVfgJs?SVr!Wa{whLswe<^4b zj3ynldN=SW<1SL%+W1ph{YCz{9*X4>_(hs z**di}T7FmPLb02q1%Y~pKP&v&l=0I7tMfmU)PrG7Q%6HbKOc-P&T3buOi+;?5Z{yw zi}nm@05geS24lb^Xz&9H21a41bc4u*O1I%scW|3&$>aldpBZnmAX!lE1rkq;X|f?tk$OtG7az|wisEE(M04^NMjh7!+YIX<9*@RDt^gAgodhz zYBiTvp%@}oT76}s!1$#GJ)7C6FN>}Lc{&NV0umB47NzCVs(@eNcaaxIt*-@q|ynn(S2=GIAc=@tav4pVVATOzsqeKBB^D3 zhw*>HonAP$V*=em3qV4t(hBIW(hvt}FFIcWQ?Ebool$4mr&q0Be7}(c*#xH1udRn#E%921HOd{66rq|VXCo&yFzA{N;vJT+ z5iKQeJS9Z3200p8cw^=D#OnQ_t z4(|?b1cC(jO2bL0~@Al47?gKc6~%Z6r=XY`!^LnE$i(-Bz)4#TMOVeXlYoysjUP*oMlTUo z=bjY~+v+2*&=F?K#+nnW0Vzma|LQ_^)(xbfI*PDIO59CXZZp5`PA)dAnD>=VJH+kb&zafFX`s3B5nfwoWW+#F#H}skXHz*GD=||(vPs!kaMw_nOhSMJt z0~?w6pSO`l!09?)f0FUdOEJpE5IgY~HWkSB_J3%2Amsfj>Osd5@Ao7)&QmBx$OHx@ zsDg&kxYy$)P&u3$^}Izg7lYJ$kQBIMTt5P9nm z)4Ts-C9iDEln%l)DIyRJ@0J$Ggof$3+E(`GM1r?P_k_t|^S% z257pSrNlBblbq&ogs+^)WH*hp6QJ!T82@0E#Oz)v=tIp-@I&288StlE7c@5E3-UyO zE$E3=TACr`6pRH{k*!9ISW}ZI{Hwr`CZB*3iE z@;lfH*B5dh_Po0_c^2;0s4}4`+NVALW`HduI_SroI(o>}^Icbpu%8RRmQS)kNb>7* zd{$?&AF52t5G5^RJRg!xs(K$2OrRe9Tn|Q~=V>!B1m=mdUD*?Kdc+-{f^WnWYH?F8 zkHlIY75xy4&TeVo9w&{34g=}O@m|pCAICHrkn7oN(hMt-2)ZaOn~bI+7SS7=6MdBs z9FH@r&P3r91hXQ^#1M}BG$=SaMT3IK5AnlbkH(Khq+Xgrxr6x@ZgQMPZw2G(+=a|% zHo$A!0m#M(%JQF3W4MQaU_vt6;(4{^nlA0ceRyj@FgfZ&FgUG>1tyk`<8$Z82#?+y z9(|_3c-F3(*1C%Ra~)^&;Njc% z8Gpq{)RAq8Dx;fADiDHG&!(J8&a`}it5X9^y zUqX^gy7IaB8&J8n;n#gk#g@8?_QtxC-=NKs-mc(bx52rp-&zm%aP;vVhdXZde~+jh zzC={uW2>4S+ef3@jO8ZC7oOl)nJ)hcb43@`b3J=Lv^ENSOg#Q4#C(!=i8%f87RRO+ zk#X`T-Dif_D zvDLd*8f16O2)D82@4KE~Nu&|Jb5cs*mC_gTP)#$+$yI~F(>CZ57&0bpG93zLM6Utr zuQnWz-VQRX`MPF!nZ?}M6O65({eKX5{@iMw0ao7nw>>5l8XADIw>)OpXAY^ShtNaQ zu7Gl_S8LsD;@rT}(!W&Hk=J?a*5|<6=_tyPj9P za57B7=QRE(vJ`9|&ZPnmD4{}MiuASMb1^V4uM~BW0Qx3wEh2(59UW)ma7}~#_thn_ zD}u=)#4`fPOg`!6jTslEN`zxPZ}{05t>5=Q#5}&%Tq4WLO;r_d7$e&Fn2JutIjyr& z{P!P7St#E9>osJ-nT?x=2F~*H$b8TB=Bd$-*0+e?AjQh^7^CWS)wR$Hi3qW1KIe~~ zx7$UjCS6!l^AE+6gRqm2HH}AWlz)B1n62t!G!*tf9V?4jM$udsje(V;hELZsr@X>@I||W zHTCZ}Ws2CH{&e201Oi@00

    fZr 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 Z{{z*duzOfzRZsu`002ovPDHLkV1ix)N-+Qc literal 0 HcmV?d00001 diff --git a/frontend/docs/images/submit-form.png b/frontend/docs/images/submit-form.png new file mode 100644 index 0000000000000000000000000000000000000000..f2505dc5b654bcd96260efaa1188b981f0d389d7 GIT binary patch literal 789557 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� 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%0A1O~)(wEej^T8ZO$N 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%0D!0SA9Zw_(Ew@X@% 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%0D*kh$!fOUDwp;Q`()WUue#3nZvE8@e!+vh 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

    dMXlK{&F0CVqg0$J7v6^Z@7sXGEj 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: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%0AAsp$(l6-fKntY;-@HbbFF;;9s4gsrW5MK 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

    fQ}?TV?{}`rT21R*iS;4zitKp#*w?@6 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

    |6pB{N|nYyj5uLED9cM5-NhR64c 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⁢*fg*B9>AV`4<7k<*2@Z#e{9+9*lu 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 Vt0TO`Qd0l`002ovPDHLkV1n69tQ!CT literal 0 HcmV?d00001 diff --git a/frontend/docs/images/validation-form.png b/frontend/docs/images/validation-form.png new file mode 100644 index 0000000000000000000000000000000000000000..0680dd984621669a0dbce0dc2e4f69d9d5089aa5 GIT binary patch literal 948776 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

    cR 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�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

    gU{3TP(THno~aY<96tO^Uc2 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%0D{Spay7uZoQyQcM677ZLh??IUME+KXp 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

    wx?h1tOMoy3rl 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≫;coj;og?wAXs?G^miKUX9?4Dcg^ULi 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 z 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

    UBTk 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 XWA|^{G$>E40e*h9b2vh>^@{l)-WJ@4 literal 0 HcmV?d00001 diff --git a/frontend/docs/routing.md b/frontend/docs/routing.md new file mode 100644 index 00000000..d84c7e30 --- /dev/null +++ b/frontend/docs/routing.md @@ -0,0 +1,30 @@ +# Routing + +El proyecto usa `react-router-dom` para manejar las rutas de la aplicación. Las rutas se definen en el archivo `src/index.tsx` y se deben agregar en el objeto `router` de la siguiente manera: + +```jsx +const router = createRouter([ + { + // Main as a layout element + path: '/', + element: , + children: [ + { path: 'onboarding', element: }, + { path: 'preview', element: }, + { path: 'process', element: }, + ], + }, + { + path: '/login', + element: , + }, +]); +``` + +Al ser un proyecto basado en _Electron_, el router que utilizamos no es el mismo que se usa en un proyecto web normal. Para este caso, usamos un [_memory router_](https://reactrouter.com/en/main/routers/create-memory-router#creatememoryrouter) que mantiene en memoria el history stack de las rutas. + +## Protección de rutas + +Existen dos high order components que se encargan de proteger las rutas de la aplicación dependiendo qué se requiere: + +- `withAuthProtection`: verifica si el usuario está autenticado y redirige a `/login` si no lo está. diff --git a/frontend/docs/url_selector.md b/frontend/docs/url_selector.md new file mode 100644 index 00000000..2eecec44 --- /dev/null +++ b/frontend/docs/url_selector.md @@ -0,0 +1,17 @@ +# URL Selector + +En la pantalla de inicio el usuario puede elegir cómo desea conectarse a la API de AyMurAI. Hay dos opciones: + +- De manera local: esto significa, levantando Docker localmente ya sea de forma manual o utilizando el ejecutable desarrollado por el equipo de Collective AI para levantar la API utilizando **[Miniconda](https://docs.anaconda.com/miniconda/)**. + +La aplicación incluye el archivo run_server.bat que, en conjunto con el instalador desarrollado por Collective, procura levantar el server local de modo automático. El funcionamiento de esta feature está condicionada a que el usuario efectivamente tenga el directorio de Miniconda en su PC y esté utilizando Windows. En caso de que dicha ejecución falle, se muestra una alerta al usuario que le indica que deberá hacerlo de forma manual. + +- A través de un servidor: los distintos juzgados pueden tener servidores propios a las que se accede a través de su URL. + + Por razones de seguridad, no es conveniente que estas URLs estén en el código de la aplicación, por lo cual el usuario deberá ingrearlas manualmente. + + A fin de mejorar la experiencia de uso, la URL se preserva y autocompleta evitando así que el usuario tenga que reingresarla cada vez que inicia la aplicación. + +| Pantalla inicial | Selector | +| ------------------------------------------------ | ------------------------------------------ | +| ![Pantalla inicial](./images/initial-screen.png) | ![Selector URL](./images/url-selector.png) | diff --git a/frontend/docs/validator/README.md b/frontend/docs/validator/README.md new file mode 100644 index 00000000..d4d13239 --- /dev/null +++ b/frontend/docs/validator/README.md @@ -0,0 +1,55 @@ +# Validación + +El proceso de guardar la información analizada por la AI tiene que ser validado +por un usuario para asegurar que la información es correcta. La validación se +realiza medianete un formulario en el cual se carga la información que devuelve +la API y el usuario puede modificarla si es necesario. + +![Validation form view](../images/validation-form.png) + +Se desarrollaron varias herramientas para hacer más fácil la generación de las +distintas partes de la pantalla de validación. Entre ellas está el hook +`useForm` y el componente de formulario ``. + +## Hook `useForm` + +Este hook ofrece dos funciones útiles para generar formularios: + +- `submit`: una función que se encarga de recolectar toda la información de los +campos del formulario para poder utilizarla a conveniencia del desarrollador. + + ```tsx + // Ejemplo de uso + const { submit } = useForm(); + const handler = submit(data => ...) + + return
    + ``` + +- `register`: función que permite agregar campos al "state" (más bien una +lista de referencias a los ``) para luego ser recolectados por el +`submit`. Acepta un `string` que representa el "id" del campo. + + ```tsx + // Ejemplo de uso + const { register } = useForm(); + + return + ``` + +> 💡 Más información sobre cómo están compuestas y se utilizan estas funciones en +el archivo del [hook useForm](../../src/hooks/useForm/index.ts) + +## Componente `` + +La pantalla de validación se constituye por varios `
    ` encapsulados por el +componente `` para "estandarizar" su comportamiento. +Simplemente se encarga de envolver los campos (a los cuales se les pasa un +handler `onChange` para detectar cuando se ingresa algún valor) y de agregar un +botón de submit. + +> ⚠️ El botón de submit NO envía toda la pantalla, si no que valida el grupo de +campos individual. Para enviar TODA la información (o pasar a la siguiente +resolución) se debe usar el botón del footer. + +![Submit button](../images/submit-form.png) diff --git a/frontend/electron-builder.yml b/frontend/electron-builder.yml new file mode 100644 index 00000000..46eea126 --- /dev/null +++ b/frontend/electron-builder.yml @@ -0,0 +1,44 @@ +appId: aymurai.app +productName: AymurAI +directories: + buildResources: build +files: + - '!**/.vscode/*' + - '!src/*' + - '!electron.vite.config.{js,ts,mjs,cjs}' + - '!{.eslintcache,eslint.config.mjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}' + - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}' + - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}' +asarUnpack: + - resources/** +win: + executableName: AymurAI + icon: src/renderer/public/brand/logo.jpg +nsis: + artifactName: ${name}-${version}-setup.${ext} + shortcutName: ${productName} + uninstallDisplayName: ${productName} + createDesktopShortcut: always +mac: + entitlementsInherit: build/entitlements.mac.plist + icon: src/renderer/public/brand/logo.jpg + extendInfo: + - NSCameraUsageDescription: Application requests access to the device's camera. + - NSMicrophoneUsageDescription: Application requests access to the device's microphone. + - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder. + - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder. +dmg: + artifactName: ${name}-${version}.${ext} +linux: + target: + - AppImage + - snap + - deb + maintainer: datagenero.org + category: Utility +appImage: + artifactName: ${name}-${version}.${ext} +npmRebuild: false +publish: + provider: generic + url: https://example.com/auto-updates diff --git a/frontend/electron.vite.config.ts b/frontend/electron.vite.config.ts new file mode 100644 index 00000000..a0453cb7 --- /dev/null +++ b/frontend/electron.vite.config.ts @@ -0,0 +1,42 @@ +/** + * Electron-vite config for building the desktop app. + * Used by the `dev`, `build`, and `build:*` scripts. + * + * Configures all three Electron processes: main, preload, and renderer. + * `envDir` is set explicitly so `.env` files are resolved from the project root. + */ +import { tanstackRouter } from "@tanstack/router-plugin/vite"; +import react from "@vitejs/plugin-react"; +import { defineConfig, externalizeDepsPlugin } from "electron-vite"; +import { resolve } from "node:path"; + +export default defineConfig({ + main: { + plugins: [externalizeDepsPlugin()], + }, + preload: { + plugins: [externalizeDepsPlugin()], + }, + renderer: { + envDir: resolve("."), + // Use relative asset URLs so the renderer works under the file:// protocol + // when the app is packaged. The standalone web build (vite.config.ts) + // keeps the default base of "/". + base: "./", + server: { + port: 3000, + }, + resolve: { + alias: { + "@": resolve("src/renderer/src"), + }, + }, + plugins: [ + tanstackRouter({ + target: "react", + autoCodeSplitting: true, + }), + react(), + ], + }, +}); diff --git a/frontend/forge.config.js b/frontend/forge.config.js new file mode 100644 index 00000000..7c0bc436 --- /dev/null +++ b/frontend/forge.config.js @@ -0,0 +1,58 @@ +const path = require("node:path"); +const fs = require("node:fs"); + +module.exports = { + packagerConfig: { + // This forces forge to only package already builded files + ignore: ["^\\/public$", "^\\/src$", "^\\/node_modules$", "^\\/[.].+"], + icon: "public/brand/logo256-text", + name: "AymurAI", + protocols: [ + { + name: "AymurAI", + schemes: ["aymurai.app"], + }, + ], + }, + rebuildConfig: {}, + makers: [ + { + name: "@electron-forge/maker-squirrel", + config: {}, + }, + { + name: "@electron-forge/maker-zip", + platforms: ["darwin"], + }, + { + name: "@electron-forge/maker-deb", + config: { + mimeType: ["x-scheme-handler/aymurai.app"], + }, + }, + { + name: "@electron-forge/maker-rpm", + config: {}, + }, + ], + hooks: { + packageAfterCopy: async ( + _config, + buildPath, + _electronVersion, + _platform, + _arch, + ) => { + // Create logs in the root directory + const twoAbove = path.join(buildPath, "../../"); + // const logMessage = `Build Path: ${twoAbove}\nDirname: ${__dirname}\n---\n`; + // fs.appendFileSync(path.join(__dirname, "logs.txt"), logMessage); + + // biome-ignore lint/style/noVar: Don't know why this is needed + var src = path.join(__dirname, "build/app/run_server.bat"); + // biome-ignore lint/style/noVar: Don't know why this is needed + var dst = `${twoAbove}/run_server.bat`; + fs.cpSync(src, dst, { recursive: true }); + }, + }, +}; diff --git a/frontend/knip.json b/frontend/knip.json new file mode 100644 index 00000000..4651583e --- /dev/null +++ b/frontend/knip.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://unpkg.com/knip@6/schema.json", + "tags": [ + "-lintignore" + ] +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 00000000..1830abf8 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,100 @@ +{ + "name": "aymurai", + "version": "1.5.0", + "private": true, + "main": "./out/main/index.js", + "scripts": { + "dev:web": "cross-env VITE_APP_MODE=web vite --config vite.config.ts", + "dev": "cross-env VITE_APP_MODE=electron electron-vite dev", + "start": "cross-env VITE_APP_MODE=electron electron-vite preview", + "start:web": "cross-env VITE_APP_MODE=web vite preview --config vite.config.ts", + "lint": "biome check", + "lint:fix": "biome check --write", + "format": "biome format", + "format:fix": "biome format --write", + "typecheck:node": "tsc --noEmit -p tsconfig.node.json --composite false", + "typecheck:web": "tsc --noEmit -p tsconfig.web.json --composite false", + "typecheck": "npm run typecheck:node; npm run typecheck:web", + "validate": "npm run lint && npm run check-types:react && npm run check-types:renderer", + "pre-commit": "lint-staged", + "package": "rm -rf build && npm run build && electron-forge package", + "make": "rm -rf build && npm run build && electron-forge make", + "postinstall": "electron-builder install-app-deps || true", + "panda:codegen": "panda codegen", + "prepare": "panda codegen", + "build:web": "cross-env VITE_APP_MODE=web vite build --config vite.config.ts", + "build": "npm run typecheck && cross-env VITE_APP_MODE=electron electron-vite build", + "build:unpack": "npm run build && electron-builder --dir", + "build:win": "npm run build && electron-builder --win", + "build:mac": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --mac", + "build:linux": "cross-env VITE_APP_MODE=electron electron-vite build && electron-builder --linux", + "knip": "knip", + "test": "vitest run", + "test:watch": "vitest" + }, + "dependencies": { + "@electron-toolkit/preload": "^3.0.2", + "@electron-toolkit/utils": "^4.0.0", + "electron-squirrel-startup": "^1.0.0", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2" + }, + "devDependencies": { + "@biomejs/biome": "^1.9.4", + "@dnd-kit/core": "^6.3.1", + "@dnd-kit/sortable": "^10.0.0", + "@dnd-kit/utilities": "^3.2.2", + "@electron-forge/cli": "^6.0.4", + "@electron-forge/maker-deb": "^6.0.4", + "@electron-forge/maker-rpm": "^6.0.4", + "@electron-forge/maker-squirrel": "^6.0.4", + "@electron-forge/maker-zip": "^6.0.4", + "@electron-toolkit/tsconfig": "^1.0.1", + "@pandacss/dev": "^1.8.1", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-popover": "^1.1.15", + "@radix-ui/react-select": "^2.2.6", + "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tooltip": "^1.2.8", + "@stitches/react": "^1.2.8", + "@tanstack/react-form": "1.11.0", + "@tanstack/react-query": "^5.100.5", + "@tanstack/react-router": "^1.139.12", + "@tanstack/react-router-devtools": "^1.139.12", + "@tanstack/router-plugin": "^1.139.12", + "@types/node": "20", + "@types/react": "19", + "@types/react-dom": "19", + "@types/regex-escape": "^3.4.1", + "@vitejs/plugin-react": "^4.5.0", + "axios": "^1.12.0", + "concurrently": "^7.5.0", + "cross-env": "^7.0.3", + "electron": "^22.3.25", + "electron-builder": "^26.0.12", + "electron-debug": "^3.2.0", + "electron-devtools-installer": "^3.2.1", + "electron-vite": "^3.1.0", + "exceljs": "^4.4.0", + "husky": "^8.0.0", + "i18next": "^25.8.13", + "knip": "^6.7.0", + "lint-staged": "^13.0.3", + "markdownlint-cli": "^0.32.2", + "nodemon": "^2.0.20", + "phosphor-react": "^1.4.1", + "prettier": "^2.7.1", + "react": "19", + "react-dom": "19", + "react-hot-toast": "^2.6.0", + "react-i18next": "^16.5.4", + "regex-escape": "^3.4.10", + "typescript": "^5.9.2", + "vite": "^6.3.5", + "vitest": "^4.1.6", + "wait-on": "^6.0.1", + "zod": "^4.0.14", + "zustand": "^5.0.7" + } +} \ No newline at end of file diff --git a/frontend/panda.config.ts b/frontend/panda.config.ts new file mode 100644 index 00000000..72f545b2 --- /dev/null +++ b/frontend/panda.config.ts @@ -0,0 +1,233 @@ +import { defineConfig, defineGlobalStyles } from "@pandacss/dev"; + +const globalCss = defineGlobalStyles({ + "*": { + fontFamily: + '"Archivo", -apple-system, Helvetica Neue, Helvetica, Roboto, sans-serif', // TODO: Replace token here (was $primary) + }, + + html: { + color: "#110041", + }, + + "mark.predicted-word": { + backgroundColor: "#E6E8FF", // TODO: Replace token here (was $primaryAlt) + fontFamily: '"Times New Roman", Times, serif', // TODO: Replace token here (was $file) + padding: "0px 0px 0px 2px", + borderRadius: "8px", + + "& strong": { + fontSize: "12px", + padding: "0px", + margin: "0px", + }, + + "& button.remove-tag": { + visibility: "hidden", + position: "relative", + backgroundColor: "#DC582E", // TODO: Replace token here (was $errorPrimary) + color: "#FFFFFF", // TODO: Replace token here (was $white) + padding: "3px 5px", + borderRadius: "8px", + cursor: "pointer", + fontSize: "10px", + fontWeight: 800, // TODO: Replace token here (was $heavy) + textAlign: "center", + top: "-10px", + right: "-5px", + border: "none", + }, + + "&:hover": { + cursor: "pointer", + "& button.remove-tag": { + visibility: "visible", + }, + }, + }, + + "mark.searched-word": { + backgroundColor: "#E0DDE2", // TODO: Replace token here (was $bgSecondaryAlt) + fontFamily: '"Times New Roman", Times, serif', // TODO: Replace token here (was $file) + padding: "0px 2px", + borderRadius: "8px", + + "&:hover": { + cursor: "pointer", + }, + + "& button.add-tag": { + position: "relative", + backgroundColor: "#1B834E", // TODO: Replace token here (was $successPrimary) + color: "#FFFFFF", // TODO: Replace token here (was $white) + padding: "2px 5px", + borderRadius: "8px", + cursor: "pointer", + fontSize: "12px", + fontWeight: 800, // TODO: Replace token here (was $heavy) + textAlign: "center", + top: "-10px", + right: "-5px", + border: "none", + }, + }, +}); + +const text = (size: number, weight: number, lineHeight: string) => ({ + value: { + fontSize: `${size}px`, + fontWeight: weight, + lineHeight, + }, +}); + +const color = (hex: string) => ({ value: hex }); + +export default defineConfig({ + // Use CSS reset + preflight: true, + + // Where to look for CSS declarations + include: ["./src/renderer/src/**/*.{ts,tsx}"], + + // Files to exclude + exclude: [], + + // JSX framework + jsxFramework: "react", + + // Output directory for generated styled-system + outdir: "src/renderer/src/styled", + + // Global styles (migrated from Stitches globalStyles.ts) + globalCss, + + // Other configuration + strictTokens: true, + + theme: { + extend: { + keyframes: { + fadeIn: { + from: { opacity: "0" }, + to: { opacity: "1" }, + }, + fadeOut: { + from: { opacity: "1" }, + to: { opacity: "0" }, + }, + }, + tokens: { + animations: { + fadeIn: { value: "fadeIn 0.15s ease-out" }, + fadeOut: { value: "fadeOut 0.1s ease-in" }, + }, + }, + }, + textStyles: { + title: { + md: { + strong: text(32, 700, "120%"), + default: text(32, 400, "120%"), + }, + }, + subtitle: { + md: { + strong: text(20, 600, "120%"), + default: text(20, 400, "120%"), + }, + sm: { + strong: text(14, 600, "120%"), + default: text(14, 400, "120%"), + }, + }, + paragraph: { + md: { + strong: text(18, 600, "150%"), + default: text(18, 400, "150%"), + }, + sm: { + strong: text(16, 600, "140%"), + default: text(16, 400, "140%"), + }, + xsm: { + strong: text(10, 600, "140%"), + default: text(10, 400, "140%"), + }, + }, + cta: { + md: { + strong: text(16, 600, "100%"), + default: text(16, 400, "100%"), + }, + sm: { + strong: text(16, 600, "115%"), + default: text(16, 400, "115%"), + }, + }, + label: { + md: { + strong: text(16, 600, "120%"), + default: text(16, 400, "120%"), + }, + sm: { + strong: text(12, 600, "120%"), + default: text(12, 400, "120%"), + }, + }, + }, + semanticTokens: { + colors: { + brand: { + primary: color("#3F479D"), + secondary: color("#C3CCD7"), + tertiary: color("#4A5568"), + }, + text: { + default: color("#110041"), + lighter: color("#625C68"), + "onbutton-default": color("#110041"), + "onbutton-alternative": color("#FFFFFF"), + "onbutton-disabled": color("#2D3748"), + }, + action: { + default: color("#C5CAFF"), + disabled: color("#E0DDE2"), + "alt-default": color("#3F479D"), + hover: color("#110041"), + pressed: color("#3F479D"), + focus: color("#C5CAFF"), + }, + bg: { + primary: color("#F6F5F7"), + secondary: color("#FFFFFF"), + "primary-alternative": color("#E5E8FF"), + "primary-highlight": color("#C5CAFF"), + "secondary-highlight": color("#E0DDE2"), + }, + system: { + success: color("#1B834E"), + "success-secondary": color("#E0FAED"), + error: color("#DC582E"), + "error-secondary": color("#FFECE5"), + warning: color("#F2BA2C"), + "warning-secondary": color("#FFF7DB"), + info: color("#3F479D"), + "info-secondary": color("#F6F5F7"), + }, + }, + borders: { + primary: { value: "1px solid #BCBAB8" }, + secondary: { value: "1px solid #EDF2F7" }, + "primary-alt": { value: "1px solid #110041" }, + error: { value: "1px solid {colors.system.error}" }, + }, + gradients: { + primary: { + value: + "linear-gradient(249.5deg, #C5CAFF -33.26%, #8591E8 28.49%, #3F479D 82.99%)", + }, + }, + }, + }, +}); diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml new file mode 100644 index 00000000..e5bbfd38 --- /dev/null +++ b/frontend/pnpm-lock.yaml @@ -0,0 +1,11035 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@dnd-kit/core': + specifier: ^6.3.1 + version: 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@dnd-kit/sortable': + specifier: ^10.0.0 + version: 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4) + '@dnd-kit/utilities': + specifier: ^3.2.2 + version: 3.2.2(react@19.2.4) + '@electron-toolkit/preload': + specifier: ^3.0.2 + version: 3.0.2(electron@22.3.27) + '@electron-toolkit/utils': + specifier: ^4.0.0 + version: 4.0.0(electron@22.3.27) + electron-squirrel-startup: + specifier: ^1.0.0 + version: 1.0.1 + devDependencies: + '@biomejs/biome': + specifier: ^1.9.4 + version: 1.9.4 + '@electron-forge/cli': + specifier: ^6.0.4 + version: 6.4.2(encoding@0.1.13) + '@electron-forge/maker-deb': + specifier: ^6.0.4 + version: 6.4.2 + '@electron-forge/maker-rpm': + specifier: ^6.0.4 + version: 6.4.2 + '@electron-forge/maker-squirrel': + specifier: ^6.0.4 + version: 6.4.2 + '@electron-forge/maker-zip': + specifier: ^6.0.4 + version: 6.4.2 + '@electron-toolkit/tsconfig': + specifier: ^1.0.1 + version: 1.0.1(@types/node@20.19.1) + '@pandacss/dev': + specifier: ^1.8.1 + version: 1.8.1(hono@4.11.7)(typescript@5.9.2) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-popover': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-select': + specifier: ^2.2.6 + version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-switch': + specifier: ^1.2.6 + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@stitches/react': + specifier: ^1.2.8 + version: 1.2.8(react@19.2.4) + '@tanstack/react-form': + specifier: 1.11.0 + version: 1.11.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-query': + specifier: ^5.100.5 + version: 5.100.5(react@19.2.4) + '@tanstack/react-router': + specifier: ^1.139.12 + version: 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/react-router-devtools': + specifier: ^1.139.12 + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3) + '@tanstack/router-plugin': + specifier: ^1.139.12 + version: 1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) + '@types/node': + specifier: '20' + version: 20.19.1 + '@types/react': + specifier: '19' + version: 19.2.13 + '@types/react-dom': + specifier: '19' + version: 19.2.3(@types/react@19.2.13) + '@types/regex-escape': + specifier: ^3.4.1 + version: 3.4.1 + '@vitejs/plugin-react': + specifier: ^4.5.0 + version: 4.5.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) + axios: + specifier: ^1.12.0 + version: 1.13.4 + concurrently: + specifier: ^7.5.0 + version: 7.6.0 + cross-env: + specifier: ^7.0.3 + version: 7.0.3 + electron: + specifier: ^22.3.25 + version: 22.3.27 + electron-builder: + specifier: ^26.0.12 + version: 26.0.12(electron-builder-squirrel-windows@26.0.12) + electron-debug: + specifier: ^3.2.0 + version: 3.2.0 + electron-devtools-installer: + specifier: ^3.2.1 + version: 3.2.1 + electron-vite: + specifier: ^3.1.0 + version: 3.1.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) + exceljs: + specifier: ^4.4.0 + version: 4.4.0 + husky: + specifier: ^8.0.0 + version: 8.0.3 + i18next: + specifier: ^25.8.13 + version: 25.8.13(typescript@5.9.2) + knip: + specifier: ^6.7.0 + version: 6.7.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + lint-staged: + specifier: ^13.0.3 + version: 13.3.0 + markdownlint-cli: + specifier: ^0.32.2 + version: 0.32.2 + nodemon: + specifier: ^2.0.20 + version: 2.0.22 + phosphor-react: + specifier: ^1.4.1 + version: 1.4.1(react@19.2.4) + prettier: + specifier: ^2.7.1 + version: 2.8.8 + react: + specifier: '19' + version: 19.2.4 + react-dom: + specifier: '19' + version: 19.2.4(react@19.2.4) + react-hot-toast: + specifier: ^2.6.0 + version: 2.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react-i18next: + specifier: ^16.5.4 + version: 16.5.4(i18next@25.8.13(typescript@5.9.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.2) + regex-escape: + specifier: ^3.4.10 + version: 3.4.11 + typescript: + specifier: ^5.9.2 + version: 5.9.2 + vite: + specifier: ^6.3.5 + version: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + vitest: + specifier: ^4.1.6 + version: 4.1.6(@types/node@20.19.1)(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) + wait-on: + specifier: ^6.0.1 + version: 6.0.1 + zod: + specifier: ^4.0.14 + version: 4.0.14 + zustand: + specifier: ^5.0.7 + version: 5.0.7(@types/react@19.2.13)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)) + +packages: + + 7zip-bin@5.2.0: + resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.27.3': + resolution: {integrity: sha512-V42wFfx1ymFte+ecf6iXghnnP8kWTO+ZLXIyZq+1LAXHHvTZdVxicn4yiVYdYMGaCO3tmqub11AorKkv+iodqw==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.27.4': + resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.28.5': + resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.27.3': + resolution: {integrity: sha512-xnlJYj5zepml8NXtjkG0WquFUv8RskFqyFcVgTBp5k+NaA/8uw/K+OSVf8AMGw5e9HKP2ETd5xpK5MLZQD6b4Q==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-replace-supers@7.27.1': + resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.27.4': + resolution: {integrity: sha512-Y+bO6U+I7ZKaM5G5rDUZiYfUvQPUibYmAFe7EnKdnKBbVXDZxvp+MWOH5gYciY0EPk4EScsuFMQBbEfpdRKSCQ==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.28.4': + resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.27.4': + resolution: {integrity: sha512-BRmLHGwpUqLFR2jzx9orBuX/ABDkj2jLKOXrHDTN2aOKL+jFDDKaRNo9nyYsIl9h/UE/7lMKdDjKQQyxKKDZ7g==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-commonjs@7.27.1': + resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-typescript@7.28.5': + resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.27.1': + resolution: {integrity: sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==} + engines: {node: '>=6.9.0'} + + '@babel/runtime@7.28.6': + resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.27.4': + resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.27.3': + resolution: {integrity: sha512-Y1GkI4ktrtvmawoSq+4FCVHNryea6uR+qUQy0AGxLSsjCX0nVmkYQMBLHDkXZuo5hGx7eYdnIaslsdBFm7zbUw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + + '@biomejs/biome@1.9.4': + resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} + engines: {node: '>=14.21.3'} + hasBin: true + + '@biomejs/cli-darwin-arm64@1.9.4': + resolution: {integrity: sha512-bFBsPWrNvkdKrNCYeAp+xo2HecOGPAy9WyNyB/jKnnedgzl4W4Hb9ZMzYNbf8dMCGmUdSavlYHiR01QaYR58cw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] + + '@biomejs/cli-darwin-x64@1.9.4': + resolution: {integrity: sha512-ngYBh/+bEedqkSevPVhLP4QfVPCpb+4BBe2p7Xs32dBgs7rh9nY2AIYUL6BgLw1JVXV8GlpKmb/hNiuIxfPfZg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@1.9.4': + resolution: {integrity: sha512-v665Ct9WCRjGa8+kTr0CzApU0+XXtRgwmzIf1SeKSGAv+2scAlW6JR5PMFo6FzqqZ64Po79cKODKf3/AAmECqA==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@1.9.4': + resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@1.9.4': + resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@1.9.4': + resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@1.9.4': + resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@1.9.4': + resolution: {integrity: sha512-8Y5wMhVIPaWe6jw2H+KlEm4wP/f7EW3810ZLmDlrEEy5KvBsb9ECEfu/kMWD484ijfQ8+nIi0giMgu9g1UAuuA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] + + '@clack/core@0.5.0': + resolution: {integrity: sha512-p3y0FIOwaYRUPRcMO7+dlmLh8PSRcrjuTndsiA0WAFbWES0mLZlrjVoBRZ9DzkPFJZG6KGkJmoEAY0ZcVWTkow==} + + '@clack/prompts@0.11.0': + resolution: {integrity: sha512-pMN5FcrEw9hUkZA4f+zLlzivQSeQf5dRGJjSUbvVYDLvpKCdQx5OaknvKzgbtXOizhP+SJJJjqEbOe55uKKfAw==} + + '@csstools/postcss-cascade-layers@5.0.2': + resolution: {integrity: sha512-nWBE08nhO8uWl6kSAeCx4im7QfVko3zLrtgWZY4/bP87zrSPpSyN/3W3TDqz1jJuH+kbKOHXg5rJnK+ZVYcFFg==} + engines: {node: '>=18'} + peerDependencies: + postcss: ^8.4 + + '@csstools/selector-specificity@5.0.0': + resolution: {integrity: sha512-PCqQV3c4CoVm3kdPhyeZ07VmBRdH2EpMFA/pd9OASpOEC3aXNGoqPDAZ80D0cLpMBxnmk0+yNhGsEx31hq7Gtw==} + engines: {node: '>=18'} + peerDependencies: + postcss-selector-parser: ^7.0.0 + + '@develar/schema-utils@2.6.5': + resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} + engines: {node: '>= 8.9.0'} + + '@dnd-kit/accessibility@3.1.1': + resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==} + peerDependencies: + react: '>=16.8.0' + + '@dnd-kit/core@6.3.1': + resolution: {integrity: sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@dnd-kit/sortable@10.0.0': + resolution: {integrity: sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg==} + peerDependencies: + '@dnd-kit/core': ^6.3.0 + react: '>=16.8.0' + + '@dnd-kit/utilities@3.2.2': + resolution: {integrity: sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg==} + peerDependencies: + react: '>=16.8.0' + + '@electron-forge/cli@6.4.2': + resolution: {integrity: sha512-bM6YVTV0uUEpIL1jkpARlSm4Li26XZn+avC/lyTdpPqnd65T/oXZNkrAD+2Jb0RlgplOaM21qWm7ybtvKDGDyA==} + engines: {node: '>= 14.17.5'} + hasBin: true + + '@electron-forge/core-utils@6.4.2': + resolution: {integrity: sha512-CjB3aakmRsXAMMDYc8PxNTMf4FdI29y4PErfv7eCXlL5oo3JW0VSKZIV7R8/Po0S0got85q2kmhZgCKuxL1BNA==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/core@6.4.2': + resolution: {integrity: sha512-VtrFZ1Q7NG1ov0jJO/tUvUiYdWZ0Y31xw762is/jfpRPD6V/soOpwJJAoWoPK9TZVkTm2pkS8S5LikCMbNCLxw==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/maker-base@6.4.2': + resolution: {integrity: sha512-zW3GH+LqDK9nxQmQEFkJPR8RqiX0lVk6a4mXll3ngujN1fPevO4ivUAWmaEVeC1dH/hXbN7s9m0S6a37MigftQ==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/maker-deb@6.4.2': + resolution: {integrity: sha512-tlV8ffivgBP94vtYXgAeXgzeKCaRyLuWH9LT8PQW1QrYbAFpCMmuwk/zFaJkyMklImCWmDFTPYMEqdEJGd7Npg==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/maker-rpm@6.4.2': + resolution: {integrity: sha512-+hfbY5pYbAer0y07OtOzVgVBHoTRmemqqZ//T0mKJpyK2ThHKGTvyW8FFlr5jlQs5LoDCM2WHKE8oGtRhivsMg==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/maker-squirrel@6.4.2': + resolution: {integrity: sha512-ukK3RcFaBrQXUzR52PsHxfwDq5XKSnj6A1kkXiyHWqgj+HIU97prBScBb5JRtasPvYN+nDdQO2vlInsLaqcx9Q==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/maker-zip@6.4.2': + resolution: {integrity: sha512-k2nfhhnxcYbUS7rCKCisuqEalxtH9l73+lrtfL0aQZiE/BLbDXyNckDIDOPvX0tBEg62nVzUdJonZwOhZVvAMw==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/plugin-base@6.4.2': + resolution: {integrity: sha512-g6AAtQ7fZ94djBmwcnWasQ8xgaNVNjgaQ00GLK0NkmQ7n0PNbsnlMDuw9vdfTiL6WaLg5nxNSYc9bFJP/rtyeA==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/publisher-base@6.4.2': + resolution: {integrity: sha512-Tnf9O8MFzdT1gsb5EDDaQUoslt7gUuUywtsr+lT/fpBlBQbei2fvioTwvZ1Q1cmsKnld7XhRh6unfgdWLTZzgw==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/shared-types@6.4.2': + resolution: {integrity: sha512-DKOUMsdTXZIq8XiqY0Hi3C+dam/JKUnvfBjwcUeyZqPdgEE1qry8xZmmjorXuLrRf1Jq8rhxYGQInSK4af0QYw==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/template-base@6.4.2': + resolution: {integrity: sha512-vsQh+64Fr2Vxg6k8DAahWq4MAdB2F2qTig+LgIJENv8ksbzC1YIq05SBAS/g2674cdr7WdwyukMy2rgxe3rhnQ==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/template-vite-typescript@6.4.2': + resolution: {integrity: sha512-h3pn6onvC/nLglmJuelYU82Qzrh0l6MqvbBGoT39bbDoRLIqmlhWTWppHgDJVXAGrSoH+9BEpptipeBQWirFwg==} + engines: {node: ^14.18.0 || >=16.0.0} + + '@electron-forge/template-vite@6.4.2': + resolution: {integrity: sha512-NX7jHRblBmIqufMbqWgpI/VnpgF/qMSTq9ZPmDSXamBhid336MC6+DoWzDpXceQZEp0m/jpMLR04ynr8O4jGlg==} + engines: {node: ^14.18.0 || >=16.0.0} + + '@electron-forge/template-webpack-typescript@6.4.2': + resolution: {integrity: sha512-MPAZQ4v6piCED7NT1LTVQf61o6Eg/laNoKbhbrFBSH1i20OUwbtV2MLj6Op292ynI9+1qdHKmFgctr6qPTCAQw==} + engines: {node: '>= 14.17.5'} + + '@electron-forge/template-webpack@6.4.2': + resolution: {integrity: sha512-9QYr/td4cmnGOj8UF25W6An/eI+JXj9T/b+KFybL3cQ87H1yrQOn2T84Bm5/JaB4SPdIu4FdKRjqwR7C7R0g2w==} + engines: {node: '>= 14.17.5'} + + '@electron-toolkit/preload@3.0.2': + resolution: {integrity: sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==} + peerDependencies: + electron: '>=13.0.0' + + '@electron-toolkit/tsconfig@1.0.1': + resolution: {integrity: sha512-M0Mol3odspvtCuheyujLNAW7bXq7KFNYVMRtpjFa4ZfES4MuklXBC7Nli/omvc+PRKlrklgAGx3l4VakjNo8jg==} + peerDependencies: + '@types/node': '*' + + '@electron-toolkit/utils@4.0.0': + resolution: {integrity: sha512-qXSntwEzluSzKl4z5yFNBknmPGjPa3zFhE4mp9+h0cgokY5ornAeP+CJQDBhKsL1S58aOQfcwkD3NwLZCl+64g==} + peerDependencies: + electron: '>=13.0.0' + + '@electron/asar@3.2.18': + resolution: {integrity: sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==} + engines: {node: '>=10.12.0'} + hasBin: true + + '@electron/asar@3.4.1': + resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} + engines: {node: '>=10.12.0'} + hasBin: true + + '@electron/fuses@1.8.0': + resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} + hasBin: true + + '@electron/get@2.0.3': + resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} + engines: {node: '>=12'} + + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': + resolution: {gitHosted: true, integrity: sha512-MXgzlTDEEndJB3TBbvd5uFQO/8gaINo1Hfen8vef5rq/VHVPeB63uuv/uO5+8GFsAJ/rauu6XB79S6K4+aXc+w==, tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} + version: 10.2.0-electron.1 + engines: {node: '>=12.13.0'} + hasBin: true + + '@electron/notarize@1.2.4': + resolution: {integrity: sha512-W5GQhJEosFNafewnS28d3bpQ37/s91CDWqxVchHfmv2dQSTWpOzNlUVQwYzC1ay5bChRV/A9BTL68yj0Pa+TSg==} + engines: {node: '>= 10.0.0'} + + '@electron/notarize@2.5.0': + resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} + engines: {node: '>= 10.0.0'} + + '@electron/osx-sign@1.3.1': + resolution: {integrity: sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==} + engines: {node: '>=12.0.0'} + hasBin: true + + '@electron/osx-sign@1.3.3': + resolution: {integrity: sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==} + engines: {node: '>=12.0.0'} + hasBin: true + + '@electron/rebuild@3.7.0': + resolution: {integrity: sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==} + engines: {node: '>=12.13.0'} + hasBin: true + + '@electron/rebuild@3.7.2': + resolution: {integrity: sha512-19/KbIR/DAxbsCkiaGMXIdPnMCJLkcf8AvGnduJtWBs/CBwiAjY1apCqOLVxrXg+rtXFCngbXhBanWjxLUt1Mg==} + engines: {node: '>=12.13.0'} + hasBin: true + + '@electron/universal@1.5.1': + resolution: {integrity: sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw==} + engines: {node: '>=8.6'} + + '@electron/universal@2.0.1': + resolution: {integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==} + engines: {node: '>=16.4'} + + '@electron/windows-sign@1.2.2': + resolution: {integrity: sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==} + engines: {node: '>=14.14'} + hasBin: true + + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@esbuild/aix-ppc64@0.25.5': + resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.5': + resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.5': + resolution: {integrity: sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.5': + resolution: {integrity: sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.5': + resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.5': + resolution: {integrity: sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.5': + resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.5': + resolution: {integrity: sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.5': + resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.5': + resolution: {integrity: sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.5': + resolution: {integrity: sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.25.5': + resolution: {integrity: sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.5': + resolution: {integrity: sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.5': + resolution: {integrity: sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.5': + resolution: {integrity: sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.5': + resolution: {integrity: sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.5': + resolution: {integrity: sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.5': + resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.5': + resolution: {integrity: sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.5': + resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.5': + resolution: {integrity: sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.25.5': + resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.5': + resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.5': + resolution: {integrity: sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.5': + resolution: {integrity: sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@fast-csv/format@4.3.5': + resolution: {integrity: sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==} + + '@fast-csv/parse@4.3.6': + resolution: {integrity: sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==} + + '@floating-ui/core@1.7.4': + resolution: {integrity: sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg==} + + '@floating-ui/dom@1.7.5': + resolution: {integrity: sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg==} + + '@floating-ui/react-dom@2.1.7': + resolution: {integrity: sha512-0tLRojf/1Go2JgEVm+3Frg9A3IW8bJgKgdO0BN5RkF//ufuz2joZM63Npau2ff3J6lUVYgDSNzNkR+aH3IVfjg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + + '@gar/promisify@1.1.3': + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + + '@hono/node-server@1.19.9': + resolution: {integrity: sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw==} + engines: {node: '>=18.14.1'} + peerDependencies: + hono: ^4 + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@malept/cross-spawn-promise@1.1.1': + resolution: {integrity: sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==} + engines: {node: '>= 10'} + + '@malept/cross-spawn-promise@2.0.0': + resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} + engines: {node: '>= 12.13.0'} + + '@malept/flatpak-bundler@0.4.0': + resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} + engines: {node: '>= 10.0.0'} + + '@modelcontextprotocol/sdk@1.25.3': + resolution: {integrity: sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@napi-rs/wasm-runtime@1.1.4': + resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@npmcli/fs@2.1.2': + resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + '@npmcli/move-file@2.0.1': + resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This functionality has been moved to @npmcli/fs + + '@oxc-parser/binding-android-arm-eabi@0.127.0': + resolution: {integrity: sha512-0LC7ye4hvqbIKxAzThzvswgHLFu2AURKzYLeSVvLdu2TBOYWQDmHnTqPLeA597BcUCxiLqLsS4CJ5uoI5WYWCQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@oxc-parser/binding-android-arm64@0.127.0': + resolution: {integrity: sha512-b5jtVTH6AU5CJXHNdj7Jj9IEiR9yVjjnwHzPJhGyHGPdcsZSzBCkS9GBbV33niRMvKthDwQRFRJfI4a+k4PvYg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@oxc-parser/binding-darwin-arm64@0.127.0': + resolution: {integrity: sha512-obCE8B7ISKkJidjlhv9xRGJPOSDG2Yu6PRga9Ruaz35uintHxbp1Ki/Yc71wx4rj3Edrm0a1kzG1TAwit0wFpg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@oxc-parser/binding-darwin-x64@0.127.0': + resolution: {integrity: sha512-JL6Xb5IwPQT8rUzlpsX7E+AgfcdNklXNPFp8pjCQQ5MQOQo5rtEB2ui+3Hgg9Sn7Y9Egj6YOLLiHhLpdAe12Aw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@oxc-parser/binding-freebsd-x64@0.127.0': + resolution: {integrity: sha512-SDQ/3MQFw58fqQz3Z1PhSKFF3JoCF4gmlNjziDm8X02tTahCw0qJbd7FGPDKw1i4VTBZene9JPyC3mHtSvi+wA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@oxc-parser/binding-linux-arm-gnueabihf@0.127.0': + resolution: {integrity: sha512-Av+D1MIqzV0YMGPT9we2SIZaMKD7Cxs4CvXSx/yxaWHewZjYEjScpOf5igc8IILASViw4WTnjlwUdI1KzVtDHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm-musleabihf@0.127.0': + resolution: {integrity: sha512-Cs2fdJ8cPpFdeebj6p4dag8A4+56hPvZ0AhQQzlaLswGz1tz7bXt1nETLeorrM9+AMcWFFkqxcXwDGfTVidY8g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@oxc-parser/binding-linux-arm64-gnu@0.127.0': + resolution: {integrity: sha512-qdOfTcT6SY8gsJrrV92uyEUyjqMGPpIB5JZUG6QN5dukYd+7/j0kX6MwK1DgQj39jtUYixxPiaRUiEN1+0CXgQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-arm64-musl@0.127.0': + resolution: {integrity: sha512-EoTCZneNFU/P2qrpEM+RHmQwt+CvDkyGESG6qhr7KaegXLZwePfbrkCDfAk8/rhxbDUVGsZILX+2tqPzFtoFWA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@oxc-parser/binding-linux-ppc64-gnu@0.127.0': + resolution: {integrity: sha512-zALjmZYgxFLHjXeudcDF0xFGNydTAtkAeXAr2EuC17ywCyFxcmQra4w0BMde0Yi/re4Bi4iwEoEXtYN7l6eBLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-gnu@0.127.0': + resolution: {integrity: sha512-fPP8M6zQLS7Jz7o9d5ArUSuAuSK3e+WCYVrCpdzeCOejidtZExJ9tjhDrAd3HEPqARBCPmdpqxESPFqy44vkBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-riscv64-musl@0.127.0': + resolution: {integrity: sha512-7IcC4Ao02oGpfnjt+X/oF4U2mllo2qoSkw5xxiXNKL9MCTsTiAC6616beOuehdxGcnz1bRoPC1RQ2f1GQDdN+g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + + '@oxc-parser/binding-linux-s390x-gnu@0.127.0': + resolution: {integrity: sha512-pbXIhiNFHoqWeqDNLiJ9JkpHz1IM9k4DXa66x+1GTWMG7iLxtkXgE53iiuKSXwmk3zIYmaPVfBvgcAhS583K4Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@oxc-parser/binding-linux-x64-gnu@0.127.0': + resolution: {integrity: sha512-MYCguB9RvBvlSd6gbuNI7QwiLoCCAlGnlRJFPrzLI6U1/9wkC/WK6LtBAUln55H1Ctqw45PWmqrobKoMhsYQzQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-linux-x64-musl@0.127.0': + resolution: {integrity: sha512-5eY0B/bxf1xIUxb4NOTvOI3KWtBQfPWYyKAzgcrCt0mDibSZygVpO1Pz8bkeiSZ5Jj9+M09dkggG3H8I5d0Uyg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@oxc-parser/binding-openharmony-arm64@0.127.0': + resolution: {integrity: sha512-Gld0ajrFTUXNtdw20fVBuTQx66FA75nIVg+//pPfR3sXkuABB4mTBhl3r9JNzrJpgW//qiwxf0nWXUWGJSL3UQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@oxc-parser/binding-wasm32-wasi@0.127.0': + resolution: {integrity: sha512-T6KVD7rhLzFlwGRXMnxUFfkCZD8FHnb968wVXW1mXzgRFc5RNXOBY2mPPDZ77x5Ln76ltLMgtPg0cOkU1NSrEQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@oxc-parser/binding-win32-arm64-msvc@0.127.0': + resolution: {integrity: sha512-Ujvw4X+LD1CCGULcsQcvb4YNVoBGqt+JHgNNzGGaCImELiZLk477ifUH53gIbE7EKd933NdTi25JWEr9K2HwXw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@oxc-parser/binding-win32-ia32-msvc@0.127.0': + resolution: {integrity: sha512-0cwxKO7KHQQQfo4Uf4B2SQrhgm+cJaP9OvFFhx52Tkg4bezsacu83GB2/In5bC415Ueeym+kXdnge/57rbSfTw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] + + '@oxc-parser/binding-win32-x64-msvc@0.127.0': + resolution: {integrity: sha512-rOrnSQSCbhI2kowr9XxE7m9a8oQXnBHjnS6j95LxxAnEZ0+Fz20WlRXG4ondQb+ejjt2KOsa65sE6++L6kUd+w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@oxc-project/types@0.127.0': + resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} + + '@oxc-resolver/binding-android-arm-eabi@11.19.1': + resolution: {integrity: sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg==} + cpu: [arm] + os: [android] + + '@oxc-resolver/binding-android-arm64@11.19.1': + resolution: {integrity: sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA==} + cpu: [arm64] + os: [android] + + '@oxc-resolver/binding-darwin-arm64@11.19.1': + resolution: {integrity: sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ==} + cpu: [arm64] + os: [darwin] + + '@oxc-resolver/binding-darwin-x64@11.19.1': + resolution: {integrity: sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ==} + cpu: [x64] + os: [darwin] + + '@oxc-resolver/binding-freebsd-x64@11.19.1': + resolution: {integrity: sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw==} + cpu: [x64] + os: [freebsd] + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': + resolution: {integrity: sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': + resolution: {integrity: sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ==} + cpu: [arm] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-gnu@11.19.1': + resolution: {integrity: sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': + resolution: {integrity: sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew==} + cpu: [arm64] + os: [linux] + + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': + resolution: {integrity: sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ==} + cpu: [ppc64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': + resolution: {integrity: sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': + resolution: {integrity: sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw==} + cpu: [riscv64] + os: [linux] + + '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': + resolution: {integrity: sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA==} + cpu: [s390x] + os: [linux] + + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': + resolution: {integrity: sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-linux-x64-musl@11.19.1': + resolution: {integrity: sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw==} + cpu: [x64] + os: [linux] + + '@oxc-resolver/binding-openharmony-arm64@11.19.1': + resolution: {integrity: sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA==} + cpu: [arm64] + os: [openharmony] + + '@oxc-resolver/binding-wasm32-wasi@11.19.1': + resolution: {integrity: sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': + resolution: {integrity: sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ==} + cpu: [arm64] + os: [win32] + + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': + resolution: {integrity: sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA==} + cpu: [ia32] + os: [win32] + + '@oxc-resolver/binding-win32-x64-msvc@11.19.1': + resolution: {integrity: sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw==} + cpu: [x64] + os: [win32] + + '@pandacss/config@1.8.1': + resolution: {integrity: sha512-SvFvfDav//c2lbk9+IPRGCLGhUd1G8z/Nxs0CwZNLXpI0xTNy0ISGMV1ZKkqBFbmH95e+/5oZXnnM4rAS1LO0g==} + + '@pandacss/core@1.8.1': + resolution: {integrity: sha512-8axy9BApvc/oX5/K2/qX23HX1cHvp3MI/fm+CDx31v9zH3MIy4X49MMDeEU9o6L2Q6p6yinPgQZi7gtOqw+mfQ==} + + '@pandacss/dev@1.8.1': + resolution: {integrity: sha512-rHE7JEDNbqLVpybgT1Ff5R1loYxX3sF/a729EVvsBUtcd/xSHZyjhg8vnB5hXajaWt9Ro+u7chAB6+pdqd1Jog==} + hasBin: true + + '@pandacss/extractor@1.8.1': + resolution: {integrity: sha512-fgztRMZq1f/M8zdCku9ads+Wslje9/stypjN/qLjV436NI2LWktDmWYGTiEyHZTR5yEfI2LtJCa1b1BvZcU07g==} + + '@pandacss/generator@1.8.1': + resolution: {integrity: sha512-+20L+KeSbd2tqalH51M8pAMcJ6HM9rgnKXOyNAN/kx78WXec4jCZN9z9CSCFbrRxH/qpcIx20oAXZBbNghHSyQ==} + + '@pandacss/is-valid-prop@1.8.1': + resolution: {integrity: sha512-gf2HTBCOboc65Jlb9swAjbffXSIv+A4vzSQ9iHyTCDLMcXTHYjPOQNliI36WkuQgR0pNXggBbQXGNaT9wKcrAw==} + + '@pandacss/logger@1.8.1': + resolution: {integrity: sha512-u++vUM+roJPPle0PQ1BGl6GkxwusfzEbKtX35L/5GtF6+CQ1ZfbD07HlMjEzmyEQ+KeQ8joR1Ubh/YGrZdEWrQ==} + + '@pandacss/mcp@1.8.1': + resolution: {integrity: sha512-z3VOz9XVvpdQ0bf6a1REGZToFFcwU/0jyK699fRD3jzMg+OJ24j/T8RZvlFoDPCWcifjXI7eUCSnUJ1TVqXfcQ==} + + '@pandacss/node@1.8.1': + resolution: {integrity: sha512-59Cb55sFL+TO2Sd/s2SxSvh0nY/ouBsJQYqRvUkgLL56FDH28euCYvj8Tt6H9rISKl6xhCpixF7svA8YjTOuXg==} + + '@pandacss/parser@1.8.1': + resolution: {integrity: sha512-dyWX+P4zouBuvqbWqySKDWnrIeq/C2jdeS/GjswQny3pGQHwm1np9yqHfNEtKlaIouXYACbjP1cXl/tEgiKXHA==} + + '@pandacss/postcss@1.8.1': + resolution: {integrity: sha512-xopXqr/Bh/KTewxgsYe2muHIsuLqrZ64RH1cW4KRY5TOI+JaL7M4qAPTqa/fVMh+LV9k0woTd423g7Q3d2oivA==} + + '@pandacss/preset-base@1.8.1': + resolution: {integrity: sha512-NJtVQz4Dn3FuFLci8GvbXVGegKvAkYh7xB5TwJA5mqwRIOqWZ6+U/WoVXu9aR9wj3/EYAhqA5qUJQXrC6dUFmA==} + + '@pandacss/preset-panda@1.8.1': + resolution: {integrity: sha512-89QSWcSdhr1ViW6o0YMAQrSCxmY+xsrr0eA6GnNT6FWkjwL1QAtwjezWwODHN26BjlNTLmW8aK39Tepj6Wh2Aw==} + + '@pandacss/reporter@1.8.1': + resolution: {integrity: sha512-aTAObZ8ALxhGIXtHMEJ0KzDx3au1qlwHe60EA4BGGEPfBg25ntM8SaSbxOMhwUcbD5VffzywRoJeqWMaPmg3zw==} + + '@pandacss/shared@1.8.1': + resolution: {integrity: sha512-8U+iqqvb1hmTRHOCkO4q29OMv//szv/wJAQG6SPEuYth7QH+fEvPMl2qsZyDTe1b+pkB1bt7tpvTF4+lR1K8EA==} + + '@pandacss/token-dictionary@1.8.1': + resolution: {integrity: sha512-6uDH/QbxE/sS/QzfaSswxa+hMdDR1U3PUGVD/uCrt3tJ4zTHgR2icZ3vH9GN9k17WFutzcVQaKTKscY3PYn9TA==} + + '@pandacss/types@1.8.1': + resolution: {integrity: sha512-5hNn6PsbmSWdHmfETGTGW+gpFmzf0xdKlzbFHIIKHZK+zicCtHIg6iMahZsf9wvYiBu0LAKwgdKR+kDMya5N8w==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-select@2.2.6': + resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-switch@1.2.6': + resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-tooltip@1.2.8': + resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@rolldown/pluginutils@1.0.0-beta.9': + resolution: {integrity: sha512-e9MeMtVWo186sgvFFJOPGy7/d2j2mZhLJIdVW0C/xDluuOvymEATqz6zKsP0ZmXGzQtqlyjz5sC1sYQUoJG98w==} + + '@rollup/rollup-android-arm-eabi@4.41.1': + resolution: {integrity: sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.41.1': + resolution: {integrity: sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.41.1': + resolution: {integrity: sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.41.1': + resolution: {integrity: sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.41.1': + resolution: {integrity: sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.41.1': + resolution: {integrity: sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.41.1': + resolution: {integrity: sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.41.1': + resolution: {integrity: sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.41.1': + resolution: {integrity: sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.41.1': + resolution: {integrity: sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.41.1': + resolution: {integrity: sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-powerpc64le-gnu@4.41.1': + resolution: {integrity: sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.41.1': + resolution: {integrity: sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.41.1': + resolution: {integrity: sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.41.1': + resolution: {integrity: sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.41.1': + resolution: {integrity: sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.41.1': + resolution: {integrity: sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.41.1': + resolution: {integrity: sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.41.1': + resolution: {integrity: sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.41.1': + resolution: {integrity: sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + cpu: [x64] + os: [win32] + + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@stitches/react@1.2.8': + resolution: {integrity: sha512-9g9dWI4gsSVe8bNLlb+lMkBYsnIKCZTmvqvDG+Avnn69XfmHZKiaMrx7cgTaddq7aTPPmXiTsbFcUy0xgI4+wA==} + peerDependencies: + react: '>= 16.3.0' + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@tanstack/form-core@1.11.0': + resolution: {integrity: sha512-BaEnQ73h4S72AXdjgQowmDBJPHbAvPnWTY2xeY74O7/qfesZKbgPA7DQi5BW1qMv15BkthloJMi9Qljbf5mi7Q==} + + '@tanstack/history@1.139.0': + resolution: {integrity: sha512-l6wcxwDBeh/7Dhles23U1O8lp9kNJmAb2yNjekR6olZwCRNAVA8TCXlVCrueELyFlYZqvQkh0ofxnzG62A1Kkg==} + engines: {node: '>=12'} + + '@tanstack/query-core@5.100.5': + resolution: {integrity: sha512-t20KrhKkf0HXzqQkPbJ5erhFesup68BAbwFgYmTrS7bxMF7O5MdmL8jUkik4thsG7Hg00fblz30h6yF1d5TxGg==} + + '@tanstack/react-form@1.11.0': + resolution: {integrity: sha512-jTsTVvRaTLWwdhCAKG0mfrH+/43wudGujwDiRRT09VYxWJeJNFoXqepXW26lY0iuq11a0+A/0lmr2TfVqPanfg==} + peerDependencies: + '@tanstack/react-start': ^1.112.0 + react: ^17.0.0 || ^18.0.0 || ^19.0.0 + vinxi: ^0.5.0 + peerDependenciesMeta: + '@tanstack/react-start': + optional: true + vinxi: + optional: true + + '@tanstack/react-query@5.100.5': + resolution: {integrity: sha512-aNwj1mi2v2bQ9IxkyR1grLOUkv3BYWoykHy9KDyLNbjC3tsahbOHJibK+Wjtr1wRhG59/AvJhiJG5OlthaCgJA==} + peerDependencies: + react: ^18 || ^19 + + '@tanstack/react-router-devtools@1.139.12': + resolution: {integrity: sha512-deMQGaojEJGFio95o0rDT4OhgtwfgrQIBZAGnXhfyC395n94IuE43uvvv7tkfBzWHQwYK0IvZIeyKMavbvAj7Q==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/react-router': ^1.139.12 + '@tanstack/router-core': ^1.139.12 + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + peerDependenciesMeta: + '@tanstack/router-core': + optional: true + + '@tanstack/react-router@1.139.12': + resolution: {integrity: sha512-qrIxb8c6XXih6MERZKKwdnYg0OannsQLJ/s+4/wRqKqGCG+QmvAMvnmNP7bfYLgFKi+KsE27HqUkHaSpZSenwQ==} + engines: {node: '>=12'} + peerDependencies: + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + + '@tanstack/react-store@0.7.0': + resolution: {integrity: sha512-S/Rq17HaGOk+tQHV/yrePMnG1xbsKZIl/VsNWnNXt4XW+tTY8dTlvpJH2ZQ3GRALsusG5K6Q3unAGJ2pd9W/Ng==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/react-store@0.8.0': + resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/router-core@1.139.12': + resolution: {integrity: sha512-HCDi4fpnAFeDDogT0C61yd2nJn0FrIyFDhyHG3xJji8emdn8Ni4rfyrN4Av46xKkXTPUGdbsqih45+uuNtunew==} + engines: {node: '>=12'} + + '@tanstack/router-devtools-core@1.139.12': + resolution: {integrity: sha512-VARlT9alLnROnPsZtHrSZsqYksIdBBQ24yGzEper5K1+1e0fzpcKLnMYLK9cwr//uWA2xmQayznvBnwcTmnUlg==} + engines: {node: '>=12'} + peerDependencies: + '@tanstack/router-core': ^1.139.12 + csstype: ^3.0.10 + solid-js: '>=1.9.5' + peerDependenciesMeta: + csstype: + optional: true + + '@tanstack/router-generator@1.139.12': + resolution: {integrity: sha512-HGs35aBml+2TVwoynsEc00/9Duw19GeT1fX+JzrY0TKNfMzq/nbjR+xxU8M1w3+gHqfKiITmW70XSZoWkXu9tw==} + engines: {node: '>=12'} + + '@tanstack/router-plugin@1.139.12': + resolution: {integrity: sha512-xX39CcU6GLMaahr6YGNQYRZOQsd1WefgCH99PtY0cxZr9VNAIpJMYPsQY8h/g8A4JI10rHI1tdKxZAvodWjZxw==} + engines: {node: '>=12'} + peerDependencies: + '@rsbuild/core': '>=1.0.2' + '@tanstack/react-router': ^1.139.12 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' + vite-plugin-solid: ^2.11.10 + webpack: '>=5.92.0' + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@tanstack/react-router': + optional: true + vite: + optional: true + vite-plugin-solid: + optional: true + webpack: + optional: true + + '@tanstack/router-utils@1.139.0': + resolution: {integrity: sha512-jT7D6NimWqoFSkid4vCno8gvTyfL1+NHpgm3es0B2UNhKKRV3LngOGilm1m6v8Qvk/gy6Fh/tvB+s+hBl6GhOg==} + engines: {node: '>=12'} + + '@tanstack/store@0.7.0': + resolution: {integrity: sha512-CNIhdoUsmD2NolYuaIs8VfWM467RK6oIBAW4nPEKZhg1smZ+/CwtCdpURgp7nxSqOaV9oKkzdWD80+bC66F/Jg==} + + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + + '@tanstack/virtual-file-routes@1.139.0': + resolution: {integrity: sha512-9PImF1d1tovTUIpjFVa0W7Fwj/MHif7BaaczgJJfbv3sDt1Gh+oW9W9uCw9M3ndEJynnp5ZD/TTs0RGubH5ssg==} + engines: {node: '>=12'} + + '@tootallnate/once@2.0.0': + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + + '@ts-morph/common@0.28.1': + resolution: {integrity: sha512-W74iWf7ILp1ZKNYXY5qbddNaml7e9Sedv5lvU1V8lftlitkc9Pq1A+jlH23ltDgWYeZFFEqGCD1Ies9hqu3O+g==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.7': + resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree@1.0.7': + resolution: {integrity: sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/fs-extra@9.0.13': + resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/node@14.18.63': + resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} + + '@types/node@16.18.126': + resolution: {integrity: sha512-OTcgaiwfGFBKacvfwuHzzn1KLxH/er8mluiy8/uM3sGXHaRe73RrSIj01jow9t4kJEW633Ov+cOexXeiApTyAw==} + + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + + '@types/node@20.19.1': + resolution: {integrity: sha512-jJD50LtlD2dodAEO653i3YF04NWak6jN3ky+Ri3Em3mGR39/glWiboM/IePaRbgwSfqM1TpGXfAg8ohn/4dTgA==} + + '@types/plist@3.0.5': + resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.13': + resolution: {integrity: sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ==} + + '@types/regex-escape@3.4.1': + resolution: {integrity: sha512-aQihdLwAzyST0/LTidv76ZKtltWbea61FprvpMHbqUToUpdZrSYUqPb3ToojMW2a29JfoJXBxtO6K5py4o8uwA==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/verror@1.10.11': + resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} + + '@types/yauzl@2.10.3': + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + + '@vitejs/plugin-react@4.5.0': + resolution: {integrity: sha512-JuLWaEqypaJmOJPLWwO335Ig6jSgC1FTONCWAxnqcQthLTK/Yc9aH6hr9z/87xciejbQcnP3GnA1FWUSWeXaeg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 + + '@vitest/expect@4.1.6': + resolution: {integrity: sha512-7EHDquPthALSV0jhhjgEW8FXaviMx7rSqu8W6oqCoAuOhKov814P99QDV1pxMA3QPv21YudvJngIhjrNI4opLg==} + + '@vitest/mocker@4.1.6': + resolution: {integrity: sha512-MCFc63czMjEInOlcY2cpQCvCN+KgbAn+60xu9cMgP4sKaLC5JNAKw7JH8QdAnoAC88hW1IiSNZ+GgVXlN1UcMQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@4.1.6': + resolution: {integrity: sha512-h5SxD/IzNhZYnrSZRsUZQIC+vD0GY8cUvq0iwsmkFKixRCKLLWqCXa/FIQ4S1R+sI+PGoojkHsdNrbZiM9Qpgw==} + + '@vitest/runner@4.1.6': + resolution: {integrity: sha512-nOPCmn2+yD0ZNmKdsXGv/UxMMWbMuKeD6GyYncNwdkYDxpQvrPSKYj2rWuDjC2Y4b6w6hjip5dBKFzEUuZe3vA==} + + '@vitest/snapshot@4.1.6': + resolution: {integrity: sha512-YhsdE6xAVfTDmzjxL2ZDUvjj+ZsgyOKe+TdQzqkD72wIOmHka8NuGQ6NpTNZv9D2Z63fbwWKJPeVpEw4EQgYxw==} + + '@vitest/spy@4.1.6': + resolution: {integrity: sha512-JFKxMx6udhwKh/Ldo270e17QX710vgunMkuPAvXjHSvC6oqLWAHhVhjg/I71q0u0CBSErIODV1Kjv0FQNSWjdg==} + + '@vitest/utils@4.1.6': + resolution: {integrity: sha512-FxIY+U81R3LGKCxaHHFRQ5+g6/iRgGLmeHWdp2Amj4ljQRrEIWHmZyDfDYBRZlpyqA7qKxtS9DD1dhk8RnRIVQ==} + + '@vue/compiler-core@3.5.25': + resolution: {integrity: sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==} + + '@vue/compiler-dom@3.5.25': + resolution: {integrity: sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==} + + '@vue/compiler-sfc@3.5.25': + resolution: {integrity: sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==} + + '@vue/compiler-ssr@3.5.25': + resolution: {integrity: sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==} + + '@vue/shared@3.5.25': + resolution: {integrity: sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==} + + '@xmldom/xmldom@0.8.10': + resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} + engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version + + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agent-base@7.1.3: + resolution: {integrity: sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==} + engines: {node: '>= 14'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-escapes@5.0.0: + resolution: {integrity: sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==} + engines: {node: '>=12'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + ansis@4.2.0: + resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + engines: {node: '>=14'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + app-builder-bin@5.0.0-alpha.12: + resolution: {integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==} + + app-builder-lib@26.0.12: + resolution: {integrity: sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==} + engines: {node: '>=14.0.0'} + peerDependencies: + dmg-builder: 26.0.12 + electron-builder-squirrel-windows: 26.0.12 + + archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + + archiver-utils@3.0.4: + resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} + engines: {node: '>= 10'} + + archiver@5.3.2: + resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} + engines: {node: '>= 10'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async-exit-hook@2.0.1: + resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} + engines: {node: '>=0.12.0'} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + author-regex@1.0.0: + resolution: {integrity: sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g==} + engines: {node: '>=0.8'} + + axios@0.25.0: + resolution: {integrity: sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==} + + axios@1.13.4: + resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} + + babel-dead-code-elimination@1.0.10: + resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.9.19: + resolution: {integrity: sha512-ipDqC8FrAl/76p2SSWKSI+H9tFwm7vYqXQrItCuiVPt26Km0jS+NzSsBWAaBusvSbQcfJG+JitdMm+wZAgTYqg==} + hasBin: true + + big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + binary@0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + + boolean@3.2.0: + resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.0: + resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + browserslist@4.28.0: + resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-equal@1.0.1: + resolution: {integrity: sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg==} + engines: {node: '>=0.4'} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-indexof-polyfill@1.0.2: + resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} + engines: {node: '>=0.10'} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffers@0.1.1: + resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} + engines: {node: '>=0.2.0'} + + builder-util-runtime@9.3.1: + resolution: {integrity: sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==} + engines: {node: '>=12.0.0'} + + builder-util@26.0.11: + resolution: {integrity: sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==} + + bundle-n-require@1.1.2: + resolution: {integrity: sha512-bEk2jakVK1ytnZ9R2AAiZEeK/GxPUM8jvcRxHZXifZDMcjkI4EG/GlsJ2YGSVYT9y/p/gA9/0yDY8rCGsSU6Tg==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cacache@16.1.3: + resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001720: + resolution: {integrity: sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==} + + caniuse-lite@1.0.30001766: + resolution: {integrity: sha512-4C0lfJ0/YPjJQHagaE9x2Elb69CIqEPZeG0anQt9SIvIoOH4a4uaRl73IavyO+0qZh6MDLH//DrXThEYKHkmYA==} + + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} + + chainsaw@0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + chromium-pickle-js@0.2.0: + resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + + cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + + cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + + cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + code-block-writer@13.0.3: + resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@11.0.0: + resolution: {integrity: sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ==} + engines: {node: '>=16'} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + + commander@9.4.1: + resolution: {integrity: sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==} + engines: {node: ^12.20.0 || >=14} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + compare-version@0.1.2: + resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} + engines: {node: '>=0.10.0'} + + compress-commons@4.1.2: + resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} + engines: {node: '>= 10'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concurrently@7.6.0: + resolution: {integrity: sha512-BKtRgvcJGeZ4XttiDiNcFiRlxoAeZOseqUvyYRUp/Vtd+9p1ULmeoSqGsDA+2ivdeDFpqrJvGvmI+StKfKl5hw==} + engines: {node: ^12.20.0 || ^14.13.0 || >=16.0.0} + hasBin: true + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + + config-file-ts@0.2.8-rc1: + resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==} + + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-es@2.0.0: + resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@4.0.3: + resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} + engines: {node: '>= 10'} + + crc@3.8.0: + resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} + + cross-dirname@0.1.0: + resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} + + cross-env@7.0.3: + resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} + engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} + hasBin: true + + cross-spawn-windows-exe@1.2.0: + resolution: {integrity: sha512-mkLtJJcYbDCxEG7Js6eUnUNndWjyUZwJ3H7bErmmtOYU/Zb99DyUkpamuIZE0b3bhmJyZ7D90uS6f+CGxRRjOw==} + engines: {node: '>= 10'} + + cross-spawn@6.0.6: + resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} + engines: {node: '>=4.8'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + cross-zip@4.0.1: + resolution: {integrity: sha512-n63i0lZ0rvQ6FXiGQ+/JFCKAUyPFhLQYJIqKaa+tSJtfKeULF/IDNDAbdnSIxgS4NTuw2b0+lj8LzfITuq+ZxQ==} + engines: {node: '>=12.10'} + + crosspath@2.0.0: + resolution: {integrity: sha512-ju88BYCQ2uvjO2bR+SsgLSTwTSctU+6Vp2ePbKPgSCZyy4MWZxYsT738DlKVRE5utUjobjPRm1MkTYKJxCmpTA==} + engines: {node: '>=14.9.0'} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-utils@5.0.1: + resolution: {integrity: sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decode-formdata@0.9.0: + resolution: {integrity: sha512-q5uwOjR3Um5YD+ZWPOF/1sGHVW9A5rCrRwITQChRXlmPkxDFBqCm4jNTIVdGHNH9OnR+V9MoZVgRhsFb+ARbUw==} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + + devalue@5.1.1: + resolution: {integrity: sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==} + + diff@8.0.2: + resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + engines: {node: '>=0.3.1'} + + dir-compare@3.3.0: + resolution: {integrity: sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg==} + + dir-compare@4.2.0: + resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} + + dmg-builder@26.0.12: + resolution: {integrity: sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==} + + dmg-license@1.0.11: + resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} + engines: {node: '>=8'} + os: [darwin] + hasBin: true + + dotenv-expand@11.0.7: + resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} + engines: {node: '>=12'} + + dotenv@16.5.0: + resolution: {integrity: sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-builder-squirrel-windows@26.0.12: + resolution: {integrity: sha512-kpwXM7c/ayRUbYVErQbsZ0nQZX4aLHQrPEG9C4h9vuJCXylwFH8a7Jgi2VpKIObzCXO7LKHiCw4KdioFLFOgqA==} + + electron-builder@26.0.12: + resolution: {integrity: sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==} + engines: {node: '>=14.0.0'} + hasBin: true + + electron-debug@3.2.0: + resolution: {integrity: sha512-7xZh+LfUvJ52M9rn6N+tPuDw6oRAjxUj9SoxAZfJ0hVCXhZCsdkrSt7TgXOiWiEOBgEV8qwUIO/ScxllsPS7ow==} + + electron-devtools-installer@3.2.1: + resolution: {integrity: sha512-FaCi+oDCOBTw0gJUsuw5dXW32b2Ekh5jO8lI1NRCQigo3azh2VogsIi0eelMVrP1+LkN/bewyH3Xoo1USjO0eQ==} + + electron-installer-common@0.10.4: + resolution: {integrity: sha512-8gMNPXfAqUE5CfXg8RL0vXpLE9HAaPkgLXVoHE3BMUzogMWenf4LmwQ27BdCUrEhkjrKl+igs2IHJibclR3z3Q==} + engines: {node: '>= 10.0.0'} + + electron-installer-debian@3.2.0: + resolution: {integrity: sha512-58ZrlJ1HQY80VucsEIG9tQ//HrTlG6sfofA3nRGr6TmkX661uJyu4cMPPh6kXW+aHdq/7+q25KyQhDrXvRL7jw==} + engines: {node: '>= 10.0.0'} + os: [darwin, linux] + hasBin: true + + electron-installer-redhat@3.4.0: + resolution: {integrity: sha512-gEISr3U32Sgtj+fjxUAlSDo3wyGGq6OBx7rF5UdpIgbnpUvMN4W5uYb0ThpnAZ42VEJh/3aODQXHbFS4f5J3Iw==} + engines: {node: '>= 10.0.0'} + os: [darwin, linux] + hasBin: true + + electron-is-accelerator@0.1.2: + resolution: {integrity: sha512-fLGSAjXZtdn1sbtZxx52+krefmtNuVwnJCV2gNiVt735/ARUboMl8jnNC9fZEqQdlAv2ZrETfmBUsoQci5evJA==} + + electron-is-dev@1.2.0: + resolution: {integrity: sha512-R1oD5gMBPS7PVU8gJwH6CtT0e6VSoD0+SzSnYpNm+dBkcijgA+K7VAMHDfnRq/lkKPZArpzplTW6jfiMYosdzw==} + + electron-localshortcut@3.2.1: + resolution: {integrity: sha512-DWvhKv36GsdXKnaFFhEiK8kZZA+24/yFLgtTwJJHc7AFgDjNRIBJZ/jq62Y/dWv9E4ypYwrVWN2bVrCYw1uv7Q==} + + electron-packager@17.1.2: + resolution: {integrity: sha512-XofXdikjYI7MVBcnXeoOvRR+yFFFHOLs3J7PF5KYQweigtgLshcH4W660PsvHr4lYZ03JBpLyEcUB8DzHZ+BNw==} + engines: {node: '>= 14.17.5'} + deprecated: Please use @electron/packager moving forward. There is no API change, just a package name change + hasBin: true + + electron-publish@26.0.11: + resolution: {integrity: sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==} + + electron-squirrel-startup@1.0.1: + resolution: {integrity: sha512-sTfFIHGku+7PsHLJ7v0dRcZNkALrV+YEozINTW8X1nM//e5O3L+rfYuvSW00lmGHnYmUjARZulD8F2V8ISI9RA==} + + electron-to-chromium@1.5.161: + resolution: {integrity: sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==} + + electron-to-chromium@1.5.283: + resolution: {integrity: sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w==} + + electron-vite@3.1.0: + resolution: {integrity: sha512-M7aAzaRvSl5VO+6KN4neJCYLHLpF/iWo5ztchI/+wMxIieDZQqpbCYfaEHHHPH6eupEzfvZdLYdPdmvGqoVe0Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@swc/core': ^1.0.0 + vite: ^4.0.0 || ^5.0.0 || ^6.0.0 + peerDependenciesMeta: + '@swc/core': + optional: true + + electron-winstaller@5.4.0: + resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} + engines: {node: '>=8.0.0'} + + electron@22.3.27: + resolution: {integrity: sha512-7Rht21vHqj4ZFRnKuZdFqZFsvMBCmDqmjetiMqPtF+TmTBiGne1mnstVXOA/SRGhN2Qy5gY5bznJKpiqogjM8A==} + engines: {node: '>= 12.20.55'} + hasBin: true + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + + end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + + entities@3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es6-error@4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + + esbuild@0.25.5: + resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + exceljs@4.4.0: + resolution: {integrity: sha512-XctvKaEMaj1Ii9oDOqbW/6e1gXknSY4g/aLCDicOXqBE4M0nRWkUu0PTp++UPNzoFY12BNHMfs/VadKIS6llvg==} + engines: {node: '>=8.3.0'} + + execa@1.0.0: + resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} + engines: {node: '>=6'} + + execa@7.2.0: + resolution: {integrity: sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==} + engines: {node: ^14.18.0 || ^16.14.0 || >=18.0.0} + + expand-tilde@2.0.2: + resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} + engines: {node: '>=0.10.0'} + + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} + + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + + extract-zip@2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + + extsprintf@1.4.1: + resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} + engines: {'0': node >=0.6.0} + + fast-csv@4.3.6: + resolution: {integrity: sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==} + engines: {node: '>=10.0.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fd-package-json@2.0.0: + resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fdir@6.4.5: + resolution: {integrity: sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + filename-reserved-regex@2.0.0: + resolution: {integrity: sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==} + engines: {node: '>=4'} + + filenamify@4.3.0: + resolution: {integrity: sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==} + engines: {node: '>=8'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-up@2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flora-colossus@2.0.0: + resolution: {integrity: sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA==} + engines: {node: '>= 12'} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + engines: {node: '>= 6'} + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + formatly@0.3.0: + resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} + engines: {node: '>=18.3.0'} + hasBin: true + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + engines: {node: '>=14.14'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fstream@1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + deprecated: This package is no longer supported. + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + galactus@1.0.0: + resolution: {integrity: sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ==} + engines: {node: '>= 12'} + + gar@1.0.4: + resolution: {integrity: sha512-w4n9cPWyP7aHxKxYHFQMegj7WIAsL/YX/C4Bs5Rr8s1H9M1rNtRWRsw+ovYMkXDQ5S4ZbYHsHAPmevPjPgw44w==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-folder-size@2.0.1: + resolution: {integrity: sha512-+CEb+GDCM7tkOS2wdMKTn9vU7DgnKUTuDlehkNJKNSovdCOVxs14OfKCk4cvSaR3za4gj+OBdl9opPN9xrJ0zA==} + hasBin: true + + get-installed-path@2.1.1: + resolution: {integrity: sha512-Qkn9eq6tW5/q9BDVdMpB8tOHljX9OSP0jRC5TRNVA4qRc839t4g8KQaR8t0Uv0EFVL0MlyG7m/ofjEgAROtYsA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-package-info@1.0.0: + resolution: {integrity: sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw==} + engines: {node: '>= 4.0'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stdin@9.0.0: + resolution: {integrity: sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==} + engines: {node: '>=12'} + + get-stream@4.1.0: + resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} + engines: {node: '>=6'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} + + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + glob@8.0.3: + resolution: {integrity: sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==} + engines: {node: '>=12'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + global-agent@3.0.0: + resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} + engines: {node: '>=10.0'} + + global-modules@1.0.0: + resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} + engines: {node: '>=0.10.0'} + + global-prefix@1.0.2: + resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} + engines: {node: '>=0.10.0'} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + goober@2.1.18: + resolution: {integrity: sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==} + peerDependencies: + csstype: ^3.0.10 + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + homedir-polyfill@1.0.3: + resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} + engines: {node: '>=0.10.0'} + + hono@4.11.7: + resolution: {integrity: sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==} + engines: {node: '>=16.9.0'} + + hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + html-parse-stringify@3.0.1: + resolution: {integrity: sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-proxy-agent@5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@4.3.1: + resolution: {integrity: sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==} + engines: {node: '>=14.18.0'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + husky@8.0.3: + resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} + engines: {node: '>=14'} + hasBin: true + + i18next@25.8.13: + resolution: {integrity: sha512-E0vzjBY1yM+nsFrtgkjLhST2NBkirkvOVoQa0MSldhsuZ3jUge7ZNpuwG0Cfc74zwo5ZwRzg3uOgT+McBn32iA==} + peerDependencies: + typescript: ^5 + peerDependenciesMeta: + typescript: + optional: true + + iconv-corefoundation@1.1.7: + resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} + engines: {node: ^8.11.2 || >=10} + os: [darwin] + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + + ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + ini@3.0.1: + resolution: {integrity: sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + interpret@3.1.1: + resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} + engines: {node: '>=10.13.0'} + + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + + is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-stream@1.1.0: + resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} + engines: {node: '>=0.10.0'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isbinaryfile@4.0.10: + resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} + engines: {node: '>= 8.0.0'} + + isbinaryfile@5.0.4: + resolution: {integrity: sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==} + engines: {node: '>= 18.0.0'} + + isbot@5.1.32: + resolution: {integrity: sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ==} + engines: {node: '>=18'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + + javascript-stringify@2.1.0: + resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} + + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true + + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + + jose@6.1.3: + resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.1.0: + resolution: {integrity: sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + jszip@3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + + junk@3.1.0: + resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} + engines: {node: '>=8'} + + keyboardevent-from-electron-accelerator@2.0.0: + resolution: {integrity: sha512-iQcmNA0M4ETMNi0kG/q0h/43wZk7rMeKYrXP7sqKIJbHkTU8Koowgzv+ieR/vWJbOwxx5nDC3UnudZ0aLSu4VA==} + + keyboardevents-areequal@0.2.2: + resolution: {integrity: sha512-Nv+Kr33T0mEjxR500q+I6IWisOQ0lK1GGOncV0kWE6n4KFmpcu7RUX5/2B0EUtX51Cb0HjZ9VJsSY3u4cBa0kw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@4.1.5: + resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} + engines: {node: '>=6'} + + knip@6.7.0: + resolution: {integrity: sha512-ckL51NDH1YJxnv1kNB0iUdDngB4f/e9Igz8uIqYfmNDoyOFmmk1V0WFv3LQ7/hzC63b2Z9X41gGUE9eOWrZpaA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + lazy-val@1.0.5: + resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + linkify-it@4.0.1: + resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==} + + lint-staged@13.3.0: + resolution: {integrity: sha512-mPRtrYnipYYv1FEE134ufbWpeggNTo+O/UPzngoaKzbzHAthvR55am+8GfHTnqNRQVRRrYQLGW9ZyUoD7DsBHQ==} + engines: {node: ^16.14.0 || >=18.0.0} + hasBin: true + + listenercount@1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + + listr2@5.0.8: + resolution: {integrity: sha512-mC73LitKHj9w6v30nLNGPetZIlfpUniNSsxxrbaPcWOjDb92SHPzJPi/t+v1YC/lxKz/AJ9egOjww0qUuFxBpA==} + engines: {node: ^14.13.1 || >=16.0.0} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + + listr2@6.6.1: + resolution: {integrity: sha512-+rAXGHh0fkEWdXBmX+L6mmfmXmXvDGEKzkjxO+8mP3+nI/r/CWznVBvsibXdxda9Zz0OW2e2ikphN3OwCT/jSg==} + engines: {node: '>=16.0.0'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + + load-json-file@2.0.0: + resolution: {integrity: sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ==} + engines: {node: '>=4'} + + locate-path@2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + + lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + + lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. + + lodash.groupby@4.6.0: + resolution: {integrity: sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash.isfunction@3.0.9: + resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} + + lodash.isnil@4.0.0: + resolution: {integrity: sha512-up2Mzq3545mwVnMhTDMdfoG1OurpA/s5t88JmQX809eH3C8491iu2sfKhTfhQtKY78oPNhiaHJUpT/dUDAAtng==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isundefined@3.0.1: + resolution: {integrity: sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + log-update@4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + + log-update@5.0.1: + resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + look-it-up@2.1.0: + resolution: {integrity: sha512-nMoGWW2HurtuJf6XAL56FWTDCWLOTSsanrgwOyaR5Y4e3zfG5N/0cU5xWZSEU3tBxhQugRbV1xL9jb+ug7yZww==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + make-fetch-happen@10.2.1: + resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + + markdown-it@13.0.1: + resolution: {integrity: sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==} + hasBin: true + + markdownlint-cli@0.32.2: + resolution: {integrity: sha512-xmJT1rGueUgT4yGNwk6D0oqQr90UJ7nMyakXtqjgswAkEhYYqjHew9RY8wDbOmh2R270IWjuKSeZzHDEGPAUkQ==} + engines: {node: '>=14'} + hasBin: true + + markdownlint-rule-helpers@0.17.2: + resolution: {integrity: sha512-XaeoW2NYSlWxMCZM2B3H7YTG6nlaLfkEZWMBhr4hSPlq9MuY2sy83+Xr89jXOqZMZYjvi5nBCGoFh7hHoPKZmA==} + engines: {node: '>=12'} + + markdownlint@0.26.2: + resolution: {integrity: sha512-2Am42YX2Ex5SQhRq35HxYWDfz1NLEOZWWN25nqd2h3AHRKsGRE+Qg1gt1++exW792eXTrR4jCNHfShfWk9Nz8w==} + engines: {node: '>=14'} + + matcher@3.0.0: + resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} + engines: {node: '>=10'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdurl@1.0.1: + resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + mem@4.3.0: + resolution: {integrity: sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==} + engines: {node: '>=6'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + microdiff@1.5.0: + resolution: {integrity: sha512-Drq+/THMvDdzRYrK0oxJmOKiC24ayUV8ahrt8l3oRK51PWt6gdtrIGrlIH3pT/lFh1z93FbAcidtsHcWbnRz8Q==} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + minimatch@10.0.1: + resolution: {integrity: sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==} + engines: {node: 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + + minipass-fetch@2.1.2: + resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + minipass-flush@1.0.7: + resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + nice-try@1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + + node-abi@3.75.0: + resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==} + engines: {node: '>=10'} + + node-addon-api@1.7.2: + resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} + + node-api-version@0.2.1: + resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} + + node-eval@2.0.0: + resolution: {integrity: sha512-Ap+L9HznXAVeJj3TJ1op6M6bg5xtTq8L5CU/PJxtkhea/DrIxdTknGKIECKd/v/Lgql95iuMAYvIzBNd0pmcMg==} + engines: {node: '>= 4'} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + nodemon@2.0.22: + resolution: {integrity: sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==} + engines: {node: '>=8.10.0'} + hasBin: true + + nopt@6.0.0: + resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + npm-run-path@2.0.2: + resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} + engines: {node: '>=4'} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object-path@0.11.8: + resolution: {integrity: sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==} + engines: {node: '>= 10.12.0'} + + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + + outdent@0.8.0: + resolution: {integrity: sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==} + + oxc-parser@0.127.0: + resolution: {integrity: sha512-bkgD4qHlN7WxLdX8bLXdaU54TtQtAIg/ZBAfm0aje/mo3MRDo3P0hZSgr4U7O3xfX+fQmR5AP04JS/TGcZLcFA==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-resolver@11.19.1: + resolution: {integrity: sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg==} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-is-promise@2.1.0: + resolution: {integrity: sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==} + engines: {node: '>=6'} + + p-limit@1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + + p-locate@2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-try@1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-manager-detector@1.6.0: + resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parse-author@2.0.0: + resolution: {integrity: sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==} + engines: {node: '>=0.10.0'} + + parse-json@2.2.0: + resolution: {integrity: sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==} + engines: {node: '>=0.10.0'} + + parse-passwd@1.0.0: + resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} + engines: {node: '>=0.10.0'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-to-regexp@8.3.0: + resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + + path-type@2.0.0: + resolution: {integrity: sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ==} + engines: {node: '>=4'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pe-library@0.4.1: + resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} + engines: {node: '>=12', npm: '>=6'} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + + phosphor-react@1.4.1: + resolution: {integrity: sha512-gO5j7U0xZrdglTAYDYPACU4xDOFBTJmptrrB/GeR+tHhCZF3nUMyGmV/0hnloKjuTrOmpSFlbfOY78H39rgjUQ==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16' + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + + plist@3.1.0: + resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} + engines: {node: '>=10.4.0'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss-discard-duplicates@7.0.2: + resolution: {integrity: sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-discard-empty@7.0.1: + resolution: {integrity: sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-merge-rules@7.0.7: + resolution: {integrity: sha512-njWJrd/Ms6XViwowaaCc+/vqhPG3SmXn725AGrnl+BgTuRPEacjiLEaGq16J6XirMJbtKkTwnt67SS+e2WGoew==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-minify-selectors@7.0.5: + resolution: {integrity: sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-nested@7.0.2: + resolution: {integrity: sha512-5osppouFc0VR9/VYzYxO03VaDa3e8F23Kfd6/9qcZTUI8P58GIYlArOET2Wq0ywSl2o2PjELhYOFI4W7l5QHKw==} + engines: {node: '>=18.0'} + peerDependencies: + postcss: ^8.2.14 + + postcss-normalize-whitespace@7.0.1: + resolution: {integrity: sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==} + engines: {node: ^18.12.0 || ^20.9.0 || >=22.0} + peerDependencies: + postcss: ^8.4.32 + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.4: + resolution: {integrity: sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + postject@1.0.0-alpha.6: + resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} + engines: {node: '>=14.0.0'} + hasBin: true + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + prettier@3.2.5: + resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + engines: {node: '>=14'} + hasBin: true + + prettier@3.7.3: + resolution: {integrity: sha512-QgODejq9K3OzoBbuyobZlUhznP5SKwPqp+6Q6xw6o8gnhr4O85L2U915iM2IDcfF2NPXVaM9zlo9tdwipnYwzg==} + engines: {node: '>=14'} + hasBin: true + + proc-log@2.0.1: + resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + + pump@3.0.2: + resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.14.1: + resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + rcedit@3.1.0: + resolution: {integrity: sha512-WRlRdY1qZbu1L11DklT07KuHfRk42l0NFFJdaExELEu4fEQ982bP5Z6OWGPj/wLLIuKRQDCxZJGAwoFsxhZhNA==} + engines: {node: '>= 10.0.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react-hot-toast@2.6.0: + resolution: {integrity: sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16' + react-dom: '>=16' + + react-i18next@16.5.4: + resolution: {integrity: sha512-6yj+dcfMncEC21QPhOTsW8mOSO+pzFmT6uvU7XXdvM/Cp38zJkmTeMeKmTrmCMD5ToT79FmiE/mRWiYWcJYW4g==} + peerDependencies: + i18next: '>= 25.6.2' + react: '>= 16.8.0' + react-dom: '*' + react-native: '*' + typescript: ^5 + peerDependenciesMeta: + react-dom: + optional: true + react-native: + optional: true + typescript: + optional: true + + react-refresh@0.17.0: + resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + read-binary-file-arch@1.0.6: + resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} + hasBin: true + + read-pkg-up@2.0.0: + resolution: {integrity: sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w==} + engines: {node: '>=4'} + + read-pkg@2.0.0: + resolution: {integrity: sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA==} + engines: {node: '>=4'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + + rechoir@0.8.0: + resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} + engines: {node: '>= 10.13.0'} + + regex-escape@3.4.11: + resolution: {integrity: sha512-051l4Hl/0HoJwTvNztrWVjoxLiseSfCrDgWqwR1cnGM/nyQSeIjmvti5zZ7HzOmsXDPaJ2k0iFxQ6/WNpJD5wQ==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resedit@1.7.2: + resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} + engines: {node: '>=12', npm: '>=6'} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-dir@1.0.1: + resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} + engines: {node: '>=0.10.0'} + + resolve-package@1.0.1: + resolution: {integrity: sha512-rzB7NnQpOkPHBWFPP3prUMqOP6yg3HkRGgcvR+lDyvyHoY3fZLFLYDkPXh78SPVBAE6VTCk/V+j8we4djg6o4g==} + engines: {node: '>=4', npm: '>=2'} + + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + + restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + roarr@2.15.4: + resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} + engines: {node: '>=8.0'} + + rollup@4.41.1: + resolution: {integrity: sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-con@1.2.12: + resolution: {integrity: sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sanitize-filename@1.6.3: + resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + + saxes@5.0.1: + resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==} + engines: {node: '>=10'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver-compare@1.0.0: + resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.0.0: + resolution: {integrity: sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==} + hasBin: true + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + + seroval-plugins@1.3.3: + resolution: {integrity: sha512-16OL3NnUBw8JG1jBLUoZJsLnQq0n5Ua6aHalhJK4fMQkz1lqR7Osz1sA30trBtd9VUDc2NgkuRCn8+/pBwqZ+w==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval-plugins@1.4.0: + resolution: {integrity: sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 + + seroval@1.3.2: + resolution: {integrity: sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ==} + engines: {node: '>=10'} + + seroval@1.4.0: + resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==} + engines: {node: '>=10'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.2: + resolution: {integrity: sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==} + engines: {node: '>= 0.4'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-update-notifier@1.1.0: + resolution: {integrity: sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==} + engines: {node: '>=8.10.0'} + + simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + smol-toml@1.6.1: + resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} + engines: {node: '>= 18'} + + socks-proxy-agent@7.0.0: + resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} + engines: {node: '>= 10'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + solid-js@1.9.10: + resolution: {integrity: sha512-Coz956cos/EPDlhs6+jsdTxKuJDPT7B5SVIWgABwROyxjY7Xbr8wkzD68Et+NxnV7DLJ3nJdAC2r9InuV/4Jew==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + spawn-command@0.0.2: + resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-license-ids@3.0.21: + resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + + sprintf-js@1.1.3: + resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + + ssri@9.0.1: + resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + stat-mode@1.0.0: + resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} + engines: {node: '>= 6'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-eof@1.0.0: + resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} + engines: {node: '>=0.10.0'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-json-comments@5.0.3: + resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} + engines: {node: '>=14.16'} + + strip-outer@1.0.1: + resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} + engines: {node: '>=0.10.0'} + + sudo-prompt@9.2.1: + resolution: {integrity: sha512-Mu7R0g4ig9TUuGSxJavny5Rv0egCEtpZRNMrZaYS1vxkiIxGiGUwoezU3LazIQ+KE04hTrTfNPgxU5gzi7F5Pw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + sumchecker@3.0.1: + resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} + engines: {node: '>= 8.0'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + temp-file@3.4.0: + resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} + + temp@0.9.4: + resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} + engines: {node: '>=6.0.0'} + + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + + tiny-async-pool@1.3.0: + resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} + + tiny-each-async@2.0.3: + resolution: {integrity: sha512-5ROII7nElnAirvFn8g7H7MtpfV1daMcyfTGQwsn/x2VtyV+VPiO5CjReCJtWLvoKTDEDmZocf3cNPraiMnBXLA==} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tiny-warning@1.0.3: + resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} + engines: {node: '>=18'} + + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} + + tmp-promise@3.0.3: + resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} + + tmp@0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + touch@3.1.1: + resolution: {integrity: sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==} + hasBin: true + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + traverse@0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + trim-repeated@1.0.0: + resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} + engines: {node: '>=0.10.0'} + + truncate-utf8-bytes@1.0.2: + resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + + ts-evaluator@1.2.0: + resolution: {integrity: sha512-ncSGek1p92bj2ifB7s9UBgryHCkU9vwC5d+Lplt12gT9DH+e41X8dMoHRQjIMeAvyG7j9dEnuHmwgOtuRIQL+Q==} + engines: {node: '>=14.19.0'} + peerDependencies: + jsdom: '>=14.x || >=15.x || >=16.x || >=17.x || >=18.x || >=19.x || >=20.x || >=21.x || >=22.x' + typescript: '>=3.2.x || >= 4.x || >= 5.x' + peerDependenciesMeta: + jsdom: + optional: true + + ts-morph@27.0.2: + resolution: {integrity: sha512-fhUhgeljcrdZ+9DZND1De1029PrE+cMkIP7ooqkLRTrRLTqcki2AstsyJm0vRNbTbVCNJ0idGlbBrfqc7/nA8w==} + + ts-pattern@5.9.0: + resolution: {integrity: sha512-6s5V71mX8qBUmlgbrfL33xDUwO0fq48rxAu2LBE11WBeGdpCPOsXksQbZJHvHwhrd3QjUusd3mAOM5Gg0mFBLg==} + + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsx@4.20.6: + resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + engines: {node: '>=18.0.0'} + hasBin: true + + type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@1.0.6: + resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} + + unbash@3.0.0: + resolution: {integrity: sha512-FeFPZ/WFT0mbRCuydiZzpPFlrYN8ZUpphQKoq4EeElVIYjYyGzPMxQR/simUwCOJIyVhpFk4RbtyO7RuMpMnHA==} + engines: {node: '>=14'} + + undefsafe@2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unique-filename@2.0.1: + resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + unique-slug@3.0.0: + resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + + unzip-crx-3@0.2.0: + resolution: {integrity: sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==} + + unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.5.0: + resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + username@5.1.0: + resolution: {integrity: sha512-PCKbdWw85JsYMvmCv5GH3kXmM66rCd9m1hBEDutPNv94b/pqCMT4NtcKyeWYvLFiE8b+ha1Jdl8XAaUdPn5QTg==} + engines: {node: '>=8'} + + utf8-byte-length@1.0.5: + resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). + hasBin: true + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + verror@1.10.1: + resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} + engines: {node: '>=0.6.0'} + + vite@6.3.5: + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vite@7.2.4: + resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@4.1.6: + resolution: {integrity: sha512-6lvjbS3p9b4CrdCmguzbh2/4uoXhGE2q71R4OX5sqF9R1bo9Xd6fGrMAfvp5wnCzlBnFVdCOp6onuTQVbo8iUQ==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.6 + '@vitest/browser-preview': 4.1.6 + '@vitest/browser-webdriverio': 4.1.6 + '@vitest/coverage-istanbul': 4.1.6 + '@vitest/coverage-v8': 4.1.6 + '@vitest/ui': 4.1.6 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + void-elements@3.1.0: + resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} + engines: {node: '>=0.10.0'} + + wait-on@6.0.1: + resolution: {integrity: sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==} + engines: {node: '>=10.0.0'} + hasBin: true + + walk-up-path@4.0.0: + resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} + engines: {node: 20 || >=22} + + wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wordwrapjs@5.1.1: + resolution: {integrity: sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==} + engines: {node: '>=12.17'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xmlbuilder@15.1.1: + resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} + engines: {node: '>=8.0'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaku@0.16.7: + resolution: {integrity: sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yaml@2.3.1: + resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} + engines: {node: '>= 14'} + + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yarn-or-npm@3.0.1: + resolution: {integrity: sha512-fTiQP6WbDAh5QZAVdbMQkecZoahnbOjClTQhzv74WX5h2Uaidj1isf9FDes11TKtsZ0/ZVfZsqZ+O3x6aLERHQ==} + engines: {node: '>=8.6.0'} + hasBin: true + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + zip-stream@4.1.1: + resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} + engines: {node: '>= 10'} + + zod-to-json-schema@3.25.1: + resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} + peerDependencies: + zod: ^3.25 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zod@4.0.14: + resolution: {integrity: sha512-nGFJTnJN6cM2v9kXL+SOBq3AtjQby3Mv5ySGFof5UGRHrRioSJ5iG680cYNjE/yWk671nROcpPj4hAS8nyLhSw==} + + zod@4.3.6: + resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + + zustand@5.0.7: + resolution: {integrity: sha512-Ot6uqHDW/O2VdYsKLLU8GQu8sCOM1LcoE8RwvLv9uuRT9s6SOHCKs0ZEOhxg+I1Ld+A1Q5lwx+UlKXXUoCZITg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + +snapshots: + + 7zip-bin@5.2.0: {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.27.3': {} + + '@babel/core@7.27.4': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) + '@babel/helpers': 7.27.4 + '@babel/parser': 7.27.4 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.3 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.27.3': + dependencies: + '@babel/parser': 7.27.4 + '@babel/types': 7.27.3 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.28.5 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.27.3 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.5 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.3 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.28.5 + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.27.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.27.3 + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.27.4': + dependencies: + '@babel/types': 7.27.3 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + transitivePeerDependencies: + - supports-color + + '@babel/runtime@7.27.1': {} + + '@babel/runtime@7.28.6': {} + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.27.4 + '@babel/types': 7.27.3 + + '@babel/traverse@7.27.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.3 + '@babel/parser': 7.27.4 + '@babel/template': 7.27.2 + '@babel/types': 7.27.3 + debug: 4.4.1 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.27.3': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@biomejs/biome@1.9.4': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 1.9.4 + '@biomejs/cli-darwin-x64': 1.9.4 + '@biomejs/cli-linux-arm64': 1.9.4 + '@biomejs/cli-linux-arm64-musl': 1.9.4 + '@biomejs/cli-linux-x64': 1.9.4 + '@biomejs/cli-linux-x64-musl': 1.9.4 + '@biomejs/cli-win32-arm64': 1.9.4 + '@biomejs/cli-win32-x64': 1.9.4 + + '@biomejs/cli-darwin-arm64@1.9.4': + optional: true + + '@biomejs/cli-darwin-x64@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-arm64@1.9.4': + optional: true + + '@biomejs/cli-linux-x64-musl@1.9.4': + optional: true + + '@biomejs/cli-linux-x64@1.9.4': + optional: true + + '@biomejs/cli-win32-arm64@1.9.4': + optional: true + + '@biomejs/cli-win32-x64@1.9.4': + optional: true + + '@clack/core@0.5.0': + dependencies: + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@clack/prompts@0.11.0': + dependencies: + '@clack/core': 0.5.0 + picocolors: 1.1.1 + sisteransi: 1.0.5 + + '@csstools/postcss-cascade-layers@5.0.2(postcss@8.5.6)': + dependencies: + '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.1.1) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + '@csstools/selector-specificity@5.0.0(postcss-selector-parser@7.1.1)': + dependencies: + postcss-selector-parser: 7.1.1 + + '@develar/schema-utils@2.6.5': + dependencies: + ajv: 6.12.6 + ajv-keywords: 3.5.2(ajv@6.12.6) + + '@dnd-kit/accessibility@3.1.1(react@19.2.4)': + dependencies: + react: 19.2.4 + tslib: 2.8.1 + + '@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@dnd-kit/accessibility': 3.1.1(react@19.2.4) + '@dnd-kit/utilities': 3.2.2(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tslib: 2.8.1 + + '@dnd-kit/sortable@10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(react@19.2.4)': + dependencies: + '@dnd-kit/core': 6.3.1(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@dnd-kit/utilities': 3.2.2(react@19.2.4) + react: 19.2.4 + tslib: 2.8.1 + + '@dnd-kit/utilities@3.2.2(react@19.2.4)': + dependencies: + react: 19.2.4 + tslib: 2.8.1 + + '@electron-forge/cli@6.4.2(encoding@0.1.13)': + dependencies: + '@electron-forge/core': 6.4.2(encoding@0.1.13) + '@electron-forge/shared-types': 6.4.2 + '@electron/get': 2.0.3 + chalk: 4.1.2 + commander: 4.1.1 + debug: 4.4.1 + fs-extra: 10.1.0 + listr2: 5.0.8 + semver: 7.7.2 + transitivePeerDependencies: + - bluebird + - encoding + - enquirer + - supports-color + + '@electron-forge/core-utils@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + '@electron/rebuild': 3.7.2 + '@malept/cross-spawn-promise': 2.0.0 + chalk: 4.1.2 + debug: 4.4.1 + find-up: 5.0.0 + fs-extra: 10.1.0 + log-symbols: 4.1.0 + semver: 7.7.2 + yarn-or-npm: 3.0.1 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/core@6.4.2(encoding@0.1.13)': + dependencies: + '@electron-forge/core-utils': 6.4.2 + '@electron-forge/maker-base': 6.4.2 + '@electron-forge/plugin-base': 6.4.2 + '@electron-forge/publisher-base': 6.4.2 + '@electron-forge/shared-types': 6.4.2 + '@electron-forge/template-base': 6.4.2 + '@electron-forge/template-vite': 6.4.2 + '@electron-forge/template-vite-typescript': 6.4.2 + '@electron-forge/template-webpack': 6.4.2 + '@electron-forge/template-webpack-typescript': 6.4.2 + '@electron/get': 2.0.3 + '@electron/rebuild': 3.7.2 + '@malept/cross-spawn-promise': 2.0.0 + chalk: 4.1.2 + debug: 4.4.1 + electron-packager: 17.1.2 + fast-glob: 3.3.3 + filenamify: 4.3.0 + find-up: 5.0.0 + fs-extra: 10.1.0 + got: 11.8.6 + interpret: 3.1.1 + listr2: 5.0.8 + lodash: 4.17.21 + log-symbols: 4.1.0 + node-fetch: 2.7.0(encoding@0.1.13) + progress: 2.0.3 + rechoir: 0.8.0 + resolve-package: 1.0.1 + semver: 7.7.2 + source-map-support: 0.5.21 + sudo-prompt: 9.2.1 + username: 5.1.0 + yarn-or-npm: 3.0.1 + transitivePeerDependencies: + - bluebird + - encoding + - enquirer + - supports-color + + '@electron-forge/maker-base@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + fs-extra: 10.1.0 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/maker-deb@6.4.2': + dependencies: + '@electron-forge/maker-base': 6.4.2 + '@electron-forge/shared-types': 6.4.2 + optionalDependencies: + electron-installer-debian: 3.2.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/maker-rpm@6.4.2': + dependencies: + '@electron-forge/maker-base': 6.4.2 + '@electron-forge/shared-types': 6.4.2 + optionalDependencies: + electron-installer-redhat: 3.4.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/maker-squirrel@6.4.2': + dependencies: + '@electron-forge/maker-base': 6.4.2 + '@electron-forge/shared-types': 6.4.2 + fs-extra: 10.1.0 + optionalDependencies: + electron-winstaller: 5.4.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/maker-zip@6.4.2': + dependencies: + '@electron-forge/maker-base': 6.4.2 + '@electron-forge/shared-types': 6.4.2 + cross-zip: 4.0.1 + fs-extra: 10.1.0 + got: 11.8.6 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/plugin-base@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/publisher-base@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/shared-types@6.4.2': + dependencies: + '@electron/rebuild': 3.7.2 + electron-packager: 17.1.2 + listr2: 5.0.8 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/template-base@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.1 + fs-extra: 10.1.0 + username: 5.1.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/template-vite-typescript@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + '@electron-forge/template-base': 6.4.2 + fs-extra: 10.1.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/template-vite@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + '@electron-forge/template-base': 6.4.2 + fs-extra: 10.1.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/template-webpack-typescript@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + '@electron-forge/template-base': 6.4.2 + fs-extra: 10.1.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-forge/template-webpack@6.4.2': + dependencies: + '@electron-forge/shared-types': 6.4.2 + '@electron-forge/template-base': 6.4.2 + fs-extra: 10.1.0 + transitivePeerDependencies: + - bluebird + - enquirer + - supports-color + + '@electron-toolkit/preload@3.0.2(electron@22.3.27)': + dependencies: + electron: 22.3.27 + + '@electron-toolkit/tsconfig@1.0.1(@types/node@20.19.1)': + dependencies: + '@types/node': 20.19.1 + + '@electron-toolkit/utils@4.0.0(electron@22.3.27)': + dependencies: + electron: 22.3.27 + + '@electron/asar@3.2.18': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.2 + + '@electron/asar@3.4.1': + dependencies: + commander: 5.1.0 + glob: 7.2.3 + minimatch: 3.1.2 + + '@electron/fuses@1.8.0': + dependencies: + chalk: 4.1.2 + fs-extra: 9.1.0 + minimist: 1.2.8 + + '@electron/get@2.0.3': + dependencies: + debug: 4.4.1 + env-paths: 2.2.1 + fs-extra: 8.1.0 + got: 11.8.6 + progress: 2.0.3 + semver: 6.3.1 + sumchecker: 3.0.1 + optionalDependencies: + global-agent: 3.0.0 + transitivePeerDependencies: + - supports-color + + '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': + dependencies: + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + glob: 8.1.0 + graceful-fs: 4.2.11 + make-fetch-happen: 10.2.1 + nopt: 6.0.0 + proc-log: 2.0.1 + semver: 7.7.2 + tar: 6.2.1 + which: 2.0.2 + transitivePeerDependencies: + - bluebird + - supports-color + + '@electron/notarize@1.2.4': + dependencies: + debug: 4.4.1 + fs-extra: 9.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/notarize@2.5.0': + dependencies: + debug: 4.4.1 + fs-extra: 9.1.0 + promise-retry: 2.0.1 + transitivePeerDependencies: + - supports-color + + '@electron/osx-sign@1.3.1': + dependencies: + compare-version: 0.1.2 + debug: 4.4.1 + fs-extra: 10.1.0 + isbinaryfile: 4.0.10 + minimist: 1.2.8 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/osx-sign@1.3.3': + dependencies: + compare-version: 0.1.2 + debug: 4.4.1 + fs-extra: 10.1.0 + isbinaryfile: 4.0.10 + minimist: 1.2.8 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/rebuild@3.7.0': + dependencies: + '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 + '@malept/cross-spawn-promise': 2.0.0 + chalk: 4.1.2 + debug: 4.4.1 + detect-libc: 2.0.4 + fs-extra: 10.1.0 + got: 11.8.6 + node-abi: 3.75.0 + node-api-version: 0.2.1 + ora: 5.4.1 + read-binary-file-arch: 1.0.6 + semver: 7.7.2 + tar: 6.2.1 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - supports-color + + '@electron/rebuild@3.7.2': + dependencies: + '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 + '@malept/cross-spawn-promise': 2.0.0 + chalk: 4.1.2 + debug: 4.4.1 + detect-libc: 2.0.4 + fs-extra: 10.1.0 + got: 11.8.6 + node-abi: 3.75.0 + node-api-version: 0.2.1 + ora: 5.4.1 + read-binary-file-arch: 1.0.6 + semver: 7.7.2 + tar: 6.2.1 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - supports-color + + '@electron/universal@1.5.1': + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 1.1.1 + debug: 4.4.1 + dir-compare: 3.3.0 + fs-extra: 9.1.0 + minimatch: 3.1.2 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/universal@2.0.1': + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 2.0.0 + debug: 4.4.1 + dir-compare: 4.2.0 + fs-extra: 11.3.0 + minimatch: 9.0.5 + plist: 3.1.0 + transitivePeerDependencies: + - supports-color + + '@electron/windows-sign@1.2.2': + dependencies: + cross-dirname: 0.1.0 + debug: 4.4.1 + fs-extra: 11.3.0 + minimist: 1.2.8 + postject: 1.0.0-alpha.6 + transitivePeerDependencies: + - supports-color + optional: true + + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.25.5': + optional: true + + '@esbuild/android-arm64@0.25.5': + optional: true + + '@esbuild/android-arm@0.25.5': + optional: true + + '@esbuild/android-x64@0.25.5': + optional: true + + '@esbuild/darwin-arm64@0.25.5': + optional: true + + '@esbuild/darwin-x64@0.25.5': + optional: true + + '@esbuild/freebsd-arm64@0.25.5': + optional: true + + '@esbuild/freebsd-x64@0.25.5': + optional: true + + '@esbuild/linux-arm64@0.25.5': + optional: true + + '@esbuild/linux-arm@0.25.5': + optional: true + + '@esbuild/linux-ia32@0.25.5': + optional: true + + '@esbuild/linux-loong64@0.25.5': + optional: true + + '@esbuild/linux-mips64el@0.25.5': + optional: true + + '@esbuild/linux-ppc64@0.25.5': + optional: true + + '@esbuild/linux-riscv64@0.25.5': + optional: true + + '@esbuild/linux-s390x@0.25.5': + optional: true + + '@esbuild/linux-x64@0.25.5': + optional: true + + '@esbuild/netbsd-arm64@0.25.5': + optional: true + + '@esbuild/netbsd-x64@0.25.5': + optional: true + + '@esbuild/openbsd-arm64@0.25.5': + optional: true + + '@esbuild/openbsd-x64@0.25.5': + optional: true + + '@esbuild/sunos-x64@0.25.5': + optional: true + + '@esbuild/win32-arm64@0.25.5': + optional: true + + '@esbuild/win32-ia32@0.25.5': + optional: true + + '@esbuild/win32-x64@0.25.5': + optional: true + + '@fast-csv/format@4.3.5': + dependencies: + '@types/node': 14.18.63 + lodash.escaperegexp: 4.1.2 + lodash.isboolean: 3.0.3 + lodash.isequal: 4.5.0 + lodash.isfunction: 3.0.9 + lodash.isnil: 4.0.0 + + '@fast-csv/parse@4.3.6': + dependencies: + '@types/node': 14.18.63 + lodash.escaperegexp: 4.1.2 + lodash.groupby: 4.6.0 + lodash.isfunction: 3.0.9 + lodash.isnil: 4.0.0 + lodash.isundefined: 3.0.1 + lodash.uniq: 4.5.0 + + '@floating-ui/core@1.7.4': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.5': + dependencies: + '@floating-ui/core': 1.7.4 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/dom': 1.7.5 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@floating-ui/utils@0.2.10': {} + + '@gar/promisify@1.1.3': {} + + '@hapi/hoek@9.3.0': {} + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + + '@hono/node-server@1.19.9(hono@4.11.7)': + dependencies: + hono: 4.11.7 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@malept/cross-spawn-promise@1.1.1': + dependencies: + cross-spawn: 7.0.6 + + '@malept/cross-spawn-promise@2.0.0': + dependencies: + cross-spawn: 7.0.6 + + '@malept/flatpak-bundler@0.4.0': + dependencies: + debug: 4.4.1 + fs-extra: 9.1.0 + lodash: 4.17.21 + tmp-promise: 3.0.3 + transitivePeerDependencies: + - supports-color + + '@modelcontextprotocol/sdk@1.25.3(hono@4.11.7)(zod@4.0.14)': + dependencies: + '@hono/node-server': 1.19.9(hono@4.11.7) + ajv: 8.17.1 + ajv-formats: 3.0.1(ajv@8.17.1) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.6 + express: 5.2.1 + express-rate-limit: 7.5.1(express@5.2.1) + jose: 6.1.3 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.0.14 + zod-to-json-schema: 3.25.1(zod@4.0.14) + transitivePeerDependencies: + - hono + - supports-color + + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@npmcli/fs@2.1.2': + dependencies: + '@gar/promisify': 1.1.3 + semver: 7.7.2 + + '@npmcli/move-file@2.0.1': + dependencies: + mkdirp: 1.0.4 + rimraf: 3.0.2 + + '@oxc-parser/binding-android-arm-eabi@0.127.0': + optional: true + + '@oxc-parser/binding-android-arm64@0.127.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.127.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.127.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-arm64-musl@0.127.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.127.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.127.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.127.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.127.0': + optional: true + + '@oxc-parser/binding-wasm32-wasi@0.127.0': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.127.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.127.0': + optional: true + + '@oxc-parser/binding-win32-x64-msvc@0.127.0': + optional: true + + '@oxc-project/types@0.127.0': {} + + '@oxc-resolver/binding-android-arm-eabi@11.19.1': + optional: true + + '@oxc-resolver/binding-android-arm64@11.19.1': + optional: true + + '@oxc-resolver/binding-darwin-arm64@11.19.1': + optional: true + + '@oxc-resolver/binding-darwin-x64@11.19.1': + optional: true + + '@oxc-resolver/binding-freebsd-x64@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm-musleabihf@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-arm64-musl@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-ppc64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-riscv64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-riscv64-musl@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-s390x-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-x64-gnu@11.19.1': + optional: true + + '@oxc-resolver/binding-linux-x64-musl@11.19.1': + optional: true + + '@oxc-resolver/binding-openharmony-arm64@11.19.1': + optional: true + + '@oxc-resolver/binding-wasm32-wasi@11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + dependencies: + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@oxc-resolver/binding-win32-arm64-msvc@11.19.1': + optional: true + + '@oxc-resolver/binding-win32-ia32-msvc@11.19.1': + optional: true + + '@oxc-resolver/binding-win32-x64-msvc@11.19.1': + optional: true + + '@pandacss/config@1.8.1': + dependencies: + '@pandacss/logger': 1.8.1 + '@pandacss/preset-base': 1.8.1 + '@pandacss/preset-panda': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + bundle-n-require: 1.1.2 + escalade: 3.2.0 + microdiff: 1.5.0 + typescript: 5.9.3 + + '@pandacss/core@1.8.1': + dependencies: + '@csstools/postcss-cascade-layers': 5.0.2(postcss@8.5.6) + '@pandacss/is-valid-prop': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + browserslist: 4.28.0 + hookable: 5.5.3 + lightningcss: 1.30.2 + lodash.merge: 4.6.2 + outdent: 0.8.0 + postcss: 8.5.6 + postcss-discard-duplicates: 7.0.2(postcss@8.5.6) + postcss-discard-empty: 7.0.1(postcss@8.5.6) + postcss-merge-rules: 7.0.7(postcss@8.5.6) + postcss-minify-selectors: 7.0.5(postcss@8.5.6) + postcss-nested: 7.0.2(postcss@8.5.6) + postcss-normalize-whitespace: 7.0.1(postcss@8.5.6) + postcss-selector-parser: 7.1.1 + ts-pattern: 5.9.0 + + '@pandacss/dev@1.8.1(hono@4.11.7)(typescript@5.9.2)': + dependencies: + '@clack/prompts': 0.11.0 + '@pandacss/config': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/mcp': 1.8.1(hono@4.11.7)(typescript@5.9.2) + '@pandacss/node': 1.8.1(typescript@5.9.2) + '@pandacss/postcss': 1.8.1(typescript@5.9.2) + '@pandacss/preset-base': 1.8.1 + '@pandacss/preset-panda': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + cac: 6.7.14 + transitivePeerDependencies: + - '@cfworker/json-schema' + - hono + - jsdom + - supports-color + - typescript + + '@pandacss/extractor@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/shared': 1.8.1 + ts-evaluator: 1.2.0(typescript@5.9.2) + ts-morph: 27.0.2 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/generator@1.8.1': + dependencies: + '@pandacss/core': 1.8.1 + '@pandacss/is-valid-prop': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + javascript-stringify: 2.1.0 + outdent: 0.8.0 + pluralize: 8.0.0 + postcss: 8.5.6 + ts-pattern: 5.9.0 + + '@pandacss/is-valid-prop@1.8.1': {} + + '@pandacss/logger@1.8.1': + dependencies: + '@pandacss/types': 1.8.1 + kleur: 4.1.5 + + '@pandacss/mcp@1.8.1(hono@4.11.7)(typescript@5.9.2)': + dependencies: + '@clack/prompts': 0.11.0 + '@modelcontextprotocol/sdk': 1.25.3(hono@4.11.7)(zod@4.0.14) + '@pandacss/logger': 1.8.1 + '@pandacss/node': 1.8.1(typescript@5.9.2) + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + zod: 4.0.14 + transitivePeerDependencies: + - '@cfworker/json-schema' + - hono + - jsdom + - supports-color + - typescript + + '@pandacss/node@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/config': 1.8.1 + '@pandacss/core': 1.8.1 + '@pandacss/generator': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/parser': 1.8.1(typescript@5.9.2) + '@pandacss/reporter': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/token-dictionary': 1.8.1 + '@pandacss/types': 1.8.1 + browserslist: 4.28.0 + chokidar: 4.0.3 + fast-glob: 3.3.3 + fs-extra: 11.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + lodash.merge: 4.6.2 + look-it-up: 2.1.0 + outdent: 0.8.0 + p-limit: 5.0.0 + package-manager-detector: 1.6.0 + perfect-debounce: 1.0.0 + picomatch: 4.0.3 + pkg-types: 2.3.0 + pluralize: 8.0.0 + postcss: 8.5.6 + prettier: 3.2.5 + ts-morph: 27.0.2 + ts-pattern: 5.9.0 + tsconfck: 3.1.6(typescript@5.9.2) + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/parser@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/config': 1.8.1 + '@pandacss/core': 1.8.1 + '@pandacss/extractor': 1.8.1(typescript@5.9.2) + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + '@vue/compiler-sfc': 3.5.25 + magic-string: 0.30.21 + ts-morph: 27.0.2 + ts-pattern: 5.9.0 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/postcss@1.8.1(typescript@5.9.2)': + dependencies: + '@pandacss/node': 1.8.1(typescript@5.9.2) + postcss: 8.5.6 + transitivePeerDependencies: + - jsdom + - typescript + + '@pandacss/preset-base@1.8.1': + dependencies: + '@pandacss/types': 1.8.1 + + '@pandacss/preset-panda@1.8.1': + dependencies: + '@pandacss/types': 1.8.1 + + '@pandacss/reporter@1.8.1': + dependencies: + '@pandacss/core': 1.8.1 + '@pandacss/generator': 1.8.1 + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + table: 6.9.0 + wordwrapjs: 5.1.1 + + '@pandacss/shared@1.8.1': {} + + '@pandacss/token-dictionary@1.8.1': + dependencies: + '@pandacss/logger': 1.8.1 + '@pandacss/shared': 1.8.1 + '@pandacss/types': 1.8.1 + picomatch: 4.0.3 + ts-pattern: 5.9.0 + + '@pandacss/types@1.8.1': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-direction@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-id@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/react-dom': 2.1.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + aria-hidden: 1.2.6 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + react-remove-scroll: 2.7.2(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.13)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.13)(react@19.2.4)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.13)(react@19.2.4) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.13 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.13))(@types/react@19.2.13)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + '@types/react-dom': 19.2.3(@types/react@19.2.13) + + '@radix-ui/rect@1.1.1': {} + + '@rolldown/pluginutils@1.0.0-beta.9': {} + + '@rollup/rollup-android-arm-eabi@4.41.1': + optional: true + + '@rollup/rollup-android-arm-eabi@4.53.3': + optional: true + + '@rollup/rollup-android-arm64@4.41.1': + optional: true + + '@rollup/rollup-android-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.41.1': + optional: true + + '@rollup/rollup-darwin-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-x64@4.41.1': + optional: true + + '@rollup/rollup-darwin-x64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.41.1': + optional: true + + '@rollup/rollup-freebsd-arm64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.41.1': + optional: true + + '@rollup/rollup-freebsd-x64@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.41.1': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.41.1': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.41.1': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.41.1': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.41.1': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.41.1': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.41.1': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.41.1': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.41.1': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.41.1': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.41.1': + optional: true + + '@rollup/rollup-linux-x64-musl@4.53.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.41.1': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.41.1': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.41.1': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.53.3': + optional: true + + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + + '@sideway/formula@3.0.1': {} + + '@sideway/pinpoint@2.0.0': {} + + '@sindresorhus/is@4.6.0': {} + + '@standard-schema/spec@1.1.0': {} + + '@stitches/react@1.2.8(react@19.2.4)': + dependencies: + react: 19.2.4 + + '@szmarczak/http-timer@4.0.6': + dependencies: + defer-to-connect: 2.0.1 + + '@tanstack/form-core@1.11.0': + dependencies: + '@tanstack/store': 0.7.0 + + '@tanstack/history@1.139.0': {} + + '@tanstack/query-core@5.100.5': {} + + '@tanstack/react-form@1.11.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/form-core': 1.11.0 + '@tanstack/react-store': 0.7.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + decode-formdata: 0.9.0 + devalue: 5.1.1 + react: 19.2.4 + transitivePeerDependencies: + - react-dom + + '@tanstack/react-query@5.100.5(react@19.2.4)': + dependencies: + '@tanstack/query-core': 5.100.5 + react: 19.2.4 + + '@tanstack/react-router-devtools@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3)': + dependencies: + '@tanstack/react-router': 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-devtools-core': 1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + vite: 7.2.4(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + optionalDependencies: + '@tanstack/router-core': 1.139.12 + transitivePeerDependencies: + - '@types/node' + - csstype + - jiti + - less + - lightningcss + - sass + - sass-embedded + - solid-js + - stylus + - sugarss + - terser + - tsx + - yaml + + '@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/history': 1.139.0 + '@tanstack/react-store': 0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@tanstack/router-core': 1.139.12 + isbot: 5.1.32 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/react-store@0.7.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/store': 0.7.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.5.0(react@19.2.4) + + '@tanstack/react-store@0.8.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@tanstack/store': 0.8.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + + '@tanstack/router-core@1.139.12': + dependencies: + '@tanstack/history': 1.139.0 + '@tanstack/store': 0.8.0 + cookie-es: 2.0.0 + seroval: 1.4.0 + seroval-plugins: 1.4.0(seroval@1.4.0) + tiny-invariant: 1.3.3 + tiny-warning: 1.0.3 + + '@tanstack/router-devtools-core@1.139.12(@tanstack/router-core@1.139.12)(@types/node@20.19.1)(csstype@3.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(solid-js@1.9.10)(tsx@4.20.6)(yaml@2.8.3)': + dependencies: + '@tanstack/router-core': 1.139.12 + clsx: 2.1.1 + goober: 2.1.18(csstype@3.2.3) + solid-js: 1.9.10 + tiny-invariant: 1.3.3 + vite: 7.2.4(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + optionalDependencies: + csstype: 3.2.3 + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + + '@tanstack/router-generator@1.139.12': + dependencies: + '@tanstack/router-core': 1.139.12 + '@tanstack/router-utils': 1.139.0 + '@tanstack/virtual-file-routes': 1.139.0 + prettier: 3.7.3 + recast: 0.23.11 + source-map: 0.7.6 + tsx: 4.20.6 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@tanstack/router-plugin@1.139.12(@tanstack/react-router@1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@tanstack/router-core': 1.139.12 + '@tanstack/router-generator': 1.139.12 + '@tanstack/router-utils': 1.139.0 + '@tanstack/virtual-file-routes': 1.139.0 + babel-dead-code-elimination: 1.0.10 + chokidar: 3.6.0 + unplugin: 2.3.11 + zod: 3.25.76 + optionalDependencies: + '@tanstack/react-router': 1.139.12(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + + '@tanstack/router-utils@1.139.0': + dependencies: + '@babel/core': 7.28.5 + '@babel/generator': 7.28.5 + '@babel/parser': 7.28.5 + '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) + ansis: 4.2.0 + diff: 8.0.2 + pathe: 2.0.3 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - supports-color + + '@tanstack/store@0.7.0': {} + + '@tanstack/store@0.8.0': {} + + '@tanstack/virtual-file-routes@1.139.0': {} + + '@tootallnate/once@2.0.0': {} + + '@ts-morph/common@0.28.1': + dependencies: + minimatch: 10.0.1 + path-browserify: 1.0.1 + tinyglobby: 0.2.15 + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.27.4 + '@babel/types': 7.27.3 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.7 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.27.3 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.27.4 + '@babel/types': 7.27.3 + + '@types/babel__traverse@7.20.7': + dependencies: + '@babel/types': 7.27.3 + + '@types/cacheable-request@6.0.3': + dependencies: + '@types/http-cache-semantics': 4.0.4 + '@types/keyv': 3.1.4 + '@types/node': 16.18.126 + '@types/responselike': 1.0.3 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + + '@types/estree@1.0.7': {} + + '@types/estree@1.0.8': {} + + '@types/fs-extra@9.0.13': + dependencies: + '@types/node': 16.18.126 + + '@types/http-cache-semantics@4.0.4': {} + + '@types/keyv@3.1.4': + dependencies: + '@types/node': 16.18.126 + + '@types/ms@2.1.0': {} + + '@types/node@14.18.63': {} + + '@types/node@16.18.126': {} + + '@types/node@17.0.45': {} + + '@types/node@20.19.1': + dependencies: + undici-types: 6.21.0 + + '@types/plist@3.0.5': + dependencies: + '@types/node': 16.18.126 + xmlbuilder: 15.1.1 + optional: true + + '@types/react-dom@19.2.3(@types/react@19.2.13)': + dependencies: + '@types/react': 19.2.13 + + '@types/react@19.2.13': + dependencies: + csstype: 3.2.3 + + '@types/regex-escape@3.4.1': {} + + '@types/responselike@1.0.3': + dependencies: + '@types/node': 16.18.126 + + '@types/verror@1.10.11': + optional: true + + '@types/yauzl@2.10.3': + dependencies: + '@types/node': 16.18.126 + optional: true + + '@vitejs/plugin-react@4.5.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3))': + dependencies: + '@babel/core': 7.27.4 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.27.4) + '@rolldown/pluginutils': 1.0.0-beta.9 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@4.1.6': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 + chai: 6.2.2 + tinyrainbow: 3.1.0 + + '@vitest/mocker@4.1.6(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3))': + dependencies: + '@vitest/spy': 4.1.6 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + + '@vitest/pretty-format@4.1.6': + dependencies: + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.6': + dependencies: + '@vitest/utils': 4.1.6 + pathe: 2.0.3 + + '@vitest/snapshot@4.1.6': + dependencies: + '@vitest/pretty-format': 4.1.6 + '@vitest/utils': 4.1.6 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@4.1.6': {} + + '@vitest/utils@4.1.6': + dependencies: + '@vitest/pretty-format': 4.1.6 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + '@vue/compiler-core@3.5.25': + dependencies: + '@babel/parser': 7.28.5 + '@vue/shared': 3.5.25 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.25': + dependencies: + '@vue/compiler-core': 3.5.25 + '@vue/shared': 3.5.25 + + '@vue/compiler-sfc@3.5.25': + dependencies: + '@babel/parser': 7.28.5 + '@vue/compiler-core': 3.5.25 + '@vue/compiler-dom': 3.5.25 + '@vue/compiler-ssr': 3.5.25 + '@vue/shared': 3.5.25 + estree-walker: 2.0.2 + magic-string: 0.30.21 + postcss: 8.5.6 + source-map-js: 1.2.1 + + '@vue/compiler-ssr@3.5.25': + dependencies: + '@vue/compiler-dom': 3.5.25 + '@vue/shared': 3.5.25 + + '@vue/shared@3.5.25': {} + + '@xmldom/xmldom@0.8.10': {} + + abbrev@1.1.1: {} + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn@8.15.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + agent-base@7.1.3: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + aggregate-error@3.1.0: + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + + ajv-formats@3.0.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-keywords@3.5.2(ajv@6.12.6): + dependencies: + ajv: 6.12.6 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-colors@4.1.3: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-escapes@5.0.0: + dependencies: + type-fest: 1.4.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + ansis@4.2.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + app-builder-bin@5.0.0-alpha.12: {} + + app-builder-lib@26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12): + dependencies: + '@develar/schema-utils': 2.6.5 + '@electron/asar': 3.2.18 + '@electron/fuses': 1.8.0 + '@electron/notarize': 2.5.0 + '@electron/osx-sign': 1.3.1 + '@electron/rebuild': 3.7.0 + '@electron/universal': 2.0.1 + '@malept/flatpak-bundler': 0.4.0 + '@types/fs-extra': 9.0.13 + async-exit-hook: 2.0.1 + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chromium-pickle-js: 0.2.0 + config-file-ts: 0.2.8-rc1 + debug: 4.4.1 + dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12) + dotenv: 16.5.0 + dotenv-expand: 11.0.7 + ejs: 3.1.10 + electron-builder-squirrel-windows: 26.0.12(dmg-builder@26.0.12) + electron-publish: 26.0.11 + fs-extra: 10.1.0 + hosted-git-info: 4.1.0 + is-ci: 3.0.1 + isbinaryfile: 5.0.4 + js-yaml: 4.1.0 + json5: 2.2.3 + lazy-val: 1.0.5 + minimatch: 10.0.1 + plist: 3.1.0 + resedit: 1.7.2 + semver: 7.7.2 + tar: 6.2.1 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + transitivePeerDependencies: + - bluebird + - supports-color + + archiver-utils@2.1.0: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.8 + + archiver-utils@3.0.4: + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + archiver@5.3.2: + dependencies: + archiver-utils: 2.1.0 + async: 3.2.6 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 2.2.0 + zip-stream: 4.1.1 + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + assert-plus@1.0.0: + optional: true + + assertion-error@2.0.1: {} + + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 + + astral-regex@2.0.0: {} + + async-exit-hook@2.0.1: {} + + async@3.2.6: {} + + asynckit@0.4.0: {} + + at-least-node@1.0.0: {} + + author-regex@1.0.0: {} + + axios@0.25.0: + dependencies: + follow-redirects: 1.15.9 + transitivePeerDependencies: + - debug + + axios@1.13.4: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + babel-dead-code-elimination@1.0.10: + dependencies: + '@babel/core': 7.28.5 + '@babel/parser': 7.27.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.9.19: {} + + big-integer@1.6.52: {} + + binary-extensions@2.3.0: {} + + binary@0.3.0: + dependencies: + buffers: 0.1.1 + chainsaw: 0.1.0 + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + bluebird@3.4.7: {} + + bluebird@3.7.2: {} + + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.14.1 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + boolean@3.2.0: + optional: true + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@2.1.0: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.25.0: + dependencies: + caniuse-lite: 1.0.30001720 + electron-to-chromium: 1.5.161 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.0) + + browserslist@4.28.0: + dependencies: + baseline-browser-mapping: 2.9.19 + caniuse-lite: 1.0.30001766 + electron-to-chromium: 1.5.283 + node-releases: 2.0.27 + update-browserslist-db: 1.2.3(browserslist@4.28.0) + + buffer-crc32@0.2.13: {} + + buffer-equal@1.0.1: {} + + buffer-from@1.1.2: {} + + buffer-indexof-polyfill@1.0.2: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffers@0.1.1: {} + + builder-util-runtime@9.3.1: + dependencies: + debug: 4.4.1 + sax: 1.4.1 + transitivePeerDependencies: + - supports-color + + builder-util@26.0.11: + dependencies: + 7zip-bin: 5.2.0 + '@types/debug': 4.1.12 + app-builder-bin: 5.0.0-alpha.12 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + fs-extra: 10.1.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + is-ci: 3.0.1 + js-yaml: 4.1.0 + sanitize-filename: 1.6.3 + source-map-support: 0.5.21 + stat-mode: 1.0.0 + temp-file: 3.4.0 + tiny-async-pool: 1.3.0 + transitivePeerDependencies: + - supports-color + + bundle-n-require@1.1.2: + dependencies: + esbuild: 0.25.5 + node-eval: 2.0.0 + + bytes@3.1.2: {} + + cac@6.7.14: {} + + cacache@16.1.3: + dependencies: + '@npmcli/fs': 2.1.2 + '@npmcli/move-file': 2.0.1 + chownr: 2.0.0 + fs-minipass: 2.1.0 + glob: 8.1.0 + infer-owner: 1.0.4 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-flush: 1.0.7 + minipass-pipeline: 1.2.4 + mkdirp: 1.0.4 + p-map: 4.0.0 + promise-inflight: 1.0.1 + rimraf: 3.0.2 + ssri: 9.0.1 + tar: 6.2.1 + unique-filename: 2.0.1 + transitivePeerDependencies: + - bluebird + + cacheable-lookup@5.0.4: {} + + cacheable-request@7.0.4: + dependencies: + clone-response: 1.0.3 + get-stream: 5.2.0 + http-cache-semantics: 4.2.0 + keyv: 4.5.4 + lowercase-keys: 2.0.0 + normalize-url: 6.1.0 + responselike: 2.0.1 + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + caniuse-api@3.0.0: + dependencies: + browserslist: 4.28.0 + caniuse-lite: 1.0.30001720 + lodash.memoize: 4.1.2 + lodash.uniq: 4.5.0 + + caniuse-lite@1.0.30001720: {} + + caniuse-lite@1.0.30001766: {} + + chai@6.2.2: {} + + chainsaw@0.1.0: + dependencies: + traverse: 0.3.9 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.3.0: {} + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chownr@2.0.0: {} + + chromium-pickle-js@0.2.0: {} + + ci-info@3.9.0: {} + + clean-stack@2.2.0: {} + + cli-cursor@3.1.0: + dependencies: + restore-cursor: 3.1.0 + + cli-cursor@4.0.0: + dependencies: + restore-cursor: 4.0.0 + + cli-spinners@2.9.2: {} + + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + + cli-truncate@3.1.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + optional: true + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-response@1.0.3: + dependencies: + mimic-response: 1.0.1 + + clone@1.0.4: {} + + clsx@2.1.1: {} + + code-block-writer@13.0.3: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@11.0.0: {} + + commander@4.1.1: {} + + commander@5.1.0: {} + + commander@9.4.1: {} + + commander@9.5.0: + optional: true + + compare-version@0.1.2: {} + + compress-commons@4.1.2: + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.3 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + + concat-map@0.0.1: {} + + concurrently@7.6.0: + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 7.8.2 + shell-quote: 1.8.2 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + confbox@0.2.2: {} + + config-file-ts@0.2.8-rc1: + dependencies: + glob: 10.4.5 + typescript: 5.9.2 + + content-disposition@1.0.1: {} + + content-type@1.0.5: {} + + convert-source-map@2.0.0: {} + + cookie-es@2.0.0: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + core-util-is@1.0.2: + optional: true + + core-util-is@1.0.3: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + crc-32@1.2.2: {} + + crc32-stream@4.0.3: + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + + crc@3.8.0: + dependencies: + buffer: 5.7.1 + optional: true + + cross-dirname@0.1.0: + optional: true + + cross-env@7.0.3: + dependencies: + cross-spawn: 7.0.6 + + cross-spawn-windows-exe@1.2.0: + dependencies: + '@malept/cross-spawn-promise': 1.1.1 + is-wsl: 2.2.0 + which: 2.0.2 + + cross-spawn@6.0.6: + dependencies: + nice-try: 1.0.5 + path-key: 2.0.1 + semver: 5.7.2 + shebang-command: 1.2.0 + which: 1.3.1 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + cross-zip@4.0.1: {} + + crosspath@2.0.0: + dependencies: + '@types/node': 17.0.45 + + cssesc@3.0.0: {} + + cssnano-utils@5.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + csstype@3.2.3: {} + + date-fns@2.30.0: + dependencies: + '@babel/runtime': 7.27.1 + + dayjs@1.11.13: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@3.2.7(supports-color@5.5.0): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 5.5.0 + + debug@4.3.4: + dependencies: + ms: 2.1.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decode-formdata@0.9.0: {} + + decompress-response@6.0.0: + dependencies: + mimic-response: 3.1.0 + + deep-extend@0.6.0: {} + + defaults@1.0.4: + dependencies: + clone: 1.0.4 + + defer-to-connect@2.0.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + optional: true + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + optional: true + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + detect-libc@2.0.4: {} + + detect-node-es@1.1.0: {} + + detect-node@2.1.0: + optional: true + + devalue@5.1.1: {} + + diff@8.0.2: {} + + dir-compare@3.3.0: + dependencies: + buffer-equal: 1.0.1 + minimatch: 3.1.2 + + dir-compare@4.2.0: + dependencies: + minimatch: 3.1.2 + p-limit: 3.1.0 + + dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12): + dependencies: + app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + fs-extra: 10.1.0 + iconv-lite: 0.6.3 + js-yaml: 4.1.0 + optionalDependencies: + dmg-license: 1.0.11 + transitivePeerDependencies: + - bluebird + - electron-builder-squirrel-windows + - supports-color + + dmg-license@1.0.11: + dependencies: + '@types/plist': 3.0.5 + '@types/verror': 1.10.11 + ajv: 6.12.6 + crc: 3.8.0 + iconv-corefoundation: 1.1.7 + plist: 3.1.0 + smart-buffer: 4.2.0 + verror: 1.10.1 + optional: true + + dotenv-expand@11.0.7: + dependencies: + dotenv: 16.5.0 + + dotenv@16.5.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer2@0.1.4: + dependencies: + readable-stream: 2.3.8 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.2 + + electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12): + dependencies: + app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) + builder-util: 26.0.11 + electron-winstaller: 5.4.0 + transitivePeerDependencies: + - bluebird + - dmg-builder + - supports-color + + electron-builder@26.0.12(electron-builder-squirrel-windows@26.0.12): + dependencies: + app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12) + fs-extra: 10.1.0 + is-ci: 3.0.1 + lazy-val: 1.0.5 + simple-update-notifier: 2.0.0 + yargs: 17.7.2 + transitivePeerDependencies: + - bluebird + - electron-builder-squirrel-windows + - supports-color + + electron-debug@3.2.0: + dependencies: + electron-is-dev: 1.2.0 + electron-localshortcut: 3.2.1 + transitivePeerDependencies: + - supports-color + + electron-devtools-installer@3.2.1: + dependencies: + rimraf: 3.0.2 + semver: 7.7.2 + tslib: 2.8.1 + unzip-crx-3: 0.2.0 + + electron-installer-common@0.10.4: + dependencies: + '@electron/asar': 3.4.1 + '@malept/cross-spawn-promise': 1.1.1 + debug: 4.4.1 + fs-extra: 9.1.0 + glob: 7.2.3 + lodash: 4.17.21 + parse-author: 2.0.0 + semver: 7.7.2 + tmp-promise: 3.0.3 + optionalDependencies: + '@types/fs-extra': 9.0.13 + transitivePeerDependencies: + - supports-color + optional: true + + electron-installer-debian@3.2.0: + dependencies: + '@malept/cross-spawn-promise': 1.1.1 + debug: 4.4.1 + electron-installer-common: 0.10.4 + fs-extra: 9.1.0 + get-folder-size: 2.0.1 + lodash: 4.17.21 + word-wrap: 1.2.5 + yargs: 16.2.0 + transitivePeerDependencies: + - supports-color + optional: true + + electron-installer-redhat@3.4.0: + dependencies: + '@malept/cross-spawn-promise': 1.1.1 + debug: 4.4.1 + electron-installer-common: 0.10.4 + fs-extra: 9.1.0 + lodash: 4.17.21 + word-wrap: 1.2.5 + yargs: 16.2.0 + transitivePeerDependencies: + - supports-color + optional: true + + electron-is-accelerator@0.1.2: {} + + electron-is-dev@1.2.0: {} + + electron-localshortcut@3.2.1: + dependencies: + debug: 4.4.1 + electron-is-accelerator: 0.1.2 + keyboardevent-from-electron-accelerator: 2.0.0 + keyboardevents-areequal: 0.2.2 + transitivePeerDependencies: + - supports-color + + electron-packager@17.1.2: + dependencies: + '@electron/asar': 3.4.1 + '@electron/get': 2.0.3 + '@electron/notarize': 1.2.4 + '@electron/osx-sign': 1.3.3 + '@electron/universal': 1.5.1 + cross-spawn-windows-exe: 1.2.0 + debug: 4.4.1 + extract-zip: 2.0.1 + filenamify: 4.3.0 + fs-extra: 11.3.0 + galactus: 1.0.0 + get-package-info: 1.0.0 + junk: 3.1.0 + parse-author: 2.0.0 + plist: 3.1.0 + rcedit: 3.1.0 + resolve: 1.22.10 + semver: 7.7.2 + yargs-parser: 21.1.1 + transitivePeerDependencies: + - supports-color + + electron-publish@26.0.11: + dependencies: + '@types/fs-extra': 9.0.13 + builder-util: 26.0.11 + builder-util-runtime: 9.3.1 + chalk: 4.1.2 + form-data: 4.0.2 + fs-extra: 10.1.0 + lazy-val: 1.0.5 + mime: 2.6.0 + transitivePeerDependencies: + - supports-color + + electron-squirrel-startup@1.0.1: + dependencies: + debug: 2.6.9 + transitivePeerDependencies: + - supports-color + + electron-to-chromium@1.5.161: {} + + electron-to-chromium@1.5.283: {} + + electron-vite@3.1.0(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)): + dependencies: + '@babel/core': 7.27.4 + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.27.4) + cac: 6.7.14 + esbuild: 0.25.5 + magic-string: 0.30.17 + picocolors: 1.1.1 + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + + electron-winstaller@5.4.0: + dependencies: + '@electron/asar': 3.4.1 + debug: 4.4.1 + fs-extra: 7.0.1 + lodash: 4.17.21 + temp: 0.9.4 + optionalDependencies: + '@electron/windows-sign': 1.2.2 + transitivePeerDependencies: + - supports-color + + electron@22.3.27: + dependencies: + '@electron/get': 2.0.3 + '@types/node': 16.18.126 + extract-zip: 2.0.1 + transitivePeerDependencies: + - supports-color + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + encoding@0.1.13: + dependencies: + iconv-lite: 0.6.3 + optional: true + + end-of-stream@1.4.4: + dependencies: + once: 1.4.0 + + entities@3.0.1: {} + + entities@4.5.0: {} + + env-paths@2.2.1: {} + + err-code@2.0.3: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@2.1.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es6-error@4.1.1: + optional: true + + esbuild@0.25.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.5 + '@esbuild/android-arm': 0.25.5 + '@esbuild/android-arm64': 0.25.5 + '@esbuild/android-x64': 0.25.5 + '@esbuild/darwin-arm64': 0.25.5 + '@esbuild/darwin-x64': 0.25.5 + '@esbuild/freebsd-arm64': 0.25.5 + '@esbuild/freebsd-x64': 0.25.5 + '@esbuild/linux-arm': 0.25.5 + '@esbuild/linux-arm64': 0.25.5 + '@esbuild/linux-ia32': 0.25.5 + '@esbuild/linux-loong64': 0.25.5 + '@esbuild/linux-mips64el': 0.25.5 + '@esbuild/linux-ppc64': 0.25.5 + '@esbuild/linux-riscv64': 0.25.5 + '@esbuild/linux-s390x': 0.25.5 + '@esbuild/linux-x64': 0.25.5 + '@esbuild/netbsd-arm64': 0.25.5 + '@esbuild/netbsd-x64': 0.25.5 + '@esbuild/openbsd-arm64': 0.25.5 + '@esbuild/openbsd-x64': 0.25.5 + '@esbuild/sunos-x64': 0.25.5 + '@esbuild/win32-arm64': 0.25.5 + '@esbuild/win32-ia32': 0.25.5 + '@esbuild/win32-x64': 0.25.5 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: + optional: true + + esprima@4.0.1: {} + + estree-walker@2.0.2: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + etag@1.8.1: {} + + eventemitter3@5.0.1: {} + + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + + exceljs@4.4.0: + dependencies: + archiver: 5.3.2 + dayjs: 1.11.13 + fast-csv: 4.3.6 + jszip: 3.10.1 + readable-stream: 3.6.2 + saxes: 5.0.1 + tmp: 0.2.3 + unzipper: 0.10.14 + uuid: 8.3.2 + + execa@1.0.0: + dependencies: + cross-spawn: 6.0.6 + get-stream: 4.1.0 + is-stream: 1.1.0 + npm-run-path: 2.0.2 + p-finally: 1.0.0 + signal-exit: 3.0.7 + strip-eof: 1.0.0 + + execa@7.2.0: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 4.3.1 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 3.0.7 + strip-final-newline: 3.0.0 + + expand-tilde@2.0.2: + dependencies: + homedir-polyfill: 1.0.3 + + expect-type@1.3.0: {} + + exponential-backoff@3.1.3: {} + + express-rate-limit@7.5.1(express@5.2.1): + dependencies: + express: 5.2.1 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.1 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.1 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + exsolve@1.0.8: {} + + extract-zip@2.0.1: + dependencies: + debug: 4.4.1 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + + extsprintf@1.4.1: + optional: true + + fast-csv@4.3.6: + dependencies: + '@fast-csv/format': 4.3.5 + '@fast-csv/parse': 4.3.6 + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-uri@3.1.0: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fd-package-json@2.0.0: + dependencies: + walk-up-path: 4.0.0 + + fd-slicer@1.1.0: + dependencies: + pend: 1.2.0 + + fdir@6.4.5(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + filename-reserved-regex@2.0.0: {} + + filenamify@4.3.0: + dependencies: + filename-reserved-regex: 2.0.0 + strip-outer: 1.0.1 + trim-repeated: 1.0.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@2.1.0: + dependencies: + locate-path: 2.0.0 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flora-colossus@2.0.0: + dependencies: + debug: 4.4.1 + fs-extra: 10.1.0 + transitivePeerDependencies: + - supports-color + + follow-redirects@1.15.9: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.2: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + mime-types: 2.1.35 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + formatly@0.3.0: + dependencies: + fd-package-json: 2.0.0 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fs-constants@1.0.0: {} + + fs-extra@10.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@11.3.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-extra@7.0.1: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@8.1.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + fs-minipass@2.1.0: + dependencies: + minipass: 3.3.6 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + fstream@1.0.12: + dependencies: + graceful-fs: 4.2.11 + inherits: 2.0.4 + mkdirp: 0.5.6 + rimraf: 2.7.1 + + function-bind@1.1.2: {} + + galactus@1.0.0: + dependencies: + debug: 4.4.1 + flora-colossus: 2.0.0 + fs-extra: 10.1.0 + transitivePeerDependencies: + - supports-color + + gar@1.0.4: + optional: true + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-folder-size@2.0.1: + dependencies: + gar: 1.0.4 + tiny-each-async: 2.0.3 + optional: true + + get-installed-path@2.1.1: + dependencies: + global-modules: 1.0.0 + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-package-info@1.0.0: + dependencies: + bluebird: 3.7.2 + debug: 2.6.9 + lodash.get: 4.4.2 + read-pkg-up: 2.0.0 + transitivePeerDependencies: + - supports-color + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stdin@9.0.0: {} + + get-stream@4.1.0: + dependencies: + pump: 3.0.2 + + get-stream@5.2.0: + dependencies: + pump: 3.0.2 + + get-stream@6.0.1: {} + + get-tsconfig@4.13.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + get-tsconfig@4.14.0: + dependencies: + resolve-pkg-maps: 1.0.0 + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.0.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.9 + once: 1.4.0 + + global-agent@3.0.0: + dependencies: + boolean: 3.2.0 + es6-error: 4.1.1 + matcher: 3.0.0 + roarr: 2.15.4 + semver: 7.7.2 + serialize-error: 7.0.1 + optional: true + + global-modules@1.0.0: + dependencies: + global-prefix: 1.0.2 + is-windows: 1.0.2 + resolve-dir: 1.0.1 + + global-prefix@1.0.2: + dependencies: + expand-tilde: 2.0.2 + homedir-polyfill: 1.0.3 + ini: 1.3.8 + is-windows: 1.0.2 + which: 1.3.1 + + globals@11.12.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + optional: true + + goober@2.1.18(csstype@3.2.3): + dependencies: + csstype: 3.2.3 + + gopd@1.2.0: {} + + got@11.8.6: + dependencies: + '@sindresorhus/is': 4.6.0 + '@szmarczak/http-timer': 4.0.6 + '@types/cacheable-request': 6.0.3 + '@types/responselike': 1.0.3 + cacheable-lookup: 5.0.4 + cacheable-request: 7.0.4 + decompress-response: 6.0.0 + http2-wrapper: 1.0.3 + lowercase-keys: 2.0.0 + p-cancelable: 2.1.1 + responselike: 2.0.1 + + graceful-fs@4.2.11: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + optional: true + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + homedir-polyfill@1.0.3: + dependencies: + parse-passwd: 1.0.0 + + hono@4.11.7: {} + + hookable@5.5.3: {} + + hosted-git-info@2.8.9: {} + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + html-parse-stringify@3.0.1: + dependencies: + void-elements: 3.1.0 + + http-cache-semantics@4.2.0: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + http-proxy-agent@5.0.0: + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.3 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + http2-wrapper@1.0.3: + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.3 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + human-signals@4.3.1: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + husky@8.0.3: {} + + i18next@25.8.13(typescript@5.9.2): + dependencies: + '@babel/runtime': 7.28.6 + optionalDependencies: + typescript: 5.9.2 + + iconv-corefoundation@1.1.7: + dependencies: + cli-truncate: 2.1.0 + node-addon-api: 1.7.2 + optional: true + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + ieee754@1.2.1: {} + + ignore-by-default@1.0.1: {} + + ignore@5.2.4: {} + + immediate@3.0.6: {} + + imurmurhash@0.1.4: {} + + indent-string@4.0.0: {} + + infer-owner@1.0.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ini@1.3.8: {} + + ini@3.0.1: {} + + interpret@3.1.1: {} + + ip-address@10.1.0: {} + + ipaddr.js@1.9.1: {} + + is-arrayish@0.2.1: {} + + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-ci@3.0.1: + dependencies: + ci-info: 3.9.0 + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-docker@2.2.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-interactive@1.0.0: {} + + is-lambda@1.0.1: {} + + is-number@7.0.0: {} + + is-promise@4.0.0: {} + + is-stream@1.1.0: {} + + is-stream@3.0.0: {} + + is-unicode-supported@0.1.0: {} + + is-windows@1.0.2: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + isarray@1.0.0: {} + + isbinaryfile@4.0.10: {} + + isbinaryfile@5.0.4: {} + + isbot@5.1.32: {} + + isexe@2.0.0: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + + javascript-stringify@2.1.0: {} + + jiti@2.6.1: {} + + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + + jose@6.1.3: {} + + js-tokens@4.0.0: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + json-stringify-safe@5.0.1: + optional: true + + json5@2.2.3: {} + + jsonc-parser@3.1.0: {} + + jsonfile@4.0.0: + optionalDependencies: + graceful-fs: 4.2.11 + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jszip@3.10.1: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + junk@3.1.0: {} + + keyboardevent-from-electron-accelerator@2.0.0: {} + + keyboardevents-areequal@0.2.2: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@4.1.5: {} + + knip@6.7.0(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + formatly: 0.3.0 + get-tsconfig: 4.14.0 + jiti: 2.6.1 + minimist: 1.2.8 + oxc-parser: 0.127.0 + oxc-resolver: 11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + picomatch: 4.0.4 + smol-toml: 1.6.1 + strip-json-comments: 5.0.3 + tinyglobby: 0.2.16 + unbash: 3.0.0 + yaml: 2.8.3 + zod: 4.3.6 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + lazy-val@1.0.5: {} + + lazystream@1.0.1: + dependencies: + readable-stream: 2.3.8 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + lilconfig@2.1.0: {} + + linkify-it@4.0.1: + dependencies: + uc.micro: 1.0.6 + + lint-staged@13.3.0: + dependencies: + chalk: 5.3.0 + commander: 11.0.0 + debug: 4.3.4 + execa: 7.2.0 + lilconfig: 2.1.0 + listr2: 6.6.1 + micromatch: 4.0.5 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.3.1 + transitivePeerDependencies: + - enquirer + - supports-color + + listenercount@1.0.1: {} + + listr2@5.0.8: + dependencies: + cli-truncate: 2.1.0 + colorette: 2.0.20 + log-update: 4.0.0 + p-map: 4.0.0 + rfdc: 1.4.1 + rxjs: 7.8.2 + through: 2.3.8 + wrap-ansi: 7.0.0 + + listr2@6.6.1: + dependencies: + cli-truncate: 3.1.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 5.0.1 + rfdc: 1.4.1 + wrap-ansi: 8.1.0 + + load-json-file@2.0.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 2.2.0 + pify: 2.3.0 + strip-bom: 3.0.0 + + locate-path@2.0.0: + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.defaults@4.2.0: {} + + lodash.difference@4.5.0: {} + + lodash.escaperegexp@4.1.2: {} + + lodash.flatten@4.4.0: {} + + lodash.get@4.4.2: {} + + lodash.groupby@4.6.0: {} + + lodash.isboolean@3.0.3: {} + + lodash.isequal@4.5.0: {} + + lodash.isfunction@3.0.9: {} + + lodash.isnil@4.0.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.isundefined@3.0.1: {} + + lodash.memoize@4.1.2: {} + + lodash.merge@4.6.2: {} + + lodash.truncate@4.4.2: {} + + lodash.union@4.6.0: {} + + lodash.uniq@4.5.0: {} + + lodash@4.17.21: {} + + log-symbols@4.1.0: + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + + log-update@4.0.0: + dependencies: + ansi-escapes: 4.3.2 + cli-cursor: 3.1.0 + slice-ansi: 4.0.0 + wrap-ansi: 6.2.0 + + log-update@5.0.1: + dependencies: + ansi-escapes: 5.0.0 + cli-cursor: 4.0.0 + slice-ansi: 5.0.0 + strip-ansi: 7.1.0 + wrap-ansi: 8.1.0 + + look-it-up@2.1.0: {} + + lowercase-keys@2.0.0: {} + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + lru-cache@7.18.3: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-fetch-happen@10.2.1: + dependencies: + agentkeepalive: 4.6.0 + cacache: 16.1.3 + http-cache-semantics: 4.2.0 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + is-lambda: 1.0.1 + lru-cache: 7.18.3 + minipass: 3.3.6 + minipass-collect: 1.0.2 + minipass-fetch: 2.1.2 + minipass-flush: 1.0.7 + minipass-pipeline: 1.2.4 + negotiator: 0.6.4 + promise-retry: 2.0.1 + socks-proxy-agent: 7.0.0 + ssri: 9.0.1 + transitivePeerDependencies: + - bluebird + - supports-color + + map-age-cleaner@0.1.3: + dependencies: + p-defer: 1.0.0 + + markdown-it@13.0.1: + dependencies: + argparse: 2.0.1 + entities: 3.0.1 + linkify-it: 4.0.1 + mdurl: 1.0.1 + uc.micro: 1.0.6 + + markdownlint-cli@0.32.2: + dependencies: + commander: 9.4.1 + get-stdin: 9.0.0 + glob: 8.0.3 + ignore: 5.2.4 + js-yaml: 4.1.0 + jsonc-parser: 3.1.0 + markdownlint: 0.26.2 + markdownlint-rule-helpers: 0.17.2 + minimatch: 5.1.6 + run-con: 1.2.12 + + markdownlint-rule-helpers@0.17.2: {} + + markdownlint@0.26.2: + dependencies: + markdown-it: 13.0.1 + + matcher@3.0.0: + dependencies: + escape-string-regexp: 4.0.0 + optional: true + + math-intrinsics@1.1.0: {} + + mdurl@1.0.1: {} + + media-typer@1.1.0: {} + + mem@4.3.0: + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 2.1.0 + p-is-promise: 2.1.0 + + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + microdiff@1.5.0: {} + + micromatch@4.0.5: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mime@2.6.0: {} + + mimic-fn@2.1.0: {} + + mimic-fn@4.0.0: {} + + mimic-response@1.0.1: {} + + mimic-response@3.1.0: {} + + minimatch@10.0.1: + dependencies: + brace-expansion: 2.0.1 + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.1.0 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass-collect@1.0.2: + dependencies: + minipass: 3.3.6 + + minipass-fetch@2.1.2: + dependencies: + minipass: 3.3.6 + minipass-sized: 1.0.3 + minizlib: 2.1.2 + optionalDependencies: + encoding: 0.1.13 + + minipass-flush@1.0.7: + dependencies: + minipass: 3.3.6 + + minipass-pipeline@1.2.4: + dependencies: + minipass: 3.3.6 + + minipass-sized@1.0.3: + dependencies: + minipass: 3.3.6 + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@5.0.0: {} + + minipass@7.1.2: {} + + minizlib@2.1.2: + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@1.0.4: {} + + ms@2.0.0: {} + + ms@2.1.2: {} + + ms@2.1.3: {} + + nanoid@3.3.11: {} + + negotiator@0.6.4: {} + + negotiator@1.0.0: {} + + nice-try@1.0.5: {} + + node-abi@3.75.0: + dependencies: + semver: 7.7.2 + + node-addon-api@1.7.2: + optional: true + + node-api-version@0.2.1: + dependencies: + semver: 7.7.2 + + node-eval@2.0.0: + dependencies: + path-is-absolute: 1.0.1 + + node-fetch@2.7.0(encoding@0.1.13): + dependencies: + whatwg-url: 5.0.0 + optionalDependencies: + encoding: 0.1.13 + + node-releases@2.0.19: {} + + node-releases@2.0.27: {} + + nodemon@2.0.22: + dependencies: + chokidar: 3.6.0 + debug: 3.2.7(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 5.7.2 + simple-update-notifier: 1.1.0 + supports-color: 5.5.0 + touch: 3.1.1 + undefsafe: 2.0.5 + + nopt@6.0.0: + dependencies: + abbrev: 1.1.1 + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.10 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + normalize-path@3.0.0: {} + + normalize-url@6.1.0: {} + + npm-run-path@2.0.2: + dependencies: + path-key: 2.0.1 + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: + optional: true + + object-path@0.11.8: {} + + obug@2.1.1: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + ora@5.4.1: + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + + outdent@0.8.0: {} + + oxc-parser@0.127.0: + dependencies: + '@oxc-project/types': 0.127.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.127.0 + '@oxc-parser/binding-android-arm64': 0.127.0 + '@oxc-parser/binding-darwin-arm64': 0.127.0 + '@oxc-parser/binding-darwin-x64': 0.127.0 + '@oxc-parser/binding-freebsd-x64': 0.127.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.127.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.127.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.127.0 + '@oxc-parser/binding-linux-arm64-musl': 0.127.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.127.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.127.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.127.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.127.0 + '@oxc-parser/binding-linux-x64-gnu': 0.127.0 + '@oxc-parser/binding-linux-x64-musl': 0.127.0 + '@oxc-parser/binding-openharmony-arm64': 0.127.0 + '@oxc-parser/binding-wasm32-wasi': 0.127.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.127.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.127.0 + '@oxc-parser/binding-win32-x64-msvc': 0.127.0 + + oxc-resolver@11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2): + optionalDependencies: + '@oxc-resolver/binding-android-arm-eabi': 11.19.1 + '@oxc-resolver/binding-android-arm64': 11.19.1 + '@oxc-resolver/binding-darwin-arm64': 11.19.1 + '@oxc-resolver/binding-darwin-x64': 11.19.1 + '@oxc-resolver/binding-freebsd-x64': 11.19.1 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.19.1 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.19.1 + '@oxc-resolver/binding-linux-arm64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-arm64-musl': 11.19.1 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-riscv64-musl': 11.19.1 + '@oxc-resolver/binding-linux-s390x-gnu': 11.19.1 + '@oxc-resolver/binding-linux-x64-gnu': 11.19.1 + '@oxc-resolver/binding-linux-x64-musl': 11.19.1 + '@oxc-resolver/binding-openharmony-arm64': 11.19.1 + '@oxc-resolver/binding-wasm32-wasi': 11.19.1(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@oxc-resolver/binding-win32-arm64-msvc': 11.19.1 + '@oxc-resolver/binding-win32-ia32-msvc': 11.19.1 + '@oxc-resolver/binding-win32-x64-msvc': 11.19.1 + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + + p-cancelable@2.1.1: {} + + p-defer@1.0.0: {} + + p-finally@1.0.0: {} + + p-is-promise@2.1.0: {} + + p-limit@1.3.0: + dependencies: + p-try: 1.0.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.2 + + p-locate@2.0.0: + dependencies: + p-limit: 1.3.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-map@4.0.0: + dependencies: + aggregate-error: 3.1.0 + + p-try@1.0.0: {} + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + package-manager-detector@1.6.0: {} + + pako@1.0.11: {} + + parse-author@2.0.0: + dependencies: + author-regex: 1.0.0 + + parse-json@2.2.0: + dependencies: + error-ex: 1.3.2 + + parse-passwd@1.0.0: {} + + parseurl@1.3.3: {} + + path-browserify@1.0.1: {} + + path-exists@3.0.0: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@2.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-to-regexp@8.3.0: {} + + path-type@2.0.0: + dependencies: + pify: 2.3.0 + + pathe@2.0.3: {} + + pe-library@0.4.1: {} + + pend@1.2.0: {} + + perfect-debounce@1.0.0: {} + + phosphor-react@1.4.1(react@19.2.4): + dependencies: + react: 19.2.4 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.2: {} + + picomatch@4.0.3: {} + + picomatch@4.0.4: {} + + pidtree@0.6.0: {} + + pify@2.3.0: {} + + pkce-challenge@5.0.1: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pkg-types@2.3.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.8 + pathe: 2.0.3 + + plist@3.1.0: + dependencies: + '@xmldom/xmldom': 0.8.10 + base64-js: 1.5.1 + xmlbuilder: 15.1.1 + + pluralize@8.0.0: {} + + postcss-discard-duplicates@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-discard-empty@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + + postcss-merge-rules@7.0.7(postcss@8.5.6): + dependencies: + browserslist: 4.28.0 + caniuse-api: 3.0.0 + cssnano-utils: 5.0.1(postcss@8.5.6) + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-minify-selectors@7.0.5(postcss@8.5.6): + dependencies: + cssesc: 3.0.0 + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-nested@7.0.2(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-selector-parser: 7.1.1 + + postcss-normalize-whitespace@7.0.1(postcss@8.5.6): + dependencies: + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.4: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + postject@1.0.0-alpha.6: + dependencies: + commander: 9.5.0 + optional: true + + prettier@2.8.8: {} + + prettier@3.2.5: {} + + prettier@3.7.3: {} + + proc-log@2.0.1: {} + + process-nextick-args@2.0.1: {} + + progress@2.0.3: {} + + promise-inflight@1.0.1: {} + + promise-retry@2.0.1: + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + proxy-from-env@1.1.0: {} + + pstree.remy@1.1.8: {} + + pump@3.0.2: + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + + punycode@2.3.1: {} + + qs@6.14.1: + dependencies: + side-channel: 1.1.0 + + queue-microtask@1.2.3: {} + + quick-lru@5.1.1: {} + + range-parser@1.2.1: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 + + rcedit@3.1.0: + dependencies: + cross-spawn-windows-exe: 1.2.0 + + react-dom@19.2.4(react@19.2.4): + dependencies: + react: 19.2.4 + scheduler: 0.27.0 + + react-hot-toast@2.6.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): + dependencies: + csstype: 3.2.3 + goober: 2.1.18(csstype@3.2.3) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + react-i18next@16.5.4(i18next@25.8.13(typescript@5.9.2))(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.2): + dependencies: + '@babel/runtime': 7.28.6 + html-parse-stringify: 3.0.1 + i18next: 25.8.13(typescript@5.9.2) + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + react-dom: 19.2.4(react@19.2.4) + typescript: 5.9.2 + + react-refresh@0.17.0: {} + + react-remove-scroll-bar@2.3.8(@types/react@19.2.13)(react@19.2.4): + dependencies: + react: 19.2.4 + react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + react-remove-scroll@2.7.2(@types/react@19.2.13)(react@19.2.4): + dependencies: + react: 19.2.4 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.13)(react@19.2.4) + react-style-singleton: 2.2.3(@types/react@19.2.13)(react@19.2.4) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.13)(react@19.2.4) + use-sidecar: 1.1.3(@types/react@19.2.13)(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.13 + + react-style-singleton@2.2.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + get-nonce: 1.0.1 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + react@19.2.4: {} + + read-binary-file-arch@1.0.6: + dependencies: + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + read-pkg-up@2.0.0: + dependencies: + find-up: 2.1.0 + read-pkg: 2.0.0 + + read-pkg@2.0.0: + dependencies: + load-json-file: 2.0.0 + normalize-package-data: 2.5.0 + path-type: 2.0.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdir-glob@1.1.3: + dependencies: + minimatch: 5.1.6 + + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + + readdirp@4.1.2: {} + + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + + rechoir@0.8.0: + dependencies: + resolve: 1.22.10 + + regex-escape@3.4.11: {} + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resedit@1.7.2: + dependencies: + pe-library: 0.4.1 + + resolve-alpn@1.2.1: {} + + resolve-dir@1.0.1: + dependencies: + expand-tilde: 2.0.2 + global-modules: 1.0.0 + + resolve-package@1.0.1: + dependencies: + get-installed-path: 2.1.1 + + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + responselike@2.0.1: + dependencies: + lowercase-keys: 2.0.0 + + restore-cursor@3.1.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + restore-cursor@4.0.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + retry@0.12.0: {} + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rimraf@2.6.3: + dependencies: + glob: 7.2.3 + + rimraf@2.7.1: + dependencies: + glob: 7.2.3 + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + roarr@2.15.4: + dependencies: + boolean: 3.2.0 + detect-node: 2.1.0 + globalthis: 1.0.4 + json-stringify-safe: 5.0.1 + semver-compare: 1.0.0 + sprintf-js: 1.1.3 + optional: true + + rollup@4.41.1: + dependencies: + '@types/estree': 1.0.7 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.41.1 + '@rollup/rollup-android-arm64': 4.41.1 + '@rollup/rollup-darwin-arm64': 4.41.1 + '@rollup/rollup-darwin-x64': 4.41.1 + '@rollup/rollup-freebsd-arm64': 4.41.1 + '@rollup/rollup-freebsd-x64': 4.41.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.41.1 + '@rollup/rollup-linux-arm-musleabihf': 4.41.1 + '@rollup/rollup-linux-arm64-gnu': 4.41.1 + '@rollup/rollup-linux-arm64-musl': 4.41.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.41.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.41.1 + '@rollup/rollup-linux-riscv64-gnu': 4.41.1 + '@rollup/rollup-linux-riscv64-musl': 4.41.1 + '@rollup/rollup-linux-s390x-gnu': 4.41.1 + '@rollup/rollup-linux-x64-gnu': 4.41.1 + '@rollup/rollup-linux-x64-musl': 4.41.1 + '@rollup/rollup-win32-arm64-msvc': 4.41.1 + '@rollup/rollup-win32-ia32-msvc': 4.41.1 + '@rollup/rollup-win32-x64-msvc': 4.41.1 + fsevents: 2.3.3 + + rollup@4.53.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.53.3 + '@rollup/rollup-android-arm64': 4.53.3 + '@rollup/rollup-darwin-arm64': 4.53.3 + '@rollup/rollup-darwin-x64': 4.53.3 + '@rollup/rollup-freebsd-arm64': 4.53.3 + '@rollup/rollup-freebsd-x64': 4.53.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 + '@rollup/rollup-linux-arm-musleabihf': 4.53.3 + '@rollup/rollup-linux-arm64-gnu': 4.53.3 + '@rollup/rollup-linux-arm64-musl': 4.53.3 + '@rollup/rollup-linux-loong64-gnu': 4.53.3 + '@rollup/rollup-linux-ppc64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-gnu': 4.53.3 + '@rollup/rollup-linux-riscv64-musl': 4.53.3 + '@rollup/rollup-linux-s390x-gnu': 4.53.3 + '@rollup/rollup-linux-x64-gnu': 4.53.3 + '@rollup/rollup-linux-x64-musl': 4.53.3 + '@rollup/rollup-openharmony-arm64': 4.53.3 + '@rollup/rollup-win32-arm64-msvc': 4.53.3 + '@rollup/rollup-win32-ia32-msvc': 4.53.3 + '@rollup/rollup-win32-x64-gnu': 4.53.3 + '@rollup/rollup-win32-x64-msvc': 4.53.3 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.3.0 + transitivePeerDependencies: + - supports-color + + run-con@1.2.12: + dependencies: + deep-extend: 0.6.0 + ini: 3.0.1 + minimist: 1.2.8 + strip-json-comments: 3.1.1 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + sanitize-filename@1.6.3: + dependencies: + truncate-utf8-bytes: 1.0.2 + + sax@1.4.1: {} + + saxes@5.0.1: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.27.0: {} + + semver-compare@1.0.0: + optional: true + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.0.0: {} + + semver@7.7.2: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-error@7.0.1: + dependencies: + type-fest: 0.13.1 + optional: true + + seroval-plugins@1.3.3(seroval@1.3.2): + dependencies: + seroval: 1.3.2 + + seroval-plugins@1.4.0(seroval@1.4.0): + dependencies: + seroval: 1.4.0 + + seroval@1.3.2: {} + + seroval@1.4.0: {} + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setimmediate@1.0.5: {} + + setprototypeof@1.2.0: {} + + shebang-command@1.2.0: + dependencies: + shebang-regex: 1.0.0 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@1.0.0: {} + + shebang-regex@3.0.0: {} + + shell-quote@1.8.2: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + simple-update-notifier@1.1.0: + dependencies: + semver: 7.0.0 + + simple-update-notifier@2.0.0: + dependencies: + semver: 7.7.2 + + sisteransi@1.0.5: {} + + slice-ansi@3.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@4.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + smart-buffer@4.2.0: {} + + smol-toml@1.6.1: {} + + socks-proxy-agent@7.0.0: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + socks: 2.8.7 + transitivePeerDependencies: + - supports-color + + socks@2.8.7: + dependencies: + ip-address: 10.1.0 + smart-buffer: 4.2.0 + + solid-js@1.9.10: + dependencies: + csstype: 3.2.3 + seroval: 1.3.2 + seroval-plugins: 1.3.3(seroval@1.3.2) + + source-map-js@1.2.1: {} + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + source-map@0.7.6: {} + + spawn-command@0.0.2: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.21 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.21 + + spdx-license-ids@3.0.21: {} + + sprintf-js@1.1.3: + optional: true + + ssri@9.0.1: + dependencies: + minipass: 3.3.6 + + stackback@0.0.2: {} + + stat-mode@1.0.0: {} + + statuses@2.0.2: {} + + std-env@4.1.0: {} + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-bom@3.0.0: {} + + strip-eof@1.0.0: {} + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + strip-json-comments@5.0.3: {} + + strip-outer@1.0.1: + dependencies: + escape-string-regexp: 1.0.5 + + sudo-prompt@9.2.1: {} + + sumchecker@3.0.1: + dependencies: + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + table@6.9.0: + dependencies: + ajv: 8.17.1 + lodash.truncate: 4.4.2 + slice-ansi: 4.0.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + + tar@6.2.1: + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + + temp-file@3.4.0: + dependencies: + async-exit-hook: 2.0.1 + fs-extra: 10.1.0 + + temp@0.9.4: + dependencies: + mkdirp: 0.5.6 + rimraf: 2.6.3 + + through@2.3.8: {} + + tiny-async-pool@1.3.0: + dependencies: + semver: 5.7.2 + + tiny-each-async@2.0.3: + optional: true + + tiny-invariant@1.3.3: {} + + tiny-warning@1.0.3: {} + + tinybench@2.9.0: {} + + tinyexec@1.1.2: {} + + tinyglobby@0.2.14: + dependencies: + fdir: 6.4.5(picomatch@4.0.2) + picomatch: 4.0.2 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tinyrainbow@3.1.0: {} + + tmp-promise@3.0.3: + dependencies: + tmp: 0.2.3 + + tmp@0.2.3: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + touch@3.1.1: {} + + tr46@0.0.3: {} + + traverse@0.3.9: {} + + tree-kill@1.2.2: {} + + trim-repeated@1.0.0: + dependencies: + escape-string-regexp: 1.0.5 + + truncate-utf8-bytes@1.0.2: + dependencies: + utf8-byte-length: 1.0.5 + + ts-evaluator@1.2.0(typescript@5.9.2): + dependencies: + ansi-colors: 4.1.3 + crosspath: 2.0.0 + object-path: 0.11.8 + typescript: 5.9.2 + + ts-morph@27.0.2: + dependencies: + '@ts-morph/common': 0.28.1 + code-block-writer: 13.0.3 + + ts-pattern@5.9.0: {} + + tsconfck@3.1.6(typescript@5.9.2): + optionalDependencies: + typescript: 5.9.2 + + tslib@2.8.1: {} + + tsx@4.20.6: + dependencies: + esbuild: 0.25.5 + get-tsconfig: 4.13.0 + optionalDependencies: + fsevents: 2.3.3 + + type-fest@0.13.1: + optional: true + + type-fest@0.21.3: {} + + type-fest@1.4.0: {} + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + + typescript@5.9.2: {} + + typescript@5.9.3: {} + + uc.micro@1.0.6: {} + + unbash@3.0.0: {} + + undefsafe@2.0.5: {} + + undici-types@6.21.0: {} + + unique-filename@2.0.1: + dependencies: + unique-slug: 3.0.0 + + unique-slug@3.0.0: + dependencies: + imurmurhash: 0.1.4 + + universalify@0.1.2: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.15.0 + picomatch: 4.0.3 + webpack-virtual-modules: 0.6.2 + + unzip-crx-3@0.2.0: + dependencies: + jszip: 3.10.1 + mkdirp: 0.5.6 + yaku: 0.16.7 + + unzipper@0.10.14: + dependencies: + big-integer: 1.6.52 + binary: 0.3.0 + bluebird: 3.4.7 + buffer-indexof-polyfill: 1.0.2 + duplexer2: 0.1.4 + fstream: 1.0.12 + graceful-fs: 4.2.11 + listenercount: 1.0.1 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + + update-browserslist-db@1.1.3(browserslist@4.25.0): + dependencies: + browserslist: 4.25.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + update-browserslist-db@1.2.3(browserslist@4.28.0): + dependencies: + browserslist: 4.28.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + use-sidecar@1.1.3(@types/react@19.2.13)(react@19.2.4): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.4 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.13 + + use-sync-external-store@1.5.0(react@19.2.4): + dependencies: + react: 19.2.4 + + use-sync-external-store@1.6.0(react@19.2.4): + dependencies: + react: 19.2.4 + + username@5.1.0: + dependencies: + execa: 1.0.0 + mem: 4.3.0 + + utf8-byte-length@1.0.5: {} + + util-deprecate@1.0.2: {} + + uuid@8.3.2: {} + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + vary@1.1.2: {} + + verror@1.10.1: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.4.1 + optional: true + + vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3): + dependencies: + esbuild: 0.25.5 + fdir: 6.4.5(picomatch@4.0.2) + picomatch: 4.0.2 + postcss: 8.5.4 + rollup: 4.41.1 + tinyglobby: 0.2.14 + optionalDependencies: + '@types/node': 20.19.1 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + tsx: 4.20.6 + yaml: 2.8.3 + + vite@7.2.4(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3): + dependencies: + esbuild: 0.25.5 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.53.3 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 20.19.1 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + tsx: 4.20.6 + yaml: 2.8.3 + + vitest@4.1.6(@types/node@20.19.1)(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.6 + '@vitest/mocker': 4.1.6(vite@6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.6 + '@vitest/runner': 4.1.6 + '@vitest/snapshot': 4.1.6 + '@vitest/spy': 4.1.6 + '@vitest/utils': 4.1.6 + es-module-lexer: 2.1.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.1.0 + tinybench: 2.9.0 + tinyexec: 1.1.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 6.3.5(@types/node@20.19.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.19.1 + transitivePeerDependencies: + - msw + + void-elements@3.1.0: {} + + wait-on@6.0.1: + dependencies: + axios: 0.25.0 + joi: 17.13.3 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.2 + transitivePeerDependencies: + - debug + + walk-up-path@4.0.0: {} + + wcwidth@1.0.1: + dependencies: + defaults: 1.0.4 + + webidl-conversions@3.0.1: {} + + webpack-virtual-modules@0.6.2: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + which@1.3.1: + dependencies: + isexe: 2.0.0 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: + optional: true + + wordwrapjs@5.1.1: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + xmlbuilder@15.1.1: {} + + xmlchars@2.2.0: {} + + y18n@5.0.8: {} + + yaku@0.16.7: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yaml@2.3.1: {} + + yaml@2.8.3: {} + + yargs-parser@20.2.9: + optional: true + + yargs-parser@21.1.1: {} + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + optional: true + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yarn-or-npm@3.0.1: + dependencies: + cross-spawn: 6.0.6 + pkg-dir: 4.2.0 + + yauzl@2.10.0: + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + + yocto-queue@0.1.0: {} + + yocto-queue@1.2.2: {} + + zip-stream@4.1.1: + dependencies: + archiver-utils: 3.0.4 + compress-commons: 4.1.2 + readable-stream: 3.6.2 + + zod-to-json-schema@3.25.1(zod@4.0.14): + dependencies: + zod: 4.0.14 + + zod@3.25.76: {} + + zod@4.0.14: {} + + zod@4.3.6: {} + + zustand@5.0.7(@types/react@19.2.13)(react@19.2.4)(use-sync-external-store@1.6.0(react@19.2.4)): + optionalDependencies: + '@types/react': 19.2.13 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml new file mode 100644 index 00000000..041eb937 --- /dev/null +++ b/frontend/pnpm-workspace.yaml @@ -0,0 +1,7 @@ +allowBuilds: + "@biomejs/biome": true + electron-winstaller: true + electron: true + esbuild: true + +blockExoticSubdeps: false diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs new file mode 100644 index 00000000..1bfc8f1d --- /dev/null +++ b/frontend/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + "@pandacss/dev/postcss": {}, + }, +}; diff --git a/frontend/src/main/createWindow.ts b/frontend/src/main/createWindow.ts new file mode 100644 index 00000000..379be1e7 --- /dev/null +++ b/frontend/src/main/createWindow.ts @@ -0,0 +1,73 @@ +import { join } from "node:path"; +import { is } from "@electron-toolkit/utils"; +import { BrowserWindow, shell } from "electron"; + +import { DEV_PORT, EXTERNAL_URLS, isDebug, isProduction } from "./env"; +import { resolveHTMLPath } from "./utils"; + +export let mainWindow: BrowserWindow | null; + +/** + * Configures the main `BrowserWindow` with features and handlers + * @param window Main window created on the main process + */ +function configureWindow(window: BrowserWindow | null) { + if (!window) { + throw new Error('"mainWindow" is not defined'); + } + if (isDebug) { + window.webContents.openDevTools(); + } + if (isProduction) { + window.maximize(); + } + + window.loadURL(resolveHTMLPath()); + + // window.webContents.openDevTools(); + + /** + * HANDLERS + */ + window.on("ready-to-show", () => { + window.show(); + }); + + window.webContents.setWindowOpenHandler(({ url }) => { + if (EXTERNAL_URLS.find((val) => url.includes(val))) { + shell.openExternal(url); + } + return { action: "deny" }; + }); + + // and handlers + mainWindow?.on("closed", () => { + mainWindow = null; + }); +} + +export default function createWindow() { + // Creates the browser window. + mainWindow = new BrowserWindow({ + width: 1366, + height: 768, + autoHideMenuBar: true, + webPreferences: { + preload: join(__dirname, "../preload/index.js"), + sandbox: false, + }, + }); + + // Add configuration + configureWindow(mainWindow); + + // HMR for renderer base on electron-vite cli. + // Load the remote URL for development or the local html file for production. + if (is.dev) { + mainWindow.loadURL(`http://localhost:${DEV_PORT}`); + } else { + mainWindow.loadFile(join(__dirname, "../renderer/index.html")); + } + + return mainWindow; +} diff --git a/frontend/src/main/env.ts b/frontend/src/main/env.ts new file mode 100644 index 00000000..4b7c0e76 --- /dev/null +++ b/frontend/src/main/env.ts @@ -0,0 +1,54 @@ +/// + +import { homedir } from "node:os"; +import path from "node:path"; +import { is } from "@electron-toolkit/utils"; + +// ------------------------ +// CONFIG VARIABLES +// ------------------------ + +/** + * Port for the development app + */ +export const DEV_PORT = 3000; + +/** + * Custom URI scheme name + */ +export const URI_SCHEME = "aymurai.app"; + +/** + * Exports folder + */ +export const EXPORTS_FOLDER = path.resolve(homedir(), "Documents/AymurAI"); + +/** + * URLs that must be opened in a native browser tab + */ +export const EXTERNAL_URLS = [ + "https://www.datagenero.org/", + "https://accounts.google.com/o/oauth2/v2/auth", + "https://docs.google.com/spreadsheets", + "https://www.aymurai.info", +]; + +/** + * Is the app in development mode? + */ +export const isDebug = is.dev; + +/** + * Is the app in production mode? + */ +export const isProduction = !is.dev; + +/** + * Is the app running on Windows? + */ +export const isWindows = process.platform === "win32"; + +/** + * Is the app running on macOS? + */ +export const isMac = process.platform === "darwin"; diff --git a/frontend/src/main/extensions.ts b/frontend/src/main/extensions.ts new file mode 100644 index 00000000..836b32a9 --- /dev/null +++ b/frontend/src/main/extensions.ts @@ -0,0 +1,17 @@ +import installer, { + REACT_DEVELOPER_TOOLS, + EMBER_INSPECTOR, +} from "electron-devtools-installer"; + +export const installExtensions = async (): Promise => { + const extensions = [EMBER_INSPECTOR, REACT_DEVELOPER_TOOLS]; + + return installer(extensions, { + forceDownload: true, + loadExtensionOptions: { + allowFileAccess: true, + }, + }) + .then(console.log) + .catch(console.error); +}; diff --git a/frontend/src/main/index.ts b/frontend/src/main/index.ts new file mode 100644 index 00000000..1f133afc --- /dev/null +++ b/frontend/src/main/index.ts @@ -0,0 +1,54 @@ +import { electronApp, optimizer } from "@electron-toolkit/utils"; +import { BrowserWindow, app, ipcMain } from "electron"; + +import createWindow from "./createWindow"; +import { installExtensions } from "./extensions"; +import { excel, feedback, subprocess, taskbar } from "./utils"; + +// This method will be called when Electron has finished +// initialization and is ready to create browser windows. +// Some APIs can only be used after this event occurs. +app.whenReady().then(async () => { + // Set app user model id for windows + electronApp.setAppUserModelId("com.electron"); + + // Default open or close DevTools by F12 in development + // and ignore CommandOrControl + R in production. + // see https://github.com/alex8088/electron-toolkit/tree/master/packages/utils + app.on("browser-window-created", (_, window) => { + optimizer.watchWindowShortcuts(window); + }); + + ipcMain.handle("EXPORT_FEEDBACK", (_, fileName: string, data: object) => + feedback.export(fileName, data), + ); + ipcMain.handle("EXCEL_READ", excel.read); + ipcMain.handle("EXCEL_WRITE", (_, buffer: ArrayBuffer) => + excel.write(buffer), + ); + ipcMain.handle("EXCEL_OPEN", excel.open); + + // TASKBAR + ipcMain.handle("TASKBAR_NOTIFY", taskbar.notify); + + ipcMain.handle("RUN_BATCH", subprocess.run); + + await installExtensions(); + createWindow(); + + app.on("activate", () => { + // On macOS it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) createWindow(); + }); +}); + +// Quit when all windows are closed, except on macOS. There, it's common +// for applications and their menu bar to stay active until the user quits +// explicitly with Cmd + Q. +app.on("window-all-closed", async () => { + subprocess.stop(); + if (process.platform !== "darwin") { + app.quit(); + } +}); diff --git a/frontend/src/main/utils/__tests__/excel.test.ts b/frontend/src/main/utils/__tests__/excel.test.ts new file mode 100644 index 00000000..235565e7 --- /dev/null +++ b/frontend/src/main/utils/__tests__/excel.test.ts @@ -0,0 +1,52 @@ +import fs from "node:fs/promises"; +import os from "node:os"; +import path from "node:path"; +import { Workbook } from "exceljs"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("electron", () => ({ + shell: { + openPath: vi.fn(), + }, +})); + +vi.mock("@electron-toolkit/utils", () => ({ + is: { + dev: true, + }, +})); + +describe("main excel filesystem bridge", () => { + let tempHome: string; + + beforeEach(async () => { + tempHome = await fs.mkdtemp(path.join(os.tmpdir(), "aymurai-excel-")); + vi.spyOn(os, "homedir").mockReturnValue(tempHome); + vi.resetModules(); + }); + + afterEach(async () => { + vi.restoreAllMocks(); + await fs.rm(tempHome, { recursive: true, force: true }); + }); + + it("returns the exact file bytes when reading the dataset workbook", async () => { + const { default: excel } = await import("../excel"); + const workbook = new Workbook(); + workbook.addWorksheet("set_de_datos").addRow(["ok"]); + + const original = await workbook.xlsx.writeBuffer(); + await excel.write(original); + + const loaded = await excel.read(); + expect(loaded.byteLength).toBe(original.byteLength); + + const reloaded = new Workbook(); + const loadedBuffer = Buffer.from(new Uint8Array(loaded as ArrayBuffer)); + const loadWorkbook = reloaded.xlsx.load.bind(reloaded.xlsx) as ( + data: unknown, + ) => Promise; + await expect(loadWorkbook(loadedBuffer)).resolves.toBeDefined(); + expect(reloaded.worksheets[0].getCell("A1").value).toBe("ok"); + }); +}); diff --git a/frontend/src/main/utils/excel.ts b/frontend/src/main/utils/excel.ts new file mode 100644 index 00000000..5548796b --- /dev/null +++ b/frontend/src/main/utils/excel.ts @@ -0,0 +1,44 @@ +import fs from "node:fs/promises"; +import { shell } from "electron"; + +import { EXPORTS_FOLDER } from "../env"; +import filesystem from "./filesystem"; + +const FILENAME = "set_de_datos.xlsx"; +const PATH = `${EXPORTS_FOLDER}/${FILENAME}`; + +/** + * Reads the raw data from the data_set excel file + * @returns The `Promise` read from the file + */ +function read() { + return fs.readFile(PATH).then(({ buffer }) => buffer); +} + +/** + * Writes a .xlsx file to the filesystem + * @param buffer Data buffer to write. This is the .xlsx file + */ +async function write(arrBuffer: ArrayBuffer) { + // Create directory if necessary + if (!(await filesystem.exists(EXPORTS_FOLDER))) { + await fs.mkdir(EXPORTS_FOLDER, { recursive: true }); + } + + await fs.writeFile(PATH, Buffer.from(arrBuffer)); +} + +/** + * Opens the previously created .xlsx using the default app + * @returns Message if the opening was succesfull or not + */ +function open() { + return shell.openPath(PATH); +} + +const excel = { + read, + write, + open, +}; +export default excel; diff --git a/frontend/src/main/utils/feedback.ts b/frontend/src/main/utils/feedback.ts new file mode 100644 index 00000000..0224e3f5 --- /dev/null +++ b/frontend/src/main/utils/feedback.ts @@ -0,0 +1,61 @@ +import { promises as fs } from "node:fs"; + +import { EXPORTS_FOLDER } from "../env"; +import filesystem from "./filesystem"; + +const FEEDBACK_FOLDER = `${EXPORTS_FOLDER}/feedback`; + +/** + * Gets the current date and time in the format `YYYY-MM-DD-HH_MM_SS` + */ +function getDate() { + const now = new Date(Date.now()); + const [date, time] = now.toISOString().split("T"); + + const fileDate = `${date}-${ + time // Time in format xx:yy:zz.zzz + .split(".")[0] // We are left with xx:yy:zz + .replace(/:/g, "_") // Transform it into xx_yy_zz + }`; + + return fileDate; +} + +function formatName(fileName: string) { + // Remove extension and spaces from the name + const formattedName = fileName + .replace(/\.docx/g, "") // Remove extension + .replace(/\s/g, "_"); // Remove whitespace + + return `aymurai--${formattedName}`; +} + +async function mkdir() { + await fs.mkdir(FEEDBACK_FOLDER, { recursive: true }); +} + +/** + * Parses a validation object into a JSON that is written into a feedback file + * @param fileName Name of the file + * @param content Validation object + */ +async function exportFeedback(fileName: string, content: object) { + const date = getDate(); + const name = formatName(fileName); + const json = JSON.stringify(content); + + // Create directory if necessary + if (!(await filesystem.exists(FEEDBACK_FOLDER))) { + await mkdir(); + } + + // Create file + await fs.writeFile(`${FEEDBACK_FOLDER}/${name}--${date}.json`, json, { + flag: "w", + }); +} + +const feedback = { + export: exportFeedback, +}; +export default feedback; diff --git a/frontend/src/main/utils/filesystem.ts b/frontend/src/main/utils/filesystem.ts new file mode 100644 index 00000000..bba048e0 --- /dev/null +++ b/frontend/src/main/utils/filesystem.ts @@ -0,0 +1,20 @@ +import fs from "node:fs/promises"; + +/** + * Check for the existence of a specific director or file + * @param path Path to check + * @returns `true` if the directory/file exists, `false` otherwise + */ +async function exists(path: string) { + try { + await fs.access(path, fs.constants.F_OK); + return true; + } catch { + return false; + } +} + +const filesystem = { + exists, +}; +export default filesystem; diff --git a/frontend/src/main/utils/index.ts b/frontend/src/main/utils/index.ts new file mode 100644 index 00000000..7c4176e3 --- /dev/null +++ b/frontend/src/main/utils/index.ts @@ -0,0 +1,7 @@ +import excel from "./excel"; +import feedback from "./feedback"; +import resolveHTMLPath from "./resolveHTMLPath"; +import taskbar from "./taskbar"; +export { excel, feedback, resolveHTMLPath, taskbar }; + +export * as subprocess from "./subprocess"; diff --git a/frontend/src/main/utils/resolveHTMLPath.ts b/frontend/src/main/utils/resolveHTMLPath.ts new file mode 100644 index 00000000..e7f0e539 --- /dev/null +++ b/frontend/src/main/utils/resolveHTMLPath.ts @@ -0,0 +1,20 @@ +import path from "node:path"; +import { URL } from "node:url"; + +import { DEV_PORT, isDebug } from "../env"; + +/** + * Retrieves the HMTL path to the requested file + * @param fileName Name of the file, default to `index.html` + * @returns An HTML path to the file, wether on the file system or the web + */ +export default function resolveHTMLPath(fileName = "index.html") { + if (isDebug) { + const url = new URL(`http://localhost:${DEV_PORT}`); + + return url.href; + } + + const pathToFile = path.resolve(__dirname, "../app", fileName); + return `file://${pathToFile}`; +} diff --git a/frontend/src/main/utils/subprocess.ts b/frontend/src/main/utils/subprocess.ts new file mode 100644 index 00000000..0dd06696 --- /dev/null +++ b/frontend/src/main/utils/subprocess.ts @@ -0,0 +1,31 @@ +import { exec, spawn } from "node:child_process"; +import path from "node:path"; +import { app } from "electron"; + +export const run = () => { + const batFilePath = path.join(app.getPath("exe"), "../run_server.bat"); + const child = spawn(batFilePath); + + return new Promise((ok, no) => { + if (!child) return no(new Error("Child process not found")); + + child.on("spawn", () => { + ok(true); + }); + child.on("error", (err) => { + no(err); + }); + }); +}; + +export const stop = (): Promise => { + return new Promise((ok, no) => { + exec( + 'powershell "& Get-Process -Name python | ? { $_.Path -eq \\"$env:USERPROFILE\\miniconda3\\envs\\aymurai-backend\\python.exe\\"} | Stop-Process"', + (err) => { + if (err) return no(err); + ok(true); + }, + ); + }); +}; diff --git a/frontend/src/main/utils/taskbar.ts b/frontend/src/main/utils/taskbar.ts new file mode 100644 index 00000000..dca71e34 --- /dev/null +++ b/frontend/src/main/utils/taskbar.ts @@ -0,0 +1,27 @@ +import { app } from "electron"; +import { mainWindow } from "../createWindow"; +import { isMac, isWindows } from "../env"; + +/** + * Notify the user through the taskbar + */ +const notify = () => { + if (isWindows) { + if (!mainWindow) return; + + // Flash taskbar icon (windows) + mainWindow.flashFrame(true); + + mainWindow.once("focus", () => mainWindow?.flashFrame(false)); + } else if (isMac) { + if (!app || !app.dock) return; + + // Bounce dock icon (macOS) + app.dock.bounce("informational"); + } +}; + +const taskbar = { + notify, +}; +export default taskbar; diff --git a/frontend/src/preload/index.d.ts b/frontend/src/preload/index.d.ts new file mode 100644 index 00000000..5d8869bd --- /dev/null +++ b/frontend/src/preload/index.d.ts @@ -0,0 +1,22 @@ +declare global { + interface Window { + filesystem?: { + feedback: { + export: (fileName: string, data: object) => Promise; + }; + excel: { + read: () => Promise; + write: (arrBuffer: ArrayBuffer) => Promise; + open: () => Promise; + }; + }; + taskbar?: { + notify: () => Promise; + }; + electronAPI?: { + runBatch: () => Promise; + }; + } +} + +export {}; diff --git a/frontend/src/preload/index.ts b/frontend/src/preload/index.ts new file mode 100644 index 00000000..a1a0ebbc --- /dev/null +++ b/frontend/src/preload/index.ts @@ -0,0 +1,39 @@ +import { electronAPI } from "@electron-toolkit/preload"; +import { contextBridge, ipcRenderer } from "electron"; + +// Custom APIs for renderer +const api = {}; + +// Use `contextBridge` APIs to expose Electron APIs to +// renderer only if context isolation is enabled, otherwise +// just add to the DOM global. +if (process.contextIsolated) { + try { + contextBridge.exposeInMainWorld("filesystem", { + feedback: { + export: (fileName: string, object: object) => + ipcRenderer.invoke("EXPORT_FEEDBACK", fileName, object), + }, + excel: { + read: () => ipcRenderer.invoke("EXCEL_READ"), + write: (buffer: Buffer) => ipcRenderer.invoke("EXCEL_WRITE", buffer), + open: () => ipcRenderer.invoke("EXCEL_OPEN"), + }, + }); + + contextBridge.exposeInMainWorld("taskbar", { + notify: () => ipcRenderer.invoke("TASKBAR_NOTIFY"), + }); + + contextBridge.exposeInMainWorld("electronAPI", { + runBatch: (result: unknown) => ipcRenderer.invoke("RUN_BATCH", result), + }); + } catch (error) { + console.error(error); + } +} else { + // @ts-ignore (define in dts) + window.electron = electronAPI; + // @ts-ignore (define in dts) + window.api = api; +} diff --git a/frontend/src/renderer/index.html b/frontend/src/renderer/index.html new file mode 100644 index 00000000..93cd96fa --- /dev/null +++ b/frontend/src/renderer/index.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + AymurAI + + + +
    + + + + \ No newline at end of file diff --git a/frontend/src/renderer/public/audio/notification.mp3 b/frontend/src/renderer/public/audio/notification.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..6b4b277ffb1b69fca49d907f45f6c9c4956e8ee1 GIT binary patch literal 6587 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 L|FFCN|EB&2lp#Tj literal 0 HcmV?d00001 diff --git a/frontend/src/renderer/public/brand/aymurai-hor-darkpurple.svg b/frontend/src/renderer/public/brand/aymurai-hor-darkpurple.svg new file mode 100644 index 00000000..efde8df1 --- /dev/null +++ b/frontend/src/renderer/public/brand/aymurai-hor-darkpurple.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/renderer/public/brand/aymurai-iso-darkpurple.svg b/frontend/src/renderer/public/brand/aymurai-iso-darkpurple.svg new file mode 100644 index 00000000..9fa89d34 --- /dev/null +++ b/frontend/src/renderer/public/brand/aymurai-iso-darkpurple.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/renderer/public/brand/aymurai-iso-purple.svg b/frontend/src/renderer/public/brand/aymurai-iso-purple.svg new file mode 100644 index 00000000..35114f7c --- /dev/null +++ b/frontend/src/renderer/public/brand/aymurai-iso-purple.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/renderer/public/brand/aymurai-vert-darkpurple.svg b/frontend/src/renderer/public/brand/aymurai-vert-darkpurple.svg new file mode 100644 index 00000000..452bbe89 --- /dev/null +++ b/frontend/src/renderer/public/brand/aymurai-vert-darkpurple.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/renderer/public/brand/aymurai-vert-purple.png b/frontend/src/renderer/public/brand/aymurai-vert-purple.png new file mode 100644 index 0000000000000000000000000000000000000000..fa78e70d24d8753942f8640a4fa5f5439e41a45d GIT binary patch literal 48246 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 z

    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 literal 0 HcmV?d00001 diff --git a/frontend/src/renderer/public/brand/datagenero.svg b/frontend/src/renderer/public/brand/datagenero.svg new file mode 100644 index 00000000..a07225aa --- /dev/null +++ b/frontend/src/renderer/public/brand/datagenero.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/renderer/public/brand/iso-white.png b/frontend/src/renderer/public/brand/iso-white.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1359f1015afb3847eeb63a95debf848cbaaf82 GIT binary patch literal 38733 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 I&Fbv`1A798J^%m! literal 0 HcmV?d00001 diff --git a/frontend/src/renderer/public/brand/logo.jpg b/frontend/src/renderer/public/brand/logo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8e3872376256799231063b46b18681a7ca01cde GIT binary patch literal 80050 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

    s7;-}0*Vt9#F?bUoLI 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 + + + + + diff --git a/frontend/src/renderer/public/button-icons/add-one.svg b/frontend/src/renderer/public/button-icons/add-one.svg new file mode 100644 index 00000000..3ecb521c --- /dev/null +++ b/frontend/src/renderer/public/button-icons/add-one.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/renderer/public/button-icons/delete-all.svg b/frontend/src/renderer/public/button-icons/delete-all.svg new file mode 100644 index 00000000..9a3f48bf --- /dev/null +++ b/frontend/src/renderer/public/button-icons/delete-all.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/renderer/public/button-icons/delete-one.svg b/frontend/src/renderer/public/button-icons/delete-one.svg new file mode 100644 index 00000000..aebeacbe --- /dev/null +++ b/frontend/src/renderer/public/button-icons/delete-one.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/renderer/public/button-icons/replace-all.svg b/frontend/src/renderer/public/button-icons/replace-all.svg new file mode 100644 index 00000000..109ec00d --- /dev/null +++ b/frontend/src/renderer/public/button-icons/replace-all.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/renderer/public/button-icons/replace-one.svg b/frontend/src/renderer/public/button-icons/replace-one.svg new file mode 100644 index 00000000..409bb51b --- /dev/null +++ b/frontend/src/renderer/public/button-icons/replace-one.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/renderer/public/favicon.ico b/frontend/src/renderer/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..7e5894654a8a1bef9febea2bce693a07c4c76356 GIT binary patch literal 16958 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 literal 0 HcmV?d00001 diff --git a/frontend/src/renderer/public/manifest.json b/frontend/src/renderer/public/manifest.json new file mode 100644 index 00000000..3536cc5d --- /dev/null +++ b/frontend/src/renderer/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "Electron App", + "name": "Electron Desktop App", + "icons": [ + { + "src": "favicon.ico", + "sizes": "64x64 32x32 24x24 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/frontend/src/renderer/public/onboarding-steps/step1.png b/frontend/src/renderer/public/onboarding-steps/step1.png new file mode 100644 index 0000000000000000000000000000000000000000..1e560fe45d6b8db6193e42aff04df80664ed6898 GIT binary patch literal 11061 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 literal 0 HcmV?d00001 diff --git a/frontend/src/renderer/public/onboarding-steps/step4.png b/frontend/src/renderer/public/onboarding-steps/step4.png new file mode 100644 index 0000000000000000000000000000000000000000..01abcb982d11df77ead6cd8a48dd2eefbb82540c GIT binary patch literal 10186 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 Buo?gW literal 0 HcmV?d00001 diff --git a/frontend/src/renderer/public/robots.txt b/frontend/src/renderer/public/robots.txt new file mode 100644 index 00000000..e9e57dc4 --- /dev/null +++ b/frontend/src/renderer/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/frontend/src/renderer/src/app.tsx b/frontend/src/renderer/src/app.tsx new file mode 100644 index 00000000..da40d36e --- /dev/null +++ b/frontend/src/renderer/src/app.tsx @@ -0,0 +1,49 @@ +import { + RouterProvider, + createMemoryHistory, + createRouter, +} from "@tanstack/react-router"; +import { Toaster } from "react-hot-toast"; + +import { ThemeProvider } from "@/components"; +import FileProvider from "@/context/File"; +import { TooltipProvider } from "@/components/ui/tooltip"; +import * as TanstackReactQuery from "@/features/ReactQueryProvider"; + +// Import the generated route tree +import { routeTree } from "./routeTree.gen"; + +const TanStackQueryProviderContext = TanstackReactQuery.getContext(); + +const history = + import.meta.env.VITE_APP_MODE === "electron" + ? createMemoryHistory({ initialEntries: ["/"] }) + : undefined; +const router = createRouter({ + routeTree, + history, + context: { ...TanStackQueryProviderContext }, + defaultViewTransition: true, +}); + +declare module "@tanstack/react-router" { + interface Register { + router: typeof router; + } +} + +export default function App() { + return ( + + {/* Stitches global styles */} + + + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/anonymizer-label-select.tsx b/frontend/src/renderer/src/components/anonymizer/anonymizer-label-select.tsx new file mode 100644 index 00000000..c4d5e774 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/anonymizer-label-select.tsx @@ -0,0 +1,370 @@ +import * as RadixSelect from "@radix-ui/react-select"; +import { CaretDown, Check, MagnifyingGlass } from "phosphor-react"; +import { useEffect, useId, useMemo, useRef, useState } from "react"; + +import type { SelectOption } from "@/components/ui/select"; +import { + ANONYMIZER_CATEGORY_NAMES, + getAnonymizerLabelsForCategory, +} from "@/constants/anonymizer-categories"; +import { css, sva } from "@/styled/css"; +import { styled } from "@/styled/jsx"; +import { stack } from "@/styled/patterns"; +import { normalizeEntityText } from "@/utils/anonymizer/entity-similarity"; + +interface AnonymizerLabelSelectProps { + options: SelectOption[]; + value?: string; + onChange?: (value: SelectOption) => void; + onOpenChange?: (open: boolean) => void; + placeholder?: string; + disabled?: boolean; + size?: "md" | "sm"; + currentCategory?: string; +} + +interface LabelSection { + category: string; + labels: SelectOption[]; +} + +const select = sva({ + slots: [ + "container", + "trigger", + "value", + "caret", + "content", + "search", + "searchInput", + "viewport", + "groupLabel", + "item", + "itemIndicator", + "empty", + ], + base: { + container: { ...stack.raw({ gap: "1" }), width: "full" }, + trigger: { + display: "flex", + alignItems: "center", + gap: "2", + width: "full", + bg: "white", + border: "primary", + rounded: "sm", + cursor: "pointer", + textAlign: "left", + appearance: "none", + textStyle: "label.md.default", + color: "text.default", + + "&[data-state='open']": { + boxShadow: "[0px 2px 2px rgba(0, 0, 0, 0.16)]", + borderColor: "[#110041]", + }, + "&:focus-visible": { + outlineColor: "brand.primary", + outlineWidth: "0.5", + outlineStyle: "solid", + outlineOffset: "0.5", + }, + "&[data-disabled]": { + bg: "bg.primary", + cursor: "not-allowed", + color: "text.lighter", + }, + "&[data-placeholder]": { + color: "text.lighter", + }, + }, + value: { + flex: "[1]", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + }, + caret: { + flexShrink: "0", + color: "text.default", + transition: "[transform 0.15s ease]", + + "[data-state='open'] > &": { + transform: "[rotate(180deg)]", + }, + }, + content: { + bg: "white", + rounded: "sm", + boxShadow: "[0px 8px 16px rgba(0, 0, 0, 0.08)]", + border: "secondary", + overflow: "hidden", + zIndex: "50", + minWidth: "[var(--radix-select-trigger-width)]", + }, + search: { + display: "flex", + alignItems: "center", + gap: "2", + px: "3", + py: "2", + borderBottom: "[1px solid #E5E1DD]", + color: "text.lighter", + }, + searchInput: { + width: "full", + minW: "0", + outline: "none", + color: "text.default", + textStyle: "label.md.default", + "&::placeholder": { + color: "text.lighter", + }, + }, + viewport: { + maxHeight: "[360px]", + overflowY: "auto", + py: "1", + }, + groupLabel: { + px: "3", + pt: "3", + pb: "1", + textStyle: "label.sm.default", + color: "text.lighter", + textTransform: "uppercase", + }, + item: { + display: "flex", + alignItems: "center", + gap: "2", + textStyle: "label.md.default", + color: "text.default", + cursor: "pointer", + outline: "none", + userSelect: "none", + + "&[data-highlighted]": { + bg: "bg.primary-alternative", + }, + "&[data-state='checked']": { + bg: "bg.primary-alternative", + }, + }, + itemIndicator: { + color: "brand.primary", + display: "flex", + alignItems: "center", + flexShrink: "0", + }, + empty: { + px: "3", + py: "4", + textStyle: "label.md.default", + color: "text.lighter", + }, + }, + variants: { + size: { + md: { + trigger: { px: "3", py: "3" }, + item: { px: "3", py: "3" }, + }, + sm: { + trigger: { px: "3", py: "1" }, + item: { px: "3", py: "3" }, + }, + }, + }, + defaultVariants: { + size: "md", + }, +}); + +const technicalId = css({ + color: "text.lighter", + textStyle: "label.sm.default", + whiteSpace: "nowrap", +}); + +function labelMatches(option: SelectOption, query: string) { + const normalizedQuery = normalizeEntityText(query); + if (!normalizedQuery) return true; + + const haystacks = [option.id, option.text, option.shortText ?? ""] + .map((value) => normalizeEntityText(value)) + .filter(Boolean); + + if (haystacks.some((value) => value.includes(normalizedQuery))) return true; + + const labelTokens = haystacks.flatMap((value) => value.split(" ")); + return normalizedQuery + .split(" ") + .every((queryToken) => + labelTokens.some((labelToken) => labelToken.includes(queryToken)), + ); +} + +function buildSections( + options: SelectOption[], + query: string, + currentCategory?: string, +): LabelSection[] { + const optionById = new Map(options.map((option) => [option.id, option])); + const seen = new Set(); + const categories = currentCategory + ? [ + currentCategory, + ...ANONYMIZER_CATEGORY_NAMES.filter( + (category) => category !== currentCategory, + ), + ] + : ANONYMIZER_CATEGORY_NAMES; + + return categories + .map((category) => { + const labels = getAnonymizerLabelsForCategory(category) + .map((label) => optionById.get(label.id)) + .filter((label): label is SelectOption => !!label) + .filter((label) => { + if (seen.has(label.id)) return false; + return labelMatches(label, query); + }); + + labels.forEach((label) => seen.add(label.id)); + + return { category, labels }; + }) + .filter((section) => section.labels.length > 0); +} + +export default function AnonymizerLabelSelect({ + options, + value, + onChange, + onOpenChange, + placeholder = "", + disabled = false, + size = "md", + currentCategory, +}: AnonymizerLabelSelectProps) { + const [query, setQuery] = useState(""); + const [open, setOpen] = useState(false); + const triggerId = useId(); + const searchInputRef = useRef(null); + const classes = select({ size }); + + const selectedOption = options.find((option) => option.id === value); + const sections = useMemo( + () => buildSections(options, query, currentCategory), + [currentCategory, options, query], + ); + + useEffect(() => { + if (!open) return; + const timer = window.setTimeout( + () => searchInputRef.current?.focus({ preventScroll: true }), + 0, + ); + return () => window.clearTimeout(timer); + }, [open]); + + const handleOpenChange = (nextOpen: boolean) => { + setOpen(nextOpen); + onOpenChange?.(nextOpen); + if (!nextOpen) setQuery(""); + }; + + const handleChange = (id: string) => { + const option = options.find((item) => item.id === id); + if (option) onChange?.(option); + }; + + return ( +

    + + + {/* biome-ignore lint/a11y/useSemanticElements lint/a11y/useAriaPropsForRole: Radix merges role, aria-expanded, aria-controls, and tabIndex onto this div at runtime via asChild */} +
    + + {selectedOption?.shortText ?? selectedOption?.text ?? placeholder} + + + +
    +
    + + + +
    + + { + setQuery(event.target.value); + window.requestAnimationFrame(() => + searchInputRef.current?.focus({ preventScroll: true }), + ); + }} + onPointerDown={(event) => event.stopPropagation()} + onKeyDownCapture={(event) => { + if (event.key !== "Escape") event.stopPropagation(); + }} + onKeyDown={(event) => { + if (event.key !== "Escape") event.stopPropagation(); + }} + /> +
    + + {sections.length === 0 ? ( +
    Sin resultados
    + ) : ( + sections.map((section) => ( + + + {section.category} + + {section.labels.map((option) => ( + + + + + + {option.text} + + {option.id} + + ))} + + )) + )} +
    +
    +
    +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx new file mode 100644 index 00000000..16c956d9 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/config-tab.tsx @@ -0,0 +1,232 @@ +import { HStack, Stack, styled } from "@/styled/jsx"; +import type { AnonymizerLabels } from "@/types/aymurai"; +import { useState } from "react"; + +import Button from "@/components/ui/button"; +import { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import Input from "@/components/ui/input"; +import BaseSwitch from "@/components/ui/switch"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { + ANONYMIZER_CATEGORY_NAMES, + getAnonymizerLabelsForCategory, +} from "@/constants/anonymizer-categories"; +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; +import { + useExcludedTagsConfig, + useExcludedTagsConfigActions, +} from "@/store/useLocal"; +import { css } from "@/styled/css"; +import { Trash } from "phosphor-react"; +import { Label } from "./label"; +import LabelManagerSection from "./section"; + +const iconButton = css({ + cursor: "pointer", + color: "text.lighter", + bg: "transparent", + border: "[1px solid #BCBAB8]", + rounded: "sm", + display: "flex", + alignItems: "center", + justifyContent: "center", + p: "1.5", + flexShrink: "0", + "&:hover": { + color: "white", + bg: "action.hover", + borderColor: "action.hover", + }, +}); + +const tooltipContent = css({ + bg: "action.hover", + color: "white", + px: "1.5", + py: "0.5", + rounded: "sm", + fontSize: "[12px]", + boxShadow: "[none]", +}); + +interface ToggleProps { + name: string; + value: boolean; + onToggle: (value: boolean) => void; +} +function Switch({ name, value, onToggle }: ToggleProps) { + return ( + + + + + {name} + + + + + + Incluir o excluir esta categoría de la anonimización + + + ); +} + +interface LabelConfigTabProps { + expandedSections: Record; + onSectionOpenChange: (section: string, open: boolean) => void; +} + +const EXCLUDED_TERMS_SECTION = "Términos excluidos"; + +export default function LabelConfigTab({ + expandedSections, + onSectionOpenChange, +}: LabelConfigTabProps) { + const { tags: storedTags, words: storedWords } = useExcludedTagsConfig(); + const { setTags, setWords } = useExcludedTagsConfigActions(); + + const [toggles, setToggles] = useState>( + storedTags ?? EXCLUDED_TAGS, + ); + const [excludedWords, setExcludedWords] = useState(storedWords); + const [inputValue, setInputValue] = useState(""); + const [clearDialogOpen, setClearDialogOpen] = useState(false); + + function handleToggle(id: string, value: boolean) { + const next = { ...toggles, [id]: value }; + setToggles(next); + setTags(next as Record); + } + + function handleAddWord() { + const trimmed = inputValue.trim(); + if (!trimmed || excludedWords.includes(trimmed)) return; + const next = [...excludedWords, trimmed]; + setExcludedWords(next); + setWords(next); + setInputValue(""); + } + + function handleRemoveWord(word: string) { + const next = excludedWords.filter((w) => w !== word); + setExcludedWords(next); + setWords(next); + } + + function handleClearAllWords() { + setExcludedWords([]); + setWords([]); + } + + return ( + + + {ANONYMIZER_CATEGORY_NAMES.map((category, index) => ( + + {index > 0 && } + onSectionOpenChange(category, open)} + > + + {getAnonymizerLabelsForCategory(category).map((label) => ( + handleToggle(label.id, value)} + /> + ))} + + + + ))} + + + onSectionOpenChange(EXCLUDED_TERMS_SECTION, open) + } + headerAction={ + excludedWords.length > 0 ? ( + + ) : undefined + } + > + + + setInputValue(e.target.value)} + onKeyDown={(e) => e.key === "Enter" && handleAddWord()} + /> + + + {excludedWords.length > 0 && ( + + {excludedWords.map((word) => ( + + ))} + + )} + + + + + + Borrar términos excluidos + + + Esta acción no se puede deshacer. ¿Deseas continuar? + + + + + + + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx new file mode 100644 index 00000000..91e6c096 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/entity-tab.tsx @@ -0,0 +1,959 @@ +import AnonymizerLabelSelect from "@/components/anonymizer/anonymizer-label-select"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { + ANONYMIZER_CATEGORY_NAMES, + getAnonymizerCategoryForLabel, + getLabelsPrioritizingCategory, +} from "@/constants/anonymizer-categories"; +import { useFileDispatch, useFiles } from "@/hooks"; +import { useEntityGroups } from "@/hooks/useEntityGroups"; +import { + mergeGroups, + moveMentionToGroup, + removePredictionValueByCanonicalId, + removePredictionsByCanonicalId, + updatePredictionsByCanonicalId, +} from "@/reducers/file/actions"; +import { useHoverState } from "@/store/useHoverState"; +import { css } from "@/styled/css"; +import { HStack, Stack, styled } from "@/styled/jsx"; +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; +import { + DndContext, + type DragEndEvent, + type DragOverEvent, + DragOverlay, + type DragStartEvent, + KeyboardSensor, + PointerSensor, + closestCenter, + useDraggable, + useSensor, + useSensors, +} from "@dnd-kit/core"; +import { + SortableContext, + arrayMove, + sortableKeyboardCoordinates, + verticalListSortingStrategy, +} from "@dnd-kit/sortable"; +import { + ArrowsLeftRight, + DotsSixVertical, + PlusCircle, + Trash, + Warning, + XCircle, +} from "phosphor-react"; +import { useEffect, useMemo, useState } from "react"; + +import type { EntityGroup } from "@/hooks/useEntityGroups"; +import { + useExcludedTagsConfig, + useGroupOrder, + useGroupOrderActions, +} from "@/store/useLocal"; +import { normalizeEntityText } from "@/utils/anonymizer/entity-similarity"; +import { filterActivePredictions } from "@/utils/anonymizer/predictions"; +import MergeDialog from "./merge-dialog"; +import RemoveDialog from "./remove-dialog"; +import LabelManagerSection from "./section"; +import SortableGroup from "./sortable-group"; + +function normalizeText(t: string) { + return normalizeEntityText(t); +} + +const GROUP_PREFIX = "group:"; +const TEXT_PREFIX = "text:"; + +function groupDndId(id: string) { + return `${GROUP_PREFIX}${id}`; +} +function textDndId(canonicalId: string, normText: string) { + return `${TEXT_PREFIX}${canonicalId}:::${normText}`; +} +function parseGroupDndId(id: string): string | null { + return id.startsWith(GROUP_PREFIX) ? id.slice(GROUP_PREFIX.length) : null; +} +function parseTextDndId( + id: string, +): { canonicalId: string; text: string } | null { + if (!id.startsWith(TEXT_PREFIX)) return null; + const rest = id.slice(TEXT_PREFIX.length); + const sep = rest.indexOf(":::"); + if (sep === -1) return null; + return { canonicalId: rest.slice(0, sep), text: rest.slice(sep + 3) }; +} + +const iconButton = css({ + cursor: "pointer", + color: "text.lighter", + bg: "transparent", + border: "[1px solid #BCBAB8]", + rounded: "sm", + display: "flex", + alignItems: "center", + justifyContent: "center", + p: "1.5", + flexShrink: "0", + "&:hover": { + color: "white", + bg: "action.hover", + borderColor: "action.hover", + }, +}); + +const suffixBadge = css({ + display: "inline-flex", + alignItems: "center", + justifyContent: "center", + px: "1.5", + py: "0.5", + bg: "[#E6E8FF]", + color: "[#3F479D]", + rounded: "xs", + fontVariantNumeric: "tabular-nums", + userSelect: "none", + flexShrink: "1", + minW: "0", + maxW: "full", + overflowWrap: "anywhere", + wordBreak: "break-word", + whiteSpace: "normal", + textAlign: "right", + fontSize: "[11px]", + fontWeight: "bold", + letterSpacing: "wide", +}); + +const textItemSplitHighlight = { + bg: "[#D9DCFF]", + boxShadow: "[inset 0 0 0 1px #8A92D8]", +} as const; + +const textItemConfirmingSplitHighlight = { + bg: "[#C8CDF8]", + boxShadow: "[inset 0 0 0 2px #6F78CE]", +} as const; + +const textItemStyle = css({ + display: "flex", + alignItems: "flex-start", + gap: "1", + px: "1.5", + py: "0.5", + bg: "bg.primary-alternative", + rounded: "xs", + minW: "0", + w: "full", + boxSizing: "border-box", + "&:hover": textItemSplitHighlight, +}); + +const textItemDraggingStyle = css({ opacity: "0.35" }); +const textItemPendingSplitStyle = css(textItemSplitHighlight); +const textItemConfirmingSplitStyle = css({ + ...textItemConfirmingSplitHighlight, + "&:hover": textItemConfirmingSplitHighlight, +}); + +const textContextMenu = css({ + position: "fixed", + zIndex: "60", + minW: "[150px]", + bg: "bg.primary", + border: "[1px solid #BCBAB8]", + rounded: "sm", + boxShadow: "[0_8px_20px_rgba(17,0,65,0.14)]", + p: "1", +}); + +const textContextMenuButton = css({ + display: "flex", + alignItems: "center", + gap: "1.5", + w: "full", + px: "2", + py: "1.5", + bg: "transparent", + border: "none", + rounded: "xs", + cursor: "pointer", + color: "text.default", + textStyle: "label.md.default", + textAlign: "left", + "&:hover": { + bg: "[#D9DCFF]", + color: "[#1B0D58]", + }, + "&:focus-visible": { + outline: "[2px solid #3F479D]", + outlineOffset: "[1px]", + }, +}); + +const groupCardStyle = css({ + bg: "bg.primary", + border: "[1px solid #BCBAB8]", + rounded: "sm", + minW: "0", + w: "full", +}); + +// Used for both drag-over drop target and hover — same inset outline + violet bg +const groupHoverStyle = css({ + bg: "bg.primary-alternative", + boxShadow: "[inset 0 0 0 2px #3F479D]", +}); + +const duplicateBadge = css({ + display: "inline-flex", + alignItems: "center", + gap: "1", + px: "1.5", + py: "0.5", + bg: "[#ECEEFF]", + color: "[#3F479D]", + border: "[1px solid #7B84D4]", + rounded: "xs", + fontSize: "[11px]", + fontWeight: "semibold", + cursor: "pointer", + maxW: "full", + minW: "0", + overflow: "hidden", + "& > span": { + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + }, + "&:hover": { bg: "[#D8DBFF]" }, +}); + +const groupHeader = css({ + display: "flex", + alignItems: "center", + justifyContent: "space-between", + gap: "1", + minW: "0", +}); + +const groupHeaderLeft = css({ + display: "flex", + alignItems: "center", + minW: "0", + flex: "1", + overflow: "hidden", +}); + +interface DraggableTextChipProps { + canonicalId: string; + normalizedText: string; + displayText: string; + onRemove: () => void; + onCreateGroup: (position: { x: number; y: number }) => void; + canCreateGroup: boolean; + isSplitTarget: boolean; + isSplitActionHovered: boolean; +} + +function DraggableTextChip({ + canonicalId, + normalizedText, + displayText, + onRemove, + onCreateGroup, + canCreateGroup, + isSplitTarget, + isSplitActionHovered, +}: DraggableTextChipProps) { + const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ + id: textDndId(canonicalId, normalizedText), + data: { type: "text", canonicalId, text: normalizedText, displayText }, + }); + + return ( +
    { + if (!canCreateGroup) return; + event.preventDefault(); + event.stopPropagation(); + onCreateGroup({ x: event.clientX, y: event.clientY }); + }} + > + + + {displayText} + + +
    + ); +} + +function TextChipOverlay({ text }: { text: string }) { + return ( +
    + + {text} +
    + ); +} + +interface LabelEntityTabProps { + expandedGroups: Record; + expandedSections: Record; + onDerivedGroupRemove: (canonicalId: string) => void; + onDerivedValueRemove: (canonicalId: string, value: string) => void; + onDerivedLabelChange: ( + canonicalId: string, + labelId: string | undefined, + ) => void; + onGroupOpenChange: (canonicalId: string, open: boolean) => void; + onSectionOpenChange: (section: string, open: boolean) => void; +} + +export default function LabelEntityTab({ + expandedGroups, + expandedSections, + onDerivedGroupRemove, + onDerivedValueRemove, + onDerivedLabelChange, + onGroupOpenChange, + onSectionOpenChange, +}: LabelEntityTabProps) { + const files = useFiles(); + const dispatch = useFileDispatch(); + const { tags, words } = useExcludedTagsConfig(); + const activeFiles = useMemo( + () => + files.map((file) => ({ + ...file, + predictions: filterActivePredictions(file.predictions, tags, words), + })), + [files, tags, words], + ); + const groups = useEntityGroups(activeFiles); + const { + hoveredCanonicalId, + lastEditedCanonicalId, + setHoveredCanonicalId, + setLastEditedCanonicalId, + } = useHoverState(); + + const { groupOrder } = useGroupOrder(); + const { setGroupOrder } = useGroupOrderActions(); + + const [pendingRemoval, setPendingRemoval] = useState<{ + canonicalId: string; + label: string; + } | null>(null); + const [pendingMerge, setPendingMerge] = useState<{ + source: EntityGroup; + target: EntityGroup; + } | null>(null); + const [activeTextDrag, setActiveTextDrag] = useState<{ + normalizedText: string; + displayText: string; + fromCanonicalId: string; + } | null>(null); + const [overGroupId, setOverGroupId] = useState(null); + const [textMenu, setTextMenu] = useState<{ + x: number; + y: number; + canonicalId: string; + normalizedText: string; + } | null>(null); + const [textMenuActionHovered, setTextMenuActionHovered] = useState(false); + + const sensors = useSensors( + useSensor(PointerSensor, { activationConstraint: { distance: 5 } }), + useSensor(KeyboardSensor, { + coordinateGetter: sortableKeyboardCoordinates, + }), + ); + + const groupsByCategory = useMemo(() => { + const result: Record = Object.fromEntries( + ANONYMIZER_CATEGORY_NAMES.map((c) => [c, []]), + ); + for (const g of groups) { + const cat = getAnonymizerCategoryForLabel(g.renderBase); + result[cat] ??= []; + result[cat].push(g); + } + return result; + }, [groups]); + + useEffect(() => { + if (!textMenu) return; + + const close = () => { + setTextMenu(null); + setTextMenuActionHovered(false); + }; + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") close(); + }; + + window.addEventListener("click", close); + window.addEventListener("contextmenu", close); + window.addEventListener("keydown", handleKeyDown); + window.addEventListener("scroll", close, true); + + return () => { + window.removeEventListener("click", close); + window.removeEventListener("contextmenu", close); + window.removeEventListener("keydown", handleKeyDown); + window.removeEventListener("scroll", close, true); + }; + }, [textMenu]); + + function getOrderedGroups(category: string): EntityGroup[] { + const catGroups = groupsByCategory[category] ?? []; + const order = groupOrder?.[category]; + if (!order) return catGroups; + const byId = new Map(catGroups.map((g) => [g.canonicalId, g])); + const ordered: EntityGroup[] = []; + for (const id of order) { + const g = byId.get(id); + if (g) { + ordered.push(g); + byId.delete(id); + } + } + for (const g of byId.values()) ordered.push(g); + return ordered; + } + + function handleDragStart(event: DragStartEvent) { + const data = event.active.data.current; + if (data?.type === "text") { + setActiveTextDrag({ + normalizedText: data.text, + displayText: data.displayText ?? data.text, + fromCanonicalId: data.canonicalId, + }); + } + } + + function handleDragOver(event: DragOverEvent) { + if (!activeTextDrag) { + setOverGroupId(null); + return; + } + const overId = event.over?.id as string | undefined; + if (!overId) { + setOverGroupId(null); + return; + } + const groupId = + parseGroupDndId(overId) ?? parseTextDndId(overId)?.canonicalId ?? null; + setOverGroupId(groupId); + } + + function handleDragEnd(event: DragEndEvent) { + const { active, over } = event; + setActiveTextDrag(null); + setOverGroupId(null); + if (!over) return; + + const activeId = active.id as string; + const overId = over.id as string; + const textParsed = parseTextDndId(activeId); + + if (textParsed) { + const targetCanonicalId = + parseGroupDndId(overId) ?? parseTextDndId(overId)?.canonicalId ?? null; + if (!targetCanonicalId || targetCanonicalId === textParsed.canonicalId) + return; + const sourceGroup = groups.find( + (g) => g.canonicalId === textParsed.canonicalId, + ); + const targetGroup = groups.find( + (g) => g.canonicalId === targetCanonicalId, + ); + if (!sourceGroup || !targetGroup) return; + for (const mention of sourceGroup.mentions.filter( + (m) => normalizeText(m.text) === normalizeText(textParsed.text), + )) { + dispatch( + moveMentionToGroup( + mention.mentionId, + targetGroup.canonicalId, + targetGroup.renderBase as AllLabels | AllLabelsWithSufix, + ), + ); + } + setLastEditedCanonicalId(targetGroup.canonicalId); + return; + } + + const groupParsed = parseGroupDndId(activeId); + if (groupParsed) { + const targetCanonicalId = parseGroupDndId(overId); + if (!targetCanonicalId || targetCanonicalId === groupParsed) return; + const sourceGroup = groups.find((g) => g.canonicalId === groupParsed); + if (!sourceGroup) return; + const category = getAnonymizerCategoryForLabel(sourceGroup.renderBase); + if (!category) return; + const orderedGroups = getOrderedGroups(category); + const ids = orderedGroups.map((g) => g.canonicalId); + const oldIdx = ids.indexOf(groupParsed); + const newIdx = ids.indexOf(targetCanonicalId); + if (oldIdx === -1 || newIdx === -1) return; + setGroupOrder({ + ...groupOrder, + [category]: arrayMove(ids, oldIdx, newIdx), + }); + } + } + + function handleLabelChange(canonicalId: string, labelId: string | undefined) { + if (!labelId) return; + dispatch( + updatePredictionsByCanonicalId( + canonicalId, + labelId as AllLabels | AllLabelsWithSufix, + ), + ); + onDerivedLabelChange(canonicalId, labelId); + setLastEditedCanonicalId(canonicalId); + } + + function handleRemoveValue(canonicalId: string, normalizedText: string) { + dispatch(removePredictionValueByCanonicalId(canonicalId, normalizedText)); + onDerivedValueRemove(canonicalId, normalizedText); + } + + function handleCreateGroupFromText() { + if (!textMenu) return; + + const sourceGroup = groups.find( + (group) => group.canonicalId === textMenu.canonicalId, + ); + if (!sourceGroup) { + setTextMenu(null); + setTextMenuActionHovered(false); + return; + } + + const targetCanonicalId = crypto.randomUUID(); + const targetLabel = sourceGroup.renderBase as + | AllLabels + | AllLabelsWithSufix; + const mentionsToSplit = sourceGroup.mentions.filter( + (mention) => normalizeText(mention.text) === textMenu.normalizedText, + ); + if (mentionsToSplit.length === 0) { + setTextMenu(null); + setTextMenuActionHovered(false); + return; + } + + for (const mention of mentionsToSplit) { + dispatch( + moveMentionToGroup(mention.mentionId, targetCanonicalId, targetLabel), + ); + } + + const category = getAnonymizerCategoryForLabel(sourceGroup.renderBase); + const existingOrder = groupOrder?.[category]; + if (existingOrder) { + const sourceIndex = existingOrder.indexOf(sourceGroup.canonicalId); + const nextOrder = existingOrder.filter((id) => id !== targetCanonicalId); + nextOrder.splice( + sourceIndex === -1 ? nextOrder.length : sourceIndex + 1, + 0, + targetCanonicalId, + ); + setGroupOrder({ ...groupOrder, [category]: nextOrder }); + } + + setLastEditedCanonicalId(targetCanonicalId); + setTextMenu(null); + setTextMenuActionHovered(false); + } + + function confirmRemoval() { + if (!pendingRemoval) return; + dispatch(removePredictionsByCanonicalId(pendingRemoval.canonicalId)); + onDerivedGroupRemove(pendingRemoval.canonicalId); + setPendingRemoval(null); + } + + function confirmMerge() { + if (!pendingMerge) return; + dispatch( + mergeGroups( + pendingMerge.source.canonicalId, + pendingMerge.target.canonicalId, + pendingMerge.target.renderBase as AllLabels | AllLabelsWithSufix, + ), + ); + setPendingMerge(null); + setLastEditedCanonicalId(null); + } + + return ( + <> + { + if (!open) setPendingRemoval(null); + }} + onConfirm={confirmRemoval} + /> + setPendingMerge(null)} + onConfirm={confirmMerge} + /> + + + {textMenu && ( +
    event.stopPropagation()} + onContextMenu={(event) => { + event.preventDefault(); + event.stopPropagation(); + }} + onPointerEnter={() => setTextMenuActionHovered(true)} + onPointerLeave={() => setTextMenuActionHovered(false)} + > + +
    + )} + + + {ANONYMIZER_CATEGORY_NAMES.map((category, i) => { + const orderedGroups = getOrderedGroups(category); + if (orderedGroups.length === 0) return null; + const labelOptions = getLabelsPrioritizingCategory(category); + + return ( + + {i > 0 && } + onSectionOpenChange(category, open)} + > + + + groupDndId(g.canonicalId), + )} + strategy={verticalListSortingStrategy} + > + {orderedGroups.map((group) => { + const isDropTarget = + activeTextDrag !== null && + overGroupId === group.canonicalId; + const duplicatePrimary = group.duplicateOf + ? groups.find( + (g) => g.canonicalId === group.duplicateOf, + ) + : null; + + // When the user recently edited THIS group and it became a primary with a + // duplicate pointing to it, show the badge on this group instead. + const reverseDuplicate = + !group.isDuplicate && + group.canonicalId === lastEditedCanonicalId + ? (groups.find( + (g) => + g.isDuplicate && + g.duplicateOf === group.canonicalId, + ) ?? null) + : null; + const badgeTarget = + reverseDuplicate ?? duplicatePrimary; + const isGroupOpen = + expandedGroups[group.canonicalId] ?? true; + + return ( + + onGroupOpenChange(group.canonicalId, !isGroupOpen) + } + toggleLabel={ + isGroupOpen + ? `Colapsar ${group.renderToken}` + : `Expandir ${group.renderToken}` + } + > + + setHoveredCanonicalId(group.canonicalId) + } + onMouseLeave={() => setHoveredCanonicalId(null)} + > +
    +
    + {badgeTarget && ( + + + + + + + Grupo idéntico a{" "} + {badgeTarget.renderToken}. Clic para + unificar. + + + + )} +
    + + {group.renderToken} + +
    + + +
    + + handleLabelChange( + group.canonicalId, + opt.id, + ) + } + /> +
    + +
    + + {isGroupOpen && ( + + {group.uniqueTexts.flatMap((normText, idx) => + group.displayTexts[idx].map((verbatim) => ( + + handleRemoveValue( + group.canonicalId, + normText, + ) + } + canCreateGroup={ + group.mentions.length > 1 + } + onCreateGroup={(position) => { + setTextMenu({ + ...position, + canonicalId: group.canonicalId, + normalizedText: normText, + }); + setTextMenuActionHovered(false); + }} + isSplitTarget={ + textMenu?.canonicalId === + group.canonicalId && + textMenu.normalizedText === normText + } + isSplitActionHovered={ + textMenuActionHovered + } + /> + )), + )} + {group.uniqueTexts.length === 0 && ( + + Sin menciones + + )} + + )} +
    +
    + ); + })} +
    +
    +
    +
    + ); + })} +
    + + + {activeTextDrag && ( + + )} + +
    + + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/index.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/index.tsx new file mode 100644 index 00000000..f556ca9a --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/index.tsx @@ -0,0 +1,190 @@ +import { useState } from "react"; + +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { useFileDispatch } from "@/hooks"; +import { + removePredictionValueByCanonicalId, + removePredictionsByCanonicalId, + updatePredictionsByCanonicalId, +} from "@/reducers/file/actions"; +import { css, sva } from "@/styled/css"; +import { HStack } from "@/styled/jsx"; +import { stack } from "@/styled/patterns"; +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; +import LabelConfigTab from "./config-tab"; +import LabelEntityTab from "./entity-tab"; +import LabelManagerTab from "./tab"; + +type ExpandedState = Record; + +const styles = sva({ + slots: ["container", "header", "body", "close"], + base: { + container: { + ...stack.raw({ gap: "0" }), + width: "[400px]", + maxWidth: "[400px]", + h: "full", + minH: "0", + flexShrink: "0", + overflow: "hidden", + overflowX: "hidden", + + bg: "bg.primary", + }, + header: { + px: "5", + py: "6", + pb: "4", + flexShrink: "0", + bg: "bg.primary", + borderBottom: "[1px solid #BCBAB8]", + zIndex: "1", + }, + body: { + px: "5", + pt: "6", + pb: "6", + flex: "1", + minH: "0", + overflowY: "auto", + overflowX: "hidden", + }, + close: { + cursor: "pointer", + }, + }, +}); + +const tooltipContent = css({ + bg: "action.hover", + color: "white", + px: "1.5", + py: "0.5", + rounded: "sm", + fontSize: "[12px]", + boxShadow: "[none]", +}); + +interface LabelManagerProps { + onClose: () => void; +} +export default function LabelManager({ onClose }: LabelManagerProps) { + const [selectedTab, setSelectedTab] = useState<"entity" | "config">("entity"); + const [expandedEntitySections, setExpandedEntitySections] = + useState({}); + const [expandedEntityGroups, setExpandedEntityGroups] = + useState({}); + const [expandedConfigSections, setExpandedConfigSections] = + useState({}); + const dispatch = useFileDispatch(); + + const classes = styles(); + + function handleDerivedGroupRemove(canonicalId: string) { + dispatch(removePredictionsByCanonicalId(canonicalId)); + } + + function handleDerivedValueRemove(canonicalId: string, value: string) { + dispatch(removePredictionValueByCanonicalId(canonicalId, value)); + } + + function handleDerivedLabelChange( + canonicalId: string, + labelId: string | undefined, + ) { + if (!labelId) return; + dispatch( + updatePredictionsByCanonicalId( + canonicalId, + labelId as AllLabels | AllLabelsWithSufix, + ), + ); + } + + function handleEntitySectionOpenChange(section: string, open: boolean) { + setExpandedEntitySections((prev) => ({ ...prev, [section]: open })); + } + + function handleEntityGroupOpenChange(canonicalId: string, open: boolean) { + setExpandedEntityGroups((prev) => ({ ...prev, [canonicalId]: open })); + } + + function handleConfigSectionOpenChange(section: string, open: boolean) { + setExpandedConfigSections((prev) => ({ ...prev, [section]: open })); + } + + return ( +
    + + + + + + setSelectedTab("entity")} + > + Entidades + + + + Revisar, editar y organizar los grupos de entidades reconocidos + + + + + setSelectedTab("config")} + > + Configuración + + + + Elegir qué categorías anonimizar y definir términos excluidos + + + + + + + + + Cerrar gestor de etiquetas + + + + +
    + {selectedTab === "entity" ? ( + + ) : ( + + )} +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/label.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/label.tsx new file mode 100644 index 00000000..45b25748 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/label.tsx @@ -0,0 +1,40 @@ +import { css } from "@/styled/css"; +import { HStack, styled } from "@/styled/jsx"; +import { XCircle } from "phosphor-react"; + +interface LabelProps { + children: string | string[]; + onRemove: () => void; +} +export function Label({ children, onRemove }: LabelProps) { + return ( + + {children} + + + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/merge-dialog.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/merge-dialog.tsx new file mode 100644 index 00000000..f84a1ce0 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/merge-dialog.tsx @@ -0,0 +1,48 @@ +import Button from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogTitle, +} from "@/components/ui/dialog"; +import type { EntityGroup } from "@/hooks/useEntityGroups"; + +interface MergeDialogProps { + source: EntityGroup | null; + target: EntityGroup | null; + onClose: () => void; + onConfirm: () => void; +} + +export default function MergeDialog({ + source, + target, + onClose, + onConfirm, +}: MergeDialogProps) { + return ( + { + if (!open) onClose(); + }} + > + + Unificar grupos + {source && target && ( +

    + ¿Deseas unificar {source.renderToken} con{" "} + {target.renderToken}?
    + Todas las menciones de {source.renderToken} pasarán a + pertenecer a {target.renderToken} y el grupo original será + eliminado. +

    + )} + + + + +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/remove-dialog.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/remove-dialog.tsx new file mode 100644 index 00000000..c6d82475 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/remove-dialog.tsx @@ -0,0 +1,36 @@ +import Button from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogTitle, +} from "@/components/ui/dialog"; + +interface RemoveDialogProps { + isOpen: boolean; + label: string; + onClose: (open: boolean) => void; + onConfirm: () => void; +} +export default function RemoveDialog({ + isOpen, + onClose, + onConfirm, + label, +}: RemoveDialogProps) { + return ( + + + Eliminar todas las ocurrencias +

    + ¿Deseas eliminar todas las ocurrencias del grupo con la etiqueta{" "} + {label}? +

    + + + + +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/section.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/section.tsx new file mode 100644 index 00000000..6055e2e1 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/section.tsx @@ -0,0 +1,76 @@ +import { useState } from "react"; + +import { css } from "@/styled/css"; +import { HStack, Stack, styled } from "@/styled/jsx"; +import { CaretUp } from "phosphor-react"; + +const header = css({ + cursor: "pointer", +}); + +const caret = css({ + transition: "transform", + transitionDuration: "[0.2s]", + transitionTimingFunction: "[ease]", +}); + +const contentOuter = css({ + display: "grid", + transition: "[grid-template-rows]", + transitionDuration: "[0.3s]", + transitionTimingFunction: "[ease]", +}); + +const contentInner = css({ + minHeight: "[0]", + overflow: "hidden", +}); + +interface SectionProps { + children: React.ReactNode; + open?: boolean; + onOpenChange?: (open: boolean) => void; + title: string; + headerAction?: React.ReactNode; +} +export default function LabelManagerSection({ + open: controlledOpen, + onOpenChange, + title: sectionTitle, + children, + headerAction, +}: SectionProps) { + const [uncontrolledOpen, setUncontrolledOpen] = useState(true); + const open = controlledOpen ?? uncontrolledOpen; + + function toggleOpen() { + const nextOpen = !open; + onOpenChange?.(nextOpen); + if (controlledOpen === undefined) setUncontrolledOpen(nextOpen); + } + + return ( + + + +
    + +
    + + {sectionTitle} + +
    + {headerAction} +
    +
    +
    {children}
    +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/sortable-group.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/sortable-group.tsx new file mode 100644 index 00000000..988657f8 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/sortable-group.tsx @@ -0,0 +1,103 @@ +import { css } from "@/styled/css"; +import { useSortable } from "@dnd-kit/sortable"; +import { CSS } from "@dnd-kit/utilities"; +import { DotsSixVertical } from "phosphor-react"; +import { type PointerEvent, type ReactNode, useRef } from "react"; + +const handle = css({ + cursor: "grab", + color: "text.lighter", + display: "flex", + alignItems: "center", + p: "0", + bg: "transparent", + border: "none", + "&:hover": { color: "text.default" }, + "&:active": { cursor: "grabbing" }, +}); + +const wrapper = css({ + display: "flex", + alignItems: "flex-start", + gap: "2", + minW: "0", + w: "full", + transition: "[opacity 0.2s, box-shadow 0.2s]", +}); + +const content = css({ + flex: "1", + minW: "0", +}); + +interface SortableGroupProps { + id: string; + children: ReactNode; + isOpen?: boolean; + onToggleOpen?: () => void; + toggleLabel?: string; +} + +export default function SortableGroup({ + id, + children, + isOpen, + onToggleOpen, + toggleLabel, +}: SortableGroupProps) { + const pointerStartRef = useRef<{ x: number; y: number } | null>(null); + const movedRef = useRef(false); + const { + attributes, + listeners, + setNodeRef, + transform, + transition, + isDragging, + } = useSortable({ id }); + + const style = { + transform: CSS.Transform.toString(transform), + transition, + opacity: isDragging ? 0.5 : 1, + boxShadow: isDragging ? "0 4px 12px rgba(0,0,0,0.15)" : "none", + }; + + function handlePointerDown(event: PointerEvent) { + pointerStartRef.current = { x: event.clientX, y: event.clientY }; + movedRef.current = false; + } + + function handlePointerMove(event: PointerEvent) { + const pointerStart = pointerStartRef.current; + if (!pointerStart) return; + + const dx = event.clientX - pointerStart.x; + const dy = event.clientY - pointerStart.y; + if (Math.hypot(dx, dy) > 4) movedRef.current = true; + } + + function handleClick() { + if (movedRef.current) return; + onToggleOpen?.(); + } + + return ( +
    + +
    {children}
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/anonymizer/label-manager/tab.tsx b/frontend/src/renderer/src/components/anonymizer/label-manager/tab.tsx new file mode 100644 index 00000000..926897e2 --- /dev/null +++ b/frontend/src/renderer/src/components/anonymizer/label-manager/tab.tsx @@ -0,0 +1,33 @@ +import { Tab } from "@/components/tabs"; +import { css } from "@/styled/css"; +import { type ButtonHTMLAttributes, forwardRef } from "react"; + +const button = css({ + cursor: "pointer", +}); + +interface LabelManagerTabProps + extends Omit, "children"> { + children: string; + onClick: () => void; + isSelected: boolean; +} +const LabelManagerTab = forwardRef( + function LabelManagerTab({ onClick, children, isSelected, ...props }, ref) { + return ( + + ); + }, +); + +export default LabelManagerTab; diff --git a/frontend/src/renderer/src/components/arrow/LeftArrow.tsx b/frontend/src/renderer/src/components/arrow/LeftArrow.tsx new file mode 100644 index 00000000..5ba65537 --- /dev/null +++ b/frontend/src/renderer/src/components/arrow/LeftArrow.tsx @@ -0,0 +1,13 @@ +export default function LeftArrow() { + return ( + + + + ); +} diff --git a/frontend/src/renderer/src/components/arrow/RightArrow.tsx b/frontend/src/renderer/src/components/arrow/RightArrow.tsx new file mode 100644 index 00000000..446b8a6f --- /dev/null +++ b/frontend/src/renderer/src/components/arrow/RightArrow.tsx @@ -0,0 +1,16 @@ +export default function RightArrow() { + return ( + + + + ); +} diff --git a/frontend/src/renderer/src/components/arrow/index.ts b/frontend/src/renderer/src/components/arrow/index.ts new file mode 100644 index 00000000..e1939cb8 --- /dev/null +++ b/frontend/src/renderer/src/components/arrow/index.ts @@ -0,0 +1,9 @@ +import LeftArrow from "./LeftArrow"; +import RightArrow from "./RightArrow"; + +const Arrow = { + Right: RightArrow, + Left: LeftArrow, +}; + +export default Arrow; diff --git a/frontend/src/renderer/src/components/brand/built-by.tsx b/frontend/src/renderer/src/components/brand/built-by.tsx new file mode 100644 index 00000000..dd7a4a79 --- /dev/null +++ b/frontend/src/renderer/src/components/brand/built-by.tsx @@ -0,0 +1,29 @@ +import { DATAGENERO_URL } from "@/constants/config"; +import { styled } from "@/styled/jsx"; +import { type StackStyles, stack } from "@/styled/patterns"; +import { useTranslation } from "react-i18next"; + +interface BuiltByProps { + size?: number; + gap?: StackStyles["gap"]; +} +export default function BuiltBy({ size = 150, gap = "2" }: BuiltByProps) { + const { t } = useTranslation(); + return ( +
    + + {t("platformBuiltBy")} + + DataGenero isologo + + ); +} diff --git a/frontend/src/renderer/src/components/checkbox/checkbox-group/CheckboxGroup.styles.ts b/frontend/src/renderer/src/components/checkbox/checkbox-group/CheckboxGroup.styles.ts new file mode 100644 index 00000000..f727702b --- /dev/null +++ b/frontend/src/renderer/src/components/checkbox/checkbox-group/CheckboxGroup.styles.ts @@ -0,0 +1,30 @@ +import { styled } from "@/styles"; + +export const Legend = styled("legend", { + fontWeight: "$default", + fontSize: "$subtitleSm", + lineHeight: "$subtitleSm", + color: "$textLighter", + + mb: "$xs", +}); + +export const Group = styled("fieldset", { + display: "flex", + gap: "$m", + flexWrap: "wrap", + + variants: { + direction: { + horizontal: { + flexDirection: "row", + }, + vertical: { + flexDirection: "column", + }, + }, + }, + defaultVariants: { + direction: "horizontal", + }, +}); diff --git a/frontend/src/renderer/src/components/checkbox/checkbox-group/index.tsx b/frontend/src/renderer/src/components/checkbox/checkbox-group/index.tsx new file mode 100644 index 00000000..93d4fc96 --- /dev/null +++ b/frontend/src/renderer/src/components/checkbox/checkbox-group/index.tsx @@ -0,0 +1,39 @@ +import { + Children, + type ReactElement, + type ReactNode, + cloneElement, + isValidElement, +} from "react"; + +import type { Props as CheckboxProps } from "../checkbox"; +import { Group, Legend } from "./CheckboxGroup.styles"; + +interface Props { + children: ReactNode; + title?: string; + name: string; + direction?: "horizontal" | "vertical"; +} +export default function CheckboxGroup({ + title, + name, + direction = "horizontal", + children, +}: Props) { + // Inject the name to the children + const checkboxWithName = Children.map(children, (child) => { + if (isValidElement(child)) { + return cloneElement(child as ReactElement, { + name, + }); + } + }); + + return ( + + {title && {title}} + {checkboxWithName} + + ); +} diff --git a/frontend/src/renderer/src/components/checkbox/checkbox/Checkbox.styles.ts b/frontend/src/renderer/src/components/checkbox/checkbox/Checkbox.styles.ts new file mode 100644 index 00000000..c29cec78 --- /dev/null +++ b/frontend/src/renderer/src/components/checkbox/checkbox/Checkbox.styles.ts @@ -0,0 +1,143 @@ +import { styled } from "@/styles"; + +export const Input = styled("input", { + position: "absolute", + top: 0, + left: 0, + + opacity: 0, +}); + +export const Checkbox = styled("div", { + display: "flex", + alignItems: "center", + justifyContent: "center", + + width: 18, + height: 18, + p: 1, + + borderRadius: "$xs", + boxSizing: "border-box", +}); + +export const Wrapper = styled("label", { + // Unchecked + $$checkbox_bg_default: "$colors$white", + $$checkbox_border_default: "$sizes$xxs solid $colors$actionDefaultAlt", + // hover + $$checkbox_bgHover_default: "$colors$white", + $$checkbox_borderHover_default: "1px solid $colors$borderPrimary", + // disabled + $$checkbox_bgDisabled_default: "$colors$actionDisabled", + $$checkbox_borderDisabled_default: "$sizes$xxs solid $colors$borderPrimary", + // focus + $$checkbox_bgFocus_default: "$colors$white", + $$checkbox_borderFocus_default: "1px solid $colors$borderPrimary", + + // Checked + $$checkbox_bg_checked: "$colors$actionDefaultAlt", + $$checkbox_border_checked: "none", + // hover + $$checkbox_bgHover_checked: "$colors$actionHover", + $$checkbox_borderHover_checked: "none", + // disabled + $$checkbox_bgDisabled_checked: "$colors$actionDisabled", + $$checkbox_borderDisabled_checked: "none", + // focus + $$checkbox_bgFocus_checked: "$colors$actionDefaultAlt", + $$checkbox_borderFocus_checked: "none", + + // Focus + $$checkbox_outlineFocus_noText: "3px solid $colors$borderPrimaryAlt", + $$checkbox_outlineFocus_Text: "3px solid $colors$borderPrimary", + + position: "relative", + + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "$s", + + transitionDuration: "$transitions$s", + transitionProperty: "outline, border-radius, border", + transitionTimingFunction: "ease", + + variants: { + hasText: { + true: { + p: "$s", + "&:focus-within": { + outline: "$$checkbox_outlineFocus_Text", + borderRadius: "3px", + }, + }, + false: { + "&:focus-within": { + outline: "$$checkbox_outlineFocus_noText", + borderRadius: "$xs", + }, + // Focus for checkbox + [`& > input:checked:focus-visible + ${Checkbox}`]: { + bg: "$$checkbox_bgFocus_checked", + b: "$$checkbox_borderFocus_checked", + }, + [`& > input:focus-visible + ${Checkbox}`]: { + bg: "$$checkbox_bgFocus_default", + b: "$$checkbox_borderFocus_default", + }, + }, + }, + isDisabled: { + true: { + "&, & > *": { + cursor: "not-allowed", + }, + }, + false: { + "&, & > *": { + cursor: "pointer", + }, + }, + }, + }, + defaultVariants: { + hasText: false, + isDisabled: false, + }, + + // Checkbox styles + [`& > ${Checkbox}`]: { + b: "$$checkbox_border_default", + bg: "$$checkbox_bg_default", + }, + [`& > input:checked + ${Checkbox}`]: { + bg: "$$checkbox_bg_checked", + border: "$$checkbox_border_checked", + }, + + // Hide SVG when unchecked + [`& > input:not(:checked) + ${Checkbox} svg`]: { + display: "none", + }, + + // Hover + [`&:hover > ${Checkbox}`]: { + b: "$$checkbox_borderHover_default", + bg: "$$checkbox_bgHover_default", + }, + [`&:hover > input:checked + ${Checkbox}`]: { + b: "$$checkbox_borderHover_checked", + bg: "$$checkbox_bgHover_checked", + }, + + // Disabled + [`& > input:disabled + ${Checkbox}`]: { + bg: "$$checkbox_bgDisabled_default", + b: "$$checkbox_borderDisabled_default", + }, + [`& > input:checked:disabled + ${Checkbox}`]: { + bg: "$$checkbox_bgDisabled_checked", + b: "$$checkbox_borderDisabled_checked", + }, +}); diff --git a/frontend/src/renderer/src/components/checkbox/checkbox/index.tsx b/frontend/src/renderer/src/components/checkbox/checkbox/index.tsx new file mode 100644 index 00000000..37568f73 --- /dev/null +++ b/frontend/src/renderer/src/components/checkbox/checkbox/index.tsx @@ -0,0 +1,65 @@ +import { Check } from "phosphor-react"; +import { + type ChangeEventHandler, + type ReactNode, + forwardRef, + useImperativeHandle, + useState, +} from "react"; + +import type { CSS } from "@/styles"; +import { colors } from "@/styles/tokens"; +import { Input, Checkbox as StyledCheckbox, Wrapper } from "./Checkbox.styles"; + +export interface Props { + children?: ReactNode; + disabled?: boolean; + checked?: boolean; + onChange?: (value: boolean) => void; + name?: string; + css?: CSS; +} +export default forwardRef<{ value: boolean }, Props>(function Checkbox( + { disabled = false, checked = false, name, onChange, children, css }, + ref, +) { + const [isChecked, setIsChecked] = useState(checked); + + const hasText = !!children; + + // Only exposes `value` object to the parent component + useImperativeHandle( + ref, + () => { + return { + value: isChecked, + }; + }, + [isChecked], + ); + + const handleToggle: ChangeEventHandler = (e) => { + setIsChecked(e.target.checked); + onChange?.(isChecked); + }; + + const iconColor = disabled + ? colors.textOnButtonDisabled + : colors.textOnButtonAlternative; + + return ( + + + + + + {children} + + ); +}); diff --git a/frontend/src/renderer/src/components/checkbox/index.ts b/frontend/src/renderer/src/components/checkbox/index.ts new file mode 100644 index 00000000..eebc899c --- /dev/null +++ b/frontend/src/renderer/src/components/checkbox/index.ts @@ -0,0 +1,4 @@ +import Checkbox from "./checkbox"; +import CheckboxGroup from "./checkbox-group"; + +export { Checkbox, CheckboxGroup }; diff --git a/frontend/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts b/frontend/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts new file mode 100644 index 00000000..0dd8c7a1 --- /dev/null +++ b/frontend/src/renderer/src/components/decision-tabs/DecisionTabs.styles.ts @@ -0,0 +1,16 @@ +import { styled } from "@/styles"; + +export const PlusButton = styled("button", { + boxShadow: "4px 0px 4px rgba(0, 0, 0, 0.05)", + + // Marked as important because of Stitches hierarchy + px: "$s !important", + py: "$s !important", + // b: '2px solid $actionDefaultAlt', + width: 48, + height: 51, + "&:disabled": { + boxShadow: "none", + color: "$textLighter", + }, +}); diff --git a/frontend/src/renderer/src/components/decision-tabs/index.tsx b/frontend/src/renderer/src/components/decision-tabs/index.tsx new file mode 100644 index 00000000..a6520c8d --- /dev/null +++ b/frontend/src/renderer/src/components/decision-tabs/index.tsx @@ -0,0 +1,52 @@ +import { Tab, TabName } from "@/components"; +import { css } from "@/styled/css"; +import { Stack } from "@/styled/jsx"; +import nArray from "@/utils/nArray"; +import { Plus } from "phosphor-react"; + +const button = css({ + cursor: "pointer", + p: "2", + display: "flex", + alignItems: "center", + justifyContent: "center", + + height: "full", + width: "12", +}); + +interface Props { + selected: number; + decisionAmount: number; + addDecision: () => void; + selectDecision: (n: number) => void; +} +export default function DecisionTabs({ + selected, + decisionAmount, + addDecision, + selectDecision, +}: Props) { + const decisionArr = nArray(decisionAmount, undefined).map((_, i) => i); + + const selectDecisionHandler = (n: number) => () => selectDecision(n); + + return ( + + {decisionArr.map((dec) => ( + + Decisión {dec + 1} + + ))} + + + ); +} diff --git a/frontend/src/renderer/src/components/dialog/index.tsx b/frontend/src/renderer/src/components/dialog/index.tsx new file mode 100644 index 00000000..16c2539c --- /dev/null +++ b/frontend/src/renderer/src/components/dialog/index.tsx @@ -0,0 +1,109 @@ +import { styled } from "@/styles"; +import { X } from "phosphor-react"; +import type { FC, ReactNode } from "react"; +import Button from "../ui/button"; + +export interface DialogOption { + id: string; + label: string; + action: () => void; +} + +interface DialogProps { + isOpen: boolean; + title?: string; + message?: string; + options?: DialogOption[]; + onClose: () => void; + children?: ReactNode; +} + +export const Overlay = styled("div", { + position: "fixed", + top: 0, + left: 0, + right: 0, + bottom: 0, + backgroundColor: "rgba(0, 0, 0, 0.5)", + display: "flex", + alignItems: "center", + justifyContent: "center", + zIndex: 1000, +}); + +export const DialogContainer = styled("div", { + backgroundColor: "$white", + borderRadius: "$xs", + padding: "$l", + minWidth: 300, + maxWidth: 700, + boxShadow: "0px 4px 8px rgba(0, 0, 0, 0.1)", +}); + +export const DialogHeader = styled("div", { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + marginBottom: "$m", +}); + +export const DialogTitle = styled("h3", { + fontSize: "$titleMd", + fontWeight: 600, + color: "$textDefault", + margin: 0, +}); + +export const DialogMessage = styled("label", { + color: "$textDefault", + marginBottom: "$l", +}); + +export const DialogButtons = styled("div", { + display: "flex", + gap: "$s", + justifyContent: "flex-end", + alignItems: "center", + marginTop: "$xl", +}); + +const Dialog: FC = ({ + isOpen, + title = "", + message, + options, + onClose, + children, +}) => { + if (!isOpen) return null; + + return ( + + e.stopPropagation()}> + + {title} + + + {message && {message}} + {children} + {options && options.length > 0 && ( + + {options.map((option, index) => ( + + ))} + + )} + + + ); +}; + +export default Dialog; diff --git a/frontend/src/renderer/src/components/drop-area.tsx b/frontend/src/renderer/src/components/drop-area.tsx new file mode 100644 index 00000000..4226066f --- /dev/null +++ b/frontend/src/renderer/src/components/drop-area.tsx @@ -0,0 +1,153 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; +import { css, cva } from "@/styled/css"; +import { Stack, styled } from "@/styled/jsx"; +import { File } from "phosphor-react"; +import { useCallback, useRef, useState } from "react"; + +function FileIcon() { + return ( + + + + ); +} + +const styles = cva({ + base: { + display: "flex", + flexDirection: "column", + alignItems: "center", + justifyContent: "center", + gap: "8", + + w: "full", + h: "[335px]", + p: "8", + + rounded: "sm", + border: "primary", + + bg: "[#F3F4FF]", + cursor: "pointer", + + transitionProperty: "[border-color, background-color, box-shadow]", + transitionTimingFunction: "default", + transitionDuration: "normal", + }, + variants: { + dragging: { + true: { + borderColor: "brand.primary", + bg: "bg.primary-alternative", + boxShadow: "[0px 0px 15px 0px #3F479D66]", + }, + }, + }, +}); + +interface DropAreaProps { + onDropFiles: (files: File[]) => void; + title: string; + description: string; + multiple?: boolean; +} + +export default function DropArea({ + onDropFiles, + title, + description, + multiple = true, +}: DropAreaProps) { + const [dragging, setDragging] = useState(false); + const inputRef = useRef(null); + const dragCounter = useRef(0); + + const accept = WHITELISTED_EXTENSIONS.map((ext) => `.${ext}`).join(","); + + const handleFiles = useCallback( + (fileList: FileList) => { + const files = Array.from(fileList).filter((file) => { + const ext = file.name.split(".").pop()?.toLowerCase(); + return ext && WHITELISTED_EXTENSIONS.includes(ext); + }); + if (files.length > 0) onDropFiles(files); + }, + [onDropFiles], + ); + + const handleDragEnter = useCallback((e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + dragCounter.current++; + setDragging(true); + }, []); + + const handleDragLeave = useCallback((e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + dragCounter.current--; + if (dragCounter.current === 0) setDragging(false); + }, []); + + const handleDragOver = useCallback((e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + }, []); + + const handleDrop = useCallback( + (e: React.DragEvent) => { + e.preventDefault(); + e.stopPropagation(); + dragCounter.current = 0; + setDragging(false); + if (e.dataTransfer.files.length > 0) { + handleFiles(e.dataTransfer.files); + } + }, + [handleFiles], + ); + + const handleClick = () => inputRef.current?.click(); + + const handleChange: React.ChangeEventHandler = (e) => { + if (e.target.files) handleFiles(e.target.files); + }; + + return ( +
    + + + + {title} + + + {description} + + + +
    + ); +} diff --git a/frontend/src/renderer/src/components/feature-icon.tsx b/frontend/src/renderer/src/components/feature-icon.tsx new file mode 100644 index 00000000..d83f1d5b --- /dev/null +++ b/frontend/src/renderer/src/components/feature-icon.tsx @@ -0,0 +1,65 @@ +import { cva } from "@/styled/css"; +import { stack } from "@/styled/patterns"; +import type { FeatureFlowEnum } from "@/types/features"; +import { FEATURE_ICON } from "@/utils/config"; +import type { Icon } from "phosphor-react"; + +const styles = cva({ + base: { + ...stack.raw({ align: "center", justify: "center" }), + p: "4", + borderRadius: "[14px]", + }, + variants: { + disabled: { + true: { + bg: "bg.secondary", + color: "text.lighter", + }, + false: { + color: "text.default", + bg: "bg.primary-alternative", + }, + }, + size: { + lg: { + width: "[70px]", + height: "[70px]", + p: "[14px]", + rounded: "[14px]", + }, + sm: { + width: "10", + height: "10", + p: "2", + rounded: "lg", + }, + }, + }, + defaultVariants: { + disabled: false, + size: "lg", + }, +}); + +type FeatureIconProps = { + size: "lg" | "sm"; + disabled?: boolean; +} & ( + | { feature: FeatureFlowEnum; icon?: never } + | { feature?: never; icon: Icon } +); + +export default function FeatureIcon({ + feature, + size, + icon: OverrideIcon, + disabled = false, +}: FeatureIconProps) { + const Icon = OverrideIcon ?? FEATURE_ICON[feature]; + return ( +
    + +
    + ); +} diff --git a/frontend/src/renderer/src/components/features-menu.tsx b/frontend/src/renderer/src/components/features-menu.tsx new file mode 100644 index 00000000..3a158668 --- /dev/null +++ b/frontend/src/renderer/src/components/features-menu.tsx @@ -0,0 +1,64 @@ +import { useFileDispatch } from "@/hooks/useFiles"; +import { removeAllFiles } from "@/reducers/file/actions"; +import { Grid, Stack, styled } from "@/styled/jsx"; +import { FeatureFlowEnum, featureNamespace, getFeatureRouteSlug } from "@/types/features"; +import { Link } from "@tanstack/react-router"; +import { DotsNine, Gear } from "phosphor-react"; +import { useTranslation } from "react-i18next"; +import FeatureIcon from "./feature-icon"; +import Button from "./ui/button"; +import Card from "./ui/card"; +import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; + +export default function FeaturesMenu() { + const { t } = useTranslation(); + const dispatch = useFileDispatch(); + const features = Object.values(FeatureFlowEnum); + + const handleClearFiles = () => { + dispatch(removeAllFiles()); + }; + + return ( + + + + + + + {features.map((feature) => ( + + + + + + {t("title", { ns: featureNamespace[feature] })} + + + + + ))} + + + + + + + {t("settings")} + + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts b/frontend/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts new file mode 100644 index 00000000..5c825801 --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/FileAnnotator.styles.ts @@ -0,0 +1,30 @@ +import { styled } from "@/styles"; + +export const Container = styled("div", { + flex: 1, + minWidth: 0, + // boxShadow: "0px 0px 10px rgba(0, 0, 0, 0.1)", + + zIndex: 1, + display: "flex", + flexDirection: "column", + overflow: "hidden", +}); + +export const File = styled("div", { + flex: 1, + overflowY: "scroll", + px: "$xl", + pb: "$xl", + // pt: "$l", + + "& p, & span, & em": { + fontFamily: "$file", + fontSize: 16, + lineHeight: "160%", + }, +}); + +export const Paragraph = styled("p", { + margin: "8px 0px", +}); diff --git a/frontend/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx b/frontend/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx new file mode 100644 index 00000000..93c909ed --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/SearchBar/Counter.tsx @@ -0,0 +1,66 @@ +import { css } from "@/styled/css"; +import { Stack, styled } from "@/styled/jsx"; +import { + CaretDown as NextIcon, + CaretUp as PreviousIcon, + XCircle, +} from "phosphor-react"; + +import { Button } from "@/components"; + +const counterClass = css({ + display: "flex", + alignItems: "center", + gap: "1", +}); + +interface Props { + count: number; + cursor: number; + next: () => void; + previous: () => void; + clear: () => void; + isSearching: boolean; +} + +export const Counter = ({ + count, + previous, + next, + cursor, + clear, + isSearching, +}: Props) => { + if (!isSearching) return null; + + return ( +
    + + + + + {count === 0 ? "0 ocurrencias" : `${cursor} de ${count}`} + + + + + +
    + ); +}; diff --git a/frontend/src/renderer/src/components/file-annotator/SearchBar/SearchBar.styles.ts b/frontend/src/renderer/src/components/file-annotator/SearchBar/SearchBar.styles.ts new file mode 100644 index 00000000..81c2e7eb --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/SearchBar/SearchBar.styles.ts @@ -0,0 +1,94 @@ +import { styled } from "@/styles"; + +export const WrapperSearch = styled("div", { + display: "flex", + alignItems: "center", + flexDirection: "row", + gap: "$s", + + p: 12, + height: 48, + + bg: "$bgSecondary", + border: "1px solid $borderPrimary", + borderRadius: "$xl", + + cursor: "text", + + "&:focus-within": { + border: "1px solid $borderPrimaryAlt", + boxShadow: "0px 2px 2px rgba(0, 0, 0, 0.16)", + }, +}); + +export const ContainerLabel = styled("div", { + display: "flex", + justifyContent: "space-between", + alignItems: "center", + gap: "$s", + width: "100%", +}); + +export const WrapperLabel = styled("div", { + width: "100%", +}); + +export const WrapperSufixLabel = styled("div", { + display: "flex", + alignItems: "center", + flexDirection: "row", + gap: "$s", + + p: 12, + height: 48, + + bg: "$bgSecondary", + border: "1px solid $borderPrimary", + + cursor: "text", + + "&:focus-within": { + border: "1px solid $borderPrimaryAlt", + boxShadow: "0px 2px 2px rgba(0, 0, 0, 0.16)", + }, +}); + +export const InputContainer = styled("div", { + display: "flex", + alignItems: "center", + gap: "$xxs", + flex: 1, +}); + +export const Input = styled("input", { + flex: 1, + + fontSize: "$labelMd", + lineHeight: "$LabelMd", + color: "$textDefault", + + p: 0, + width: "$xxl", + + border: "none", + outline: "none", +}); + +export const Counter = styled("div", { + display: "flex", + alignItems: "center", + gap: "$xxs", +}); + +export const SuggestionContainer = styled("div", { + display: "flex", + gap: "$s", +}); + +export const Suggestion = styled("mark", { + backgroundColor: "$bgSecondaryAlt", + fontFamily: "$primary", + padding: "0px $sizes$s", + borderRadius: "$s", + cursor: "pointer", +}); diff --git a/frontend/src/renderer/src/components/file-annotator/SearchBar/index.tsx b/frontend/src/renderer/src/components/file-annotator/SearchBar/index.tsx new file mode 100644 index 00000000..c8c66b2d --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/SearchBar/index.tsx @@ -0,0 +1,198 @@ +import { + type ChangeEvent, + type KeyboardEvent, + useEffect, + useRef, + useState, +} from "react"; + +import AnonymizerLabelSelect from "@/components/anonymizer/anonymizer-label-select"; +import Button from "@/components/ui/button"; +import type { SelectOption } from "@/components/ui/select"; +import { useExcludedTagsConfig } from "@/store/useLocal"; +import { sva } from "@/styled/css"; +import { Grid, HStack, styled } from "@/styled/jsx"; +import { hstack } from "@/styled/patterns"; +import { getActiveAnonymizerLabelOptions } from "@/utils/anonymizer/labels"; +import { MagnifyingGlass } from "phosphor-react"; +import { SEARCH_MIN_LENGTH } from "../annotations"; +import { Counter } from "./Counter"; + +const searchClasses = sva({ + slots: ["searchBar", "input", "verticalHr"], + base: { + searchBar: { + ...hstack.raw({ alignItems: "center", gap: "2" }), + height: "12", + p: "3", + rounded: "3xl", + // minWidth: "[450px]", + width: "full", + border: "primary", + }, + input: { + outline: "none", + width: "full", + }, + verticalHr: { + width: "[1px]", + alignSelf: "stretch", + borderWidth: "0", + backgroundColor: "[#BCBAB8]", + height: "12", + }, + }, +}); + +interface Props { + isAnnotable?: boolean; + isLabelManagerOpen: boolean; + onSearchChange?: (value: string) => void; + onLabelChange?: (object: SelectOption | undefined) => void; + labelValue?: string; + onLabelManagerToggle: () => void; + matchesCount: number; + activeIndex: number | null; + onNext: () => void; + onPrevious: () => void; + onFocusDocument: () => void; +} + +export const SearchBar = ({ + isAnnotable = false, + isLabelManagerOpen, + onSearchChange, + onLabelChange, + labelValue, + onLabelManagerToggle, + matchesCount, + activeIndex, + onNext, + onPrevious, + onFocusDocument, +}: Props) => { + const [search, setSearch] = useState(""); + const { tags } = useExcludedTagsConfig(); + + const inputSearchRef = useRef(null); + + const classes = searchClasses(); + const labelOptions = getActiveAnonymizerLabelOptions(tags); + + useEffect(() => { + const isEditableTarget = (target: EventTarget | null) => { + if (!(target instanceof HTMLElement)) return false; + if (target === inputSearchRef.current) return false; + if (target.isContentEditable) return true; + return ["INPUT", "TEXTAREA", "SELECT"].includes(target.tagName); + }; + + const handleKeyDown = (event: globalThis.KeyboardEvent) => { + const isSearchShortcut = + (event.ctrlKey || event.metaKey) && + !event.altKey && + !event.shiftKey && + event.key.toLowerCase() === "b"; + + if (!isSearchShortcut || isEditableTarget(event.target)) return; + + event.preventDefault(); + inputSearchRef.current?.focus(); + inputSearchRef.current?.select(); + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, []); + + const changeSearchHandler = (e: ChangeEvent) => { + const text = e.target.value; + setSearch(text); + onSearchChange?.(e.target.value); + }; + + const clickSearchHandler = () => { + if (inputSearchRef.current) { + inputSearchRef.current.select(); + } + }; + + const handleClear = () => { + setSearch(""); + onSearchChange?.(""); + }; + + const handleInputKeyDown = (event: KeyboardEvent) => { + if (event.key !== "Escape") return; + event.preventDefault(); + handleClear(); + onFocusDocument(); + }; + + const searchFocus = () => inputSearchRef.current?.focus(); + + const changeLabelSelectHandler = (e: SelectOption | undefined) => { + onLabelChange?.(e); + }; + + return ( + +
    + + + + + = SEARCH_MIN_LENGTH} + /> +
    + {isAnnotable && ( + +
    + + Aplicar etiquetas + +
    + +
    + {!isLabelManagerOpen && ( + <> +
    + + + )} +
    + )} +
    + ); +}; diff --git a/frontend/src/renderer/src/components/file-annotator/annotations.ts b/frontend/src/renderer/src/components/file-annotator/annotations.ts new file mode 100644 index 00000000..de14b733 --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/annotations.ts @@ -0,0 +1,171 @@ +import type { + AllLabels, + AllLabelsWithSufix, + PredictLabel, +} from "@/types/aymurai"; +import type { Paragraph } from "@/types/file"; +import { includes } from "@/utils/regex"; +import type { Annotation } from "./types"; + +export const SEARCH_MIN_LENGTH = 3; + +export interface SearchMatch { + id: string; + paragraphId: string; + start: number; + end: number; + index: number; +} + +/** + * Converts a predict label to an annotation + * @param labels List of predict labels from the API + * @returns List of annotations + */ +const labelToAnnotation = (labels: PredictLabel[]): Annotation[] => { + return labels.map( + ({ start_char, end_char, attrs, paragraphId, mentionId }) => ({ + start: start_char, + end: end_char, + type: "tag", + tag: attrs.aymurai_label, + paragraphId, + canonical_entity_id: attrs.canonical_entity_id, + mentionId, + }), + ); +}; + +/** + * Finds the indexes where the search string is found in the paragraph + * @param paragraph Paragraph to search in + * @param search Search string + * @returns List of indexes where the search string is found + */ +const findSearchIndexes = (paragraph: string, search: string) => { + const regex = includes(search); + + const indexes: number[] = []; + let match = regex.exec(paragraph); + + while (match) { + indexes.push(match.index); + match = regex.exec(paragraph); + } + + return indexes; +}; + +/** + * Appends search annotations to the list of label annotations + * @param arr List of label annotations + * @param search Search string + * @param paragraph Paragraph to search in + * @returns List of annotations with search annotations appended + */ +const getSearchAnnotations = ( + searchMatches: SearchMatch[], + label: AllLabels | AllLabelsWithSufix | null, + activeSearchMatchId: string | null, +): Annotation[] => { + return searchMatches.map( + (match) => + ({ + start: match.start, + end: match.end, + type: "search", + tag: label, + paragraphId: match.paragraphId, + searchMatchId: match.id, + searchIndex: match.index, + isActive: match.id === activeSearchMatchId, + }) as Annotation, + ); +}; + +/** + * Converts the predictions array into a map with the paragraph id as key + * @param predictions List of labels predicted by AymurAI + * @returns A map with the paragraph id as key and an array of predictions as value + */ +export const predictionsToMap = ( + predictions: PredictLabel[], +): Map => { + const map = new Map(); + + for (const token of predictions) { + // Ignore characters + if ([":", ",", ".", ")", "(", "-", "_"].includes(token.text)) continue; + + const paragraphPredictions = map.get(token.paragraphId); + if (paragraphPredictions) { + paragraphPredictions.push(token); + } else { + map.set(token.paragraphId, [token]); + } + } + + return map; +}; + +export const createSearchMatches = ( + paragraphs: Paragraph[], + search: string, +): SearchMatch[] => { + if (!search || search.length < SEARCH_MIN_LENGTH) return []; + + const matches: SearchMatch[] = []; + paragraphs.forEach((paragraph) => { + const indexes = findSearchIndexes(paragraph.value, search); + indexes.forEach((start) => { + const index = matches.length; + matches.push({ + id: `${paragraph.id}:${start}:${index}`, + paragraphId: paragraph.id, + start, + end: start + search.length, + index, + }); + }); + }); + + return matches; +}; + +export const searchMatchesToMap = ( + matches: SearchMatch[], +): Map => { + const map = new Map(); + + for (const match of matches) { + const paragraphMatches = map.get(match.paragraphId) ?? []; + paragraphMatches.push(match); + map.set(match.paragraphId, paragraphMatches); + } + + return map; +}; + +/** + * Transform the predictions made by AymurAI into annotations. Also append each search result as an annotation. + * @param predictions List of AymurAI predictions + * @param search Search string + * @param paragraph Paragraph to analyze + * @param searchLabel Label to assign to the search annotations + * @returns List of annotations ready to be displayed + */ +export const createAnnotationsWithSearch = ( + predictions: PredictLabel[], + searchMatches: SearchMatch[], + searchLabel: AllLabels | AllLabelsWithSufix | null, + activeSearchMatchId: string | null, +): Annotation[] => { + const matchingAnnotations = labelToAnnotation(predictions); + const searchAnnotations = getSearchAnnotations( + searchMatches, + searchLabel, + activeSearchMatchId, + ); + + return [...matchingAnnotations, ...searchAnnotations]; +}; diff --git a/frontend/src/renderer/src/components/file-annotator/generateSplits.ts b/frontend/src/renderer/src/components/file-annotator/generateSplits.ts new file mode 100644 index 00000000..24bb977a --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/generateSplits.ts @@ -0,0 +1,119 @@ +import type { Annotation, Split } from "./types"; + +const addTrailingText = (splits: Split[], i: number, { start }: Annotation) => { + if (start > i) { + splits.push({ + end: start, + start: i, + type: "text", + }); + } +}; +const addLeadingText = (splits: Split[], i: number, { length }: string) => { + if (i < length) { + splits.push({ + end: length, + start: i, + type: "text", + }); + } +}; + +const sortTokens = (tokens: Annotation[]) => { + return tokens.sort((a, b) => a.start - b.start); +}; +const rangesOverlap = (a: Annotation, b: Annotation) => { + return a.start < b.end && b.start < a.end; +}; +const isRightConflicting = (splits: Split[], token: Annotation) => { + return (splits.at(-1)?.end ?? 0) > token.start; +}; + +const isLeftConflicting = (token: Annotation, next: Annotation | undefined) => { + if (!next) return false; + + return ( + token.type === "search" && next.type === "tag" && token.end > next.start + ); +}; + +const mergeSearchIntoTags = (tokens: Annotation[]): Annotation[] => { + const tags = tokens.filter((token) => token.type === "tag"); + const searches = tokens.filter((token) => token.type === "search"); + const overlappingSearchIds = new Set(); + + const enrichedTags = tags.map((tag) => { + const overlappingSearches = searches.filter((search) => + rangesOverlap(tag, search), + ); + if (overlappingSearches.length === 0) return tag; + + for (const search of overlappingSearches) { + if (search.searchMatchId) overlappingSearchIds.add(search.searchMatchId); + } + + const activeSearch = + overlappingSearches.find((search) => search.isActive) ?? + overlappingSearches[0]; + + return { + ...tag, + searchMatchId: activeSearch?.searchMatchId, + searchIndex: activeSearch?.searchIndex, + isActive: activeSearch?.isActive ?? false, + }; + }); + + const visibleSearches = searches.filter( + (search) => + !search.searchMatchId || !overlappingSearchIds.has(search.searchMatchId), + ); + + return [...enrichedTags, ...visibleSearches]; +}; + +/** + * Generates a list of splits from a paragraph and a list of annotations + * @param paragraph Paragraph text to split + * @param tokens List of annotations + * @returns List of splits + */ +export const generateSplits = ( + paragraph: string, + tokens: Annotation[], +): Split[] => { + if (!tokens.length) + return [ + { + start: 0, + end: paragraph.length, + type: "text", + }, + ]; + + const sortedTokens = sortTokens(mergeSearchIntoTags(tokens)); + const splits: Split[] = []; + // Represents the last index used to split + let i = 0; + + sortedTokens.forEach((token, tokenIndex) => { + // Avoid token superposition on search tokens + if ( + isRightConflicting(splits, token) || + isLeftConflicting(token, sortedTokens[tokenIndex + 1]) + ) + return; + + // Add trailing text split if necessary + addTrailingText(splits, i, token); + + splits.push(token); + // Move the cursor to the last position + i = token.end; + }); + + // Add a remaining split if the `i` has not reached the end + addLeadingText(splits, i, paragraph); + + return splits; +}; diff --git a/frontend/src/renderer/src/components/file-annotator/index.tsx b/frontend/src/renderer/src/components/file-annotator/index.tsx new file mode 100644 index 00000000..fdce8da6 --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/index.tsx @@ -0,0 +1,269 @@ +import { + memo, + useCallback, + useEffect, + useMemo, + useRef, + useState, + useTransition, +} from "react"; + +import { SearchBar } from "./SearchBar"; + +import type { SelectOption } from "@/components/ui/select"; +import AnnotationProvider, { useAnnotation } from "@/context/Annotation"; +import { useExcludedTagsConfig } from "@/store/useLocal"; +import { css } from "@/styled/css"; +import { HStack } from "@/styled/jsx"; +import type { AllLabels, PredictLabel } from "@/types/aymurai"; +import type { DocFile, Paragraph as ParagraphType } from "@/types/file"; +import { getActiveAnonymizerLabelOptions } from "@/utils/anonymizer/labels"; +import { filterActivePredictions } from "@/utils/anonymizer/predictions"; +import LabelManager from "../anonymizer/label-manager"; +import SearchAnnotation from "../file/search-annotation"; +import TagAnnotation from "../file/tag-annotation"; +import * as S from "./FileAnnotator.styles"; +import { + type SearchMatch, + createAnnotationsWithSearch, + createSearchMatches, + predictionsToMap, + searchMatchesToMap, +} from "./annotations"; +import { generateSplits } from "./generateSplits"; + +const labelManagerWrapper = css({ + display: "flex", + h: "full", + minH: "0", + flexShrink: "0", + "&[hidden]": { + display: "none", + }, +}); + +interface ParagraphProps { + children: string; + paragraph: ParagraphType; + predictions: PredictLabel[]; + searchMatches: SearchMatch[]; + activeSearchMatchId: string | null; +} +const Paragraph = memo( + ({ + children, + paragraph, + predictions, + searchMatches, + activeSearchMatchId, + }: ParagraphProps) => { + const { label } = useAnnotation(); + + const annotations = useMemo(() => { + return createAnnotationsWithSearch( + predictions, + searchMatches, + label, + activeSearchMatchId, + ); + }, [predictions, searchMatches, label, activeSearchMatchId]); + + const splits = generateSplits(children, annotations); + + return ( + + {splits.map((s) => { + const content = children.slice(s.start, s.end); + const key = `${s.type}-${s.start}-${s.end}`; + + switch (s.type) { + case "search": + return ( + + {content} + + ); + case "tag": + return ( + + {content} + + ); + case "text": + default: + return ( + + {content} + + ); + } + })} + + ); + }, +); + +interface Props { + file: DocFile; + isAnnotable?: boolean; +} +export default function FileAnnotator({ file, isAnnotable = false }: Props) { + const [search, setSearch] = useState(""); + const [activeSearchIndex, setActiveSearchIndex] = useState( + null, + ); + const [, startTransition] = useTransition(); + const fileRef = useRef(null); + + const [label, setLabel] = useState(null); + const [labelManagerOpen, setLabelManagerOpen] = useState(isAnnotable); + + const paragraphs = file.paragraphs ?? []; + const { tags, words } = useExcludedTagsConfig(); + const activeLabelOptions = useMemo( + () => getActiveAnonymizerLabelOptions(tags), + [tags], + ); + + useEffect(() => { + if (label && !activeLabelOptions.some((option) => option.id === label)) { + setLabel(null); + } + }, [activeLabelOptions, label]); + + const filteredPredictions = useMemo( + () => filterActivePredictions(file.predictions, tags, words), + [file.predictions, tags, words], + ); + + const predictionsMap = useMemo( + () => predictionsToMap(filteredPredictions), + [filteredPredictions], + ); + + const searchMatches = useMemo( + () => createSearchMatches(paragraphs, search), + [paragraphs, search], + ); + + const searchMatchesMap = useMemo( + () => searchMatchesToMap(searchMatches), + [searchMatches], + ); + + const activeSearchMatch = + activeSearchIndex === null + ? null + : (searchMatches[activeSearchIndex] ?? null); + const activeSearchMatchId = activeSearchMatch?.id ?? null; + + useEffect(() => { + if (searchMatches.length === 0) { + setActiveSearchIndex(null); + return; + } + + setActiveSearchIndex(0); + }, [searchMatches]); + + useEffect(() => { + if (!activeSearchMatchId) return; + + const timer = window.setTimeout(() => { + const container = fileRef.current; + const element = Array.from( + container?.querySelectorAll("[data-search-match-id]") ?? [], + ).find((el) => el.getAttribute("data-search-match-id") === activeSearchMatchId); + if (!element || !container) return; + + const containerRect = container.getBoundingClientRect(); + const elementRect = element.getBoundingClientRect(); + const scrollOffset = + elementRect.top - + containerRect.top - + containerRect.height / 2 + + elementRect.height / 2; + + container.scrollBy({ + top: scrollOffset, + behavior: "smooth", + }); + }, 50); + + return () => window.clearTimeout(timer); + }, [activeSearchMatchId]); + + const selectChangeHandler = (option?: SelectOption) => { + setLabel((option?.id as AllLabels) ?? null); + }; + + const toggleManagerLabel = () => { + setLabelManagerOpen(!labelManagerOpen); + }; + + const handleSearchChange = (value: string) => { + startTransition(() => setSearch(value)); + }; + + const handleSearchNext = useCallback(() => { + setActiveSearchIndex((current) => { + if (searchMatches.length === 0) return null; + if (current === null) return 0; + return Math.min(current + 1, searchMatches.length - 1); + }); + }, [searchMatches.length]); + + const handleSearchPrevious = useCallback(() => { + setActiveSearchIndex((current) => { + if (searchMatches.length === 0) return null; + if (current === null) return 0; + return Math.max(current - 1, 0); + }); + }, [searchMatches.length]); + + const focusDocument = useCallback(() => { + fileRef.current?.focus(); + }, []); + + return ( + + + + + + {paragraphs.map((p) => ( + + {p.value} + + ))} + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/file-annotator/types.ts b/frontend/src/renderer/src/components/file-annotator/types.ts new file mode 100644 index 00000000..cf62be88 --- /dev/null +++ b/frontend/src/renderer/src/components/file-annotator/types.ts @@ -0,0 +1,39 @@ +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; + +export interface BaseAnnotation { + start: number; + end: number; +} + +interface BaseLabelAnnotation extends BaseAnnotation { + paragraphId: string; + tag?: AllLabels | AllLabelsWithSufix; + canonical_entity_id?: string | null; + mentionId?: string; + searchMatchId?: string; + searchIndex?: number; + isActive?: boolean; +} + +export interface LabelAnnotation extends BaseLabelAnnotation { + type: "tag"; +} + +export interface SearchAnnotation extends BaseLabelAnnotation { + type: "search"; +} + +export interface TextAnnotation extends BaseAnnotation { + type: "text"; +} + +export type Annotation = LabelAnnotation | SearchAnnotation | TextAnnotation; +export type Split = Annotation; + +export interface Metadata { + "data-start": number; + "data-end": number; + "data-tag"?: string; + "data-search-match-id"?: string; + "data-search-active"?: string; +} diff --git a/frontend/src/renderer/src/components/file-check/ErrorText.ts b/frontend/src/renderer/src/components/file-check/ErrorText.ts new file mode 100644 index 00000000..9626281f --- /dev/null +++ b/frontend/src/renderer/src/components/file-check/ErrorText.ts @@ -0,0 +1,13 @@ +import { styled } from "@/styles"; + +const ErrorText = styled("p", { + fontStyle: "italic", + color: "$errorPrimary", + textAlign: "center", + fontSize: "$subtitleSm", + lineHeight: "$subtitleSm", + fontWeight: "$default", + whiteSpace: "pre-line", +}); + +export default ErrorText; diff --git a/frontend/src/renderer/src/components/file-check/FileCheck.styles.ts b/frontend/src/renderer/src/components/file-check/FileCheck.styles.ts new file mode 100644 index 00000000..3ff2e007 --- /dev/null +++ b/frontend/src/renderer/src/components/file-check/FileCheck.styles.ts @@ -0,0 +1,53 @@ +import { styled } from "@/styles"; + +export const Wrapper = styled("div", { + display: "flex", + flexDirection: "column", + flexWrap: "wrap", + justifyContent: "center", + alignItems: "center", + gap: "$s", + + position: "relative", + + // Settings to enable ellipsis on file name + maxWidth: 150, + "& p": { + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + width: "100%", + }, +}); + +export const Card = styled("div", { + display: "flex", + flexDirection: "column", + flexWrap: "wrap", + justifyContent: "center", + alignItems: "center", + + height: 200, + width: 150, + + borderWidth: "$sizes$xs", + borderStyle: "solid", + borderRadius: "$s", + boxShadow: "0px 0px $sizes$xs rgba(0, 0, 0, 0.1)", + + variants: { + hasError: { + true: { + bg: "$errorSecondary", + borderColor: "$errorPrimary", + }, + false: { + bg: "$bgPrimary", + borderColor: "$borderPrimary", + }, + }, + }, + defaultVariants: { + hasError: false, + }, +}); diff --git a/frontend/src/renderer/src/components/file-check/Icon.tsx b/frontend/src/renderer/src/components/file-check/Icon.tsx new file mode 100644 index 00000000..9358703e --- /dev/null +++ b/frontend/src/renderer/src/components/file-check/Icon.tsx @@ -0,0 +1,14 @@ +import { Spinner } from "@/components"; +import { CheckCircle, XCircle } from "phosphor-react"; + +import { colors } from "@/styles/tokens"; + +interface Props { + hasError: boolean; + isLoading: boolean; +} +export default function Icon({ hasError, isLoading }: Props) { + if (hasError) return ; + if (isLoading) return ; + return ; +} diff --git a/frontend/src/renderer/src/components/file-check/index.tsx b/frontend/src/renderer/src/components/file-check/index.tsx new file mode 100644 index 00000000..a6b3467f --- /dev/null +++ b/frontend/src/renderer/src/components/file-check/index.tsx @@ -0,0 +1,27 @@ +import { Text } from "@/components"; +import ErrorText from "./ErrorText"; +import { Card, Wrapper } from "./FileCheck.styles"; +import Icon from "./Icon"; + +interface Props { + fileName: string; + hasError?: boolean; + isLoading?: boolean; + errorMessage?: string; +} +export default function FileCheck({ + fileName, + hasError = false, + isLoading = false, + errorMessage = "Error de guardado\nVolvé a cargar el archivo", +}: Props) { + return ( + + + + + {fileName} + {hasError && {errorMessage}} + + ); +} diff --git a/frontend/src/renderer/src/components/file-preview/FilePreview.styles.ts b/frontend/src/renderer/src/components/file-preview/FilePreview.styles.ts new file mode 100644 index 00000000..0e968ff1 --- /dev/null +++ b/frontend/src/renderer/src/components/file-preview/FilePreview.styles.ts @@ -0,0 +1,70 @@ +import { styled } from "@/styles"; + +export const Wrapper = styled("div", { + display: "flex", + flexDirection: "column", + flexWrap: "wrap", + justifyContent: "start", + alignItems: "center", + gap: "$s", + + position: "relative", + + // Settings to enable ellipsis on file name + maxWidth: 150, + "& p": { + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + width: "100%", + }, +}); + +export const FileContainer = styled("div", { + height: 200, + width: 150, + p: "$xs", + + boxShadow: "0px 0px $sizes$xs rgba(0, 0, 0, 0.1)", + borderRadius: "$s", + b: "$sizes$xs solid $borderPrimary", + + "& p, & span, & strong, & em": { + fontFamily: "$file", + fontSize: 8, + lineHeight: "100%", + my: "1em", + }, + + // Only shows text that fits into the box + overflow: "hidden", + + variants: { + isLoading: { + true: { + display: "flex", + alignItems: "center", + justifyContent: "center", + }, + false: {}, + }, + + error: { + true: { + borderColor: "$colors$errorPrimary", + backgroundColor: "$colors$errorSecondary", + }, + false: {}, + }, + }, +}); + +export const Paragraph = styled("p", { + fontFamily: "$file", + fontSize: "$s", + lineHeight: "$s", + margin: 0, + padding: 0, + whiteSpace: "pre-wrap", + wordBreak: "break-word", +}); diff --git a/frontend/src/renderer/src/components/file-preview/index.tsx b/frontend/src/renderer/src/components/file-preview/index.tsx new file mode 100644 index 00000000..765e6cfe --- /dev/null +++ b/frontend/src/renderer/src/components/file-preview/index.tsx @@ -0,0 +1,89 @@ +import { FileX } from "phosphor-react"; + +import { Checkbox, Spinner, Text } from "@/components"; +import { useFileDispatch } from "@/hooks"; +import type { PredictStatus } from "@/hooks/usePredict"; +import { toggleSelected } from "@/reducers/file/actions"; +import type { DocFile } from "@/types/file"; + +import { FeatureFlowEnum, parseFeatureRouteSlug } from "@/types/features"; +import { useParams } from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; +import * as S from "./FilePreview.styles"; + +interface Props { + file: DocFile; + status: PredictStatus; +} +export default function FilePreview({ file, status }: Props) { + const { feature: featureSlug } = useParams({ from: "/$feature/preview" }); + const feature = parseFeatureRouteSlug(featureSlug); + const { t } = useTranslation(); + const dispatch = useFileDispatch(); + + const isAnonymizer = feature === FeatureFlowEnum.Anonymizer; + const moreThanOneParagraph = file.paragraphs && file.paragraphs.length > 1; + const isError = status === "error"; + const isPending = status === "processing"; + + if (isError) { + return ( + + + + + + + {t("filePreview.loadError")} + + + ); + } + + if (isPending || !file.paragraphs) { + return ( + + + + + + ); + } + + return ( + + {!isAnonymizer && moreThanOneParagraph && ( + dispatch(toggleSelected(file.data.name))} + /> + )} + + + {file.paragraphs.map((p) => ( + + {p.value} + + ))} + + + + {file.data.name} + + + ); +} diff --git a/frontend/src/renderer/src/components/file-processing/FileProcessing.styles.ts b/frontend/src/renderer/src/components/file-processing/FileProcessing.styles.ts new file mode 100644 index 00000000..ec6c0d5c --- /dev/null +++ b/frontend/src/renderer/src/components/file-processing/FileProcessing.styles.ts @@ -0,0 +1,52 @@ +import { styled } from "@/styles"; + +export const BarContainer = styled("div", { + height: "$m", + width: "100%", + + bg: "$bgPrimary", + borderRadius: "$xxs", + + overflow: "hidden", +}); + +export const Bar = styled("div", { + width: "100%", + height: "100%", + + backgroundSize: "$sizes$xl $sizes$xl", + + transition: "width $s ease", + + variants: { + isCompleted: { + true: { + backgroundImage: `linear-gradient( + 135deg, + $actionDefaultAlt 37.50%, + $actionDefault 37.50%, + $actionDefault 50%, + $actionDefaultAlt 50%, + $actionDefaultAlt 87.50%, + $actionDefault 87.50%, + $actionDefault 100% + )`, + }, + false: { + backgroundImage: `linear-gradient( + 135deg, + $actionDefault 37.50%, + $actionDefaultAlt 37.50%, + $actionDefaultAlt 50%, + $actionDefault 50%, + $actionDefault 87.50%, + $actionDefaultAlt 87.50%, + $actionDefaultAlt 100% + )`, + }, + }, + }, + defaultVariants: { + isCompleted: false, + }, +}); diff --git a/frontend/src/renderer/src/components/file-processing/ProgressBar.tsx b/frontend/src/renderer/src/components/file-processing/ProgressBar.tsx new file mode 100644 index 00000000..222ee715 --- /dev/null +++ b/frontend/src/renderer/src/components/file-processing/ProgressBar.tsx @@ -0,0 +1,45 @@ +import { Label, Stack } from "@/components"; +import type { PredictStatus } from "@/hooks/usePredict"; +import { CheckCircle } from "phosphor-react"; +import { Bar, BarContainer } from "./FileProcessing.styles"; +import { ProgressLabel } from "./ProgressLabel"; + +interface Props { + fileName: string; + progress: number; + status: PredictStatus; +} +export default function ProgressBar({ fileName, progress, status }: Props) { + const getProgressText = () => { + const text = { + processing: `${progress}%`, + completed: ( + <> + Carga finalizada 100% + + ), + error: "Error de carga de archivo. Volvelo a intentar", + stopped: "Detuviste el procesamiento de este archivo", + }; + + return text[status]; + }; + + return ( + + {/* Texts */} + + + + {getProgressText()} + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/file-processing/ProgressLabel.ts b/frontend/src/renderer/src/components/file-processing/ProgressLabel.ts new file mode 100644 index 00000000..971ccaed --- /dev/null +++ b/frontend/src/renderer/src/components/file-processing/ProgressLabel.ts @@ -0,0 +1,29 @@ +import Label from "@/components/label"; +import { styled } from "@/styles"; + +export const ProgressLabel = styled(Label, { + display: "flex", + alignItems: "center", + gap: "$xs", + + variants: { + progress: { + processing: { + color: "$textDefault", + }, + error: { + color: "$errorPrimary", + }, + stopped: { + color: "$textLighter", + fontStyle: "italic", + }, + completed: { + color: "$actionPressed", + }, + }, + }, + defaultVariants: { + progress: "processing", + }, +}); diff --git a/frontend/src/renderer/src/components/file-processing/index.tsx b/frontend/src/renderer/src/components/file-processing/index.tsx new file mode 100644 index 00000000..6768cea2 --- /dev/null +++ b/frontend/src/renderer/src/components/file-processing/index.tsx @@ -0,0 +1,111 @@ +import { ArrowsLeftRight, Stop, X } from "phosphor-react"; +import { type ChangeEventHandler, type MouseEventHandler, useRef } from "react"; + +import HiddenInput from "@/components/hidden-input"; +import Button from "@/components/ui/button"; +import { useFileDispatch } from "@/hooks"; +import type { PredictStatus } from "@/hooks/usePredict"; +import { removeFile, replaceFile } from "@/reducers/file/actions"; +import { css } from "@/styled/css"; +import { Stack } from "@/styled/jsx"; +import { useQueryClient } from "@tanstack/react-query"; +import ProgressBar from "./ProgressBar"; + +function ActionButton({ + status, + onClick, +}: { status: PredictStatus; onClick: MouseEventHandler }) { + return ( + + ); +} + +interface Props { + fileName: string; + status: PredictStatus; + progress: number; + onAbort?: () => void; +} +export default function FileProcessing({ + fileName, + status, + progress, + onAbort, +}: Props) { + const inputRef = useRef(null); + const dispatch = useFileDispatch(); + const queryClient = useQueryClient(); + + const handleOpenFinder = () => { + inputRef.current?.click(); + }; + + const handleAddedFile: ChangeEventHandler = (e) => { + const rawFiles = e.target.files; + + if (rawFiles) { + const fileList = Array.from(rawFiles); + if (fileList.length > 0) { + queryClient.removeQueries({ + queryKey: ["file-parser", fileName], + exact: false, + }); + queryClient.removeQueries({ + queryKey: ["disambiguate", fileName], + exact: false, + }); + queryClient.removeQueries({ + predicate: (query) => { + const key = query.queryKey as unknown[]; + return key[0] === "predict" && key[2] === fileName; + }, + }); + dispatch(replaceFile(fileName, fileList[0])); + } + } + }; + + const handleStop = () => { + onAbort?.(); + }; + + const remove = () => { + onAbort?.(); + dispatch(removeFile(fileName)); + }; + + return ( + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/file-stepper/FileStepper.styles.ts b/frontend/src/renderer/src/components/file-stepper/FileStepper.styles.ts new file mode 100644 index 00000000..850c59e8 --- /dev/null +++ b/frontend/src/renderer/src/components/file-stepper/FileStepper.styles.ts @@ -0,0 +1,26 @@ +import { Button as BaseButton } from "@/components"; +import { styled } from "@/styles"; + +export const CaretButton = styled(BaseButton, { + boxShadow: "4px 0px 4px rgba(0, 0, 0, 0.05)", + + // Marked as important because of Stitches hierarchy + px: "0px !important", + py: "$s !important", + + "&:disabled": { + boxShadow: "none", + color: "$textLighter", + }, +}); + +export const Carousel = styled("div", { + display: "flex", + flexDirection: "row", + gap: "$s", + alignItems: "center", + wrap: "no-wrap", + flex: 1, + + overflowX: "scroll", +}); diff --git a/frontend/src/renderer/src/components/file-stepper/Icons.tsx b/frontend/src/renderer/src/components/file-stepper/Icons.tsx new file mode 100644 index 00000000..e5907826 --- /dev/null +++ b/frontend/src/renderer/src/components/file-stepper/Icons.tsx @@ -0,0 +1,26 @@ +import { CaretLeft, CaretRight, CheckCircle } from "phosphor-react"; + +import { colors } from "@/styles/tokens"; + +function ArrowRight() { + return ; +} +function ArrowLeft() { + return ; +} + +interface Props { + status: "completed" | "focus" | "default"; +} +function Check({ status }: Props) { + return status === "completed" ? ( + + ) : null; +} + +const Icons = { + ArrowRight, + ArrowLeft, + Check, +}; +export default Icons; diff --git a/frontend/src/renderer/src/components/file-stepper/index.tsx b/frontend/src/renderer/src/components/file-stepper/index.tsx new file mode 100644 index 00000000..1053e8c4 --- /dev/null +++ b/frontend/src/renderer/src/components/file-stepper/index.tsx @@ -0,0 +1,67 @@ +import { TabName as FileName, Tab as FileStep, Stack } from "@/components"; +import { useFiles } from "@/hooks"; +import type { DocFile } from "@/types/file"; +import { CaretButton, Carousel } from "./FileStepper.styles"; +import Icons from "./Icons"; +import { canMoveLeft as checkLeft, canMoveRight as checkRight } from "./utils"; + +interface Props { + selected: number; + nextFile: () => void; + previousFile: () => void; +} +export default function FileStepper({ + selected, + nextFile, + previousFile, +}: Props) { + const files = useFiles(); + + const canMoveLeft = checkLeft(selected, files); + const canMoveRight = checkRight(selected, files); + const isLeftDisabled = selected === 0; + const isRightDisabled = selected === files.length - 1; // -1 because we are using base 0 notation + + const getStatus = (current: number, file: DocFile) => { + if (file.validated) { + return "completed"; + } + return selected === current ? "focus" : "default"; + }; + + return ( + + {/* <- */} + {canMoveLeft && ( + + + + )} + + {/* List of files */} + + {files.map((file, i) => ( + + {file.data.name} + + + ))} + + + {/* -> */} + {canMoveRight && ( + + + + )} + + ); +} diff --git a/frontend/src/renderer/src/components/file-stepper/utils.ts b/frontend/src/renderer/src/components/file-stepper/utils.ts new file mode 100644 index 00000000..ef1e2034 --- /dev/null +++ b/frontend/src/renderer/src/components/file-stepper/utils.ts @@ -0,0 +1,27 @@ +import type { DocFile } from "@/types/file"; + +/** + * Check if the stepper can move to the left + * @param cur Current `selected` index + * @param state State array of files + * @returns `true` if the stepper can move to the left (or to a previous file), `false` otherwise + */ +export function canMoveLeft(cur: number, state: DocFile[]) { + const sliced = state.slice(0, cur); + + // Check if we find any file that is not validated yet + return !!sliced.find((file) => !file.validated); +} + +/** + * Check if the stepper can move to the right + * @param cur Current `selected` index + * @param state State array of files + * @returns `true` if the stepper can move to the right (or to a next file), `false` otherwise + */ +export function canMoveRight(cur: number, state: DocFile[]) { + const sliced = state.slice(cur + 1, state.length); + + // Check if we find any file that is not validated yet + return !!sliced.find((file) => !file.validated); +} diff --git a/frontend/src/renderer/src/components/file/annotation-popover/index.tsx b/frontend/src/renderer/src/components/file/annotation-popover/index.tsx new file mode 100644 index 00000000..e8693bde --- /dev/null +++ b/frontend/src/renderer/src/components/file/annotation-popover/index.tsx @@ -0,0 +1,191 @@ +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { css } from "@/styled/css"; +import type { AllLabels } from "@/types/aymurai"; +import type { FocusEventHandler, ReactNode } from "react"; +import { useEffect, useId, useRef, useState } from "react"; +import Tagger from "./tagger"; + +const CLOSE_DELAY_MS = 120; +const OPEN_EVENT = "aymurai:annotation-popover-open"; + +const triggerFocus = css({ + "&:focus-visible": { + outline: "[2px solid token(colors.action.hover)]", + outlineOffset: "[2px]", + borderRadius: "sm", + }, +}); + +interface AnnotationPopoverProps { + children: ReactNode; + onClickOne: (label: AllLabels) => void; + onClickAll: (label: AllLabels) => void; + onDeleteOne?: () => void; + onDeleteAll?: () => void; + onHoverChange?: (hovered: boolean) => void; +} + +export default function AnnotationPopover({ + children, + onClickAll, + onClickOne, + onDeleteOne, + onDeleteAll, + onHoverChange, +}: AnnotationPopoverProps) { + const popoverId = useId(); + const [open, setOpen] = useState(false); + const closeTimer = useRef | null>(null); + const isTriggerHovered = useRef(false); + const isContentHovered = useRef(false); + const isFocusInside = useRef(false); + const isKeyboardOpen = useRef(false); + + const cancelClose = () => { + if (closeTimer.current) { + clearTimeout(closeTimer.current); + closeTimer.current = null; + } + }; + + useEffect(() => { + const closeWhenAnotherOpens = (event: Event) => { + const openedId = (event as CustomEvent).detail; + if (openedId === popoverId) return; + + isTriggerHovered.current = false; + isContentHovered.current = false; + isFocusInside.current = false; + setOpen(false); + if (closeTimer.current) { + clearTimeout(closeTimer.current); + closeTimer.current = null; + } + }; + + window.addEventListener(OPEN_EVENT, closeWhenAnotherOpens); + + return () => { + window.removeEventListener(OPEN_EVENT, closeWhenAnotherOpens); + if (closeTimer.current) clearTimeout(closeTimer.current); + }; + }, [popoverId]); + + const setInteractive = (nextOpen: boolean, announce = false) => { + setOpen(nextOpen); + onHoverChange?.(nextOpen); + if (nextOpen && announce) { + window.dispatchEvent(new CustomEvent(OPEN_EVENT, { detail: popoverId })); + } + }; + + const scheduleClose = () => { + cancelClose(); + closeTimer.current = setTimeout(() => { + if ( + !isFocusInside.current && + !isTriggerHovered.current && + !isContentHovered.current + ) { + setInteractive(false); + } + }, CLOSE_DELAY_MS); + }; + + const handleBlur: FocusEventHandler = (e) => { + if (!e.currentTarget.contains(e.relatedTarget)) { + isFocusInside.current = false; + scheduleClose(); + } + }; + + return ( + { + if (nextOpen) { + cancelClose(); + setInteractive(true, true); + return; + } + if ( + isTriggerHovered.current || + isContentHovered.current || + isFocusInside.current + ) { + scheduleClose(); + return; + } + setInteractive(false); + }} + > + { + isTriggerHovered.current = true; + cancelClose(); + setInteractive(true, true); + }} + onMouseLeave={() => { + isTriggerHovered.current = false; + scheduleClose(); + }} + onFocus={() => { + isFocusInside.current = true; + cancelClose(); + setInteractive(true, true); + }} + onBlur={() => { + isFocusInside.current = false; + scheduleClose(); + }} + onKeyDown={(e) => { + if (e.key === " " || e.key === "Enter") { + isKeyboardOpen.current = true; + } + }} + > + {children} + + { + if (!isKeyboardOpen.current) e.preventDefault(); + }} + onCloseAutoFocus={(e) => { + if (!isKeyboardOpen.current) e.preventDefault(); + isKeyboardOpen.current = false; + }} + onMouseEnter={() => { + isContentHovered.current = true; + cancelClose(); + onHoverChange?.(true); + }} + onMouseLeave={() => { + isContentHovered.current = false; + scheduleClose(); + }} + onFocus={() => { + isFocusInside.current = true; + cancelClose(); + onHoverChange?.(true); + }} + onBlur={handleBlur} + > + + + + ); +} diff --git a/frontend/src/renderer/src/components/file/annotation-popover/tagger-button.tsx b/frontend/src/renderer/src/components/file/annotation-popover/tagger-button.tsx new file mode 100644 index 00000000..29501fd0 --- /dev/null +++ b/frontend/src/renderer/src/components/file/annotation-popover/tagger-button.tsx @@ -0,0 +1,79 @@ +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { sva } from "@/styled/css"; +import { styled } from "@/styled/jsx"; + +const button = sva({ + slots: ["button", "tooltipContent"], + base: { + button: { + p: "0.5", + rounded: "[6px]", + cursor: "pointer", + flexShrink: "0", + _hover: { + bg: "action.hover", + }, + }, + tooltipContent: { + bg: "action.hover", + color: "white", + px: "1", + py: "0.5", + rounded: "sm", + }, + }, + variants: { + disabled: { + true: { + button: { + cursor: "not-allowed", + _hover: { + bg: "transparent", + }, + }, + }, + }, + }, +}); + +interface TaggerButtonProps { + tooltip: string; + children: React.ReactNode; + onClick: () => void; + disabled?: boolean; +} +export default function TaggerButton({ + children, + tooltip, + onClick, + disabled = false, +}: TaggerButtonProps) { + const classes = button({ disabled }); + return ( + + + + + + +
    + {tooltip} +
    +
    +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/file/annotation-popover/tagger.tsx b/frontend/src/renderer/src/components/file/annotation-popover/tagger.tsx new file mode 100644 index 00000000..2218a185 --- /dev/null +++ b/frontend/src/renderer/src/components/file/annotation-popover/tagger.tsx @@ -0,0 +1,174 @@ +import { useState } from "react"; + +import { sva } from "@/styled/css"; +import { styled } from "@/styled/jsx"; +import { hstack } from "@/styled/patterns"; + +import AnonymizerLabelSelect from "@/components/anonymizer/anonymizer-label-select"; +import type { SelectOption } from "@/components/ui/select"; +import { useAnnotation } from "@/context/Annotation"; +import { useExcludedTagsConfig } from "@/store/useLocal"; +import type { AllLabels } from "@/types/aymurai"; +import { getActiveAnonymizerLabelOptions } from "@/utils/anonymizer/labels"; + +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; + +import TaggerButton from "./tagger-button"; + +const IMG_SIZE = 24; + +const tagger = sva({ + slots: ["container", "button", "divider", "tooltipContent"], + base: { + container: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + p: "1", + bg: "action.alt-default", + rounded: "lg", + }, + button: { + cursor: "pointer", + }, + divider: { + alignSelf: "stretch", + width: "[1px]", + bg: "[#5960B0]", + + my: "1", + }, + tooltipContent: { + bg: "action.hover", + color: "white", + px: "1", + py: "0.5", + rounded: "sm", + }, + }, +}); + +interface MarkTaggerProps { + onClickOne: (label: AllLabels) => void; + onClickAll: (label: AllLabels) => void; + onDeleteOne?: () => void; + onDeleteAll?: () => void; +} +export default function Tagger({ + onClickAll, + onClickOne, + onDeleteOne, + onDeleteAll, +}: MarkTaggerProps) { + const { label: initialLabel } = useAnnotation(); + const { tags } = useExcludedTagsConfig(); + + const [label, setLabel] = useState(initialLabel); + const [isSelectOpen, setIsSelectOpen] = useState(false); + const options = getActiveAnonymizerLabelOptions(tags); + const activeLabel = + label && options.some((option) => option.id === label) ? label : null; + + const handleClickOne = () => { + if (!activeLabel) return; + onClickOne(activeLabel); + }; + const handleClickAll = () => { + if (!activeLabel) return; + onClickAll(activeLabel); + }; + + const handleLabelChange = (value: SelectOption) => { + setLabel(value.id as AllLabels); + }; + + const classes = tagger(); + return ( +
    + + + +
    + +
    +
    + +
    + + Selecciona tipo de etiqueta + +
    +
    +
    +
    +
    + + Afectar una ocurrencia + +
    + + Afectar todas las ocurrencias + + {onDeleteOne && ( + <> +
    + + Eliminar esta ocurrencia + + + )} + {onDeleteAll && ( + <> +
    + + Eliminar todas las ocurrencias + + + )} +
    + ); +} diff --git a/frontend/src/renderer/src/components/file/manual-entity-resolution-dialog.tsx b/frontend/src/renderer/src/components/file/manual-entity-resolution-dialog.tsx new file mode 100644 index 00000000..ab15cfb6 --- /dev/null +++ b/frontend/src/renderer/src/components/file/manual-entity-resolution-dialog.tsx @@ -0,0 +1,227 @@ +import { useEffect, useMemo, useState } from "react"; + +import Button from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogTitle, +} from "@/components/ui/dialog"; +import Select from "@/components/ui/select"; +import { css } from "@/styled/css"; +import { Stack, styled } from "@/styled/jsx"; +import type { + ManualEntityResolution, + SimilarEntityGroupCandidate, +} from "@/utils/anonymizer/entity-similarity"; + +export interface ManualEntityResolutionRequest { + text: string; + label: string; + count: number; + candidates: SimilarEntityGroupCandidate[]; +} + +interface ManualEntityResolutionDialogProps { + request: ManualEntityResolutionRequest | null; + onClose: () => void; + onResolve: (resolution: ManualEntityResolution) => void; +} + +const candidateSummary = css({ + bg: "bg.primary", + border: "[1px solid #BCBAB8]", + rounded: "sm", + p: "2.5", + display: "grid", + gridTemplateColumns: "minmax(0, 1fr) max-content", + alignItems: "center", + columnGap: "3", + rowGap: "0.5", + minW: "0", +}); + +const candidateText = css({ + display: "grid", + gap: "0.5", + minW: "0", +}); + +const candidateToken = css({ + minW: "0", + overflowWrap: "anywhere", + wordBreak: "break-word", +}); + +const candidateReference = css({ + minW: "0", + color: "text.default", + overflowWrap: "anywhere", + wordBreak: "break-word", +}); + +const candidateMeta = css({ + display: "grid", + alignContent: "center", + justifyItems: "end", + gap: "0.5", + justifySelf: "end", + w: "[fit-content]", + maxW: "full", + px: "1.5", + py: "0.5", + bg: "[#E6E8FF]", + color: "[#3F479D]", + rounded: "xs", + whiteSpace: "nowrap", +}); + +const categoryLabel = css({ + fontSize: "[11px]", + fontWeight: "bold", + lineHeight: "[1.2]", +}); + +const scoreValue = css({ + fontSize: "[11px]", + fontWeight: "bold", + lineHeight: "[1.2]", +}); + +function getCandidateLabel(candidate: SimilarEntityGroupCandidate) { + const text = candidate.matchedText || "sin texto"; + return `${candidate.group.renderToken} - ${text} (${candidate.score}%)`; +} + +export default function ManualEntityResolutionDialog({ + request, + onClose, + onResolve, +}: ManualEntityResolutionDialogProps) { + const [selectedCanonicalId, setSelectedCanonicalId] = useState( + null, + ); + + useEffect(() => { + setSelectedCanonicalId(request?.candidates[0]?.group.canonicalId ?? null); + }, [request]); + + const candidate = useMemo(() => { + if (!request) return null; + return ( + request.candidates.find( + (item) => item.group.canonicalId === selectedCanonicalId, + ) ?? + request.candidates[0] ?? + null + ); + }, [request, selectedCanonicalId]); + + const candidateOptions = useMemo( + () => + request?.candidates.map((item) => ({ + id: item.group.canonicalId, + text: getCandidateLabel(item), + })) ?? [], + [request], + ); + + const isLabelConflict = candidate ? !candidate.labelMatches : false; + const selectedGroupText = candidate?.group.renderToken ?? ""; + const selectedGroupLabel = candidate?.group.renderBase ?? ""; + const mentionCount = request?.count ?? 0; + + return ( + { + if (!open) onClose(); + }} + > + + Resolver grupo de entidad + {request && candidate && ( + + + {isLabelConflict + ? `Encontramos texto similar en otra categoría. Seleccionaste ${request.label} para "${request.text}".` + : `Encontramos un grupo similar para "${request.text}".`} + + + {request.candidates.length > 1 && ( + + ); +} diff --git a/frontend/src/renderer/src/components/home/choose-host.tsx b/frontend/src/renderer/src/components/home/choose-host.tsx new file mode 100644 index 00000000..9ae555bb --- /dev/null +++ b/frontend/src/renderer/src/components/home/choose-host.tsx @@ -0,0 +1,66 @@ +import { Button } from "@/components"; +import { useRunLocalServer } from "@/services/aymurai"; +import { css } from "@/styled/css"; +import { Stack, styled } from "@/styled/jsx"; +import { useNavigate } from "@tanstack/react-router"; +import { HardDrives, Monitor } from "phosphor-react"; +import { useTranslation } from "react-i18next"; + +interface ChooseHostProps { + onRemoteClick: () => void; +} +export default function ChooseHost({ onRemoteClick }: ChooseHostProps) { + const navigate = useNavigate(); + const { run: runLocalServer, isRunning } = useRunLocalServer({ + onSuccess: () => + navigate({ + to: "/home/features", + }), + }); + + const { t } = useTranslation(); + + return ( + + + +

    + {t("home.host.howToConnect")} +

    + + +

    + {t("home.host.optionOr")} +

    + +
    +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/home/connect-to-host.tsx b/frontend/src/renderer/src/components/home/connect-to-host.tsx new file mode 100644 index 00000000..8581f422 --- /dev/null +++ b/frontend/src/renderer/src/components/home/connect-to-host.tsx @@ -0,0 +1,108 @@ +import { useConnectToHost } from "@/services/aymurai"; +import * as localStore from "@/store/useLocal"; +import { css } from "@/styled/css"; +import { Stack } from "@/styled/jsx"; +import { useNavigate } from "@tanstack/react-router"; +import { AxiosError } from "axios"; +import { ArrowLeft } from "phosphor-react"; +import { + type ChangeEventHandler, + type SubmitEventHandler, + useState, +} from "react"; +import { useTranslation } from "react-i18next"; +import { ZodError } from "zod"; +import Button from "../ui/button"; +import Input from "../ui/input"; + +const BackButton = ({ onClick }: { onClick: () => void }) => ( + +); + +interface ConnectToHostProps { + onBackClick: () => void; +} +export default function ConnectToHost({ onBackClick }: ConnectToHostProps) { + const navigate = useNavigate(); + const remoteHost = localStore.useServerHost() ?? ""; + const { setServerHost } = localStore.useServerHostActions(); + const { t } = useTranslation(); + + const [host, setHost] = useState(remoteHost); + + const { mutate: connectToHost, isPending, error, reset } = useConnectToHost(); + + const handleChange: ChangeEventHandler = (e) => { + setHost(e.target.value); + reset(); + }; + + const tryConnection: SubmitEventHandler = (e) => { + e.preventDefault(); + + connectToHost(host, { + onSuccess: () => { + setServerHost(host); + navigate({ + to: "/home/features", + }); + }, + }); + }; + + const errorMessage = (err: Error | null): string => { + console.error(err); + if (err instanceof AxiosError) { + if (err.code === "ERR_NETWORK") return t("home.host.errors.network"); + return t("home.host.errors.connection"); + } + + if (err instanceof ZodError) { + return t("home.host.errors.invalidResponse"); + } + + if (err instanceof TypeError) { + return t("home.host.errors.invalidUrl"); + } + + return t("home.host.errors.unknown"); + }; + + return ( + <> + + + +

    + {t("home.host.connectServerExplanation")} +

    + + + + + + +
    + + + ); +} diff --git a/frontend/src/renderer/src/components/home/stepper.tsx b/frontend/src/renderer/src/components/home/stepper.tsx new file mode 100644 index 00000000..2810ebab --- /dev/null +++ b/frontend/src/renderer/src/components/home/stepper.tsx @@ -0,0 +1,109 @@ +import { css, sva } from "@/styled/css"; +import { stack } from "@/styled/patterns"; +import { useTranslation } from "react-i18next"; + +const stepper = css({ + ...stack.raw({ align: "center", direction: "row" }), +}); + +const step = sva({ + slots: ["container", "circle", "text"], + base: { + container: stack.raw({ direction: "row", align: "center", gap: "2" }), + circle: { + ...stack.raw({ direction: "row", align: "center", justify: "center" }), + rounded: "full", + height: "9", + width: "9", + textStyle: "cta.md.strong", + }, + text: { + color: "text.default", + textStyle: "label.md.default", + display: "none", + visibility: "hidden", + }, + }, + variants: { + status: { + complete: { + circle: { + color: "text.onbutton-alternative", + bg: "action.alt-default", + }, + }, + pending: { + circle: { + color: "text.onbutton-default", + bg: "action.disabled", + }, + }, + in_progress: { + circle: { + color: "text.onbutton-default", + bg: "action.default", + border: "primary-alt", + }, + text: { display: "inline", visibility: "visible" }, + }, + }, + }, +}); + +type StepStatus = "complete" | "pending" | "in_progress"; +interface StepProps { + children: string; + status: StepStatus; + number: number; +} +function Step({ children, status, number }: StepProps) { + const classes = step({ status }); + // Used to hide text from visuals but expose to screen readers + const srOnly = css({ + srOnly: true, + }); + + return ( +
    + + + Paso {number}: {children} + + +
    + ); +} + +interface StepperProps { + currentStep: number; +} +export default function Stepper({ currentStep }: StepperProps) { + const { t } = useTranslation(); + + const status = (step: number): StepStatus => { + if (step === currentStep) return "in_progress"; + if (step > currentStep) return "pending"; + return "complete"; + }; + + return ( +
    + + {t("stepper.selection")} + + + {t("stepper.extraction")} + + + {t("stepper.validation")} + + + {t("stepper.finalization")} + +
    + ); +} diff --git a/frontend/src/renderer/src/components/how-it-works-modal.tsx b/frontend/src/renderer/src/components/how-it-works-modal.tsx new file mode 100644 index 00000000..92541d04 --- /dev/null +++ b/frontend/src/renderer/src/components/how-it-works-modal.tsx @@ -0,0 +1,81 @@ +import { SectionTitle } from "@/layout/section-title"; +import { css } from "@/styled/css"; +import { HStack, Stack } from "@/styled/jsx"; +import type { FeatureFlowEnum } from "@/types/features"; +import { Question, X } from "phosphor-react"; +import { useTranslation } from "react-i18next"; +import HowItWorks from "./how-it-works"; +import { Dialog, DialogClose, DialogContent, DialogTrigger } from "./ui/dialog"; +import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; + +const tooltip = css({ + padding: "2", + textStyle: "label.md.default", +}); + +const modalButton = css({ + color: "text.lighter", + + padding: "0.5", + rounded: "sm", + + cursor: "pointer", + + transition: "colors", + + "&:hover": { + bg: "action.hover", + color: "text.onbutton-alternative", + }, +}); + +const closeButton = css({ + cursor: "pointer", +}); + +const content = css({ + overflowY: "auto", + maxH: "[90vh]", + maxW: "5xl!", +}); + +interface HowItWorksModalProps { + feature: FeatureFlowEnum; +} +export default function HowItWorksModal({ feature }: HowItWorksModalProps) { + const { t } = useTranslation(); + + return ( + + + + + + + + {t("howItWorks")} + + + + + {t("howItWorks")} + + + + + } + feature={feature} + /> + + + + ); +} diff --git a/frontend/src/renderer/src/components/how-it-works.tsx b/frontend/src/renderer/src/components/how-it-works.tsx new file mode 100644 index 00000000..7c8f3876 --- /dev/null +++ b/frontend/src/renderer/src/components/how-it-works.tsx @@ -0,0 +1,110 @@ +import { SectionTitle } from "@/layout/section-title"; +import { css } from "@/styled/css"; +import { Grid, Stack, styled } from "@/styled/jsx"; +import { hstack, stack } from "@/styled/patterns"; +import { type FeatureFlowEnum, featureNamespace } from "@/types/features"; +import { useTranslation } from "react-i18next"; + +const card = css({ + ...hstack.raw({ gap: "4", alignItems: "center" }), + + bg: "bg.secondary", + border: "primary", + rounded: "sm", + + px: "4", + py: "6", + + "& > img": { + width: "[200px]", + height: "[130px]", + objectFit: "contain", + flexShrink: "0", + }, +}); + +const stepStyle = css({ + ...stack.raw({ align: "center", justify: "center" }), + + bg: "action.alt-default", + color: "text.onbutton-alternative", + rounded: "full", + textStyle: "cta.md.strong", + + width: "9", + height: "9", +}); + +interface CardProps { + img: string; + imgAlt: string; + step: number; + title: string; + subtitle: string; +} +function Card({ img, imgAlt, step, title, subtitle }: CardProps) { + return ( +
    + {imgAlt} + +

    {step}

    + + {title} + {subtitle} + +
    +
    + ); +} + +interface HowItWorksProps { + title?: React.ReactNode; + feature: FeatureFlowEnum; +} +export default function HowItWorks({ title, feature }: HowItWorksProps) { + const { t } = useTranslation(); + const { t: tFeature } = useTranslation(featureNamespace[feature]); + + const renderTitle = + typeof title === "string" ? ( + {title} + ) : ( + (title ?? {t("howItWorks")}) + ); + + return ( + + {renderTitle} + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/index.ts b/frontend/src/renderer/src/components/index.ts new file mode 100644 index 00000000..15c0ea80 --- /dev/null +++ b/frontend/src/renderer/src/components/index.ts @@ -0,0 +1,23 @@ +export { default as Arrow } from "./arrow"; +export { Checkbox, CheckboxGroup } from "./checkbox"; +export { default as DecisionTabs } from "./decision-tabs"; +export { default as FileAnnotator } from "./file-annotator"; +export { default as FileCheck } from "./file-check"; +export { default as FilePreview } from "./file-preview"; +export { default as FileProcessing } from "./file-processing"; +export { default as FileStepper } from "./file-stepper"; +export { default as Grid } from "./grid"; +export { default as Label } from "./label"; +export { OnboardingGrid } from "./onboarding-grid"; +export { Radio, RadioGroup } from "./radio"; +export { default as Spinner } from "./spinner"; +export { default as Stack } from "./stack"; +export { default as Subtitle } from "./subtitle"; +export { Tab, TabName } from "./tabs"; +export { default as Text } from "./text"; +export { default as ThemeProvider } from "./theme-provider"; +export { default as Title } from "./title"; +export { default as Button } from "./ui/button"; +export { default as Input } from "./uncontrolled-input"; +export { ValidateDataset } from "./validate-dataset"; +export { default as ValidationForm } from "./validation-form"; diff --git a/frontend/src/renderer/src/components/label/index.ts b/frontend/src/renderer/src/components/label/index.ts new file mode 100644 index 00000000..08531a91 --- /dev/null +++ b/frontend/src/renderer/src/components/label/index.ts @@ -0,0 +1,42 @@ +import { styled } from "@/styles"; + +/** + * @deprecated use `textStyles` from PandaCSS instead. + */ +const Label = styled("label", { + variants: { + size: { + m: { + fontSize: "$labelMd", + lineHeight: "$labelMd", + }, + s: { + fontSize: "$labelSm", + lineHeight: "$labelSm", + }, + }, + weight: { + default: { + fontWeight: "$default", + }, + strong: { + fontWeight: "$strong", + }, + }, + status: { + default: { + color: "$textLighter", + }, + error: { + color: "$errorPrimary", + }, + }, + }, + defaultVariants: { + size: "m", + weight: "default", + status: "default", + }, +}); + +export default Label; diff --git a/frontend/src/renderer/src/components/layout/footer.tsx b/frontend/src/renderer/src/components/layout/footer.tsx new file mode 100644 index 00000000..6de643c4 --- /dev/null +++ b/frontend/src/renderer/src/components/layout/footer.tsx @@ -0,0 +1,35 @@ +import { css, cx } from "@/styled/css"; +import BuiltBy from "../brand/built-by"; + +const content = css({ + display: "flex", + flexDirection: "row", + alignItems: "center", + + borderTop: "primary", + px: "12", + py: "6", +}); +const childrenContainer = css({ + flex: "1", + display: "flex", + justifyContent: "flex-end", +}); + +interface FooterProps { + withBuiltBy?: boolean; + children?: React.ReactNode; + className?: string; +} +export default function Footer({ + withBuiltBy, + children, + className, +}: FooterProps) { + return ( +
    + {withBuiltBy && } +
    {children}
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/layout/header.tsx b/frontend/src/renderer/src/components/layout/header.tsx new file mode 100644 index 00000000..f1b1d0a4 --- /dev/null +++ b/frontend/src/renderer/src/components/layout/header.tsx @@ -0,0 +1,68 @@ +import { useTutorialSeen } from "@/store/useLocal"; +import { css } from "@/styled/css"; +import { Divider, HStack, Stack, styled } from "@/styled/jsx"; +import type { FeatureFlowEnum } from "@/types/features"; +import { Link } from "@tanstack/react-router"; +import FeaturesMenu from "../features-menu"; +import HowItWorksModal from "../how-it-works-modal"; + +const header = css({ + position: "relative", + width: "full", + height: "24", + py: "6", + px: "12", + bg: "bg.secondary", + borderBottom: "[1px solid #BCBAB8]", + display: "flex", + alignItems: "center", + justifyContent: "space-between", +}); + +const centerSlot = css({ + position: "absolute", + left: "[50%]", + transform: "translateX(-50%)", +}); + +interface HeaderProps { + title?: string; + center?: React.ReactNode; + feature?: FeatureFlowEnum; + right?: React.ReactNode; +} + +export default function Header({ title, center, feature, right }: HeaderProps) { + const tutorialSeen = useTutorialSeen(feature!); + + const img = title + ? `${import.meta.env.BASE_URL}brand/aymurai-iso-darkpurple.svg` + : `${import.meta.env.BASE_URL}brand/aymurai-hor-darkpurple.svg`; + + return ( +
    + + + AymurAI logo + {title && ( + <> + + {title} + + )} + + + {center &&
    {center}
    } + + {tutorialSeen && feature && } + {right} + + +
    + ); +} diff --git a/frontend/src/renderer/src/components/layout/home-button.tsx b/frontend/src/renderer/src/components/layout/home-button.tsx new file mode 100644 index 00000000..777409d5 --- /dev/null +++ b/frontend/src/renderer/src/components/layout/home-button.tsx @@ -0,0 +1,16 @@ +import { css } from "@/styled/css"; +import { House } from "phosphor-react"; +import Link from "../ui/link"; + +export default function HomeButton() { + return ( + + + + ); +} diff --git a/frontend/src/renderer/src/components/layout/main-content.tsx b/frontend/src/renderer/src/components/layout/main-content.tsx new file mode 100644 index 00000000..139fd857 --- /dev/null +++ b/frontend/src/renderer/src/components/layout/main-content.tsx @@ -0,0 +1,48 @@ +import { cva, cx } from "@/styled/css"; +import { stack } from "@/styled/patterns"; + +const content = cva({ + base: { + flex: "1", + minH: "0", + + width: "full", + overflowY: "auto", + + bg: "bg.primary", + }, + variants: { + full: { + true: {}, + false: { + ...stack.raw({ align: "center", gap: "0" }), + + pt: { base: "6", xl: "16" }, + px: "8", + + "& > div.spacing": { + width: "full", + maxWidth: "5xl", + }, + }, + }, + }, + defaultVariants: { + full: false, + }, +}); + +interface MainContentProps { + children: React.ReactNode; + full?: boolean; +} +export default function MainContent({ + children, + full = false, +}: MainContentProps) { + return ( +
    +
    {children}
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/onboarding-grid/index.ts b/frontend/src/renderer/src/components/onboarding-grid/index.ts new file mode 100644 index 00000000..ecf7ff3a --- /dev/null +++ b/frontend/src/renderer/src/components/onboarding-grid/index.ts @@ -0,0 +1,15 @@ +import { styled } from "@/styles"; + +export const OnboardingGrid = styled("div", { + display: "grid", + justifyItems: "center", + gridTemplateColumns: "repeat(1, minmax(200px, 1fr))", + gap: "$xl 0", + + "@md": { + gridTemplateColumns: "repeat(4, minmax(160px, 1fr))", + }, + "@xl": { + gridTemplateColumns: "repeat(4, minmax(200px, 1fr))", + }, +}); diff --git a/frontend/src/renderer/src/components/radio/index.ts b/frontend/src/renderer/src/components/radio/index.ts new file mode 100644 index 00000000..8e8c2681 --- /dev/null +++ b/frontend/src/renderer/src/components/radio/index.ts @@ -0,0 +1,4 @@ +import Radio from "./radio"; +import RadioGroup from "./radio-group"; + +export { RadioGroup, Radio }; diff --git a/frontend/src/renderer/src/components/radio/radio-group/RadioGroup.styles.ts b/frontend/src/renderer/src/components/radio/radio-group/RadioGroup.styles.ts new file mode 100644 index 00000000..f727702b --- /dev/null +++ b/frontend/src/renderer/src/components/radio/radio-group/RadioGroup.styles.ts @@ -0,0 +1,30 @@ +import { styled } from "@/styles"; + +export const Legend = styled("legend", { + fontWeight: "$default", + fontSize: "$subtitleSm", + lineHeight: "$subtitleSm", + color: "$textLighter", + + mb: "$xs", +}); + +export const Group = styled("fieldset", { + display: "flex", + gap: "$m", + flexWrap: "wrap", + + variants: { + direction: { + horizontal: { + flexDirection: "row", + }, + vertical: { + flexDirection: "column", + }, + }, + }, + defaultVariants: { + direction: "horizontal", + }, +}); diff --git a/frontend/src/renderer/src/components/radio/radio-group/index.tsx b/frontend/src/renderer/src/components/radio/radio-group/index.tsx new file mode 100644 index 00000000..1f9e0066 --- /dev/null +++ b/frontend/src/renderer/src/components/radio/radio-group/index.tsx @@ -0,0 +1,39 @@ +import { + Children, + type ReactElement, + type ReactNode, + cloneElement, + isValidElement, +} from "react"; + +import type { Props as RadioProps } from "../radio"; +import { Group, Legend } from "./RadioGroup.styles"; + +interface Props { + children: ReactNode; + label?: string; + name: string; + direction?: "horizontal" | "vertical"; +} +export default function RadioGroup({ + label, + name, + direction = "horizontal", + children, +}: Props) { + // Inject the name to the children + const radiosWithName = Children.map(children, (child) => { + if (isValidElement(child)) { + return cloneElement(child as ReactElement, { + name, + }); + } + }); + + return ( + + {label && {label}} + {radiosWithName} + + ); +} diff --git a/frontend/src/renderer/src/components/radio/radio/Radio.styles.ts b/frontend/src/renderer/src/components/radio/radio/Radio.styles.ts new file mode 100644 index 00000000..874e81b6 --- /dev/null +++ b/frontend/src/renderer/src/components/radio/radio/Radio.styles.ts @@ -0,0 +1,143 @@ +import { styled } from "@/styles"; + +export const Input = styled("input", { + position: "absolute", + top: 0, + left: 0, + + opacity: 0, +}); + +export const Radio = styled("div", { + display: "flex", + alignItems: "center", + justifyContent: "center", + + width: 18, + height: 18, + p: 1, + + borderRadius: "100%", + boxSizing: "border-box", +}); + +export const Wrapper = styled("label", { + // Unchecked + $$radio_bg_default: "$colors$white", + $$radio_border_default: "$sizes$xxs solid $colors$actionDefaultAlt", + // hover + $$radio_bgHover_default: "$colors$white", + $$radio_borderHover_default: "1px solid $colors$borderPrimary", + // disabled + $$radio_bgDisabled_default: "$colors$actionDisabled", + $$radio_borderDisabled_default: "$sizes$xxs solid $colors$borderPrimary", + // focus + $$radio_bgFocus_default: "$colors$white", + $$radio_borderFocus_default: "1px solid $colors$borderPrimary", + + // Checked + $$radio_bg_checked: "$colors$actionDefaultAlt", + $$radio_border_checked: "5px solid $colors$actionDefaultAlt", + // hover + $$radio_bgHover_checked: "$colors$actionHover", + $$radio_borderHover_checked: "5px solid $colors$actionHover", + // disabled + $$radio_bgDisabled_checked: "$colors$actionDisabled", + $$radio_borderDisabled_checked: "none", + // focus + $$radio_bgFocus_checked: "$colors$actionDefaultAlt", + $$radio_borderFocus_checked: "5px solid $colors$actionDefaultAlt", + + // Focus + $$radio_outlineFocus_noText: "3px solid $colors$borderPrimaryAlt", + $$radio_outlineFocus_Text: "3px solid $colors$borderPrimary", + + position: "relative", + + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "$s", + + transitionDuration: "$transitions$s", + transitionProperty: "outline, border-radius, border", + transitionTimingFunction: "ease", + + variants: { + hasText: { + true: { + p: "$s", + "&:focus-within": { + outline: "$$radio_outlineFocus_Text", + borderRadius: "3px", + }, + }, + false: { + "&:focus-within": { + outline: "$$radio_outlineFocus_noText", + borderRadius: "100%", + }, + // Focus for radio + [`& > input:checked:focus-visible + ${Radio}`]: { + bg: "$$radio_bgFocus_checked", + b: "$$radio_borderFocus_checked", + }, + [`& > input:focus-visible + ${Radio}`]: { + bg: "$$radio_bgFocus_default", + b: "$$radio_borderFocus_default", + }, + }, + }, + isDisabled: { + true: { + "&, & > *": { + cursor: "not-allowed", + }, + }, + false: { + "&, & > *": { + cursor: "pointer", + }, + }, + }, + }, + defaultVariants: { + hasText: "false", + isDisabled: "false", + }, + + // Radio styles + [`& > ${Radio}`]: { + b: "$$radio_border_default", + bg: "$$radio_bg_default", + }, + [`& > input:checked + ${Radio}`]: { + bg: "$$radio_bg_checked", + border: "$$radio_border_checked", + }, + + // Hide SVG when unchecked + [`& > input:not(:checked) + ${Radio} svg`]: { + display: "none", + }, + + // Hover + [`&:hover > ${Radio}`]: { + b: "$$radio_borderHover_default", + bg: "$$radio_bgHover_default", + }, + [`&:hover > input:checked + ${Radio}`]: { + b: "$$radio_borderHover_checked", + bg: "$$radio_bgHover_checked", + }, + + // Disabled + [`& > input:disabled + ${Radio}`]: { + bg: "$$radio_bgDisabled_default", + b: "$$radio_borderDisabled_default", + }, + [`& > input:checked:disabled + ${Radio}`]: { + bg: "$$radio_bgDisabled_checked", + b: "$$radio_borderDisabled_checked", + }, +}); diff --git a/frontend/src/renderer/src/components/radio/radio/index.tsx b/frontend/src/renderer/src/components/radio/radio/index.tsx new file mode 100644 index 00000000..57268d14 --- /dev/null +++ b/frontend/src/renderer/src/components/radio/radio/index.tsx @@ -0,0 +1,65 @@ +import { Circle } from "phosphor-react"; +import { + type ChangeEventHandler, + type ReactNode, + forwardRef, + useImperativeHandle, + useRef, +} from "react"; + +import type { CSS } from "@/styles"; +import { colors } from "@/styles/tokens"; +import { Input, Radio as StyledRadio, Wrapper } from "./Radio.styles"; + +export interface Props { + children?: ReactNode; + name?: string; + checked?: boolean; + disabled?: boolean; + onChange?: (value: boolean) => void; + css?: CSS; +} +export default forwardRef<{ value: boolean }, Props>(function Radio( + { name, checked = false, disabled = false, onChange, css, children }, + ref, +) { + const inputRef = useRef(null); + + const hasText = !!children; + + // Only exposes `value` object to the parent component + useImperativeHandle( + ref, + () => { + return { + value: inputRef.current?.checked ?? false, + }; + }, + [], + ); + + const handleToggle: ChangeEventHandler = (e) => { + onChange?.(e.target.checked); + }; + + const iconColor = disabled + ? colors.textOnButtonDisabled + : colors.textOnButtonAlternative; + + return ( + + + + + + {children} + + ); +}); diff --git a/frontend/src/renderer/src/components/spinner/index.tsx b/frontend/src/renderer/src/components/spinner/index.tsx new file mode 100644 index 00000000..78d6eed5 --- /dev/null +++ b/frontend/src/renderer/src/components/spinner/index.tsx @@ -0,0 +1,44 @@ +import { keyframes, styled } from "@/styles"; + +const spin = keyframes({ + "0%": { transform: "rotate(0deg)" }, + "100%": { transform: "rotate(360deg)" }, +}); + +const SVG = styled("svg", { + animation: `${spin} 1s linear infinite`, +}); + +export default function Spinner() { + return ( + + + + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/stack/index.ts b/frontend/src/renderer/src/components/stack/index.ts new file mode 100644 index 00000000..d6fae295 --- /dev/null +++ b/frontend/src/renderer/src/components/stack/index.ts @@ -0,0 +1,66 @@ +import { styled } from "@/styles"; + +/** + * @deprecated Use `Stack` from `@/styled/jsx` instead. + */ +const Stack = styled("div", { + display: "flex", + + variants: { + direction: { + row: { flexDirection: "row" }, + column: { flexDirection: "column" }, + "row-reverse": { flexDirection: "row-reverse" }, + "column-reverse": { flexDirection: "column-reverse" }, + }, + + wrap: { + wrap: { flexWrap: "wrap" }, + nowrap: { flexWrap: "nowrap" }, + "wrap-reverse": { flexWrap: "wrap-reverse" }, + }, + + justify: { + start: { justifyContent: "start" }, + end: { justifyContent: "end" }, + center: { justifyContent: "center" }, + "space-between": { justifyContent: "space-between" }, + "space-around": { justifyContent: "space-around" }, + "space-evenly": { justifyContent: "space-evenly" }, + }, + + align: { + start: { alignItems: "start" }, + end: { alignItems: "end" }, + center: { alignItems: "center" }, + stretch: { alignItems: "stretch" }, + baseline: { alignItems: "baseline" }, + }, + + spacing: { + none: { gap: 0 }, + xxs: { gap: "$xxs" }, + xs: { gap: "$xs" }, + s: { gap: "$s" }, + m: { gap: "$m" }, + l: { gap: "$l" }, + xl: { gap: "$xl" }, + }, + textColor: { + default: { + color: "$textDefault", + }, + }, + }, + + defaultVariants: { + direction: "row", + wrap: "wrap", + justify: "start", + align: "start", + spacing: "s", + textColor: "default", + }, +}); + +export default Stack; diff --git a/frontend/src/renderer/src/components/subtitle/index.ts b/frontend/src/renderer/src/components/subtitle/index.ts new file mode 100644 index 00000000..acdf6e5e --- /dev/null +++ b/frontend/src/renderer/src/components/subtitle/index.ts @@ -0,0 +1,39 @@ +import { styled } from "@/styles"; + +/** + * @deprecated Use `textStyle` from PandaCSS instead. + */ +const Subtitle = styled("p", { + variants: { + size: { + m: { + fontSize: "$subtitleMd", + lineHeight: "$subtitleMd", + }, + s: { + fontSize: "$subtitleSm", + lineHeight: "$subtitleSm", + }, + }, + weight: { + default: { + fontWeight: "$default", + }, + strong: { + fontWeight: "$strong", + }, + }, + textColor: { + default: { + color: "$textDefault", + }, + }, + }, + defaultVariants: { + size: "m", + weight: "default", + textColor: "default", + }, +}); + +export default Subtitle; diff --git a/frontend/src/renderer/src/components/tabs/index.ts b/frontend/src/renderer/src/components/tabs/index.ts new file mode 100644 index 00000000..320a5514 --- /dev/null +++ b/frontend/src/renderer/src/components/tabs/index.ts @@ -0,0 +1,56 @@ +import { styled } from "@/styles"; + +export const Tab = styled("div", { + borderRadius: "$xxs", + boxSizing: "border-box", + + display: "flex", + flexDirection: "row", + gap: "$s", + alignItems: "center", + + p: "$m", + + fontSize: 16, + + variants: { + status: { + completed: { + "& label, & span": { + color: "$textOnButtonAlternative", + }, + bg: "$actionPressed", + b: "none", + }, + focus: { + "& label, & span": { + color: "$textOnButtonDefault", + }, + bg: "$actionFocus", + boxShadow: "2px 2px 10px rgba(17, 0, 65, 0.25)", + b: "1px solid $borderPrimaryAlt", + }, + default: { + "& label, & span": { + color: "$textOnButtonDefault", + }, + bg: "$primaryAlt", + b: "none", + }, + }, + }, + defaultVariants: { + status: "default", + }, +}); + +export const TabName = styled("label", { + textOverflow: "ellipsis", + overflow: "hidden", + whiteSpace: "nowrap", + + // width: 200, + + fontSize: "$labelMd", + lineHeight: "$labelMd", +}); diff --git a/frontend/src/renderer/src/components/text/index.ts b/frontend/src/renderer/src/components/text/index.ts new file mode 100644 index 00000000..c3e12968 --- /dev/null +++ b/frontend/src/renderer/src/components/text/index.ts @@ -0,0 +1,40 @@ +import { styled } from "@/styles"; + +const Text = styled("p", { + variants: { + size: { + m: { + fontSize: "$paragraphsMd", + lineHeight: "$paragraphsMd", + }, + s: { + fontSize: "$paragraphsSm", + lineHeight: "$paragraphsSm", + }, + xs: { + fontSize: "$paragraphsXsm", + lineHeight: "$paragraphsXsm", + }, + }, + weight: { + default: { + fontWeight: "$default", + }, + strong: { + fontWeight: "$strong", + }, + }, + textColor: { + default: { + color: "$textDefault", + }, + }, + }, + defaultVariants: { + size: "m", + weight: "default", + textColor: "default", + }, +}); + +export default Text; diff --git a/frontend/src/renderer/src/components/theme-provider/ThemeProvider.types.ts b/frontend/src/renderer/src/components/theme-provider/ThemeProvider.types.ts new file mode 100644 index 00000000..6186f91e --- /dev/null +++ b/frontend/src/renderer/src/components/theme-provider/ThemeProvider.types.ts @@ -0,0 +1,3 @@ +import type { ComponentPropsWithoutRef } from "react"; + +export interface Props extends ComponentPropsWithoutRef<"div"> {} diff --git a/frontend/src/renderer/src/components/theme-provider/index.tsx b/frontend/src/renderer/src/components/theme-provider/index.tsx new file mode 100644 index 00000000..50b30fb2 --- /dev/null +++ b/frontend/src/renderer/src/components/theme-provider/index.tsx @@ -0,0 +1,6 @@ +import type { Props } from "./ThemeProvider.types"; + +export default function ThemeProvider({ children }: Props) { + // globalStyles(); + return
    {children}
    ; +} diff --git a/frontend/src/renderer/src/components/title/index.ts b/frontend/src/renderer/src/components/title/index.ts new file mode 100644 index 00000000..668b6ec4 --- /dev/null +++ b/frontend/src/renderer/src/components/title/index.ts @@ -0,0 +1,39 @@ +import { styled } from "@/styles"; + +const Title = styled("h1", { + variants: { + size: { + default: { + fontSize: "$titleMd", + lineHeight: "$titleMd", + }, + main: { + fontSize: "$titleMain", + lineHeight: "$titleMain", + }, + }, + weight: { + default: { + fontWeight: "$default", + }, + strong: { + fontWeight: "$strong", + }, + heavy: { + fontWeight: "$heavy", + }, + }, + textColor: { + default: { + color: "$textDefault", + }, + }, + }, + defaultVariants: { + weight: "default", + size: "default", + textColor: "default", + }, +}); + +export default Title; diff --git a/frontend/src/renderer/src/components/ui/back-button.tsx b/frontend/src/renderer/src/components/ui/back-button.tsx new file mode 100644 index 00000000..c70c9070 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/back-button.tsx @@ -0,0 +1,17 @@ +import { css, cx } from "@/styled/css"; +import { createLink } from "@tanstack/react-router"; +import { ArrowLeft } from "phosphor-react"; + +const link = css({ + cursor: "pointer", +}); + +const BackButton = createLink( + ({ className, children: _, ref, ...props }: React.AnchorHTMLAttributes & { ref?: React.Ref }) => ( + + + + ), +); + +export default BackButton; diff --git a/frontend/src/renderer/src/components/ui/button.tsx b/frontend/src/renderer/src/components/ui/button.tsx new file mode 100644 index 00000000..5d015f81 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/button.tsx @@ -0,0 +1,150 @@ +import { type RecipeVariantProps, css, cva, cx } from "@/styled/css"; +import { CircleNotch } from "phosphor-react"; +import type { ButtonHTMLAttributes } from "react"; + +export const button = cva({ + base: { + display: "flex", + flexDir: "row", + gap: "1", // 4px + justifyContent: "center", + alignItems: "center", + + transitionProperty: "[background-color, color, box-shadow]", + transitionDuration: "slow", // 300ms + transitionTimingFunction: "default", + + border: "none", + + textStyle: "cta.md.strong", + + cursor: "pointer", + + "&:disabled": { + cursor: "not-allowed", + }, + }, + variants: { + variant: { + primary: { + bg: "action.default", + color: "text.onbutton-default", + + "&:hover:not(:disabled)": { + bg: "action.hover", + color: "text.onbutton-alternative", + }, + + "&:active:not(:disabled)": { + bg: "action.pressed", + color: "text.onbutton-alternative", + }, + + "&:focus:not(:disabled)": { + bg: "action.focus", + outline: "primary-alt", + outlineWidth: "[2px]", + boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", + }, + + "&:disabled": { + bg: "action.disabled", + color: "text.onbutton-default", + }, + }, + secondary: { + color: "text.onbutton-default", + bg: "bg.secondary", + + borderWidth: "[2px]", + borderStyle: "solid", + borderColor: "action.alt-default", + + "&:hover:not(:disabled)": { + color: "text.onbutton-default", + bg: "bg.secondary", + borderColor: "action.hover", + }, + + "&:active:not(:disabled)": { + color: "text.onbutton-alternative", + bg: "action.pressed", + borderColor: "action.pressed", + }, + + "&:focus:not(:disabled)": { + boxShadow: "[0px 0px 10px rgba(17, 0, 65, 0.2)]", + outline: "primary-alt", + outlineWidth: "[2px]", + bg: "bg.secondary", + }, + + "&:disabled": { + color: "text.onbutton-disabled", + bg: "bg.secondary", + borderColor: "action.disabled", + }, + }, + tertiary: { + // TODO: not implemented + }, + none: { + padding: "0", + bg: "[inherit]", + }, + }, + size: { + md: { height: "12", padding: "4", rounded: "sm" }, + sm: { height: "9", py: "2", px: "4", rounded: "sm" }, + "icon-md": { + height: "12", + width: "12", + padding: "3", + rounded: "md", + }, + "icon-sm": { height: "9", width: "9", padding: "2", rounded: "md" }, + }, + checked: { + true: { + bg: "action.pressed !important", + color: "text.onbutton-alternative !important", + }, + false: {}, + }, + }, + defaultVariants: { + size: "md", + variant: "primary", + checked: false, + }, +}); + +type ButtonProps = RecipeVariantProps & + ButtonHTMLAttributes & { + isLoading?: boolean; + }; + +export default function Button({ + size, + variant, + isLoading, + disabled, + children, + className, + checked, + ...props +}: ButtonProps) { + return ( + + ); +} diff --git a/frontend/src/renderer/src/components/ui/callout.tsx b/frontend/src/renderer/src/components/ui/callout.tsx new file mode 100644 index 00000000..d215abe2 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/callout.tsx @@ -0,0 +1,106 @@ +import { cva, cx } from "@/styled/css"; +import { styled } from "@/styled/jsx"; +import { hstack } from "@/styled/patterns"; +import type { Icon } from "phosphor-react"; +import { Bell, X } from "phosphor-react"; +import type { HTMLAttributes } from "react"; + +const calloutRecipe = cva({ + base: { + ...hstack.raw({ + alignItems: "center", + gap: "3", + }), + + px: "4", + py: "3", + + rounded: "sm", + borderWidth: "[1px]", + borderStyle: "solid", + + width: "full", + + textStyle: "paragraph.sm.default", + }, + variants: { + variant: { + error: { + bg: "system.error-secondary", + borderColor: "system.error", + color: "system.error", + }, + warning: { + bg: "system.warning-secondary", + borderColor: "system.warning", + color: "system.warning", + }, + success: { + bg: "system.success-secondary", + borderColor: "system.success", + color: "system.success", + }, + info: { + bg: "system.info-secondary", + borderColor: "system.info", + color: "text.default", + }, + }, + noBorder: { + true: { + borderWidth: "0", + }, + }, + }, + defaultVariants: { + variant: "info", + noBorder: false, + }, +}); + +export type CalloutVariant = "error" | "warning" | "success" | "info"; + +interface CalloutProps extends HTMLAttributes { + message: string; + variant?: CalloutVariant; + noBorder?: boolean; + onDismiss?: () => void; + icon?: Icon; +} + +function Callout({ + message, + variant = "info", + noBorder = false, + onDismiss, + icon: IconComponent = Bell, + className, + ...props +}: CalloutProps) { + return ( +
    +
    + ); +} + +export default Callout; diff --git a/frontend/src/renderer/src/components/ui/card.tsx b/frontend/src/renderer/src/components/ui/card.tsx new file mode 100644 index 00000000..bc2b77e5 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/card.tsx @@ -0,0 +1,79 @@ +import { cva, cx } from "@/styled/css"; + +const styles = cva({ + base: { + transitionProperty: "[border, box-shadow]", + transitionTimingFunction: "default", + transitionDuration: "normal", + }, + variants: { + size: { + lg: { + p: "8", + rounded: "sm", + }, + sm: { + rounded: "lg", + p: "4", + }, + }, + disabled: { + true: { + border: "primary", + bg: "bg.primary", + color: "text.lighter", + }, + false: { + border: "primary", + bg: "bg.secondary", + }, + }, + clickable: { + true: {}, + false: {}, + }, + }, + compoundVariants: [ + { + clickable: true, + disabled: false, + css: { + cursor: "pointer", + "&:hover": { + border: "primary-alt", + boxShadow: "[0px 0px 15px 0px #3F479D66]", + }, + }, + }, + { + clickable: true, + disabled: true, + css: { + cursor: "not-allowed", + }, + }, + ], + defaultVariants: { + disabled: false, + clickable: false, + size: "lg", + }, +}); + +interface CardProps { + children?: React.ReactNode; + disabled?: boolean; + size?: "lg" | "sm"; + clickable?: boolean; + className?: string; +} +export default function Card({ + disabled = false, + size = "lg", + clickable = false, + children, + className, +}: CardProps) { + const classes = styles({ size, disabled, clickable }); + return
    {children}
    ; +} diff --git a/frontend/src/renderer/src/components/ui/dialog.tsx b/frontend/src/renderer/src/components/ui/dialog.tsx new file mode 100644 index 00000000..2cb6a475 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/dialog.tsx @@ -0,0 +1,115 @@ +import { css, cx } from "@/styled/css"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import type { ComponentPropsWithoutRef, HTMLAttributes } from "react"; + +const Dialog = DialogPrimitive.Root; +const DialogTrigger = DialogPrimitive.Trigger; +const DialogClose = DialogPrimitive.Close; +const DialogTitle = DialogPrimitive.Title; +const DialogDescription = DialogPrimitive.Description; + +const overlayStyles = css({ + position: "fixed", + inset: "[0]", + zIndex: 50, + bg: "[rgba(0, 0, 0, 0.5)]", + + "&[data-state='open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +const contentStyles = css({ + position: "fixed", + inset: "[0]", + margin: "auto", + zIndex: 50, + + bg: "bg.secondary", + rounded: "sm", + p: "6", + boxShadow: "[0px 4px 8px rgba(0, 0, 0, 0.1)]", + + width: "[90vw]", + minWidth: "[300px]", + maxWidth: "[80%]", + h: "[fit-content]", + + "&[data-state='open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +const headerStyles = css({ + display: "flex", + justifyContent: "space-between", + alignItems: "center", + mb: "4", +}); + +const footerStyles = css({ + display: "flex", + gap: "2", + justifyContent: "flex-end", + alignItems: "center", + mt: "8", +}); + +function DialogOverlay({ + className, + ...props +}: ComponentPropsWithoutRef) { + return ( + + ); +} + +function DialogContent({ + className, + container, + children, + ...props +}: ComponentPropsWithoutRef & { + container?: HTMLElement; +}) { + return ( + + + + {children} + + + ); +} + +function DialogHeader({ className, ...props }: HTMLAttributes) { + return
    ; +} + +function DialogFooter({ className, ...props }: HTMLAttributes) { + return
    ; +} + +export { + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogOverlay, + DialogTitle, + DialogTrigger, +}; diff --git a/frontend/src/renderer/src/components/ui/input.tsx b/frontend/src/renderer/src/components/ui/input.tsx new file mode 100644 index 00000000..674a1efd --- /dev/null +++ b/frontend/src/renderer/src/components/ui/input.tsx @@ -0,0 +1,207 @@ +import { WarningCircle } from "phosphor-react"; +import { useId } from "react"; + +import Suggestion from "@/components/ui/suggestion"; +import { cva, sva } from "@/styled/css"; +import { hstack, stack } from "@/styled/patterns"; + +const input = sva({ + slots: ["container", "inputBox", "input", "label", "errorMessage", "helper"], + base: { + container: stack.raw({ gap: "1", width: "full" }), + inputBox: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + + rounded: "sm", + border: "primary", + + "&:focus-within": { + outline: "none", + boxShadow: "[0px 2px 2px rgba(0, 0, 0, 0.16)]", + }, + }, + input: { + textStyle: "label.md.default", + border: "none", + outline: "none", + flex: "[1]", + + "&::placeholder": { + color: "text.lighter", + }, + }, + label: { textStyle: "label.sm.default", color: "text.lighter" }, + errorMessage: { + ...hstack.raw({ gap: "1" }), + textStyle: "label.sm.default", + color: "system.error", + }, + helper: { + textStyle: "label.sm.default", + color: "text.lighter", + }, + }, + variants: { + size: { + md: { + input: { p: "3" }, + }, + sm: { + input: { px: "3", py: "1" }, + }, + }, + disabled: { + true: { + inputBox: { + bg: "bg.primary", + border: "primary", + color: "text.lighter", + cursor: "not-allowed", + }, + input: { + cursor: "not-allowed", + }, + }, + false: { + inputBox: { + bg: "white", + }, + }, + }, + error: { + true: { + container: { + color: "system.error", + }, + inputBox: { + border: "error", + }, + input: {}, + label: { color: "system.error" }, + }, + false: {}, + }, + }, + defaultVariants: { + error: false, + disabled: false, + size: "md", + }, +}); + +const affix = cva({ + base: { + ...hstack.raw({ alignItems: "center", gap: "1" }), + userSelect: "none", + textStyle: "label.md.default", + }, + variants: { + position: { + prefix: { pl: "3", mr: "-3" }, + suffix: { pr: "3", ml: "-3" }, + }, + }, +}); + +interface InputProps + extends Omit< + React.InputHTMLAttributes, + "prefix" | "suffix" | "size" + >, + React.RefAttributes { + // Rendering + label?: string; + placeholder?: string; + prefix?: string; + suffix?: string; + suggestion?: string; + helper?: string; + // Control + id?: string; + value: string | undefined; + onChange?: React.ChangeEventHandler; + disabled?: boolean; + error?: string | null; + type?: "text" | "number"; + size?: "md" | "sm"; +} +export default function Input({ + // Rendering + label, + placeholder, + prefix, + suffix, + suggestion, + helper, + // Control + id, + ref, + value, + onChange, + disabled = false, + error, + type, + size = "md", + ...props +}: InputProps) { + const randomId = useId(); + const inputId = id ?? randomId; + const errorMessageId = `${inputId}-error`; + + const classes = input({ disabled, error: !!error, size }); + + return ( +
    + {label && ( + + )} + +
    + {prefix && ( +
    + {prefix} + {/* In the designs this vertical bar is defined as a Text, but it's + not. Use a Label instead */} + | +
    + )} + + {suggestion && {suggestion}} + + + + {suffix && ( +
    + {/* In the designs this vertical bar is defined as a Text, but it's + not. Use a Label instead */} + | + {suffix} +
    + )} +
    + + {helper && !error &&

    {helper}

    } + {error && ( + + )} +
    + ); +} diff --git a/frontend/src/renderer/src/components/ui/link.tsx b/frontend/src/renderer/src/components/ui/link.tsx new file mode 100644 index 00000000..53042173 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/link.tsx @@ -0,0 +1,33 @@ +import { type RecipeVariantProps, css, cx } from "@/styled/css"; +import { Link as TanstackLink, type LinkProps as TanstackLinkProps } from "@tanstack/react-router"; +import { CircleNotch } from "phosphor-react"; +import { button } from "./button"; + +type LinkProps = RecipeVariantProps & + TanstackLinkProps & { + isLoading?: boolean; + className?: string; + }; + +export default function Link({ + size, + variant, + checked, + isLoading, + children, + className, + ...props +}: LinkProps) { + return ( + + {isLoading ? ( + + ) : ( + children + )} + + ); +} diff --git a/frontend/src/renderer/src/components/ui/popover.tsx b/frontend/src/renderer/src/components/ui/popover.tsx new file mode 100644 index 00000000..8be12b91 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/popover.tsx @@ -0,0 +1,53 @@ +import { css, cx } from "@/styled/css"; +import * as PopoverPrimitive from "@radix-ui/react-popover"; +import type { ComponentPropsWithoutRef } from "react"; + +const Popover = PopoverPrimitive.Root; +const PopoverTrigger = PopoverPrimitive.Trigger; +const PopoverAnchor = PopoverPrimitive.Anchor; +const PopoverClose = PopoverPrimitive.Close; + +const contentStyles = css({ + zIndex: 50, + bg: "bg.primary", + rounded: "lg", + boxShadow: "[0px 0px 15px 0px #00000026]", + + "&[data-state='open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +const arrowStyles = css({ + fill: "bg.secondary", +}); + +function PopoverContent({ + className, + sideOffset = 8, + showArrow = false, + container, + children, + ...props +}: ComponentPropsWithoutRef & { + showArrow?: boolean; + container?: HTMLElement; +}) { + return ( + + + {children} + {showArrow && } + + + ); +} + +export { Popover, PopoverAnchor, PopoverClose, PopoverContent, PopoverTrigger }; diff --git a/frontend/src/renderer/src/components/ui/select.tsx b/frontend/src/renderer/src/components/ui/select.tsx new file mode 100644 index 00000000..b04110a1 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/select.tsx @@ -0,0 +1,306 @@ +import * as RadixSelect from "@radix-ui/react-select"; +import { CaretDown, CaretUp, Check } from "phosphor-react"; +import { type Ref, useId, useImperativeHandle } from "react"; + +import Suggestion from "@/components/ui/suggestion"; +import { sva } from "@/styled/css"; +import { styled } from "@/styled/jsx"; +import { stack } from "@/styled/patterns"; + +const Affix = styled("span", { + base: { + textStyle: "label.md.default", + color: "text.lighter", + flexShrink: "0", + }, +}); + +export type SelectOption = { id: string; text: string; shortText?: string }; +export type SelectSuggestion = { id: string; text?: string }; + +interface SelectProps { + options: SelectOption[]; + label?: string; + value?: string; + onChange?: (value: SelectOption) => void; + onOpenChange?: (open: boolean) => void; + prefix?: string; + suffix?: string; + suggestion?: SelectSuggestion; + priorityOrder?: string[]; + placeholder?: string; + disabled?: boolean; + size?: "md" | "sm"; + ref?: Ref<{ value: string | undefined }>; +} + +function orderByPriority(options: SelectOption[], priority: string[] = []) { + const filtered = options.filter(({ id }) => !priority.includes(id)); + const preferred = priority + .map((p) => options.find(({ id }) => p === id)) + .filter((o): o is SelectOption => !!o); + return [...preferred, ...filtered]; +} + +function secureSuggestion( + suggestion: SelectSuggestion | undefined, + options: SelectOption[], +): SelectOption | undefined { + if (!suggestion) return undefined; + if (suggestion.text) return { id: suggestion.id, text: suggestion.text }; + return options.find(({ id }) => id === suggestion.id); +} + +const select = sva({ + slots: [ + "container", + "trigger", + "value", + "caret", + "content", + "viewport", + "item", + "itemIndicator", + "scrollButton", + ], + base: { + container: { ...stack.raw({ gap: "1" }), width: "full" }, + trigger: { + display: "flex", + alignItems: "center", + gap: "2", + width: "full", + bg: "white", + border: "primary", + rounded: "sm", + cursor: "pointer", + textAlign: "left", + appearance: "none", + textStyle: "label.md.default", + color: "text.default", + + "&[data-state='open']": { + boxShadow: "[0px 2px 2px rgba(0, 0, 0, 0.16)]", + borderColor: "[#110041]", + }, + "&:focus-visible": { + outlineColor: "brand.primary", + outlineWidth: "0.5", + outlineStyle: "solid", + outlineOffset: "0.5", + }, + "&[data-disabled]": { + bg: "bg.primary", + cursor: "not-allowed", + color: "text.lighter", + }, + "&[data-placeholder]": { + color: "text.lighter", + }, + }, + value: { + flex: "[1]", + overflow: "hidden", + textOverflow: "ellipsis", + whiteSpace: "nowrap", + }, + caret: { + flexShrink: "0", + color: "text.default", + transition: "[transform 0.15s ease]", + + "[data-state='open'] > &": { + transform: "[rotate(180deg)]", + }, + }, + content: { + bg: "white", + rounded: "sm", + boxShadow: "[0px 8px 16px rgba(0, 0, 0, 0.08)]", + border: "secondary", + overflow: "hidden", + zIndex: "10", + minWidth: "[var(--radix-select-trigger-width)]", + }, + viewport: { + maxHeight: "[400px]", + overflowY: "auto", + }, + scrollButton: { + display: "flex", + alignItems: "center", + justifyContent: "center", + py: "1", + color: "text.lighter", + cursor: "default", + bg: "white", + }, + item: { + display: "flex", + alignItems: "center", + gap: "2", + textStyle: "label.md.default", + color: "text.default", + cursor: "pointer", + outline: "none", + userSelect: "none", + + "&[data-highlighted]": { + bg: "bg.primary-alternative", + }, + "&[data-state='checked']": { + bg: "bg.primary-alternative", + }, + "&[data-disabled]": { + cursor: "not-allowed", + color: "text.lighter", + }, + }, + itemIndicator: { + color: "brand.primary", + display: "flex", + alignItems: "center", + flexShrink: "0", + }, + }, + variants: { + size: { + md: { + trigger: { px: "3", py: "3" }, + item: { px: "3", py: "3" }, + }, + sm: { + trigger: { px: "3", py: "1" }, + item: { px: "3", py: "3" }, + }, + }, + }, + defaultVariants: { + size: "md", + }, +}); + +export default function Select({ + options, + label, + value, + onChange, + onOpenChange, + prefix, + suffix, + suggestion, + priorityOrder = [], + placeholder = "", + disabled = false, + size = "md", + ref, +}: SelectProps) { + const triggerId = useId(); + const classes = select({ size }); + + const orderedOptions = orderByPriority(options, priorityOrder); + const securedSuggestion = secureSuggestion(suggestion, options); + + useImperativeHandle(ref, () => ({ value }), [value]); + + const handleChange = (id: string) => { + const option = options.find((o) => o.id === id); + if (option) onChange?.(option); + }; + + const handleSuggestionClick = (e: React.MouseEvent) => { + e.stopPropagation(); + if (securedSuggestion) handleChange(securedSuggestion.id); + }; + + const handleSuggestionKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" || e.key === " ") { + e.stopPropagation(); + if (securedSuggestion) handleChange(securedSuggestion.id); + } + }; + + return ( +
    + {label && ( + + {label} + + )} + + + + {/* biome-ignore lint/a11y/useSemanticElements lint/a11y/useAriaPropsForRole: Radix merges role, aria-expanded, aria-controls, and tabIndex onto this div at runtime via asChild */} +
    + {prefix && } + + + + + + {!value && securedSuggestion ? ( + + ) : ( + + {value + ? (options.find((o) => o.id === value)?.shortText ?? + options.find((o) => o.id === value)?.text ?? + placeholder) + : undefined} + + )} + + + {suffix && } +
    +
    + + + + + + + + {orderedOptions.map(({ id, text }) => ( + + + + + {text} + + ))} + + + + + + +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/ui/suggestion.tsx b/frontend/src/renderer/src/components/ui/suggestion.tsx new file mode 100644 index 00000000..d41aa5a4 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/suggestion.tsx @@ -0,0 +1,25 @@ +import { styled } from "@/styled/jsx"; + +const Suggestion = styled("mark", { + base: { + bg: "bg.primary-alternative", + textStyle: "label.md.default", + display: "inline-flex", + }, + variants: { + clickable: { + true: { cursor: "pointer" }, + false: { cursor: "unset" }, + }, + rounded: { + true: { rounded: "md" }, + false: { rounded: "[0px]" }, + }, + }, + defaultVariants: { + clickable: false, + rounded: false, + }, +}); + +export default Suggestion; diff --git a/frontend/src/renderer/src/components/ui/switch.tsx b/frontend/src/renderer/src/components/ui/switch.tsx new file mode 100644 index 00000000..dfb2442b --- /dev/null +++ b/frontend/src/renderer/src/components/ui/switch.tsx @@ -0,0 +1,57 @@ +import * as RadixSwitch from "@radix-ui/react-switch"; +import { css } from "@/styled/css"; + +const rootStyle = css({ + width: "[44px]", + height: "[24px]", + borderRadius: "full", + border: "none", + cursor: "pointer", + position: "relative", + flexShrink: "0", + bg: "bg.primary-highlight", + + transitionProperty: "[background-color]", + transitionDuration: "slow", + transitionTimingFunction: "default", + + '&[data-state="checked"]': { + bg: "brand.primary", + }, + + "&:disabled": { + cursor: "not-allowed", + opacity: "0.4", + }, +}); + +const thumbStyle = css({ + display: "block", + width: "[20px]", + height: "[20px]", + borderRadius: "full", + bg: "white", + position: "absolute", + top: "[2px]", + left: "[2px]", + + transitionProperty: "[transform]", + transitionDuration: "slow", + transitionTimingFunction: "default", + + '&[data-state="checked"]': { + transform: "[translateX(20px)]", + }, +}); + +type SwitchProps = RadixSwitch.SwitchProps; + +function Switch(props: SwitchProps) { + return ( + + + + ); +} + +export default Switch; diff --git a/frontend/src/renderer/src/components/ui/toast.tsx b/frontend/src/renderer/src/components/ui/toast.tsx new file mode 100644 index 00000000..48f935a3 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/toast.tsx @@ -0,0 +1,35 @@ +import type { Icon } from "phosphor-react"; +import { type Toast as HotToast, toast } from "react-hot-toast"; +import Callout, { type CalloutVariant } from "./callout"; + +export type ToastVariant = CalloutVariant; + +interface ToastProps { + t: HotToast; + message: string; + variant?: ToastVariant; + icon?: Icon; +} + +const ASSERTIVE_VARIANTS: ToastVariant[] = ["error", "warning"]; + +function Toast({ t, message, variant = "info", icon }: ToastProps) { + const isAssertive = ASSERTIVE_VARIANTS.includes(variant); + + return ( +
    + toast.remove(t.id)} + role={isAssertive ? "alert" : "status"} + aria-live={isAssertive ? "assertive" : "polite"} + aria-atomic="true" + noBorder + /> +
    + ); +} + +export default Toast; diff --git a/frontend/src/renderer/src/components/ui/tooltip.tsx b/frontend/src/renderer/src/components/ui/tooltip.tsx new file mode 100644 index 00000000..537cf185 --- /dev/null +++ b/frontend/src/renderer/src/components/ui/tooltip.tsx @@ -0,0 +1,50 @@ +import { css, cx } from "@/styled/css"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; +import type { ComponentPropsWithoutRef } from "react"; + +const TooltipProvider = TooltipPrimitive.Provider; +const Tooltip = TooltipPrimitive.Root; +const TooltipTrigger = TooltipPrimitive.Trigger; + +const contentStyles = css({ + zIndex: 50, + bg: "bg.primary", + rounded: "md", + boxShadow: "[0px 0px 15px 0px #00000026]", + + "&[data-state='delayed-open']": { + animation: "fadeIn", + }, + "&[data-state='closed']": { + animation: "fadeOut", + }, +}); + +const arrowStyles = css({ + fill: "bg.primary", +}); + +function TooltipContent({ + className, + sideOffset = 6, + showArrow = true, + children, + ...props +}: ComponentPropsWithoutRef & { + showArrow?: boolean; +}) { + return ( + + + {children} + {showArrow && } + + + ); +} + +export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger }; diff --git a/frontend/src/renderer/src/components/uncontrolled-input/UncontrolledInput.styles.ts b/frontend/src/renderer/src/components/uncontrolled-input/UncontrolledInput.styles.ts new file mode 100644 index 00000000..991ff6f9 --- /dev/null +++ b/frontend/src/renderer/src/components/uncontrolled-input/UncontrolledInput.styles.ts @@ -0,0 +1,43 @@ +import { styled } from "@/styles"; + +export const Container = styled("label", { + display: "flex", + flexDirection: "column", + gap: "$xs", + + fontWeight: 400, + fontSize: "$labelSm", + lineHeight: "$labelSm", + + color: "$textDefault", +}); + +export const InputContainer = styled("div", { + display: "flex", + flexDirection: "row", + alignItems: "center", + gap: "$s", + flex: 1, + + p: 12, + + bg: "$bgSecondary", + b: "1px solid $borderPrimary", + borderRadius: "$xs", + + "&:focus": { + outline: "none", + b: "1px solid $borderPrimaryAlt", + boxShadow: "0px 2px 2px rgba(0, 0, 0, 0.16)", + }, +}); +export const Input = styled("input", { + fontWeight: 400, + fontSize: "$labelMd", + lineHeight: "$labelMd", + + b: "none", + outline: "none", + + flex: 1, +}); diff --git a/frontend/src/renderer/src/components/uncontrolled-input/index.tsx b/frontend/src/renderer/src/components/uncontrolled-input/index.tsx new file mode 100644 index 00000000..0e777e7b --- /dev/null +++ b/frontend/src/renderer/src/components/uncontrolled-input/index.tsx @@ -0,0 +1,141 @@ +import { + type ChangeEventHandler, + type KeyboardEvent, + type ReactNode, + useImperativeHandle, + useState, +} from "react"; + +import Label from "@/components/label"; +import Text from "@/components/text"; +import Suggestion from "@/components/ui/suggestion"; +import type { CSS } from "@/styles"; +import type { NativeComponent } from "@/types/component"; +import { forwardRef } from "react"; +import { + Container, + InputContainer, + Input as StyledInput, +} from "./UncontrolledInput.styles"; + +export type InputRefValue = { value: string }; +interface Props + extends NativeComponent<"input", "prefix" | "type" | "value" | "onChange"> { + label?: string; + suggestion?: string; + helper?: string; + sufix?: ReactNode; + prefix?: ReactNode; + defaultValue?: string; + onChange?: (value: string) => void; + type?: "text" | "number"; + css?: CSS; + specialCharacters?: string; +} +export default forwardRef<{ value: string }, Props>(function UncontrolledInput( + { + label, + helper, + suggestion, + prefix, + sufix, + defaultValue, + onChange, + type = "text", + specialCharacters = "", + ...props + }, + ref, +) { + const [value, setValue] = useState(defaultValue ?? ""); + + // Only exposes `selected` object to the parent component + useImperativeHandle( + ref, + () => { + return { + value, + }; + }, + [value], + ); + + const isValueEmpty = !value || value === ""; + + const updateValue = (newValue: string) => { + if (type === "number") { + const regex = new RegExp(`^[\\d${specialCharacters}.]+$`); + if (regex.test(newValue) || !newValue) { + setValue(newValue); + onChange?.(newValue); + return; + } + return; + } + + setValue(newValue); + + onChange?.(newValue); + }; + + const handleClickSuggestion = () => { + updateValue(suggestion as string); // We are sure is a string because the button is enabled only in case suggestion = string + }; + const handleKeySuggestion = (e: KeyboardEvent) => { + e.preventDefault(); + + if (e.code === "Space" || e.code === "Enter") + updateValue(suggestion as string); // We are sure is a string because the button is enabled only in case suggestion = string + }; + + const handleChange: ChangeEventHandler = (e) => { + updateValue(e.target.value); + }; + + return ( + + {/* LABEL */} + {label} + + {/* INPUT CONTAINER */} + + {/* PREFIX */} + {prefix && ( + <> + + | + + )} + + {/* INPUT */} + + + {/* SUGGESTION */} + {suggestion && isValueEmpty && ( + <> + | + + {suggestion} + + + )} + + {/* SUFIX */} + {sufix} + + + {/* HELPER */} + {helper && } + + ); +}); diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.styles.ts b/frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.styles.ts new file mode 100644 index 00000000..60f516d8 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.styles.ts @@ -0,0 +1,9 @@ +import { styled } from "@/styles"; + +const Container = styled("div", { + display: "flex", + flexDirection: "column", + gap: 64, +}); + +export default Container; diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.types.ts b/frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.types.ts new file mode 100644 index 00000000..47fea702 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/FormGroup.types.ts @@ -0,0 +1,17 @@ +import type { FormEventHandler } from "react"; + +import type { FormValue, RegisterFunction } from "@/hooks/useForm"; +import type { LabelDecisiones } from "@/types/aymurai"; +import type Suggester from "@/utils/predictions/suggestions"; + +export interface FormProps { + decision?: number; + register: RegisterFunction; + onSubmit: FormEventHandler; + onCheck: (checked: boolean) => void; + suggester: Suggester; +} + +export interface FormDecisionProps extends FormProps { + getDecisionValue: (n: number) => (field: LabelDecisiones) => FormValue; +} diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/forms/DatosAcusado.tsx b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/DatosAcusado.tsx new file mode 100644 index 00000000..e8c8a696 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/DatosAcusado.tsx @@ -0,0 +1,52 @@ +import { Input, ValidationForm } from "@/components"; +import Select from "@/components/ui/select"; +import { LabelType } from "@/types/aymurai"; +import type { FormProps } from "../FormGroup.types"; +import json from "./options.json"; + +export default function DatosAcusado({ + onSubmit, + onCheck, + register, + suggester, +}: FormProps) { + return ( + + + + + + + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoGral.tsx b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoGral.tsx new file mode 100644 index 00000000..e2548216 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoGral.tsx @@ -0,0 +1,55 @@ +import { Input, ValidationForm } from "@/components"; +import { LabelType } from "@/types/aymurai"; +import type { FormProps } from "../FormGroup.types"; + +export default function InfoGral({ + onSubmit, + onCheck, + register, + suggester, +}: FormProps) { + return ( + + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoHecho.tsx b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoHecho.tsx new file mode 100644 index 00000000..fcb71365 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/InfoHecho.tsx @@ -0,0 +1,246 @@ +import { Plus } from "phosphor-react"; +import { useState } from "react"; + +import { + Button, + Checkbox, + CheckboxGroup, + Input, + Radio, + RadioGroup, + Stack, + ValidationForm, +} from "@/components"; +import Select from "@/components/ui/select"; +import { css } from "@/styled/css"; +import { LabelDecisiones } from "@/types/aymurai"; +import nArray from "@/utils/nArray"; +import type { FormDecisionProps } from "../FormGroup.types"; +import json from "./options.json"; + +export default function DatosDenunciante({ + decision, + onSubmit, + onCheck, + register, + suggester, + getDecisionValue, +}: FormDecisionProps) { + const [frasesAgresion, setFrasesAgresion] = useState(1); + + const newFraseAgresion = () => setFrasesAgresion(frasesAgresion + 1); + + const frasesArray = nArray(frasesAgresion, undefined).map((_, i) => i); + const fraseName = (i: number) => `${LabelDecisiones.FRASES_AGRESION}${i}`; + const defaultValue = getDecisionValue(decision ?? 0); + const prop = (label: LabelDecisiones) => register(label, decision); + + return ( + + + + + + {frasesArray.map((i) => ( + 1 ? i + 1 : undefined} + ref={prop(fraseName(i) as LabelDecisiones)} // Treat this dynamic Label the same way as any other + label="Frases de la agresión" + {...suggester.text(fraseName(i) as LabelDecisiones)} + /> + ))} + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/forms/index.ts b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/index.ts new file mode 100644 index 00000000..0acd781a --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/index.ts @@ -0,0 +1,7 @@ +import DatosAcusado from "./DatosAcusado"; +import DatosDenunciante from "./DatosDenunciante"; +import Decision from "./Decision"; +import InfoGral from "./InfoGral"; +import InfoHecho from "./InfoHecho"; + +export { InfoGral, DatosDenunciante, DatosAcusado, InfoHecho, Decision }; diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/forms/options.json b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/options.json new file mode 100644 index 00000000..a35142a8 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/forms/options.json @@ -0,0 +1,1937 @@ +{ + "GENERO": [ + { "id": "varon_cis", "text": "Varón cis" }, + { "id": "mujer_cis", "text": "Mujer cis" }, + { "id": "varon_trans", "text": "Varón trans" }, + { "id": "mujer_trans", "text": "Mujer trans" }, + { "id": "travesti", "text": "Travesti" }, + { "id": "no_binaria", "text": "No binaria" }, + { "id": "sd", "text": "S/D" }, + { "id": "no_corresponde", "text": "No corresponde" } + ], + "ZONA_DEL_HECHO": [ + { "id": "zona_sur", "text": "Zona Sur" }, + { "id": "zona_este", "text": "Zona Este" }, + { "id": "zona_oeste", "text": "Zona Oeste" }, + { "id": "zona_norte", "text": "Zona Norte" }, + { "id": "provincia_de_buenos_aires", "text": "Provincia de Buenos Aires" }, + { "id": "no_corresponde", "text": "No corresponde" }, + { "id": "mas_de_una_zona", "text": "Más de una zona" }, + { "id": "s/d", "text": "S/D" } + ], + "LUGAR_DEL_HECHO": [ + { "id": "en_auto_particular", "text": "En auto particular" }, + { "id": "en_comisaria", "text": "En comisaría" }, + { + "id": "en_complejo_penitenciario", + "text": "En complejo penitenciario" + }, + { "id": "en_domicilio_laboral", "text": "En domicilio laboral" }, + { + "id": "en_domicilio_laboral_y_mediante_medios_tecnologicos", + "text": "En domicilio laboral y mediante medios tecnológicos" + }, + { "id": "en_domicilio_particular", "text": "En domicilio particular" }, + { + "id": "en_domicilio_particular_y_en_puerta_de_domicilio_particular", + "text": "En domicilio particular y en puerta de domicilio particular" + }, + { + "id": "en_domicilio_particular_y_mediante_medios_tecnologicos", + "text": "En domicilio particular y mediante medios tecnológicos" + }, + { "id": "en_estadio_de_futbol", "text": "En estadio de fútbol" }, + { "id": "en_geriatrico", "text": "En geriátrico" }, + { "id": "en_hospital", "text": "En hospital" }, + { "id": "en_institucion_privada", "text": "En institución privada" }, + { "id": "en_lugar_privado", "text": "En lugar privado" }, + { "id": "en_lugar_publico", "text": "En lugar público" }, + { + "id": "en_puerta_de_domicilio_particular_y_mediante_medios_tecnológicos", + "text": "En puerta de domicilio particular y mediante medios tecnológicos" + }, + { "id": "en_transporte_publico", "text": "En transporte público" }, + { + "id": "en_una_institucion_educativa", + "text": "En una institución educativa" + }, + { + "id": "en_via_publica_y_mediante_medios_tecnologicos", + "text": "En vía pública y mediante medios tecnológicos" + }, + { + "id": "mediante_medios_tecnologicos", + "text": "Mediante medios tecnológicos" + }, + { "id": "pasillo_de_domicilio", "text": "Pasillo de domicilio" }, + { + "id": "puerta_de_domicilio_particular_y_en_domicilio_laboral", + "text": "Puerta de domicilio particular y en domicilio laboral" + }, + { + "id": "puerta_de_domicilio_particular", + "text": "Puerta de domicilio particular" + }, + { + "id": "puerta_de_domicilio_particular_y_en_puerta_de_domicilio_laboral", + "text": "Puerta de domicilio particular y en puerta de domicilio laboral" + }, + { "id": "via_publica", "text": "Vía pública" }, + { + "id": "via_publica_y_en_domicilio_particular", + "text": "Via pública y en domicilio particular" + }, + { + "id": "via_publica_y_en_domicilio_particular_y_mediante_medios_tecnologicos", + "text": "Vía pública y en domicilio particular y mediante medios tecnológicos" + } + ], + "FRECUENCIA_EPISODIOS": [ + { "id": "primera_vez", "text": "Primera vez" }, + { "id": "esporadico", "text": "Esporádico" }, + { "id": "diario", "text": "Diario" }, + { "id": "habitual", "text": "Habitual" }, + { "id": "eventual", "text": "Eventual" }, + { "id": "sd", "text": "S/D" }, + { "id": "no_corresponde", "text": "No corresponde" } + ], + "NIVEL_INSTRUCCION": [ + { "id": "sin_instruccion", "text": "Sin instruccion" }, + { "id": "sin_escolarizar", "text": "Sin escolarizar" }, + { "id": "primario_incompleto", "text": "Primario incompleto" }, + { "id": "primario_completo", "text": "Primario completo" }, + { "id": "primario_en_curso", "text": "Primario en curso" }, + { "id": "secundario_incompleto", "text": "Secundario incompleto" }, + { "id": "secundario_completo", "text": "Secundario completo" }, + { "id": "secundario_en_curso", "text": "Secundario en curso" }, + { "id": "terciario_incompleto", "text": "Terciario incompleto" }, + { "id": "terciario_completo", "text": "Terciario completo" }, + { "id": "terciario_en_curso", "text": "Terciario en curso" }, + { + "id": "universitario_incompleto", + "text": "Universitario incompleto" + }, + { "id": "universitario_completo", "text": "Universitario completo" }, + { "id": "universitario_en_curso", "text": "Universitario en curso" }, + { "id": "sd", "text": "S/D" }, + { "id": "no_corresponde", "text": "No corresponde" } + ], + "MODALIDAD_DE_LA_VIOLENCIA": [ + { "id": "domestica", "text": "Doméstica" }, + { "id": "en_espacio_publico", "text": "En espacio público" }, + { "id": "institucional", "text": "Institucional" }, + { "id": "laboral", "text": "Laboral" }, + { "id": "libertad_reproductiva", "text": "Libertad reproductiva" }, + { "id": "mediatica", "text": "Mediática" }, + { "id": "no_corresponde", "text": "No corresponde" }, + { "id": "obstetrica", "text": "Obstétrica" }, + { "id": "publica_politica", "text": "Pública política" } + ], + "TIPO_DE_RESOLUCION": [ + { "id": "definitiva", "text": "Definitiva" }, + { "id": "interlocutoria", "text": "Interlocutoria" } + ], + "DECISION": [ + { "id": "hace_lugar", "text": "Hace lugar" }, + { "id": "no_hace_lugar", "text": "No hace lugar" } + ], + "CONDUCTA": [ + { + "id": "abandonar_animal_domestico", + "text": "Abandonar animal doméstico" + }, + { "id": "abandono_de_personas", "text": "Abandono de personas" }, + { "id": "abuso_de_armas", "text": "Abuso de armas" }, + { + "id": "abuso_de_autoridad_e_incumplimiento_deberes_funcionario_publico", + "text": "Abuso de autoridad e incumplimiento deberes funcionario público" + }, + { "id": "abuso_sexual", "text": "Abuso sexual" }, + { + "id": "acceder_lugares_distintos_segun_entrada", + "text": "Acceder lugares distintos según entrada" + }, + { + "id": "acceder_a_lugares_distintos_segun_entrada", + "text": "Acceder a lugares distintos según entrada" + }, + { + "id": "acceso_a_sistema_restringido", + "text": "Acceso a sistema restringido" + }, + { "id": "acoso_sexual_callejero", "text": "Acoso sexual callejero" }, + { + "id": "actividades_lucrativas_sin_autorizacion", + "text": "Actividades lucrativas sin autorización" + }, + { + "id": "actividades_lucrativas_sin_habilitacion", + "text": "Actividades lucrativas sin habilitación" + }, + { + "id": "actos_contenido_sexual_con_menores", + "text": "Actos contenido sexual con menores" + }, + { + "id": "administracion_fraudulenta", + "text": "Administración fraudulenta" + }, + { + "id": "afectar_desarrollo_espectaculo", + "text": "Afectar desarrollo espectáculo" + }, + { + "id": "afectar_el_desarrollo_del_espectaculo", + "text": "Afectar el desarrollo del espectáculo" + }, + { + "id": "afectar_funcionamiento_servicios_publicos", + "text": "Afectar funcionamiento servicios públicos" + }, + { + "id": "afectar_servicios_de_emergencia_o_seguridad", + "text": "Afectar servicios de emergencia o seguridad" + }, + { + "id": "afectar_servicios_emergencia", + "text": "Afectar servicios emergencia" + }, + { "id": "afectar_señalizacion", "text": "Afectar señalización" }, + { "id": "allanamiento_autonomo", "text": "Allanamiento autónomo" }, + { "id": "alterar_programa", "text": "Alterar programa" }, + { "id": "alterar_sepulturas", "text": "Alterar sepulturas" }, + { "id": "amenazas", "text": "Amenazas" }, + { "id": "amparo", "text": "Amparo" }, + { "id": "apariencia_falsa", "text": "Apariencia falsa" }, + { + "id": "apariencia_falsa_para_entrar_a_domicilio_o_lugar_privado", + "text": "Apariencia falsa para entrar a domicilio o lugar privado" + }, + { + "id": "apropiacion_indebida_de_tributos", + "text": "Apropiacion indebida de tributos" + }, + { + "id": "arrojar_cosas_que_puedan_causar_lesiones", + "text": "Arrojar cosas que puedan causar lesiones" + }, + { "id": "arrojar_cosas_sustancias", "text": "Arrojar cosas sustancias" }, + { + "id": "arrojar_sustancias_insalubres_en_lugares_publicos", + "text": "Arrojar sustancias insalubres en lugares públicos" + }, + { "id": "asociacion_ilicita", "text": "Asociacion ilícita" }, + { + "id": "asuncion_falsa_de_contravencion", + "text": "Asunción falsa de contravención" + }, + { + "id": "atentado_contra_la_autoridad", + "text": "Atentado contra la autoridad" + }, + { "id": "ausencia_de_habilitacion", "text": "Ausencia de habilitación" }, + { "id": "banderas", "text": "Banderas" }, + { "id": "carteles_afiches_volantes", "text": "Carteles afiches volantes" }, + { "id": "cierre_defectuoso", "text": "Cierre defectuoso" }, + { + "id": "circular_por_carriles_exclusivos", + "text": "Circular por carriles exclusivos" + }, + { + "id": "circular_por_lugar_prohibido", + "text": "Circular por lugar prohibido" + }, + { "id": "cohecho_activo", "text": "Cohecho activo" }, + { "id": "cohecho_pasivo", "text": "Cohecho pasivo" }, + { "id": "coimas", "text": "Coimas" }, + { "id": "competencia_desleal", "text": "Competencia desleal" }, + { + "id": "conducir_con_mayor_cantidad_de_alcohol_en_sangre_del_permitido", + "text": "Conducir con mayor cantidad de alcohol en sangre del permitido" + }, + { + "id": "conducir_con_mayor_grado_de_alcohol_o_bajo_efectos_de_estupefacientes", + "text": "Conducir con mayor grado de alcohol o bajo efectos de estupefacientes" + }, + { + "id": "conducir_sin_licencia_que_lo_habilite_por_categoria_de_vehiculo", + "text": "Conducir sin licencia que lo habilite por categoría de vehiculo" + }, + { + "id": "conducir_usando_aparato_electronico", + "text": "Conducir usando aparato electrónico" + }, + { "id": "connivencia_policial", "text": "Connivencia policial" }, + { + "id": "contactar_menor_por_medio_de_tecnologias_para_cometer_delitos_contra_su_integridad_sexual", + "text": "Contactar menor por medio de tecnologías para cometer delitos contra su integridad sexual" + }, + { "id": "cruce_de_semaforo_en_rojo", "text": "Cruce de semaforo en rojo" }, + { "id": "cuida_coche", "text": "Cuida coche" }, + { + "id": "cuidar_coches_sin_autorizacion", + "text": "Cuidar coches sin autorización" + }, + { "id": "daños", "text": "Daños" }, + { "id": "daños_informaticos", "text": "Daños informáticos" }, + { "id": "defraudacion", "text": "Defraudación" }, + { + "id": "defraudacion_contra_la_administracion_publica", + "text": "Defraudación contra la administración pública" + }, + { + "id": "delito_contra_seguridad_transito", + "text": "Delito contra seguridad tránsito" + }, + { "id": "denegacion_de_justicia", "text": "Denegación de justicia" }, + { "id": "derecho_admision", "text": "Derecho admisión" }, + { "id": "desarmado_automotor", "text": "Desarmado automotor" }, + { + "id": "desinfeccion_y_desratizacion", + "text": "Desinfección y desratización" + }, + { + "id": "desobediencia_a_cargas_procesales", + "text": "Desobediencia a cargas procesales" + }, + { + "id": "desobediencia_a_la_autoridad", + "text": "Desobediencia a la autoridad" + }, + { + "id": "difusion_no_autorizada_de_imagenes", + "text": "Difusión no autorizada de imágenes" + }, + { + "id": "difusion_no_autorizada_de_imagenes_intimas", + "text": "Difusion no autorizada de imágenes íntimas" + }, + { "id": "discriminar", "text": "Discriminar" }, + { "id": "documentacion_sanitaria", "text": "Documentación sanitaria" }, + { "id": "ejecucion_de_multa", "text": "Ejecución de multa" }, + { + "id": "ejercer_ilegitimamente_actividad", + "text": "Ejercer ilegítimamente actividad" + }, + { + "id": "ejercicio_ilegal_de_la_medicina", + "text": "Ejercicio ilegal de la medicina" + }, + { + "id": "elementos_de_prevencion_contra_incendio", + "text": "Elementos de prevención contra incendio" + }, + { "id": "encubrimiento", "text": "Encubrimiento" }, + { + "id": "encubrimiento_actividades_baile", + "text": "Encubrimiento actividades baile" + }, + { "id": "ensuciar_bienes", "text": "Ensuciar bienes" }, + { + "id": "entregar_indebidamente_armas_explosivos", + "text": "Entregar indebidamente armas explosivos" + }, + { "id": "espantar_animales", "text": "Espantar animales" }, + { "id": "espejos_retrovisores", "text": "Espejos retrovisores" }, + { "id": "estacionamiento_prohibido", "text": "Estacionamiento prohibido" }, + { + "id": "estacionamiento_sobre_senda_peatonal", + "text": "Estacionamiento sobre senda peatonal" + }, + { "id": "estafa", "text": "Estafa" }, + { "id": "evasion_tributaria", "text": "Evasión tributaria" }, + { "id": "estupefacientes", "text": "Estupefacientes" }, + { "id": "exceso_capacidad_ingreso", "text": "Exceso capacidad ingreso" }, + { "id": "exceso_de_velocidad", "text": "Exceso de velocidad" }, + { + "id": "exhibicion_de_documentacion_obligatoria", + "text": "Exhibición de documentacion obligatoria" + }, + { "id": "exhibiciones_obscenas", "text": "Exhibiciones obscenas" }, + { + "id": "exhortos_de_otras_jurisdicciones", + "text": "Exhortos de otras jurisdicciones" + }, + { + "id": "explotacion_trabajo_infantil", + "text": "Explotación trabajo infantil" + }, + { "id": "extorsion", "text": "Extorsión" }, + { + "id": "fabricar_transportar_artefactos_pirotecnicos", + "text": "Fabricar transportar artefactos pirotécnicos" + }, + { "id": "falsa_denuncia", "text": "Falsa denuncia" }, + { + "id": "falsedad_documental_de_certificado_de_aptitud_ambiental", + "text": "Falsedad documental de certificado de aptitud ambiental" + }, + { + "id": "falsificacion_certificado_medico", + "text": "Falsificación certificado médico" + }, + { + "id": "falsificacion_de_documento", + "text": "Falsificación de documento" + }, + { + "id": "falsificacion_de_marcas_firmas_señas_oficiales", + "text": "Falsificación de marcas firmas señas oficiales" + }, + { + "id": "falsificacion_de_numeracion_de_objeto_registrada_de_acuerdo_a_ley", + "text": "Falsificación de numeración de objeto registrada de acuerdo a ley" + }, + { + "id": "falta_de_poliza_de_seguros", + "text": "Falta de póliza de seguros" + }, + { + "id": "favorecimiento_evasion_persona_detenida", + "text": "Favorecimiento evasión persona detenida" + }, + { "id": "frustrar_subasta_publica", "text": "Frustrar subasta pública" }, + { + "id": "guardar_artefactos_pirotecnicos", + "text": "Guardar artefactos pirotécnicos" + }, + { + "id": "guardar_elementos_aptos_violencia", + "text": "Guardar elementos aptos violencia" + }, + { "id": "habeas_corpus", "text": "Habeas corpus" }, + { + "id": "habilitacion_en_infraccion", + "text": "Habilitación en infracción" + }, + { "id": "homicidio", "text": "Homicidio" }, + { "id": "hostigamiento", "text": "Hostigamiento" }, + { "id": "hostigamiento_digital", "text": "Hostigamiento digital" }, + { "id": "hurto", "text": "Hurto" }, + { + "id": "impedimento_de_contacto_de_menor_con_padre_no_conviviente", + "text": "Impedimento de contacto de menor con padre no conviviente" + }, + { + "id": "incendio_explosion_inundacion_con_peligro_para_bienes", + "text": "Incendio explosión inundación con peligro para bienes" + }, + { + "id": "incendios_y_otros_estragos", + "text": "Incendios y otros estragos" + }, + { "id": "incitar_desorden", "text": "Incitar desorden" }, + { "id": "incitar_al_desorden", "text": "Incitar al desorden" }, + { "id": "incumplimiento_de_plazos", "text": "Incumplimiento de plazos" }, + { + "id": "incumplimiento_deberes_familiares", + "text": "Incumplimiento deberes familiares" + }, + { + "id": "incumplimiento_deberes_funcionario_publico", + "text": "Incumplimiento deberes funcionario público" + }, + { + "id": "incumplimiento_medidas_prevencion_sanidad", + "text": "Incumplimiento medidas prevención sanidad" + }, + { + "id": "incumplimiento_perimetro_profundidad", + "text": "Incumplimiento perímetro profundidad" + }, + { "id": "incumplir_clausura", "text": "Incumplir clausura" }, + { + "id": "incumplir_obligaciones_legales", + "text": "Incumplir obligaciones legales" + }, + { "id": "inducir_menor_a_mendigar", "text": "Inducir menor a mendigar" }, + { + "id": "infraccion_reglamentos_seguridad", + "text": "Infracción reglamentos seguridad" + }, + { + "id": "ingresar_artefactos_pirotecnicos", + "text": "Ingresar artefactos pirotécnicos" + }, + { + "id": "ingresar_consumir_bebidas_alcoholicas", + "text": "Ingresar consumir bebidas alcohólicas" + }, + { + "id": "ingresar_contra_derecho_admision", + "text": "Ingresar contra derecho admisión" + }, + { + "id": "ingresar_sin_autorizacion_lugares_reservados", + "text": "Ingresar sin autorización lugares reservados" + }, + { "id": "ingresar_sin_entrada", "text": "Ingresar sin entrada" }, + { + "id": "ingresar_sin_entrada_autorizacion", + "text": "Ingresar sin entrada autorización" + }, + { + "id": "ingreso_a_domicilio_sin_autorizacion", + "text": "Ingreso a domicilio sin autorización" + }, + { "id": "inhumar_exhumar_profanar", "text": "Inhumar exhumar profanar" }, + { "id": "intimidacion", "text": "Intimidación" }, + { "id": "juego_sin_autorizacion", "text": "Juego sin autorización" }, + { + "id": "juegos_de_azar_sin_autorizacion", + "text": "Juegos de azar sin autorización" + }, + { "id": "lesiones", "text": "Lesiones" }, + { "id": "ley_451", "text": "Ley 451" }, + { "id": "licencia_vencida", "text": "Licencia vencida" }, + { "id": "maltrato", "text": "Maltrato" }, + { + "id": "mantener_animal_domestico_espacios_inadecuados", + "text": "Mantener animal doméstico espacios inadecuados" + }, + { + "id": "mantenimiento_de_cercas_y_aceras", + "text": "Mantenimiento de cercas y aceras" + }, + { + "id": "menoscabar_integridad_animal_domestico", + "text": "Menoscabar integridad animal doméstico" + }, + { "id": "mesnna_masnna", "text": "Mesnna masnna" }, + { + "id": "no_realizar_grabado_de_autopartes", + "text": "No realizar grabado de autopartes" + }, + { "id": "no_respetar_carriles", "text": "No respetar carriles" }, + { + "id": "no_respetar_senda_peatonal", + "text": "No respetar senda peatonal" + }, + { + "id": "obligacion_de_exhibir_cartel", + "text": "Obligación de exhibir cartel" + }, + { + "id": "obligacion_de_informar_prohibicion_de_fumar", + "text": "Obligación de informar prohibición de fumar" + }, + { "id": "obligacion_de_conservar", "text": "Obligación de conservar" }, + { + "id": "obstaculizar_ingreso_o_salida", + "text": "Obstaculizar ingreso o salida" + }, + { "id": "obstruccion_de_inspeccion", "text": "Obstrucción de inspección" }, + { "id": "obstruccion_de_via", "text": "Obstrucción de vía" }, + { + "id": "obstruccion_de_via_publica", + "text": "Obstruccion de vía pública" + }, + { + "id": "obstruccion_via_publica", + "text": "Obstruccion vía pública" + }, + { "id": "obstruir_salida", "text": "Obstruir salida" }, + { "id": "ocupar_via_publica", "text": "Ocupar vía pública" }, + { + "id": "oferta_demanda_sexo_espacio_publico", + "text": "Oferta demanda sexo espacio público" + }, + { + "id": "omitir_cuidados_animal_domestico", + "text": "Omitir cuidados animal doméstico" + }, + { + "id": "omitir_recaudos_de_cuidado_animal_domestico", + "text": "Omitir recaudos de cuidado animal doméstico" + }, + { + "id": "omitir_recaudos_de_organizacion", + "text": "Omitir recaudos de organización" + }, + { + "id": "omitir_recaudos_espectaculo_masivo", + "text": "Omitir recaudos espectáculo masivo" + }, + { + "id": "omitir_recaudos_organizacion_seguridad", + "text": "Omitir recaudos organización seguridad" + }, + { "id": "organizar_explotar_juego", "text": "Organizar explotar juego" }, + { + "id": "organizar_sin_autorizacion_juego", + "text": "Organizar sin autorización juego" + }, + { + "id": "participar_competencias_velocidad_via_publica", + "text": "Participar competencias velocidad via pública" + }, + { "id": "pelear_en_lugar_publico", "text": "Pelear en lugar público" }, + { "id": "permiso_y_planos_de_obra", "text": "Permiso y planos de obra" }, + { "id": "persona_no_habilitada", "text": "Persona no habilitada" }, + { + "id": "perturbar_ceremonias_religiosas_funebres", + "text": "Perturbar ceremonias religiosas fúnebres" + }, + { + "id": "perturbar_filas_ingreso_no_respetar_vallado", + "text": "Perturbar filas ingreso no respetar vallado" + }, + { "id": "placas_de_dominio", "text": "Placas de dominio" }, + { "id": "pornografia_infantil", "text": "Pornografía infantil" }, + { "id": "portacion_de_arma", "text": "Portación de arma" }, + { + "id": "portar_armas_no_convencionales", + "text": "Portar armas no convencionales" + }, + { + "id": "presencia_menores_lugar_no_autorizado", + "text": "Presencia menores lugar no autorizado" + }, + { "id": "presunta_comision_delito", "text": "Presunta comisión delito" }, + { "id": "presunta_contravencion", "text": "Presunta contravención" }, + { + "id": "privacion_ilegitima_de_la_libertad", + "text": "Privacion ilegítima de la libertad" + }, + { "id": "producir_avalanchas", "text": "Producir avalanchas" }, + { + "id": "promocion_o_facilitacion_de_prostitucion_de_personas", + "text": "Promoción o facilitación de prostitución de personas" + }, + { + "id": "promover_comerciar_ofertar_juego", + "text": "Promover comerciar ofertar juego" + }, + { + "id": "propaganda_discriminatoria", + "text": "Propaganda discriminatoria" + }, + { "id": "proteccion_animal", "text": "Protección animal" }, + { "id": "provocar_parcialidad", "text": "Provocar parcialidad" }, + { + "id": "publicidad_en_lugares_no_habilitados_via_publica", + "text": "Publicidad en lugares no habilitados via pública" + }, + { + "id": "regentear_o_administrar_casas_de_tolerancia", + "text": "Regentear o administrar casas de tolerancia" + }, + { "id": "residuos_peligrosos", "text": "Residuos peligrosos" }, + { "id": "retencion_indebida", "text": "Retención indebida" }, + { "id": "revender_entradas", "text": "Revender entradas" }, + { "id": "robo", "text": "Robo" }, + { "id": "ruidos_molestos", "text": "Ruidos molestos" }, + { "id": "ruidos_y_vibraciones", "text": "Ruidos y vibraciones" }, + { "id": "sancion_generica", "text": "Sanción generica" }, + { + "id": "servicios_de_seguridad_prohibiciones_incumplidas", + "text": "Servicios de seguridad prohibiciones incumplidas" + }, + { + "id": "servicios_de_seguridad_requisitos_incumplidos", + "text": "Servicios de seguridad requisitos incumplidos" + }, + { "id": "suministrar_alcohol_menor", "text": "Suministrar alcohol menor" }, + { + "id": "suministrar_bebidas_alcoholicas", + "text": "Suministrar bebidas alcohólicas" + }, + { + "id": "suministrar_elementos_aptos_agresion", + "text": "Suministrar elementos aptos agresión" + }, + { + "id": "suministrar_material_pornografico", + "text": "Suministrar material pornográfico" + }, + { + "id": "suministrar_objetos_peligrosos", + "text": "Suministrar objetos peligrosos" + }, + { + "id": "suministrar_productos_farmaceuticos", + "text": "Suministrar productos farmacéuticos" + }, + { + "id": "suministro_de_medicamentos", + "text": "Suministro de medicamentos" + }, + { "id": "suplantacion_identidad", "text": "Suplantación identidad" }, + { + "id": "suplantacion_digital_de_identidad", + "text": "Suplantación digital de identidad" + }, + + { + "id": "taxis_transportes_escolares_remises_sin_autorizacion", + "text": "Taxis transportes escolares remises sin autorización" + }, + { "id": "tenencia_de_arma", "text": "Tenencia de arma" }, + { "id": "transporte_de_pasajeros", "text": "Transporte de pasajeros" }, + { + "id": "transporte_de_pasajeros_sin_habilitacion", + "text": "Transporte de pasajeros sin habilitación" + }, + { + "id": "transporte_de_pasajeros_sin_habilitacion_o_autorizacion", + "text": "Transporte de pasajeros sin habilitación o autorización" + }, + { + "id": "usar_indebidamente_credencial", + "text": "Usar indebidamente credencial" + }, + { + "id": "usar_indebidamente_espacio_publico", + "text": "Usar indebidamente espacio público" + }, + { "id": "usar_indebidamente_armas", "text": "Usar indebidamente armas" }, + { + "id": "uso_de_documento_falso_o_adulterado", + "text": "Uso de documento falso o adulterado" + }, + { + "id": "uso_indebido_del_espacio_publico", + "text": "Uso indebido del espacio público" + }, + { + "id": "uso_o_exhibicion_de_franquicias", + "text": "Uso o exhibición de franquicias" + }, + { "id": "usurpacion", "text": "Usurpación" }, + { "id": "vehiculo_abandonado", "text": "Vehiculo abandonado" }, + { + "id": "vender_entradas_o_permitir_ingreso_exceso", + "text": "Vender entradas o permitir ingreso exceso" + }, + { + "id": "vender_sustancias_medicinales_sin_receta", + "text": "Vender sustancias medicinales sin receta" + }, + { + "id": "venta_o_consumo_de_bebidas_alcoholicas_fuera_del_horario", + "text": "Venta o consumo de bebidas alcohólicas fuera del horario" + }, + { "id": "verificacion_tecnica", "text": "Verificación técnica" }, + { "id": "violacion_de_peaje", "text": "Violación de peaje" }, + { "id": "violacion_de_domicilio", "text": "Violación de domicilio" }, + { + "id": "violacion_de_secretos_y_de_la_privacidad", + "text": "Violación de secretos y de la privacidad" + }, + { "id": "violar_clausura", "text": "Violar clausura" }, + { + "id": "violar_inhabilitacion_para_conducir", + "text": "Violar inhabilitación para conducir" + }, + { + "id": "violar_reglamentacion_juego", + "text": "Violar reglamentación juego" + }, + { + "id": "zanjas_y_pozos_en_via_publica", + "text": "Zanjas y pozos en via pública" + } + ], + "CONDUCTA_DESCRIPCION": [ + { "id": "agravada", "text": "Agravada" }, + { "id": "agravadas_por_edad", "text": "Agravadas por edad" }, + { + "id": "agravadas_por_el_uso_de_armas", + "text": "Agravadas por el uso de armas" + }, + { + "id": "agravadas_por_uso_de_armas", + "text": "Agravadas por uso de armas" + }, + { + "id": "agravadas_por_uso_de_armas_impropia", + "text": "Agravadas por uso de armas impropia" + }, + { "id": "agravado", "text": "Agravado" }, + { "id": "agravado_abuso_funcion", "text": "Agravado abuso función" }, + { "id": "agravado_alevosia", "text": "Agravado alevosía" }, + { + "id": "agravado_causar_sufrimiento_otra_persona", + "text": "Agravado causar sufrimiento otra persona" + }, + { "id": "agravado_concurso", "text": "Agravado concurso" }, + { "id": "agravado_familiar", "text": "Agravado familiar" }, + { + "id": "agravado_insertar_datos_en_datos_personales", + "text": "Agravado insertar datos en datos personales" + }, + { "id": "agravado_lugar_publico", "text": "Agravado lugar público" }, + { "id": "agravado_mas_personas", "text": "Agravado más personas" }, + { "id": "agravado_medio_idoneo", "text": "Agravado medio idóneo" }, + { "id": "agravado_menor_de_edad", "text": "Agravado menor de edad" }, + { "id": "agravado_miembro_fuerzas", "text": "Agravado miembro fuerzas" }, + { "id": "agravado_monumentos", "text": "Agravado monumentos" }, + { "id": "agravado_otro_delito", "text": "Agravado otro delito" }, + { + "id": "agravado_peligro_de_muerte", + "text": "Agravado peligro de muerte" + }, + { "id": "agravado_por_el_vinculo", "text": "Agravado por el vínculo" }, + { "id": "agravado_por_espacio", "text": "Agravado por espacio" }, + { + "id": "agravado_por_ser_fuerza_de_seguridad", + "text": "Agravado por ser fuerza de seguridad" + }, + { "id": "agravado_precio", "text": "Agravado precio" }, + { + "id": "agravado_relacion_de_pareja", + "text": "Agravado relación de pareja" + }, + { "id": "agravado_superior_militar", "text": "Agravado superior militar" }, + { + "id": "agravado_violar_informacion_banco_de_datos", + "text": "Agravado violar información banco de datos" + }, + { + "id": "agravado_violar_sistemas_seguridad", + "text": "Agravado violar sistemas seguridad" + }, + { + "id": "agravado_violencia_de_genero", + "text": "Agravado violencia de género" + }, + { "id": "agravado_violencia_mujer", "text": "Agravado violencia mujer" }, + { "id": "agravados", "text": "Agravados" }, + { "id": "coactivas", "text": "Coactivas" }, + { "id": "coactivas_agravadas", "text": "Coactivas agravadas" }, + { + "id": "coactivas_agravadas_por_uso_de_armas", + "text": "Coactivas agravadas por uso de armas" + }, + { + "id": "comercio_de_plantas_para_producir_estupefacientes", + "text": "Comercio de plantas para producir estupefacientes" + }, + { "id": "con_escalamiento", "text": "Con escalamiento" }, + { "id": "conduccion_imprudente", "text": "Conducción imprudente" }, + { "id": "culposas", "text": "Culposas" }, + { "id": "culposo", "text": "Culposo" }, + { "id": "de_fuego_uso_civil", "text": "De fuego uso civil" }, + { "id": "de_guerra", "text": "De guerra" }, + { + "id": "destinado_a_acreditar_identidad_de_personas_habilitacion_o_titularidad", + "text": "Destinado a acreditar identidad de personas habilitación o titularidad" + }, + { "id": "digital", "text": "Digital" }, + { "id": "digital_agravado_familiar", "text": "Digital agravado familiar" }, + { "id": "digital_agravado_jefe", "text": "Digital agravado jefe" }, + { + "id": "digital_agravado_mas_de_una_persona", + "text": "Digital agravado más de una persona" + }, + { + "id": "digital_agravado_menor_de_edad", + "text": "Digital agravado menor de edad" + }, + { + "id": "digital_agravado_relacion_de_pareja", + "text": "Digital agravado relación de pareja" + }, + { + "id": "durante_espectaculo_deportivo", + "text": "Durante espectáculo deportivo" + }, + { + "id": "en_grandes_parques_o_espectaculos_masivos", + "text": "En grandes parques o espectáculos masivos" + }, + { "id": "en_riña", "text": "En riña" }, + { + "id": "entrega_suministro_facilitacion", + "text": "Entrega suministro facilitación" + }, + { "id": "funcionario_publico", "text": "Funcionario público" }, + { "id": "ganzua_llave", "text": "Ganzúa llave" }, + { "id": "graves", "text": "Graves" }, + { "id": "graves_tentativa", "text": "Graves tentativa" }, + { "id": "informatica", "text": "Informática" }, + { + "id": "ingreso_a_domicilio_sin_autorizacion", + "text": "Ingreso a domicilio sin autorización" + }, + { + "id": "intimidacion_o_invocando_orden_superior", + "text": "Intimidación o invocando orden superior" + }, + { "id": "leves", "text": "Leves" }, + { "id": "leves_agravadas", "text": "Leves agravadas" }, + { "id": "leves_tentativa", "text": "Leves tentativa" }, + { "id": "muebles_transportables", "text": "Muebles transportables" }, + { "id": "no_denuncia_delito", "text": "No denuncia delito" }, + { "id": "no_corresponde", "text": "No corresponde" }, + { "id": "ocasion_de_incendio", "text": "Ocasión de incendio" }, + { "id": "organismo_publico", "text": "Organismo público" }, + { + "id": "para_produccion_o_tenencia_con_fines_de_comercializacion", + "text": "Para producción o tenencia con fines de comercialización" + }, + { "id": "por_despojo", "text": "Por despojo" }, + { + "id": "por_obligacion_de_devolver", + "text": "Por obligación de devolver" + }, + { + "id": "por_turbacion_de_la_posesion", + "text": "Por turbación de la posesión" + }, + { "id": "productos_separados_suelo", "text": "Productos separados suelo" }, + { "id": "publico_o_privado", "text": "Público o privado" }, + { "id": "seguido_de_muerte", "text": "Seguido de muerte" }, + { "id": "simple", "text": "Simple" }, + { "id": "simples", "text": "Simples" }, + { "id": "sin_autorizacion", "text": "Sin autorización" }, + { "id": "tarjeta_credito_debito", "text": "Tarjeta crédito débito" }, + { "id": "tenencia", "text": "Tenencia" }, + { "id": "tentativa", "text": "Tentativa" }, + { + "id": "tentativa_agravado_alevosia", + "text": "Tentativa agravado alevosía" + }, + { + "id": "transporte_de_pasajeros_sin_habilitacion_o_autorizacion", + "text": "Transporte de pasajeros sin habilitación o autorización" + }, + { "id": "uso_de_tarjeta_o_datos", "text": "Uso de tarjeta o datos" }, + { "id": "vehiculos", "text": "Vehículos" } + ], + "DETALLE": [ + { + "id": "audiencia_victima_ley_26484", + "text": "Audiencia víctima Ley 26484" + }, + { + "id": "audiencia_victima_11_bis_ley_24660", + "text": "Audiencia víctima 11 bis Ley 24660" + }, + { + "id": "audiencia_victima_ley_26485", + "text": "Audiencia victima Ley 26485" + }, + { + "id": "audiencia_acusado_ley_26485", + "text": "Audiencia acusado Ley 26485" + }, + { "id": "29_dias", "text": "29 días" }, + { "id": "30_dias", "text": "30 dias" }, + { "id": "44_dias", "text": "44 días" }, + { "id": "45_dias", "text": "45 dias" }, + { "id": "59_dias", "text": "59 días" }, + { "id": "60_dias", "text": "60 dias" }, + { "id": "89_dias", "text": "89 días" }, + { "id": "90_dias", "text": "90 dias" }, + { "id": "179_dias", "text": "179 días" }, + { "id": "180_dias", "text": "180 dias" }, + { "id": "abandono_vehiculo", "text": "Abandono vehículo" }, + { "id": "absolucion", "text": "Absolución" }, + { + "id": "absolucion_desistimiento_fiscal", + "text": "Absolución desistimiento fiscal" + }, + { "id": "accesorias_legales", "text": "Accesorias legales" }, + { + "id": "acepta_competencia_inhibitoria", + "text": "Acepta competencia inhibitoria" + }, + { "id": "acepta_cuestion_turno", "text": "Acepta cuestión turno" }, + { "id": "aclaratoria", "text": "Aclaratoria" }, + { "id": "acta_de_comprobacion", "text": "Acta de comprobación" }, + { "id": "acta_de_intimacion", "text": "Acta de intimación" }, + { + "id": "acuerdo_de_pago_levanta_embargo", + "text": "Acuerdo de pago levanta embargo" + }, + { + "id": "acumulacion_por_conexidad_y_ampliacion", + "text": "Acumulación por conexidad y ampliación" + }, + { "id": "admisibilidad", "text": "Admisibilidad" }, + { "id": "agente_encubierto", "text": "Agente encubierto" }, + { "id": "agente_revelador", "text": "Agente revelador" }, + { "id": "agotamiento_de_la_pena", "text": "Agotamiento de la pena" }, + { "id": "alimentos_provisorios", "text": "Alimentos provisorios" }, + { "id": "allanamiento", "text": "Allanamiento" }, + { "id": "apelacion", "text": "Apelación" }, + { + "id": "apertura_extraccion_examen_datos", + "text": "Apertura extracción examen datos" + }, + { "id": "aprehension", "text": "Aprehensión" }, + { "id": "arma", "text": "Arma" }, + { "id": "armas", "text": "Armas" }, + { + "id": "arresto_domiciliario_deja_sin_efecto", + "text": "Arresto domiciliario deja sin efecto" + }, + { "id": "asesor_tutelar", "text": "Asesor tutelar" }, + { "id": "atipicidad_sobreseimiento", "text": "Atipicidad sobreseimiento" }, + { + "id": "audiencia_acusado_ley_26484", + "text": "Audiencia acusado Ley 26484" + }, + { + "id": "audiencia_acusado_difiere_sentencia", + "text": "Audiencia acusado difiere sentencia" + }, + { "id": "audiencia_preliminar", "text": "Audiencia preliminar" }, + { + "id": "audiencia_victima_10_bis_ley_24660", + "text": "Audiencia víctima 10 bis Ley 24660" + }, + { "id": "bloqueo_acceso_al_dominio", "text": "Bloqueo acceso al dominio" }, + { + "id": "cadena_de_custodia_de_elementos_secuestrados", + "text": "Cadena de custodia de elementos secuestrados" + }, + { "id": "camara_gesell", "text": "Cámara Gesell" }, + { + "id": "cambio_domicilio_prision_domiciliaria", + "text": "Cambio domicilio prisión domiciliaria" + }, + { "id": "captura", "text": "Captura" }, + { "id": "captura_deja_sin_efecto", "text": "Captura deja sin efecto" }, + { "id": "caucion_real", "text": "Caución real" }, + { "id": "cedula_de_notificacion", "text": "Cédula de notificación" }, + { + "id": "cese_de_actos_de_perturbacion_o_intimidacion", + "text": "Cese de actos de perturbación o intimidación" + }, + { "id": "cese_de_medidas", "text": "Cese de medidas" }, + { "id": "cese_de_medidas_parcial", "text": "Cese de medidas parcial" }, + { "id": "cierre_de_instancia", "text": "Cierre de instancia" }, + { "id": "clausura", "text": "Clausura" }, + { "id": "clausura_deja_sin_efecto", "text": "Clausura deja sin efecto" }, + { "id": "competencia_penal_juvenil", "text": "Competencia penal juvenil" }, + { "id": "concede", "text": "Concede" }, + { "id": "concede_parcialmente", "text": "Concede parcialmente" }, + { "id": "conocimiento_personal", "text": "Conocimiento personal" }, + { "id": "consigna_policial", "text": "Consigna policial" }, + { "id": "contienda_negativa", "text": "Contienda negativa" }, + { "id": "control", "text": "Control" }, + { "id": "convalida_fallecimiento", "text": "Convalida fallecimiento" }, + { "id": "convalida_inimputabilidad", "text": "Convalida inimputabilidad" }, + { + "id": "convalidacion_otras_causales", + "text": "Convalidación otras causales" + }, + { "id": "copia_forense_celular", "text": "Copia forense celular" }, + { + "id": "copias_de_capturas_de_pantalla_mensajes_y_llamados", + "text": "Copias de capturas de pantalla mensajes y llamados" + }, + { + "id": "cosa_juzgada_sobreseimiento", + "text": "Cosa juzgada sobreseimiento" + }, + { "id": "cuarto_intermedio", "text": "Cuarto intermedio" }, + { + "id": "cuarto_intermedio_para_resolver", + "text": "Cuarto intermedio para resolver" + }, + { + "id": "cumplimiento_de_regla_de_conducta_en_complejo_penitenciario", + "text": "Cumplimiento de regla de conducta en complejo penitenciario" + }, + { + "id": "cumplimiento_de_reglas_de_conducta", + "text": "Cumplimiento de reglas de conducta" + }, + { "id": "declaracion_testimonial", "text": "Declaracion testimonial" }, + { "id": "declina_competencia", "text": "Declina competencia" }, + { "id": "defensa", "text": "Defensa" }, + { "id": "defensa_particular", "text": "Defensa particular" }, + { "id": "defensa_querella", "text": "Defensa querella" }, + { + "id": "deja_sin_efecto_inhabilitacion_y_devuelve_licencia", + "text": "Deja sin efecto inhabilitación y devuelve licencia" + }, + { + "id": "deja_sin_efecto_revocacion", + "text": "Deja sin efecto revocación" + }, + { "id": "delitos_de_accion_publica", "text": "Delitos de acción publica" }, + { + "id": "desistimiento_accion_instancia_privada_sobreseimiento", + "text": "Desistimiento accion instancia privada sobreseimiento" + }, + { "id": "desistimiento_fiscal", "text": "Desistimiento fiscal" }, + { "id": "destruccion_de_arma", "text": "Destrucción de arma" }, + { "id": "detencion", "text": "Detención" }, + { + "id": "detencion_captura_y/o_traslado", + "text": "Detención captura y/o traslado" + }, + { + "id": "detencion_captura_y/o_traslado_deja_sin_efecto", + "text": "Detención captura y/o traslado deja sin efecto" + }, + { + "id": "detencion_secuestro_y_requisa", + "text": "Detención secuestro y requisa" + }, + { + "id": "devolucion_acarreo_y_estadia", + "text": "Devolución acarreo y estadía" + }, + { "id": "dictamen_fiscal", "text": "Dictamen fiscal" }, + { "id": "difiere_decision", "text": "Difiere decisión" }, + { "id": "difiere_fundamentos", "text": "Difiere fundamentos" }, + { "id": "difiere_resolucion", "text": "Difiere resolución" }, + { + "id": "dispositivo_de_geoposicionamiento_mantiene_hasta_juicio", + "text": "Dispositivo de geoposicionamiento mantiene hasta juicio" + }, + { + "id": "domiciliaria_con_vigilancia_electronica", + "text": "Domiciliaria con vigilancia electrónica" + }, + { "id": "egreso_del_pais", "text": "Egreso del país" }, + { "id": "ejecucion_de_honorarios", "text": "Ejecución de honorarios" }, + { "id": "embargo", "text": "Embargo" }, + { "id": "embargo_deja_sin_efecto", "text": "Embargo deja sin efecto" }, + { "id": "estimulo_educativo", "text": "Estímulo educativo" }, + { "id": "estupefacientes", "text": "Estupefacientes" }, + { "id": "estupefacientes_dinero", "text": "Estupefacientes dinero" }, + { + "id": "estupefacientes_telefono_dinero", + "text": "Estupefacientes teléfono dinero" + }, + { + "id": "estupefacientes_telefono_dinero_arma", + "text": "Estupefacientes teléfono dinero arma" + }, + { + "id": "estupefacientes_telefono_vehiculo", + "text": "Estupefacientes teléfono vehículo" + }, + { + "id": "estupefacientes_vehiculo_dinero", + "text": "Estupefacientes vehículo dinero" + }, + { "id": "excarcelacion", "text": "Excarcelación" }, + { "id": "exclusion_del_hogar", "text": "Exclusión del hogar" }, + { "id": "exhorto", "text": "Exhorto" }, + { "id": "exhorto_diplomatico", "text": "Exhorto diplomático" }, + { "id": "exime_pago_multa", "text": "Exime pago multa" }, + { + "id": "exime_reparacion_del_daño_y_pago_multa", + "text": "Exime reparación del daño y pago multa" + }, + { "id": "eximicion_pago", "text": "Eximición pago" }, + { + "id": "eximicion_pauta_de_conducta", + "text": "Eximición pauta de conducta" + }, + { + "id": "expulsion_art_63_a_ley_25871", + "text": "Expulsión art. 63 a Ley 25871" + }, + { + "id": "expulsion_art_64_a_ley_25871", + "text": "Expulsion art. 64 a Ley 25871" + }, + { + "id": "extincion_accion_por_autocomposicion", + "text": "Extinción acción por autocomposición" + }, + { + "id": "extincion_accion_por_cumplimiento", + "text": "Extinción acción por cumplimiento" + }, + { + "id": "extincion_accion_sobreseimiento", + "text": "Extinción acción sobreseimiento" + }, + { + "id": "extincion_accion_sobreseimiento_por_fallecimiento", + "text": "Extinción acción sobreseimiento por fallecimiento" + }, + { "id": "extincion_de_la_pena", "text": "Extinción de la pena" }, + { + "id": "extincion_sancion_por_cumplimiento", + "text": "Extinción sanción por cumplimiento" + }, + { "id": "extrañamiento", "text": "Extrañamiento" }, + { + "id": "falta_de_accion_sobreseimiento", + "text": "Falta de acción sobreseimiento" + }, + { + "id": "falta_de_legitimacion_pasiva", + "text": "Falta de legitimación pasiva" + }, + { "id": "falta_de_participacion", "text": "Falta de participación" }, + { "id": "falta_de_presentacion", "text": "Falta de presentación" }, + { + "id": "falta_de_requisitos_procedencia", + "text": "Falta de requisitos procedencia" + }, + { "id": "fija_nueva_audiencia", "text": "Fija nueva audiencia" }, + { "id": "fondo_de_reserva", "text": "Fondo de reserva" }, + { "id": "habeas_corpus", "text": "Habeas corpus" }, + { + "id": "hasta_agotar_investigacion", + "text": "Hasta agotar investigación" + }, + { "id": "identidad_objeto_y_sujeto", "text": "Identidad objeto y sujeto" }, + { "id": "imagenes_videos", "text": "Imagenes videos" }, + { "id": "incompetencia_material", "text": "Incompetencia material" }, + { + "id": "incompetencia_por_conexidad", + "text": "Incompetencia por conexidad" + }, + { + "id": "incompetencia_por_conexidad_subjetiva", + "text": "Incompetencia por conexidad subjetiva" + }, + { "id": "incompetencia_territorial", "text": "Incompetencia territorial" }, + { + "id": "indeterminacion_imputacion", + "text": "Indeterminacion imputación" + }, + { + "id": "informacion_y_apertura_de_antenas_llamadas", + "text": "Información y apertura de antenas llamadas" + }, + { "id": "informe_cij", "text": "Informe cij" }, + { "id": "informe_mercado_libre", "text": "Informe mercado libre" }, + { "id": "informe_ncmec", "text": "Informe ncmec" }, + { "id": "informe_previo", "text": "Informe previo" }, + { + "id": "informes_llamadas_y_deteccion_de_celdas", + "text": "Informes llamadas y detección de celdas" + }, + { + "id": "inhabilitacion_para_conducir", + "text": "Inhabilitación para conducir" + }, + { + "id": "inhabilitacion_para_conducir_deja_sin_efecto", + "text": "Inhabilitación para conducir deja sin efecto" + }, + { "id": "inmovilizacion", "text": "Inmovilización" }, + { "id": "interes_en_el_caso", "text": "Interés en el caso" }, + { "id": "internacion_involuntaria", "text": "Internación involuntaria" }, + { "id": "interprete", "text": "Intérprete" }, + { "id": "interprete_y_defensa", "text": "Intérprete y defensa" }, + { "id": "interrogatorio_policial", "text": "Interrogatorio policial" }, + { + "id": "intervencion_equipo_especializado", + "text": "Intervención equipo especializado" + }, + { "id": "intervencion_previa", "text": "Intervención previa" }, + { "id": "intervencion_red_social", "text": "Intervención red social" }, + { "id": "intervencion_telefonica", "text": "Intervención telefónica" }, + { + "id": "intervencion_telefonica_con_ubicacion_de_celda_de_apertura", + "text": "Intervención telefónica con ubicación de celda de apertura" + }, + { + "id": "levantamiento_clausura_administrativa", + "text": "Levantamiento clausura administrativa" + }, + { + "id": "levantamiento_secreto_bancario", + "text": "Levantamiento secreto bancario" + }, + { + "id": "levantamiento_secreto_fiscal", + "text": "Levantamiento secreto fiscal" + }, + { "id": "liberacion_aves", "text": "Liberación aves" }, + { + "id": "libertad_asistida_incorporacion", + "text": "Libertad asistida incorporación" + }, + { + "id": "libertad_condicional_otorga", + "text": "Libertad condicional otorga" + }, + { + "id": "libertad_condicional_revoca", + "text": "Libertad condicional revoca" + }, + { "id": "litispendencia", "text": "Litispendencia" }, + { "id": "mantiene", "text": "Mantiene" }, + { "id": "mediacion", "text": "Mediación" }, + { "id": "medidas_restrictivas", "text": "Medidas restrictivas" }, + { + "id": "modifica_pauta_de_conducta", + "text": "Modifica pauta de conducta" + }, + { "id": "morigeracion_domiciliaria", "text": "Morigeración domiciliaria" }, + { "id": "no_convalida", "text": "No convalida" }, + { "id": "no_homologa_absolucion", "text": "No homologa absolución" }, + { "id": "notificacion_via_mail", "text": "Notificacion vía mail" }, + { + "id": "nulidad_incorporacion_prueba", + "text": "Nulidad incorporación prueba" + }, + { "id": "otorga_plazo", "text": "Otorga plazo" }, + { "id": "otras_vias_idoneas", "text": "Otras vías idóneas" }, + { "id": "pago_de_multa_en_cuotas", "text": "Pago de multa en cuotas" }, + { + "id": "pago_minimo_multa_sobreseimiento", + "text": "Pago mínimo multa sobreseimiento" + }, + { + "id": "pago_minimo_multa_y_reparacion_daño_63cp", + "text": "Pago mínimo multa y reparación daño 63 CP" + }, + { + "id": "pago_minimo_multa_y_reparacion_daño_64cp", + "text": "Pago minimo multa y reparacion daño 64 CP" + }, + { "id": "paradero", "text": "Paradero" }, + { "id": "paradero_deja_sin_efecto", "text": "Paradero deja sin efecto" }, + { + "id": "parcial_requerimiento_de_juicio", + "text": "Parcial requerimiento de juicio" + }, + { + "id": "parcial_requerimiento_de_juicio_falta_de_circunscripcion_temporal", + "text": "Parcial requerimiento de juicio falta de circunscripción temporal" + }, + { + "id": "parcial_requerimiento_de_juicio_falta_de_fundamentacion", + "text": "Parcial requerimiento de juicio falta de fundamentación" + }, + { + "id": "parcial_requerimiento_de_juicio_por_introduccion_de_agravante", + "text": "Parcial requerimiento de juicio por introducción de agravante" + }, + { "id": "pedido_de_informe_banco", "text": "Pedido de informe banco" }, + { + "id": "pedido_de_informe_facebook", + "text": "Pedido de informe Facebook" + }, + { + "id": "pedido_de_informe_facebook_google", + "text": "Pedido de informe Facebook Google" + }, + { + "id": "pedido_de_informe_facebook_microsoft", + "text": "Pedido de informe Facebook Microsoft" + }, + { "id": "pedido_de_informe_google", "text": "Pedido de informe Google" }, + { + "id": "pedido_de_informe_google_microsoft", + "text": "Pedido de informe Google Microsoft" + }, + { + "id": "pedido_de_informe_imgur_llc", + "text": "Pedido de informe Imgur LLC" + }, + { + "id": "pedido_de_informe_instagram", + "text": "Pedido de informe Instagram" + }, + { + "id": "pedido_de_informe_mercado_libre", + "text": "Pedido de informe Mercado Libre" + }, + { + "id": "pedido_de_informe_microsoft", + "text": "Pedido de informe Microsoft" + }, + { "id": "pedido_de_informe_skype", "text": "Pedido de informe Skype" }, + { + "id": "pedido_de_informe_telefonia", + "text": "Pedido de informe telefonía" + }, + { + "id": "pedido_de_informe_whatsapp", + "text": "Pedido de informe Whatsapp" + }, + { "id": "pedido_informe_tiktok", "text": "Pedido informe Tiktok" }, + + { + "id": "pedido_prision_domiciliaria", + "text": "Pedido prisión domiciliaria" + }, + { + "id": "pena_de_arresto_efectivo_cumplimiento", + "text": "Pena de arresto efectivo cumplimiento" + }, + { + "id": "pena_de_arresto_efectivo_cumplimiento_compurgada", + "text": "Pena de arresto efectivo cumplimiento compurgada" + }, + { + "id": "pena_de_arresto_en_suspenso", + "text": "Pena de arresto en suspenso" + }, + { + "id": "pena_de_inhabilitacion_especial", + "text": "Pena de inhabilitación especial" + }, + { + "id": "pena_de_multa_efectivo_cumplimiento", + "text": "Pena de multa efectivo cumplimiento" + }, + { "id": "pena_de_multa_en_suspenso", "text": "Pena de multa en suspenso" }, + { + "id": "pena_de_multa_sustituida_por_amonestacion", + "text": "Pena de multa sustituida por amonestación" + }, + { + "id": "pena_de_multa_sustituida_por_clausura_se_tiene_por_cumplida", + "text": "Pena de multa sustituida por clausura se tiene por cumplida" + }, + { + "id": "pena_de_multa_sustituida_por_trabajos_comunitarios", + "text": "Pena de multa sustituida por trabajos comunitarios" + }, + { + "id": "pena_de_prision_domiciliaria", + "text": "Pena de prisión domiciliaria" + }, + { + "id": "pena_de_prision_efectivo_cumplimiento", + "text": "Pena de prisión efectivo cumplimiento" + }, + { + "id": "pena_de_prision_efectivo_cumplimiento_compurgada", + "text": "Pena de prisión efectivo cumplimiento compurgada" + }, + { + "id": "pena_de_prision_efectivo_cumplimiento_domiciliaria", + "text": "Pena de prisión efectivo cumplimiento domiciliaria" + }, + { + "id": "pena_de_prision_en_suspenso", + "text": "Pena de prisión en suspenso" + }, + { + "id": "pena_de_tareas_comunitarias", + "text": "Pena de tareas comunitarias" + }, + { + "id": "pena_de_tareas_de_utilidad_publica", + "text": "Pena de tareas de utilidad pública" + }, + { "id": "pericia", "text": "Pericia" }, + { "id": "pericia_arma", "text": "Pericia arma" }, + { + "id": "pericia_examen_veterinario", + "text": "Pericia examen veterinario" + }, + { "id": "peritaje_de_telefono", "text": "Peritaje de teléfono" }, + { + "id": "peritaje_ordenadores_y_o_telefonos", + "text": "Peritaje ordenadores y o teléfonos" + }, + { "id": "peritaje_telefono", "text": "Peritaje teléfono" }, + { "id": "perito", "text": "Perito" }, + { "id": "permiso_de_viaje", "text": "Permiso de viaje" }, + { + "id": "plazo_razonable_sobreseimiento", + "text": "Plazo razonable sobreseimiento" + }, + { + "id": "plazo_razonable_sobresimiento", + "text": "Plazo razonable sobresimiento" + }, + { "id": "pleito_con_una_parte", "text": "Pleito con una parte" }, + { + "id": "por_quince_dias_hasta_tomar_contacto_con_victima", + "text": "Por quince dias hasta tomar contacto con víctima" + }, + { + "id": "prescripcion_sobreseimiento", + "text": "Prescripción sobreseimiento" + }, + { + "id": "prision_domiciliaria_mantiene", + "text": "Prisión domiciliaria mantiene" + }, + { + "id": "prision_domiciliaria_prorroga", + "text": "Prisión domiciliaria prórroga" + }, + { "id": "procedimiento", "text": "Procedimiento" }, + { + "id": "procedimiento_administrativo_pendiente", + "text": "Procedimiento administrativo pendiente" + }, + { + "id": "prohibicion_compra_tenencia_registracion_de_armas", + "text": "Prohibición compra tenencia registración de armas" + }, + { + "id": "prohibicion_de_acercamiento", + "text": "Prohibición de acercamiento" + }, + { + "id": "prohibicion_de_acercamiento_y_contacto", + "text": "Prohibición de acercamiento y contacto" + }, + { + "id": "prohibicion_de_publicar_en_redes", + "text": "Prohibición de publicar en redes" + }, + { + "id": "prohibicion_de_publicar_en_redes_sobre", + "text": "Prohibición de publicar en redes sobre" + }, + { + "id": "promocion_a_periodo_de_prueba_art_6_ley_24660", + "text": "Promoción a período de prueba art 6 Ley 24660" + }, + { + "id": "promocion_a_periodo_de_prueba_art_7_ley_24660", + "text": "Promoción a período de prueba art 7 Ley 24660" + }, + { "id": "prorroga", "text": "Prórroga" }, + { "id": "prueba_ofrecida", "text": "Prueba ofrecida" }, + { "id": "publicacion_de_edictos", "text": "Publicación de edictos" }, + { "id": "queja", "text": "Queja" }, + { "id": "querella", "text": "Querella" }, + { + "id": "quita_puntos_de_licencia_de_conducir", + "text": "Quita puntos de licencia de conducir" + }, + { "id": "realizacion", "text": "Realización" }, + { "id": "rebeldia", "text": "Rebeldía" }, + { "id": "rebeldia_deja_sin_efecto", "text": "Rebeldía deja sin efecto" }, + { "id": "rebeldia_y_captura", "text": "Rebeldía y captura" }, + { "id": "rebeldia_y_paradero", "text": "Rebeldía y paradero" }, + { "id": "rechaza_acuerdo", "text": "Rechaza acuerdo" }, + { "id": "rechaza_competencia", "text": "Rechaza competencia" }, + { + "id": "regimen_de_comunicacion_provisoria", + "text": "Regimen de comunicación provisoria" + }, + { "id": "reincidencia", "text": "Reincidencia" }, + { + "id": "reintegra_puntos_de_licencia_de_conducir", + "text": "Reintegra puntos de licencia de conducir" + }, + { "id": "remate_vehiculo", "text": "Remate vehículo" }, + { "id": "remision_a_justicia_civil", "text": "Remisión a justicia civil" }, + { + "id": "remision_camara_para_sorteo", + "text": "Remisión cámara para sorteo" + }, + { + "id": "reparacion_integral_del_daño_sobreseimiento", + "text": "Reparación integral del daño sobreseimiento" + }, + { + "id": "replica_de_arma_de_plastico", + "text": "Réplica de arma de plástico" + }, + { "id": "reposicion", "text": "Reposición" }, + { + "id": "reposicion_apelacion_subsidio", + "text": "Reposición apelación subsidio" + }, + { "id": "reprogramacion", "text": "Reprogramación" }, + { "id": "requerido_por_infractor", "text": "Requerido por infractor" }, + { "id": "requerimiento_de_juicio", "text": "Requerimiento de juicio" }, + { + "id": "requerimiento_de_juicio_falta_de_fundamentacion", + "text": "Requerimiento de juicio falta de fundamentación" + }, + { "id": "requisa", "text": "Requisa" }, + { "id": "restitucion_de_inmueble", "text": "Restitución de inmueble" }, + { + "id": "revision_psicofisica_capacidad", + "text": "Revisión psicofísica capacidad" + }, + { + "id": "revision_psiquiatrica_y_psicologica", + "text": "Revision psiquiátrica y psicológica" + }, + { "id": "revoca", "text": "Revoca" }, + { "id": "revoca_condicionalidad", "text": "Revoca condicionalidad" }, + { "id": "revocacion", "text": "Revocación" }, + { "id": "rueda_de_reconocimiento", "text": "Rueda de reconocimiento" }, + { "id": "salidas_extraordinarias", "text": "Salidas extraordinarias" }, + { "id": "salidas_transitorias", "text": "Salidas transitorias" }, + { + "id": "sancion_sustitutiva_prorroga", + "text": "Sanción sustitutiva prórroga" + }, + { "id": "secuestro", "text": "Secuestro" }, + { "id": "sin_indicacion_plazo", "text": "Sin indicación plazo" }, + { "id": "sobreseimiento", "text": "Sobreseimiento" }, + { "id": "solicita", "text": "Solicita" }, + { + "id": "solicitud_destruccion_de_estupefacientes", + "text": "Solicitud destrucción de estupefacientes" + }, + { "id": "tareas_de_investigacion", "text": "Tareas de investigación" }, + { "id": "telefono", "text": "Teléfono" }, + { + "id": "temor_parcialidad_generico", + "text": "Temor parcialidad genérico" + }, + { "id": "tiene_por_desistido", "text": "Tiene por desistido" }, + { + "id": "tiene_por_no_computado_plazo", + "text": "Tiene por no computado plazo" + }, + { "id": "tiene_presente", "text": "Tiene presente" }, + { "id": "tiene_presente_acuerdo", "text": "Tiene presente acuerdo" }, + { "id": "tobillera_refractaria", "text": "Tobillera refractaria" }, + { + "id": "traslado_por_fuerza_publica", + "text": "Traslado por fuerza pública" + }, + { + "id": "unifica_solicita_inhibitoria", + "text": "Unifica solicita inhibitoria" + }, + { "id": "unificacion_de_pena", "text": "Unificación de pena" }, + { "id": "vehiculo", "text": "Vehículo" }, + { "id": "vencimiento_plazo_ipp", "text": "Vencimiento plazo IPP" } + ], + "OBJETO_DE_LA_RESOLUCION": [ + { "id": "acumulacion_de_caso", "text": "Acumulación de caso" }, + { "id": "admisibilidad_amparo", "text": "Admisibilidad amparo" }, + { + "id": "admisibilidad_habeas_corpus", + "text": "Admisibilidad habeas corpus" + }, + { "id": "admisibilidad_prueba", "text": "Admisibilidad prueba" }, + { "id": "apartamiento", "text": "Apartamiento" }, + { "id": "archivo_fiscal", "text": "Archivo fiscal" }, + { "id": "audiencia_de_conciliacion", "text": "Audiencia de conciliación" }, + { + "id": "beneficio_litigar_sin_gastos", + "text": "Beneficio litigar sin gastos" + }, + { "id": "caducidad_de_instancia", "text": "Caducidad de instancia" }, + { "id": "cuestion_de_competencia", "text": "Cuestión de competencia" }, + { "id": "decomiso", "text": "Decomiso" }, + { "id": "desistimiento_faltas", "text": "Desistimiento faltas" }, + { "id": "ejecucion_de_la_pena", "text": "Ejecución de la pena" }, + { "id": "excepcion", "text": "Excepción" }, + { "id": "excusacion", "text": "Excusación" }, + { "id": "extraccion_testimonios", "text": "Extracción testimonios" }, + { "id": "juicio_abreviado", "text": "Juicio abreviado" }, + { "id": "juicio_oral", "text": "Juicio oral" }, + { "id": "juzgamiento_faltas", "text": "Juzgamiento faltas" }, + { "id": "mediacion", "text": "Mediación" }, + { "id": "medida_cautelar", "text": "Medida cautelar" }, + { "id": "medida_probatoria", "text": "Medida probatoria" }, + { "id": "mesa_de_dialogo", "text": "Mesa de diálogo" }, + { "id": "nulidad", "text": "Nulidad" }, + { "id": "prision_preventiva", "text": "Prisión preventiva" }, + { + "id": "prorroga_investigacion_penal_preparatoria", + "text": "Prórroga investigación penal preparatoria" + }, + { "id": "recurso", "text": "Recurso" }, + { "id": "recusacion", "text": "Recusación" }, + { "id": "regulacion_de_honorarios", "text": "Regulación de honorarios" }, + { "id": "remision_controladora", "text": "Remisión controladora" }, + { + "id": "restablecimiento_de_contacto", + "text": "Restablecimiento de contacto" + }, + { "id": "restitucion_de_efectos", "text": "Restitución de efectos" }, + { "id": "restitucion_de_inmueble", "text": "Restitución de inmueble" }, + { "id": "restitucion_efectos", "text": "Restitución efectos" }, + { + "id": "suspension_del_proceso_a_prueba", + "text": "Suspensión del proceso a prueba" + } + ], + "ART_INFRINGIDO": [ + { "id": "00", "text": "00" }, + { "id": "1", "text": "1" }, + { "id": "1.1.6", "text": "1.1.6" }, + { "id": "1.3.20", "text": "1.3.20" }, + { "id": "1.3.22", "text": "1.3.22" }, + { "id": "1.3.3", "text": "1.3.3" }, + { "id": "1.3.31", "text": "1.3.31" }, + { "id": "1.3.6.1", "text": "1.3.6.1" }, + { "id": "2.1.1", "text": "2.1.1" }, + { "id": "2.1.13", "text": "2.1.13" }, + { "id": "2.1.15", "text": "2.1.15" }, + { "id": "2.1.16", "text": "2.1.16" }, + { "id": "2.1.17", "text": "2.1.17" }, + { "id": "2.1.19", "text": "2.1.19" }, + { "id": "2.1.21", "text": "2.1.21" }, + { "id": "2.1.3", "text": "2.1.3" }, + { "id": "2.2.1", "text": "2.2.1" }, + { "id": "2.2.14", "text": "2.2.14" }, + { "id": "3", "text": "3" }, + { "id": "3.1.1", "text": "3.1.1" }, + { "id": "4.1.1", "text": "4.1.1" }, + { "id": "4.1.1.2", "text": "4.1.1.2" }, + { "id": "4.1.17", "text": "4.1.17" }, + { "id": "4.1.22", "text": "4.1.22" }, + { "id": "4.1.24", "text": "4.1.24" }, + { "id": "4.1.7", "text": "4.1.7" }, + { "id": "5c", "text": "5c" }, + { "id": "5d", "text": "5d" }, + { "id": "5e", "text": "5e" }, + { "id": "6", "text": "6" }, + { "id": "6.1.12", "text": "6.1.12" }, + { "id": "6.1.12.1", "text": "6.1.12.1" }, + { "id": "6.1.2", "text": "6.1.2" }, + { "id": "6.1.24", "text": "6.1.24" }, + { "id": "6.1.26", "text": "6.1.26" }, + { "id": "6.1.28", "text": "6.1.28" }, + { "id": "6.1.31", "text": "6.1.31" }, + { "id": "6.1.37", "text": "6.1.37" }, + { "id": "6.1.4", "text": "6.1.4" }, + { "id": "6.1.40", "text": "6.1.40" }, + { "id": "6.1.41", "text": "6.1.41" }, + { "id": "6.1.42", "text": "6.1.42" }, + { "id": "6.1.44", "text": "6.1.44" }, + { "id": "6.1.47", "text": "6.1.47" }, + { "id": "6.1.49", "text": "6.1.49" }, + { "id": "6.1.52", "text": "6.1.52" }, + { "id": "6.1.54", "text": "6.1.54" }, + { "id": "6.1.63", "text": "6.1.63" }, + { "id": "6.1.67", "text": "6.1.67" }, + { "id": "6.1.8", "text": "6.1.8" }, + { "id": "6.1.9", "text": "6.1.9" }, + { "id": "6.1.94", "text": "6.1.94" }, + { "id": "9.1.1", "text": "9.1.1" }, + { "id": "10.1.5", "text": "10.1.5" }, + { "id": "11.1.10", "text": "11.1.10" }, + { "id": "11.1.2", "text": "11.1.2" }, + { "id": "11.1.4", "text": "11.1.4" }, + { "id": "13", "text": "13" }, + { "id": "14", "text": "14" }, + { "id": "17", "text": "17" }, + { "id": "23", "text": "23" }, + { "id": "51", "text": "51" }, + { "id": "52", "text": "52" }, + { "id": "53_bis", "text": "53 bis" }, + { "id": "53_bis_inc3", "text": "53 bis inc. 3" }, + { "id": "53_bis_inc5", "text": "53 bis inc. 5" }, + { "id": "54", "text": "54" }, + { "id": "56", "text": "56" }, + { "id": "57", "text": "57" }, + { "id": "58", "text": "58" }, + { "id": "59", "text": "59" }, + { "id": "67_bis", "text": "67 bis" }, + { "id": "71_quinquies", "text": "71 quinquies" }, + { "id": "71_ter", "text": "71 ter" }, + { "id": "72", "text": "72" }, + { "id": "73", "text": "73" }, + { "id": "74", "text": "74" }, + { "id": "75", "text": "75" }, + { "id": "76", "text": "76" }, + { "id": "77", "text": "77" }, + { "id": "79", "text": "79" }, + { "id": "80", "text": "80" }, + { "id": "80_inc11", "text": "80 inc. 11" }, + { "id": "80_inc2", "text": "80 inc. 2" }, + { "id": "81", "text": "81" }, + { "id": "82", "text": "82" }, + { "id": "83", "text": "83" }, + { "id": "84", "text": "84" }, + { "id": "85", "text": "85" }, + { "id": "87", "text": "87" }, + { "id": "88", "text": "88" }, + { "id": "89", "text": "89" }, + { "id": "90", "text": "90" }, + { "id": "92", "text": "92" }, + { "id": "93", "text": "93" }, + { "id": "94", "text": "94" }, + { "id": "94_bis", "text": "94 bis" }, + { "id": "95", "text": "95" }, + { "id": "96", "text": "96" }, + { "id": "97", "text": "97" }, + { "id": "100", "text": "100" }, + { "id": "101", "text": "101" }, + { "id": "104", "text": "104" }, + { "id": "105", "text": "105" }, + { "id": "106", "text": "106" }, + { "id": "107", "text": "107" }, + { "id": "109", "text": "109" }, + { "id": "111", "text": "111" }, + { "id": "113", "text": "113" }, + { "id": "116", "text": "116" }, + { "id": "118", "text": "118" }, + { "id": "119", "text": "119" }, + { "id": "120", "text": "120" }, + { "id": "122", "text": "122" }, + { "id": "125_bis", "text": "125 bis" }, + { "id": "128", "text": "128" }, + { "id": "129", "text": "129" }, + { "id": "129_parr_2", "text": "129 párr. 2" }, + { "id": "131", "text": "131" }, + { "id": "135", "text": "135" }, + { "id": "141", "text": "141" }, + { "id": "148_bis", "text": "148 bis" }, + { "id": "149_bis", "text": "149 bis" }, + { "id": "149_bis_parr_2", "text": "149 bis párr. 2" }, + { "id": "149ter_inc2b", "text": "149 ter inc. 2b)" }, + { "id": "150", "text": "150" }, + { "id": "153", "text": "153" }, + { "id": "153_bis", "text": "153 bis" }, + { "id": "153_bis_parr_2", "text": "153 bis párr. 2" }, + { "id": "157_bis", "text": "157 bis" }, + { "id": "162", "text": "162" }, + { "id": "163", "text": "163" }, + { "id": "163_inc4", "text": "163 inc. 4" }, + { "id": "163_bis", "text": "163 bis" }, + { "id": "164", "text": "164" }, + { "id": "166", "text": "166" }, + { "id": "168", "text": "168" }, + { "id": "172", "text": "172" }, + { "id": "173_inc15", "text": "173 inc. 15" }, + { "id": "173_inc16", "text": "173 inc. 16" }, + { "id": "173_inc2", "text": "173 inc. 2" }, + { "id": "181_inc1", "text": "181 inc. 1" }, + { "id": "181_inc3", "text": "181 inc. 3" }, + { "id": "183", "text": "183" }, + { "id": "183_parr_2", "text": "183 párr. 2" }, + { "id": "184_inc5", "text": "184 inc. 5" }, + { "id": "186", "text": "186" }, + { "id": "186_inc1", "text": "186 inc. 1" }, + { "id": "186_inc4", "text": "186 inc. 4" }, + { "id": "186_inc5", "text": "186 inc. 5" }, + { "id": "189_bis", "text": "189 bis" }, + { "id": "189_bis_inc4", "text": "189 bis inc. 4" }, + { "id": "193_bis", "text": "193 bis" }, + { "id": "204_quinquies", "text": "204 quinquies" }, + { "id": "205", "text": "205" }, + { "id": "208", "text": "208" }, + { "id": "210", "text": "210" }, + { "id": "237", "text": "237" }, + { "id": "238", "text": "238" }, + { "id": "239", "text": "239" }, + { "id": "243", "text": "243" }, + { "id": "245", "text": "245" }, + { "id": "248", "text": "248" }, + { "id": "249", "text": "249" }, + { "id": "258", "text": "258" }, + { "id": "266", "text": "266" }, + { "id": "267", "text": "267" }, + { "id": "273", "text": "273" }, + { "id": "277_inc_d", "text": "277 inc. d" }, + { "id": "281", "text": "281" }, + { "id": "289_inc1", "text": "289 inc. 1" }, + { "id": "289_inc3", "text": "289 inc. 3" }, + { "id": "292_parr_1", "text": "292 párr. 1" }, + { "id": "292_parr_2", "text": "292 párr. 2" }, + { "id": "295", "text": "295" }, + { "id": "296", "text": "296" }, + { "id": "301_bis", "text": "301 bis" } + ], + "CODIGO_O_LEY": [ + { "id": "codigo_contravencional", "text": "Código contravencional" }, + { "id": "codigo_penal_de_la_nacion", "text": "Código penal de la Nación" }, + { "id": "ley_1217", "text": "Ley 1217" }, + { "id": "ley_12331", "text": "Ley 12331" }, + { "id": "ley_13944", "text": "Ley 13944" }, + { "id": "ley_14346", "text": "Ley 14346" }, + { "id": "ley_23098", "text": "Ley 23098" }, + { "id": "ley_23592", "text": "Ley 23592" }, + { "id": "ley_23737", "text": "Ley 23737" }, + { "id": "ley_24192", "text": "Ley 24192" }, + { "id": "ley_24270", "text": "Ley 24270" }, + { "id": "ley_24769", "text": "Ley 24769" }, + { "id": "ley_25761", "text": "Ley 25761" }, + { "id": "ley_26735", "text": "Ley 26735" }, + { "id": "ley_451", "text": "Ley 451" } + ], + "NACIONALIDAD": [ + { "id": "argentina", "text": "Argentina" }, + { "id": "armenia", "text": "Armenia" }, + { "id": "australiana", "text": "Australiana" }, + { "id": "belga", "text": "Belga" }, + { "id": "boliviana", "text": "Boliviana" }, + { "id": "brasilera", "text": "Brasilera" }, + { "id": "chilena", "text": "Chilena" }, + { "id": "china", "text": "China" }, + { "id": "colombiana", "text": "Colombiana" }, + { "id": "cubana", "text": "Cubana" }, + { "id": "dominicana", "text": "Dominicana" }, + { "id": "ecuatoriana", "text": "Ecuatoriana" }, + { "id": "española", "text": "Española" }, + { "id": "estadounidense", "text": "Estadounidense" }, + { "id": "estonia", "text": "Estonia" }, + { "id": "francesa", "text": "Francesa" }, + { "id": "italiana", "text": "Italiana" }, + { "id": "kazaka", "text": "Kazaka" }, + { "id": "paraguaya", "text": "Paraguaya" }, + { "id": "peruana", "text": "Peruana" }, + { "id": "rusa", "text": "Rusa" }, + { "id": "senegalesa", "text": "Senegalesa" }, + { "id": "surcoreana", "text": "Surcoreana" }, + { "id": "ucraniana", "text": "Ucraniana" }, + { "id": "uruguaya", "text": "Uruguaya" }, + { "id": "venezolana", "text": "Venezolana" }, + { "id": "no_corresponde", "text": "No corresponde" }, + { "id": "sd", "text": "s/d" } + ], + "PERSONA_ACUSADA_NO_DETERMINADA": [ + { "id": "manifestantes", "text": "Manifestantes" }, + { "id": "organo_jurisdiccional", "text": "Órgano jurisdiccional" }, + { "id": "pagina_web", "text": "Página web" }, + { "id": "persona_juridica", "text": "Persona jurídica" }, + { "id": "personal_policial", "text": "Personal policial" }, + { "id": "usuario_de_chatstep", "text": "Usuario de Chatstep" }, + { + "id": "usuario_de_cuenta_de_google", + "text": "Usuario de cuenta de Google" + }, + { "id": "usuario_de_facebook", "text": "Usuario de Facebook" }, + { "id": "usuario_de_imgur", "text": "Usuario de Imgur" }, + { "id": "usuario_de_instagram", "text": "Usuario de Instagram" }, + { "id": "usuario_de_mercado_libre", "text": "Usuario de Mercado Libre" }, + { "id": "usuario_de_outlook", "text": "Usuario de Outlook" }, + { "id": "usuario_de_skout", "text": "Usuario de Skout" }, + { "id": "usuario_de_skype", "text": "Usuario de Skype" }, + { "id": "usuario_de_tiktok", "text": "Usuario de Tiktok" }, + { "id": "usuario_de_twitter", "text": "Usuario de Twitter" }, + { "id": "usuario_de_whatsapp", "text": "Usuario de WhatsApp" }, + { "id": "usuario_de_youtube", "text": "Usuario de Youtube" }, + { "id": "usuario_microsoft", "text": "Usuario Microsoft" }, + + { "id": "no_corresponde", "text": "No corresponde" }, + { "id": "sd", "text": "s/d" } + ], + "HIJOS_HIJAS_EN_COMUN": [ + { "id": "si", "text": "Si" }, + { "id": "no", "text": "No" } + ], + + "RELACION_Y_TIPO_ENTRE_ACUSADO_Y_DENUNCIANTE": [ + { "id": "familiar", "text": "Familiar" }, + { "id": "pareja", "text": "Pareja" }, + { "id": "ex_pareja", "text": "Ex pareja" }, + { "id": "jefe_empleada", "text": "Jefe empleada" }, + { "id": "familiar_de_ex_pareja", "text": "Familiar de ex pareja" }, + { "id": "pareja_de_la_madre", "text": "Pareja de la madre" }, + { "id": "ninguna", "text": "Ninguna" }, + { "id": "vecino", "text": "Vecino/a" }, + { "id": "profesor", "text": "Profesor" }, + { + "id": "propietario_del_inmueble_de_residencia", + "text": "Propietario del inmueble de residencia" + }, + { "id": "compañero_de_trabajo", "text": "Compañero/a de trabajo" }, + { "id": "amigo", "text": "Amigo/a" }, + { "id": "familiar_de_pareja", "text": "Familiar de pareja" }, + { "id": "s/d", "text": "S/D" }, + { "id": "no_corresponde", "text": "No corresponde" } + ], + "MEDIDAS_DE_PROTECCION_VIGENTES_AL_MOMENTO_DEL_HECHO": [ + { "id": "si", "text": "Si" }, + { "id": "no", "text": "No" } + ], + "MATERIA": [ + { "id": "allanamiento_autonomo", "text": "Allanamiento autónomo" }, + { "id": "habeas_corpus", "text": "Habeas corpus" }, + { "id": "ejecucion_de_multa", "text": "Ejecución de multa" }, + { "id": "amparo", "text": "Amparo" }, + { "id": "contravencional", "text": "Contravencional" }, + { "id": "faltas", "text": "Faltas" }, + { "id": "penal", "text": "Penal" } + ] +} diff --git a/frontend/src/renderer/src/components/validate-dataset/form-group/index.tsx b/frontend/src/renderer/src/components/validate-dataset/form-group/index.tsx new file mode 100644 index 00000000..e2009660 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/form-group/index.tsx @@ -0,0 +1,97 @@ +import { useEffect, useState } from "react"; + +import { DecisionTabs } from "@/components"; +import { useFileDispatch, useForm } from "@/hooks"; +import { appendValidation } from "@/reducers/file/actions"; +import type { DocFile } from "@/types/file"; +import { Suggester, countDecisiones } from "@/utils/predictions"; +import Container from "./FormGroup.styles"; +import { + DatosAcusado, + DatosDenunciante, + Decision, + InfoGral, + InfoHecho, +} from "./forms"; + +interface Props { + file: DocFile; + onCheck: (checked: boolean) => void; +} +export default function FormGroup({ file, onCheck }: Props) { + const [decision, setDecision] = useState(0); + + const [checkedInfoGral, setCheckedInfoGral] = useState(false); + const [checkedInfoHecho, setCheckedInfoHecho] = useState(false); + const [checkedDecision, setCheckedDecision] = useState(false); + const [checkedDatosDenunciante, setCheckedDatosDenunciante] = useState(false); + const [checkedDatosAcusado, setCheckedDatosAcusado] = useState(false); + + const { register, submit, addDecision, decisionAmount, getDecisionValue } = + useForm(countDecisiones(file.predictions)); + const dispatch = useFileDispatch(); + + const createDecision = () => { + addDecision(); + }; + const selectDecision = (n: number) => setDecision(n); + + const handleSubmit = submit((data) => { + console.log({ data }); + dispatch(appendValidation(file.data.name, data)); + }); + + const props = { + register, + onSubmit: handleSubmit, + suggester: new Suggester(file.predictions), + }; + const decisionProps = { + ...props, + getDecisionValue, + }; + + useEffect(() => { + onCheck( + checkedInfoGral && + checkedInfoHecho && + checkedDecision && + checkedDatosDenunciante && + checkedDatosAcusado, + ); + }, [ + onCheck, + checkedInfoGral, + checkedInfoHecho, + checkedDecision, + checkedDatosDenunciante, + checkedDatosAcusado, + ]); + + return ( + + + + + + + + + + + + + ); +} diff --git a/frontend/src/renderer/src/components/validate-dataset/index.tsx b/frontend/src/renderer/src/components/validate-dataset/index.tsx new file mode 100644 index 00000000..c5b0f124 --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/index.tsx @@ -0,0 +1,126 @@ +import { useState } from "react"; + +import { Button, FileAnnotator, FileStepper, Grid } from "@/components"; +import Footer from "@/components/layout/footer"; +import { useFileDispatch, useFiles } from "@/hooks"; +import { SectionTitle } from "@/layout/section-title"; +import { validate } from "@/reducers/file/actions"; +import { css } from "@/styled/css"; +import { HStack, Stack } from "@/styled/jsx"; +import { isFileValidated, isValidationCompleted } from "@/utils/file"; +import { getFeatureRouteSlug, parseFeatureRouteSlug } from "@/types/features"; +import { Navigate, useNavigate, useParams } from "@tanstack/react-router"; +import FormGroup from "./form-group"; +import { moveNext, movePrevious } from "./utils"; + +export function ValidateDataset() { + // HOOKS + const { feature: featureSlug } = useParams({ from: "/$feature/validation" }); + const feature = parseFeatureRouteSlug(featureSlug); + + if (!feature) return ; + const files = useFiles(); + const [checked, setChecked] = useState(false); + const [selected, setSelected] = useState(0); + const dispatch = useFileDispatch(); + const navigate = useNavigate(); + + // FIELDS + const hasStepper = files.length > 1; + + const selectedFile = files[selected]; + // Check if the validation was completed on all the files + const canContinue = isValidationCompleted(files); + const canValidate = isFileValidated(selectedFile); + + // HANDLERS + const moveIndex = (newIndex: number | undefined) => { + if (newIndex !== undefined) setSelected(newIndex); + }; + const nextFile = () => moveIndex(moveNext(selected, files)); + const previousFile = () => moveIndex(movePrevious(selected, files)); + + const handleContinue = () => { + navigate({ + to: "/$feature/finish", + params: { feature: getFeatureRouteSlug(feature) }, + }); + }; + + const handleValidate = async () => { + // Set validated = true so the file is no longer accesible through the FileStepper component + dispatch(validate(selectedFile.data.name)); + + if (canContinue || !hasStepper) { + handleContinue(); + } else { + nextFile(); + } + }; + + const handleCheck = (checked: boolean) => { + setChecked(checked); + }; + + return ( + + + + + + 3. Validación de datos + + + + +
    + + {hasStepper && ( + + )} + + {canContinue ? ( + + ) : ( + + )} + +
    +
    + ); +} diff --git a/frontend/src/renderer/src/components/validate-dataset/utils.ts b/frontend/src/renderer/src/components/validate-dataset/utils.ts new file mode 100644 index 00000000..6cc7ca6d --- /dev/null +++ b/frontend/src/renderer/src/components/validate-dataset/utils.ts @@ -0,0 +1,37 @@ +import type { DocFile } from "@/types/file"; + +/** + * Finds the next available index and returns it + * @param cur Current `selected` index + * @param state State array of files + * @returns The next available index + */ +export function movePrevious(cur: number, state: DocFile[]) { + let index = cur; + + do { + index--; + + if (index < 0) return undefined; + } while (state[index].validated); + + return index; +} + +/** + * Finds the previous available index and returns it + * @param cur Current `selected` index + * @param state State array of files + * @returns The previous available index + */ +export function moveNext(cur: number, state: DocFile[]) { + let index = cur; + + do { + index++; + + if (index === state.length) return undefined; + } while (state[index].validated); + + return index; +} diff --git a/frontend/src/renderer/src/components/validation-form/ValidationForm.styles.ts b/frontend/src/renderer/src/components/validation-form/ValidationForm.styles.ts new file mode 100644 index 00000000..36adf124 --- /dev/null +++ b/frontend/src/renderer/src/components/validation-form/ValidationForm.styles.ts @@ -0,0 +1,7 @@ +import { styled } from "@/styles"; + +export const Form = styled("form", { + display: "flex", + flexDirection: "column", + gap: "$l", +}); diff --git a/frontend/src/renderer/src/components/validation-form/index.tsx b/frontend/src/renderer/src/components/validation-form/index.tsx new file mode 100644 index 00000000..3d15eecf --- /dev/null +++ b/frontend/src/renderer/src/components/validation-form/index.tsx @@ -0,0 +1,76 @@ +import { CheckCircle } from "phosphor-react"; +import { + Children, + type FormEvent, + type FormEventHandler, + type ReactElement, + type ReactNode, + cloneElement, + isValidElement, + useEffect, + useState, +} from "react"; + +import { Button } from "@/components"; +import type { NativeComponent } from "@/types/component"; + +import { css } from "@/styled/css"; +import { styled } from "@/styled/jsx"; +import { Form } from "./ValidationForm.styles"; + +interface Props extends NativeComponent<"form"> { + children: ReactNode; + title: string; + onSubmit: FormEventHandler; + onCheck: (checked: boolean) => void; +} +export default function ValidationForm({ + children, + title, + onSubmit, + onCheck, + ...props +}: Props) { + const [checked, setChecked] = useState(false); + + const handleClick = () => setChecked(true); + + const onChange = () => { + if (checked) setChecked(false); + }; + + // Add the onChange handler to every children + const childrenWithHandler = Children.map(children, (child) => { + if (isValidElement(child)) { + return cloneElement(child as ReactElement<{ onChange: () => void }>, { onChange }); + } + return child; + }); + + const handleSubmit = (e: FormEvent) => { + e.preventDefault(); + + onSubmit(e); + }; + + useEffect(() => { + onCheck(checked); + }, [checked, onCheck]); + + return ( +
    + {title} + {childrenWithHandler} + +
    + ); +} diff --git a/frontend/src/renderer/src/constants/anonymizer-categories.ts b/frontend/src/renderer/src/constants/anonymizer-categories.ts new file mode 100644 index 00000000..1300ddc0 --- /dev/null +++ b/frontend/src/renderer/src/constants/anonymizer-categories.ts @@ -0,0 +1,82 @@ +import { type AnonymizerLabels, anonymizerLabels } from "@/types/aymurai"; + +export const FALLBACK_ANONYMIZER_CATEGORY = "Otros datos sensibles"; + +export const ANONYMIZER_CATEGORY_LABEL_IDS = { + Roles: [ + "PER", + "DENUNCIANTE", + "ACUSADO/A", + "TESTIGO/A", + "NIÑO/A_ADOSLECENTE", + ], + Lugares: ["LOC", "DIRECCION"], + "Datos personales": ["DNI", "EDAD", "NACIONALIDAD", "ESTUDIOS"], + "Contacto e identificadores digitales": [ + "TELEFONO", + "CORREO_ELECTRONICO", + "USUARIX", + "IP", + "LINK", + "NOMBRE_ARCHIVO", + ], + "Datos judiciales": ["NUM_EXPEDIENTE", "NUM_ACTUACION", "CAUSA", "CUIJ"], + "Datos administrativos y registrales": [ + "CUIT_CUIL", + "AFILIADO", + "NUM_MATRICULA", + "PATENTE_DOMINIO", + ], + "Datos bancarios": ["BANCO", "CBU", "NUM_CAJA_AHORRO"], + Fechas: ["FECHA"], + [FALLBACK_ANONYMIZER_CATEGORY]: [ + "MARCA_AUTOMOVIL", + "INSTITUCION", + "TEXTO_ANONIMIZAR", + ], +} as const satisfies Record; + +export const ANONYMIZER_CATEGORY_NAMES = Object.keys( + ANONYMIZER_CATEGORY_LABEL_IDS, +); + +const labelById = new Map(anonymizerLabels.map((label) => [label.id, label])); + +export const ANONYMIZER_LABEL_CATEGORY = Object.fromEntries( + Object.entries(ANONYMIZER_CATEGORY_LABEL_IDS).flatMap( + ([category, labelIds]) => labelIds.map((labelId) => [labelId, category]), + ), +) as Partial>; + +export function getAnonymizerCategoryForLabel(labelId: string): string { + return ( + ANONYMIZER_LABEL_CATEGORY[labelId as AnonymizerLabels] ?? + FALLBACK_ANONYMIZER_CATEGORY + ); +} + +export function getAnonymizerLabelsForCategory(category: string) { + const configuredIds = ANONYMIZER_CATEGORY_LABEL_IDS[category] ?? []; + const configuredLabels = configuredIds + .map((labelId) => labelById.get(labelId)) + .filter((label) => label !== undefined); + + if (category !== FALLBACK_ANONYMIZER_CATEGORY) return configuredLabels; + + const configuredIdSet = new Set( + Object.values(ANONYMIZER_CATEGORY_LABEL_IDS).flat(), + ); + const uncategorizedLabels = anonymizerLabels.filter( + (label) => !configuredIdSet.has(label.id), + ); + + return [...configuredLabels, ...uncategorizedLabels]; +} + +export function getLabelsPrioritizingCategory(category: string) { + const categoryLabels = getAnonymizerLabelsForCategory(category); + const categoryIds = new Set(categoryLabels.map((label) => label.id)); + const rest = anonymizerLabels.filter((label) => !categoryIds.has(label.id)); + + return [...categoryLabels, ...rest]; +} diff --git a/frontend/src/renderer/src/constants/config.ts b/frontend/src/renderer/src/constants/config.ts new file mode 100644 index 00000000..f8968453 --- /dev/null +++ b/frontend/src/renderer/src/constants/config.ts @@ -0,0 +1,6 @@ +export const DATAGENERO_URL = "https://www.datagenero.org/"; + +/** + * Only allow these extensions to be analyzed + */ +export const WHITELISTED_EXTENSIONS = ["docx", "pdf"]; diff --git a/frontend/src/renderer/src/constants/excluded-tags.ts b/frontend/src/renderer/src/constants/excluded-tags.ts new file mode 100644 index 00000000..3d423f8c --- /dev/null +++ b/frontend/src/renderer/src/constants/excluded-tags.ts @@ -0,0 +1,8 @@ +import { type AnonymizerLabels, anonymizerLabels } from "@/types/aymurai"; + +const entries = anonymizerLabels.map((label) => [label.id, true] as const); + +export const EXCLUDED_TAGS = Object.fromEntries(entries) as Record< + AnonymizerLabels, + boolean +>; diff --git a/frontend/src/renderer/src/constants/i18n/index.ts b/frontend/src/renderer/src/constants/i18n/index.ts new file mode 100644 index 00000000..06b788ca --- /dev/null +++ b/frontend/src/renderer/src/constants/i18n/index.ts @@ -0,0 +1,27 @@ +import i18n from "i18next"; +import { initReactI18next } from "react-i18next"; +import es from "./locales/es"; + +// --- TypeScript type augmentation --- +// Tells i18next the exact shape of every namespace, +// so t('key') calls are fully typed and autocompleted. +declare module "i18next" { + interface CustomTypeOptions { + defaultNS: "common"; + resources: typeof es; + } +} + +i18n.use(initReactI18next).init({ + lng: "es", + fallbackLng: "es", + defaultNS: "common", + resources: { + es, + }, + interpolation: { + escapeValue: false, // React already escapes values + }, +}); + +export default i18n; diff --git a/frontend/src/renderer/src/constants/i18n/locales/es/anonymizer.ts b/frontend/src/renderer/src/constants/i18n/locales/es/anonymizer.ts new file mode 100644 index 00000000..5fbaada6 --- /dev/null +++ b/frontend/src/renderer/src/constants/i18n/locales/es/anonymizer.ts @@ -0,0 +1,73 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; + +const validExtensions = WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", "); + +const anonymizer = { + title: "Anonimizador", + subtitle: "Anonimiza resoluciones judiciales de manera automática y editable", + onboarding: { + sectionTitle: "1. Selección de Archivo", + validFormats: `Formatos válidos: ${validExtensions}`, + loadDocuments: "Cargar documentos", + dropAreaTitle: "Selecciona el archivo para anonimizar", + dropAreaFormats: `Formatos válidos: ${validExtensions}`, + }, + preview: { + sectionTitle: "1. Selección de Archivo", + filesLabel: "Archivos seleccionados", + validFormats: `Formatos válidos: ${validExtensions}`, + loadMore: "Cargar más documentos", + continue: "Continuar", + }, + howItWorks: { + step1: { + alt: "Interfaz web con selector y cursor", + title: "Selecciona la resolución judicial", + subtitle: "Sube el documento que quieres anonimizar.", + }, + step2: { + alt: "Barra de búsqueda con cursor", + title: "La inteligencia artificial analiza el documento", + subtitle: + "Reconoce automáticamente la información a anonimizar.", + }, + step3: { + alt: "Visor de documentos con controles de revisión", + title: "Revisión y validación humana", + subtitle: + "Es importante que verifiques que los datos sean correctos antes de exportar el archivo.", + }, + step4: { + alt: "Binoculares con globo terráqueo", + title: "Generación del documento anonimizado", + subtitle: + "Proceso terminado. El documento está listo para ser exportado.", + }, + }, + process: { + sectionTitle: "2. Procesamiento del archivo", + processingTitle: "AymurAI está extrayendo los datos del archivo", + processingSubtitle: "Este proceso puede tardar algunos minutos.", + finishText: "Se finalizó el análisis del documento.", + }, + validation: { + toastSingleSuccess: + 'Se aplicó con éxito una etiqueta de "{{label}}" en una ocurrencia.', + toastAllSuccess: + 'Se aplicó con éxito una etiqueta de "{{label}}" en todas las ocurrencias.', + }, + result: { sectionTitle: "" }, + finish: { + sectionTitle: "4. Finalización", + description: + "Los datos encontrados por AymurAI y posteriormente validados ya han sido anonimizados correctamente.", + subtitle: "Archivo procesado", + restart: "Cargar un nuevo documento", + viewResult: "Descargar ODT", + viewResultPDF: "Descargar PDF", + downloadError: + "Ocurrió un error al generar el archivo. Por favor, intente nuevamente.", + }, +}; + +export default anonymizer; diff --git a/frontend/src/renderer/src/constants/i18n/locales/es/common.ts b/frontend/src/renderer/src/constants/i18n/locales/es/common.ts new file mode 100644 index 00000000..9d4bfac6 --- /dev/null +++ b/frontend/src/renderer/src/constants/i18n/locales/es/common.ts @@ -0,0 +1,39 @@ +const common = { + back: "Volver", + howItWorks: "¿Cómo funciona?", + platformBuiltBy: "Plataforma hecha por", + settings: "Configuración", + home: { + features: { + greeting: "¡Hola! Selecciona la herramienta a utilizar", + }, + host: { + howToConnect: "¿Cómo deseas conectarte a Aymurai?", + optionLocal: "Local", + optionServer: "Servidor", + optionOr: "o", + connectServerExplanation: + "Ingresa la dirección del servidor al que deseas conectarte", + connectServerLabel: "Dirección del servidor", + connectServerSubmit: "Guardar y conectar", + errors: { + network: "No se pudo conectar al servidor", + connection: "Error de conexión", + invalidResponse: "El servidor no respondió correctamente", + invalidUrl: "El formato de la URL es incorrecto.", + unknown: "Error desconocido", + }, + }, + }, + stepper: { + selection: "Selección", + extraction: "Extracción", + validation: "Validación", + finalization: "Finalización", + }, + filePreview: { + loadError: "No se pudo cargar el archivo", + }, +}; + +export default common; diff --git a/frontend/src/renderer/src/constants/i18n/locales/es/dataset.ts b/frontend/src/renderer/src/constants/i18n/locales/es/dataset.ts new file mode 100644 index 00000000..de7fa05f --- /dev/null +++ b/frontend/src/renderer/src/constants/i18n/locales/es/dataset.ts @@ -0,0 +1,64 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; + +const validExtensions = WHITELISTED_EXTENSIONS.map((e) => `.${e}`).join(", "); + +const dataset = { + title: "Set de datos", + subtitle: "Convierte resoluciones judiciales en set de datos estructurados", + onboarding: { + sectionTitle: "1. Selección de Archivos", + validFormats: `Formatos válidos: ${validExtensions}`, + loadDocuments: "Cargar documentos", + dropAreaTitle: "Selecciona el archivo para\nagregar a la base de datos", + dropAreaFormats: `Formatos válidos: ${validExtensions}`, + }, + preview: { + sectionTitle: "1. Selección de Archivos", + filesLabel: "Archivos seleccionados", + validFormats: `Formatos válidos: ${validExtensions}`, + loadMore: "Cargar más documentos", + continue: "Continuar", + }, + howItWorks: { + step1: { + alt: "Interfaz web con selector y cursor", + title: "Selecciona las resoluciones judiciales", + subtitle: "Sube los documentos que quieres incorporar al set de datos.", + }, + step2: { + alt: "Barra de búsqueda con cursor", + title: "La inteligencia artificial analiza los documentos", + subtitle: + "Extrae automáticamente la información relevante de cada documento.", + }, + step3: { + alt: "Visor de documentos con controles de revisión", + title: "Revisión y validación humana", + subtitle: + "Es importante que verifiques que los datos sean correctos antes de exportar el archivo.", + }, + step4: { + alt: "Binoculares con globo terráqueo", + title: "Generación del set de datos", + subtitle: + "Los documentos pasan a formar parte del set de datos abiertos.", + }, + }, + process: { + sectionTitle: "2. Extracción de datos", + processingTitle: "AymurAI está extrayendo los datos de los archivos", + processingSubtitle: "Este proceso puede tardar algunos minutos.", + finishText: "Se finalizó el análisis de tus documentos.", + }, + result: { sectionTitle: "" }, + finish: { + sectionTitle: "4. Finalización", + description: + "Los datos encontrados por AymurAI y posteriormente validados ya son parte del set de datos abiertos con perspectiva de género.", + subtitle: "Archivos procesados", + restart: "Cargar más documentos", + viewResult: "Ver set de datos", + }, +}; + +export default dataset; diff --git a/frontend/src/renderer/src/constants/i18n/locales/es/index.ts b/frontend/src/renderer/src/constants/i18n/locales/es/index.ts new file mode 100644 index 00000000..d3cf487c --- /dev/null +++ b/frontend/src/renderer/src/constants/i18n/locales/es/index.ts @@ -0,0 +1,11 @@ +import anonymizer from "./anonymizer"; +import common from "./common"; +import dataset from "./dataset"; + +const es = { + common, + dataset, + anonymizer, +}; + +export default es; diff --git a/frontend/src/renderer/src/context/Annotation/index.tsx b/frontend/src/renderer/src/context/Annotation/index.tsx new file mode 100644 index 00000000..4404e057 --- /dev/null +++ b/frontend/src/renderer/src/context/Annotation/index.tsx @@ -0,0 +1,792 @@ +import type { + LabelAnnotation, + SearchAnnotation, +} from "@/components/file-annotator/types"; +import ManualEntityResolutionDialog, { + type ManualEntityResolutionRequest, +} from "@/components/file/manual-entity-resolution-dialog"; +import { getAnonymizerCategoryForLabel } from "@/constants/anonymizer-categories"; +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; +import { showToast } from "@/features/showToast"; +import { useEntityGroups, useFileDispatch, useFiles } from "@/hooks"; +import { + appendPrediction, + removePrediction, + removePredictionsByText, + updatePredictionLabel, + updatePredictionsByCanonicalId, + updatePredictionsByText, +} from "@/reducers/file/actions"; +import { useHoverState } from "@/store/useHoverState"; +import { + useExcludedTagsConfig, + useGroupOrder, + useGroupOrderActions, +} from "@/store/useLocal"; +import type { + AllLabels, + AllLabelsWithSufix, + AnonymizerLabels, + PredictLabel, +} from "@/types/aymurai"; +import { anonymizerLabels } from "@/types/aymurai"; +import type { DocFile, Paragraph } from "@/types/file"; +import { + type ManualEntityResolution, + findSimilarEntityGroups, + normalizeEntityText, + stripEntityLabelSuffix, +} from "@/utils/anonymizer/entity-similarity"; +import { findNormalizedOccurrenceRanges } from "@/utils/anonymizer/occurrences"; +import { filterActivePredictions } from "@/utils/anonymizer/predictions"; +import { Check, WarningCircle } from "phosphor-react"; +import { + type ReactNode, + createContext, + useCallback, + useContext, + useMemo, + useState, +} from "react"; +import { findSearchIndexes, getSelectionAnnotationRange } from "./utils"; + +interface AnnotationContextValues { + isAnnotable: boolean; + label: AllLabels | null; + add: (prediction: PredictLabel) => void; + remove: (prediction: PredictLabel) => void; + removeByText: (prediction: PredictLabel) => void; + updateLabel: ( + prediction: PredictLabel, + newLabel: AllLabels | AllLabelsWithSufix, + ) => void; + updateByText: ( + prediction: PredictLabel, + newLabel: AllLabels | AllLabelsWithSufix, + ) => void; + updateByCanonicalId: ( + canonicalId: string, + newLabel: AllLabels | AllLabelsWithSufix, + ) => void; + addBySearch: (search: string, label: AllLabels) => void; +} + +/** + * Provides the token received through OAuth2 login to the whole app + */ +export const AnnotationContext = createContext({ + isAnnotable: false, + label: null, + add: () => {}, + remove: () => {}, + removeByText: () => {}, + updateLabel: () => {}, + updateByText: () => {}, + updateByCanonicalId: () => {}, + addBySearch: () => {}, +}); +AnnotationContext.displayName = "AnnotationContext"; + +interface Props { + children?: ReactNode; + file: DocFile; + isAnnotable?: boolean; + label: AllLabels | null; +} + +type PendingManualResolution = ManualEntityResolutionRequest & { + predictions: PredictLabel[]; + selectedLabel: AllLabels; +}; + +const ANONYMIZER_LABEL_IDS = new Set( + anonymizerLabels.map((item) => item.id), +); + +function toBaseLabel(label: AllLabels | AllLabelsWithSufix): AllLabels { + return stripEntityLabelSuffix(String(label)) as AllLabels; +} + +function isKnownAnonymizerLabel(label: string): label is AnonymizerLabels { + return ANONYMIZER_LABEL_IDS.has(label); +} + +function isLabelEnabled( + label: AllLabels, + excludedTags: Record | null, +): boolean { + const baseLabel = stripEntityLabelSuffix(String(label)); + if (!isKnownAnonymizerLabel(baseLabel)) return true; + return (excludedTags ?? EXCLUDED_TAGS)[baseLabel] !== false; +} + +function isExcludedMention(text: string, excludedWords: string[]): boolean { + const normalizedText = normalizeEntityText(text); + return excludedWords.some( + (word) => normalizeEntityText(word) === normalizedText, + ); +} + +function withCanonicalEntity( + prediction: PredictLabel, + canonicalId: string, + label: AllLabels | AllLabelsWithSufix, +): PredictLabel { + return { + ...prediction, + attrs: { + ...prediction.attrs, + aymurai_label: label, + canonical_entity_id: canonicalId, + }, + }; +} + +function compareAppearance( + a: { paragraphIndex: number; start_char: number }, + b: { paragraphIndex: number; start_char: number }, +) { + if (a.paragraphIndex !== b.paragraphIndex) { + return a.paragraphIndex - b.paragraphIndex; + } + return a.start_char - b.start_char; +} + +function rangesOverlap( + a: { start_char: number; end_char: number }, + b: { start_char: number; end_char: number }, +) { + return a.start_char < b.end_char && b.start_char < a.end_char; +} + +function hasInternalOverlap(predictions: PredictLabel[]) { + const byParagraph = new Map(); + for (const prediction of predictions) { + const paragraphPredictions = byParagraph.get(prediction.paragraphId) ?? []; + paragraphPredictions.push(prediction); + byParagraph.set(prediction.paragraphId, paragraphPredictions); + } + + for (const paragraphPredictions of byParagraph.values()) { + const sorted = [...paragraphPredictions].sort( + (a, b) => a.start_char - b.start_char, + ); + for (let i = 1; i < sorted.length; i += 1) { + const previous = sorted[i - 1]; + const current = sorted[i]; + if (previous && current && rangesOverlap(previous, current)) return true; + } + } + + return false; +} + +export default function AnnotationProvider({ + children, + file, + isAnnotable = false, + label, +}: Props) { + const dispatch = useFileDispatch(); + const files = useFiles(); + const { tags, words } = useExcludedTagsConfig(); + const { groupOrder } = useGroupOrder(); + const { setGroupOrder } = useGroupOrderActions(); + const setLastEditedCanonicalId = useHoverState( + (s) => s.setLastEditedCanonicalId, + ); + const [pendingResolution, setPendingResolution] = + useState(null); + + const activeFiles = useMemo( + () => + files.map((item) => ({ + ...item, + predictions: filterActivePredictions(item.predictions, tags, words), + })), + [files, tags, words], + ); + const groups = useEntityGroups(activeFiles); + const activePredictionsByParagraph = useMemo(() => { + const result = new Map(); + const activePredictions = filterActivePredictions( + file.predictions, + tags, + words, + ); + + for (const prediction of activePredictions) { + const paragraphPredictions = result.get(prediction.paragraphId) ?? []; + paragraphPredictions.push(prediction); + result.set(prediction.paragraphId, paragraphPredictions); + } + + return result; + }, [file.predictions, tags, words]); + + const paragraphIndexById = useMemo(() => { + const result = new Map(); + for (const currentFile of files) { + for (const [index, paragraph] of ( + currentFile.paragraphs ?? [] + ).entries()) { + if (!result.has(paragraph.id)) result.set(paragraph.id, index); + } + } + return result; + }, [files]); + + const getFirstAppearance = useCallback( + (predictions: PredictLabel[]) => { + return predictions.reduce( + (earliest, prediction) => { + const current = { + paragraphIndex: paragraphIndexById.get(prediction.paragraphId) ?? 0, + start_char: prediction.start_char, + }; + return compareAppearance(current, earliest) < 0 ? current : earliest; + }, + { + paragraphIndex: Number.POSITIVE_INFINITY, + start_char: Number.POSITIVE_INFINITY, + }, + ); + }, + [paragraphIndexById], + ); + + const updateGroupOrderForNewGroup = useCallback( + ( + canonicalId: string, + selectedLabel: AllLabels, + predictions: PredictLabel[], + ) => { + const category = getAnonymizerCategoryForLabel(String(selectedLabel)); + const existingOrder = groupOrder?.[category]; + if (!existingOrder) return; + + const firstAppearance = getFirstAppearance(predictions); + const categoryGroups = groups + .filter( + (group) => + getAnonymizerCategoryForLabel(group.renderBase) === category, + ) + .sort((a, b) => + compareAppearance(a.firstAppearance, b.firstAppearance), + ); + const nextOrder = existingOrder.filter((id) => id !== canonicalId); + const insertBefore = categoryGroups.find( + (group) => + compareAppearance(firstAppearance, group.firstAppearance) < 0, + ); + + if (!insertBefore) { + nextOrder.push(canonicalId); + } else { + const index = nextOrder.indexOf(insertBefore.canonicalId); + if (index === -1) nextOrder.push(canonicalId); + else nextOrder.splice(index, 0, canonicalId); + } + + setGroupOrder({ ...groupOrder, [category]: nextOrder }); + }, + [getFirstAppearance, groupOrder, groups, setGroupOrder], + ); + + const commitPredictions = useCallback( + ( + predictions: PredictLabel[], + canonicalId: string, + resolvedLabel: AllLabels | AllLabelsWithSufix, + ) => { + for (const prediction of predictions) { + dispatch( + appendPrediction( + file.data.name, + withCanonicalEntity(prediction, canonicalId, resolvedLabel), + ), + ); + } + setLastEditedCanonicalId(canonicalId); + showToast( + predictions.length > 1 + ? "Se agregaron las etiquetas al grupo de entidad." + : "Se agregó la etiqueta al grupo de entidad.", + "success", + Check, + ); + }, + [dispatch, file.data.name, setLastEditedCanonicalId], + ); + + const commitNewGroup = useCallback( + (predictions: PredictLabel[], selectedLabel: AllLabels) => { + const canonicalId = crypto.randomUUID(); + commitPredictions(predictions, canonicalId, selectedLabel); + updateGroupOrderForNewGroup(canonicalId, selectedLabel, predictions); + }, + [commitPredictions, updateGroupOrderForNewGroup], + ); + + const queueManualPredictions = useCallback( + ( + predictions: PredictLabel[], + selectedLabel: AllLabels | AllLabelsWithSufix, + ) => { + if (predictions.length === 0) return; + + const baseLabel = toBaseLabel(selectedLabel); + const text = predictions[0]?.text ?? ""; + if (!normalizeEntityText(text)) return; + + if (hasInternalOverlap(predictions)) { + showToast( + "No se pueden agregar ocurrencias solapadas entre sí.", + "error", + WarningCircle, + ); + return; + } + + const overlappingPrediction = predictions.find((prediction) => + (activePredictionsByParagraph.get(prediction.paragraphId) ?? []).some( + (activePrediction) => rangesOverlap(prediction, activePrediction), + ), + ); + if (overlappingPrediction) { + showToast( + "La selección se solapa con una entidad activa. Eliminá o editá la entidad existente antes de crear otra.", + "error", + WarningCircle, + ); + return; + } + + if (!isLabelEnabled(baseLabel, tags)) { + showToast( + "La categoría seleccionada está desactivada en Configuración.", + "error", + WarningCircle, + ); + return; + } + + if (isExcludedMention(text, words)) { + showToast( + "El término seleccionado está en la lista de términos excluidos.", + "error", + WarningCircle, + ); + return; + } + + const candidates = findSimilarEntityGroups( + { + text, + normalizedText: normalizeEntityText(text), + label: String(baseLabel), + paragraphId: predictions[0]?.paragraphId, + start_char: predictions[0]?.start_char, + end_char: predictions[0]?.end_char, + }, + groups, + ); + + if (candidates.length === 0) { + commitNewGroup(predictions, baseLabel); + return; + } + + setPendingResolution({ + text, + label: String(baseLabel), + count: predictions.length, + candidates, + predictions, + selectedLabel: baseLabel, + }); + }, + [activePredictionsByParagraph, commitNewGroup, groups, tags, words], + ); + + const add = useCallback( + (prediction: PredictLabel) => { + queueManualPredictions([prediction], prediction.attrs.aymurai_label); + }, + [queueManualPredictions], + ); + + const remove = useCallback( + (prediction: PredictLabel) => { + dispatch(removePrediction(file.data.name, prediction)); + }, + [dispatch, file.data.name], + ); + + const removeByText = useCallback( + (prediction: PredictLabel) => { + dispatch(removePredictionsByText(file.data.name, prediction.text)); + }, + [dispatch, file.data.name], + ); + + const updateLabel = useCallback( + (prediction: PredictLabel, newLabel: AllLabels | AllLabelsWithSufix) => { + dispatch(updatePredictionLabel(file.data.name, prediction, newLabel)); + }, + [dispatch, file.data.name], + ); + + const updateByText = useCallback( + (prediction: PredictLabel, newLabel: AllLabels | AllLabelsWithSufix) => { + const normalizedText = normalizeEntityText(prediction.text); + if (!normalizedText) return; + + const sourceBaseLabel = toBaseLabel(prediction.attrs.aymurai_label); + const nextBaseLabel = toBaseLabel(newLabel); + const sourceCanonicalId = prediction.attrs.canonical_entity_id ?? null; + const targetCanonicalId = + sourceCanonicalId && sourceBaseLabel === nextBaseLabel + ? sourceCanonicalId + : crypto.randomUUID(); + const missingPredictions: PredictLabel[] = []; + let skippedOverlaps = 0; + + file.paragraphs?.forEach((paragraph: Paragraph) => { + const ranges = findNormalizedOccurrenceRanges( + paragraph.value, + prediction.text, + ); + + ranges.forEach((range) => { + const draftRange = { + start_char: range.start, + end_char: range.end, + }; + const activeOverlaps = ( + activePredictionsByParagraph.get(paragraph.id) ?? [] + ).filter((activePrediction) => + rangesOverlap(draftRange, activePrediction), + ); + const hasEquivalentActiveOverlap = activeOverlaps.some( + (activePrediction) => + normalizeEntityText(activePrediction.text) === normalizedText, + ); + + if (hasEquivalentActiveOverlap) return; + + if (activeOverlaps.length > 0) { + skippedOverlaps += 1; + return; + } + + missingPredictions.push({ + mentionId: crypto.randomUUID(), + start_char: range.start, + end_char: range.end, + paragraphId: paragraph.id, + text: range.text, + attrs: { + aymurai_label: newLabel, + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: range.start, + aymurai_alt_end_char: range.end, + }, + }); + }); + }); + + dispatch( + updatePredictionsByText( + file.data.name, + prediction.text, + newLabel, + targetCanonicalId, + ), + ); + + for (const missingPrediction of missingPredictions) { + dispatch( + appendPrediction( + file.data.name, + withCanonicalEntity(missingPrediction, targetCanonicalId, newLabel), + ), + ); + } + + const createdNewGroup = + !sourceCanonicalId || sourceBaseLabel !== nextBaseLabel; + if (createdNewGroup) { + updateGroupOrderForNewGroup( + targetCanonicalId, + nextBaseLabel, + missingPredictions.length > 0 ? missingPredictions : [prediction], + ); + } + + setLastEditedCanonicalId(targetCanonicalId); + + if (skippedOverlaps > 0) { + showToast( + "Algunas ocurrencias no se agregaron porque se solapan con entidades activas.", + "error", + WarningCircle, + ); + } + }, + [ + activePredictionsByParagraph, + dispatch, + file.data.name, + file.paragraphs, + setLastEditedCanonicalId, + updateGroupOrderForNewGroup, + ], + ); + + const updateByCanonicalId = useCallback( + (canonicalId: string, newLabel: AllLabels | AllLabelsWithSufix) => { + dispatch(updatePredictionsByCanonicalId(canonicalId, newLabel)); + }, + [dispatch], + ); + + const addBySearch = useCallback( + (search: string, label: AllLabels) => { + if (!search || search.length < 3) return; + + const normalizedSearch = normalizeEntityText(search); + const predictions: PredictLabel[] = []; + let skippedOverlaps = 0; + const reusableCanonicalId = [...activePredictionsByParagraph.values()] + .flat() + .find( + (prediction) => + normalizeEntityText(prediction.text) === normalizedSearch && + prediction.attrs.canonical_entity_id, + )?.attrs.canonical_entity_id; + + file.paragraphs?.forEach((paragraph: Paragraph) => { + const normalizedRanges = findNormalizedOccurrenceRanges( + paragraph.value, + search, + ); + const ranges = + normalizedRanges.length > 0 + ? normalizedRanges + : findSearchIndexes(paragraph.value, search).map((start) => ({ + start, + end: start + search.length, + text: paragraph.value.slice(start, start + search.length), + normalizedText: normalizeEntityText(search), + })); + ranges.forEach((range) => { + const draftRange = { + start_char: range.start, + end_char: range.end, + }; + const activeOverlaps = ( + activePredictionsByParagraph.get(paragraph.id) ?? [] + ).filter((activePrediction) => + rangesOverlap(draftRange, activePrediction), + ); + const hasEquivalentActiveOverlap = activeOverlaps.some( + (activePrediction) => + normalizeEntityText(activePrediction.text) === normalizedSearch, + ); + + if (hasEquivalentActiveOverlap) return; + + if (activeOverlaps.length > 0) { + skippedOverlaps += 1; + return; + } + + const prediction: PredictLabel = { + mentionId: crypto.randomUUID(), + start_char: range.start, + end_char: range.end, + paragraphId: paragraph.id, + text: range.text, + attrs: { + aymurai_label: label, + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: range.start, + aymurai_alt_end_char: range.end, + }, + }; + predictions.push(prediction); + }); + }); + + if (predictions.length === 0 && skippedOverlaps > 0) { + showToast( + "No se agregaron ocurrencias porque todas se solapan con entidades activas.", + "error", + WarningCircle, + ); + return; + } + + if (reusableCanonicalId) { + dispatch( + updatePredictionsByText( + file.data.name, + search, + label, + reusableCanonicalId, + ), + ); + + for (const prediction of predictions) { + dispatch( + appendPrediction( + file.data.name, + withCanonicalEntity(prediction, reusableCanonicalId, label), + ), + ); + } + + setLastEditedCanonicalId(reusableCanonicalId); + if (skippedOverlaps > 0) { + showToast( + "Algunas ocurrencias no se agregaron porque se solapan con entidades activas.", + "error", + WarningCircle, + ); + } + return; + } + + queueManualPredictions(predictions, label); + }, + [ + activePredictionsByParagraph, + dispatch, + file.data.name, + file.paragraphs, + queueManualPredictions, + setLastEditedCanonicalId, + ], + ); + + const selectHandler = () => { + // If the user hasn't selected any tag to search, do nothing + if (!label) return; + + const selection = window.getSelection(); + if (!selection) return; + const selectedRange = getSelectionAnnotationRange(selection); + if (!selectedRange) return; + + add({ + mentionId: crypto.randomUUID(), + start_char: selectedRange.start, + end_char: selectedRange.end, + paragraphId: selectedRange.paragraphId, + text: selectedRange.text, + attrs: { + aymurai_label: label, + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: selectedRange.start, + aymurai_alt_end_char: selectedRange.end, + }, + }); + }; + + const handleResolveManualEntity = (resolution: ManualEntityResolution) => { + if (!pendingResolution) return; + + if (resolution.type === "existing") { + commitPredictions( + pendingResolution.predictions, + resolution.candidate.group.canonicalId, + resolution.candidate.group.renderBase as AllLabels | AllLabelsWithSufix, + ); + } else { + commitNewGroup( + pendingResolution.predictions, + pendingResolution.selectedLabel, + ); + } + + setPendingResolution(null); + }; + + return ( + +
    {children}
    + setPendingResolution(null)} + onResolve={handleResolveManualEntity} + /> +
    + ); +} + +export const useAnnotation = () => { + const { + add, + remove, + removeByText, + isAnnotable, + label, + updateLabel, + updateByText, + updateByCanonicalId, + addBySearch, + } = useContext(AnnotationContext); + + const createAnnotationData = ( + text: string, + annotation: LabelAnnotation | SearchAnnotation, + labelOverride?: AllLabels | AllLabelsWithSufix, + ) => { + const { start, end, paragraphId, tag } = annotation; + const resolvedTag = labelOverride ?? tag; + if (!resolvedTag) return null; + return { + mentionId: crypto.randomUUID(), + text, + start_char: start, + end_char: end, + paragraphId: paragraphId, + attrs: { + aymurai_label: resolvedTag, + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: start, + aymurai_alt_end_char: end, + }, + } satisfies PredictLabel; + }; + + return { + add, + remove, + removeByText, + isAnnotable, + label, + updateLabel, + updateByText, + updateByCanonicalId, + addBySearch, + createAnnotationData, + }; +}; diff --git a/frontend/src/renderer/src/context/Annotation/utils.ts b/frontend/src/renderer/src/context/Annotation/utils.ts new file mode 100644 index 00000000..00ddaea4 --- /dev/null +++ b/frontend/src/renderer/src/context/Annotation/utils.ts @@ -0,0 +1,136 @@ +/** + * Check if the selection contains another Node. + * @param selection The current selection. + * @returns `true` if the selection contains a Node, `false` otherwise. + */ +export const selectionHasNodes = (selection: Selection | null): boolean => { + if (!selection) return false; + + const container = document.createElement("div"); + + for (let i = 0; i < selection.rangeCount; ++i) { + container.appendChild(selection.getRangeAt(i).cloneContents()); + } + + return new RegExp(/<.*?>/g).test(container.innerHTML); +}; + +/** + * Checks if the node is can be annotated. It checks the type of Node and its parentElement (if it's a span). + * @param node Node from the selection + * @returns `true` if the node is a valid node, `false` otherwise. + */ +export const isValidNode = (node: Node | null): node is Node => + !!node && + node instanceof Text && + node.parentElement instanceof HTMLSpanElement; + +/** + * Get the start and end boundaries of the selection. Reverses the boundaries if the selection is made from right to left. + * @param selection Selection object + * @returns The start and end boundaries of the selection + */ +export const getBoundaries = (selection: Selection): [number, number] => { + const start = selection.anchorOffset; + const end = selection.focusOffset; + return [start, end].sort((a, b) => a - b) as [number, number]; +}; + +/** + * Get the id of the paragraph where the selection is made. + * @param selection Selection object + * @returns The id of the paragraph where the selection is made + */ +export const paragraphIdFromSelection = (selection: Selection) => { + // This is evaluated after the isValidNode check, so we can safely assume that the parentElement is a span + const span = selection.anchorNode?.parentElement; + const paragraph = span?.parentElement as HTMLParagraphElement; + + return paragraph.id; +}; + +function closestOffsetElement(node: Node | null): HTMLElement | null { + const element = node instanceof HTMLElement ? node : node?.parentElement; + return element?.closest("[data-start]") ?? null; +} + +function offsetWithinElement( + element: HTMLElement, + container: Node, + offset: number, +): number | null { + const range = document.createRange(); + range.setStart(element, 0); + + try { + range.setEnd(container, offset); + } catch { + return null; + } + + return range.toString().length; +} + +export function getSelectionAnnotationRange(selection: Selection): { + paragraphId: string; + start: number; + end: number; + text: string; +} | null { + if (selection.rangeCount === 0 || selection.type !== "Range") return null; + + const range = selection.getRangeAt(0); + const text = range.toString(); + if (!text) return null; + + const startElement = closestOffsetElement(range.startContainer); + const endElement = closestOffsetElement(range.endContainer); + if (!startElement || !endElement) return null; + + const startParagraph = startElement.closest("p[id]"); + const endParagraph = endElement.closest("p[id]"); + if (!startParagraph || !endParagraph || startParagraph.id !== endParagraph.id) + return null; + + const startBase = Number(startElement.dataset.start ?? 0); + const endBase = Number(endElement.dataset.start ?? 0); + const startOffset = offsetWithinElement( + startElement, + range.startContainer, + range.startOffset, + ); + const endOffset = offsetWithinElement( + endElement, + range.endContainer, + range.endOffset, + ); + + if (startOffset === null || endOffset === null) return null; + + return { + paragraphId: startParagraph.id, + start: startBase + startOffset, + end: endBase + endOffset, + text, + }; +} + +/** + * Find all indexes where a search string appears in a text. + * @param text The text to search in + * @param search The string to search for + * @returns An array of indexes where the search string appears + */ +export const findSearchIndexes = (text: string, search: string): number[] => { + const indexes: number[] = []; + const lowerText = text.toLowerCase(); + const lowerSearch = search.toLowerCase(); + let index = lowerText.indexOf(lowerSearch); + + while (index !== -1) { + indexes.push(index); + index = lowerText.indexOf(lowerSearch, index + 1); + } + + return indexes; +}; diff --git a/frontend/src/renderer/src/context/File.tsx b/frontend/src/renderer/src/context/File.tsx new file mode 100644 index 00000000..27d2724d --- /dev/null +++ b/frontend/src/renderer/src/context/File.tsx @@ -0,0 +1,35 @@ +import { + type Dispatch, + type ReactNode, + createContext, + useReducer, +} from "react"; + +import reducer, { type Action } from "@/reducers/file"; +import type { DocFile } from "@/types/file"; + +/** + * Context used to provide files that have to be processed + */ +export const FileContext = createContext([]); +FileContext.displayName = "FileContext"; + +/** + * Context used to provide the dispatch function + */ +export const FileDispatchContext = createContext>(() => {}); +FileDispatchContext.displayName = "FileDispatchContext"; + +interface Props { + children: ReactNode; +} +export default function FileProvider({ children }: Props) { + const [state, dispatch] = useReducer(reducer, []); + return ( + + + {children} + + + ); +} diff --git a/frontend/src/renderer/src/features/APIProtected.tsx b/frontend/src/renderer/src/features/APIProtected.tsx new file mode 100644 index 00000000..0ccd1a76 --- /dev/null +++ b/frontend/src/renderer/src/features/APIProtected.tsx @@ -0,0 +1,12 @@ +import api from "@/services/api"; +import { Navigate } from "@tanstack/react-router"; +import type { ReactNode } from "react"; + +interface Props { + children: ReactNode; +} + +export default function APIProtected({ children }: Props) { + if (!api.defaults.baseURL) return ; + return children; +} diff --git a/frontend/src/renderer/src/features/ReactQueryProvider.tsx b/frontend/src/renderer/src/features/ReactQueryProvider.tsx new file mode 100644 index 00000000..33c23f18 --- /dev/null +++ b/frontend/src/renderer/src/features/ReactQueryProvider.tsx @@ -0,0 +1,55 @@ +import { + MutationCache, + QueryClient, + QueryClientProvider, + matchQuery, +} from "@tanstack/react-query"; + +export function getContext() { + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + refetchOnWindowFocus: false, + retry: false, + }, + }, + mutationCache: new MutationCache({ + onSettled: async (_data, _err, _vars, _ctx, mutation) => { + if (!mutation.meta) return; + const { invalidates, awaits } = mutation.meta; + + const promise = queryClient.invalidateQueries({ + predicate: (query) => { + if (typeof invalidates === "boolean") return invalidates; + + return ( + invalidates?.some((queryKey) => + matchQuery({ queryKey }, query), + ) ?? false + ); + }, + }); + + if (awaits) { + await promise; + } + }, + }), + }); + + return { + queryClient, + }; +} + +export function Provider({ + children, + queryClient, +}: { + children: React.ReactNode; + queryClient: QueryClient; +}) { + return ( + {children} + ); +} diff --git a/frontend/src/renderer/src/features/RequireFile.tsx b/frontend/src/renderer/src/features/RequireFile.tsx new file mode 100644 index 00000000..4e9c518f --- /dev/null +++ b/frontend/src/renderer/src/features/RequireFile.tsx @@ -0,0 +1,22 @@ +import { useFiles } from "@/hooks"; +import { getFeatureRouteSlug, parseFeatureRouteSlug } from "@/types/features"; +import { Navigate, useParams } from "@tanstack/react-router"; +import type { ReactNode } from "react"; + +interface Props { + children: ReactNode; +} + +export default function RequireFile({ children }: Props) { + const files = useFiles(); + const { feature: featureSlug } = useParams({ strict: false }) as { feature?: string }; + const feature = featureSlug ? parseFeatureRouteSlug(featureSlug) : null; + + if (!feature) return ; + + if (!files.length) { + return ; + } + + return children; +} diff --git a/frontend/src/renderer/src/features/showToast.tsx b/frontend/src/renderer/src/features/showToast.tsx new file mode 100644 index 00000000..0199ac4a --- /dev/null +++ b/frontend/src/renderer/src/features/showToast.tsx @@ -0,0 +1,7 @@ +import Toast, { type ToastVariant } from "@/components/ui/toast"; +import type { Icon } from "phosphor-react"; +import { toast } from "react-hot-toast"; + +export function showToast(message: string, variant: ToastVariant = "info", icon?: Icon) { + toast.custom((t) => ); +} diff --git a/frontend/src/renderer/src/hooks/index.ts b/frontend/src/renderer/src/hooks/index.ts new file mode 100644 index 00000000..a5b268f4 --- /dev/null +++ b/frontend/src/renderer/src/hooks/index.ts @@ -0,0 +1,8 @@ +import { useFileDispatch, useFiles } from "./useFiles"; +import useForm from "./useForm"; + +export { useEntityGroups } from "./useEntityGroups"; +export type { EntityGroup } from "./useEntityGroups"; +export { usePredict } from "./usePredict"; + +export { useFileDispatch, useFiles, useForm }; diff --git a/frontend/src/renderer/src/hooks/useDisambiguate.ts b/frontend/src/renderer/src/hooks/useDisambiguate.ts new file mode 100644 index 00000000..b4ce9704 --- /dev/null +++ b/frontend/src/renderer/src/hooks/useDisambiguate.ts @@ -0,0 +1,81 @@ +import { useEffect, useRef } from "react"; + +import { useFileDispatch } from "@/hooks"; +import { addPredictions, removePredictions } from "@/reducers/file/actions"; +import { disambiguate } from "@/services/aymurai/queries"; +import type { DocFile } from "@/types/file"; +import { useQueries } from "@tanstack/react-query"; + +import type { PredictStatus } from "./usePredict"; + +type FileDisambiguate = { status: PredictStatus }; + +/** + * Runs disambiguation for each file **after all its predictions have arrived**. + * When `enabled` is false (e.g. datapublic flow) every file resolves to + * `"completed"` immediately and no requests are made. + * + * Aligned index-wise with `files`: `queries[i]` corresponds to `files[i]`. + */ +export function useDisambiguate( + files: DocFile[], + predictStatuses: Record< + string, + { status: PredictStatus; fromValidation?: boolean } + >, + enabled: boolean, +): Record { + const dispatch = useFileDispatch(); + // Track which files have already had their disambiguated predictions dispatched + const dispatchedRef = useRef(new Set()); + + const queries = useQueries({ + queries: files.map((file) => ({ + ...disambiguate(file), + // Fire only when this step is enabled, predict is fully done, AND the + // predictions were not loaded from stored DB validation (which is already + // post-disambiguation data and must not be overwritten). + enabled: + enabled && + predictStatuses[file.data.name]?.status === "completed" && + !predictStatuses[file.data.name]?.fromValidation, + })), + }); + + // Dispatch disambiguated predictions exactly once per file on success + useEffect(() => { + queries.forEach((query, i) => { + const fileName = files[i].data.name; + if (!query.isSuccess || dispatchedRef.current.has(fileName)) return; + + dispatchedRef.current.add(fileName); + // Replace raw predictions with the disambiguated ones + dispatch(removePredictions(fileName)); + dispatch(addPredictions(fileName, query.data)); + }); + }); + + const result: Record = {}; + + files.forEach((file, i) => { + const fileName = file.data.name; + const query = queries[i]; + const predictDone = predictStatuses[fileName]?.status === "completed"; + + result[fileName] = { + status: !enabled + ? "completed" // this step is skipped for non-anonymizer flows + : predictStatuses[fileName]?.fromValidation + ? "completed" // predictions came from DB validation; disambiguation not needed + : !predictDone + ? "processing" // still waiting on predict + : query.isError + ? "error" + : query.isSuccess + ? "completed" + : "processing", + }; + }); + + return result; +} diff --git a/frontend/src/renderer/src/hooks/useEntityGroups.ts b/frontend/src/renderer/src/hooks/useEntityGroups.ts new file mode 100644 index 00000000..fcdf99b8 --- /dev/null +++ b/frontend/src/renderer/src/hooks/useEntityGroups.ts @@ -0,0 +1,269 @@ +import { useMemo } from "react"; + +import type { PredictLabel } from "@/types/aymurai"; +import type { DocFile } from "@/types/file"; +import { + normalizeEntityText, + stripEntityLabelSuffix, +} from "@/utils/anonymizer/entity-similarity"; + +// ─── Public types ───────────────────────────────────────────────────────────── + +export interface EntityGroup { + /** The canonical_entity_id that identifies this group. */ + canonicalId: string; + /** aymurai_label with numeric suffix stripped (e.g. "PER", "DNI"). */ + renderBase: string; + /** 1-indexed position among all groups sharing the same renderBase, ordered + * by first appearance (paragraphIndex then start_char). */ + suffixIndex: number; + /** Human-readable render token shown to the user (e.g. "PER_1"). */ + renderToken: string; + /** All individual mention predictions belonging to this group. */ + mentions: PredictLabel[]; + /** Deduplicated normalised texts, sorted alphabetically. Used internally for matching. */ + uniqueTexts: string[]; + /** Verbatim texts corresponding 1-to-1 with {@link uniqueTexts}. Each inner array holds all distinct + * surface forms that share the same normalised text (e.g. ["PUERTO BELGRANO", "Puerto Belgrano"]). + * Use for display; use {@link uniqueTexts} for matching/removal. */ + displayTexts: string[][]; + /** Location of the earliest mention, for ordering and UX. */ + firstAppearance: { paragraphIndex: number; start_char: number }; + /** Whether the group should be anonymised (majority vote from mentions). */ + anonymize: boolean; + /** True when another group has the same renderBase and uniqueTexts set. */ + isDuplicate: boolean; + /** canonicalId of the earliest group that is identical to this one. */ + duplicateOf: string | null; +} + +// ─── Helpers ────────────────────────────────────────────────────────────────── + +/** Strip a numeric suffix like `_1`, `_12` from a label string. */ +export function stripSuffix(label: string): string { + return stripEntityLabelSuffix(label); +} + +// ─── Main hook ──────────────────────────────────────────────────────────────── + +/** + * Derives a flat array of {@link EntityGroup} objects from all predictions + * across the provided files. + * + * Groups are identified by `canonical_entity_id`. Mentions without a + * canonical id are silently skipped (they are raw predict results that haven't + * been through the disambiguate step yet). + * + * Suffix indices are assigned by first-appearance order per `renderBase`. + * Duplicate detection compares `(renderBase, uniqueTexts)`. + */ +export function useEntityGroups(files: DocFile[]): EntityGroup[] { + return useMemo(() => { + // Build a paragraphId → index map across all files so we can order + // mentions by paragraph position. + const paragraphIndexByParagraphId = new Map(); + for (const file of files) { + for (const [i, p] of (file.paragraphs ?? []).entries()) { + if (!paragraphIndexByParagraphId.has(p.id)) { + paragraphIndexByParagraphId.set(p.id, i); + } + } + } + + // Accumulate mentions per canonicalId, plus track renderBase and first appearance. + const byCanonicalId = new Map< + string, + { + mentions: PredictLabel[]; + renderBase: string; + firstAppearance: { paragraphIndex: number; start_char: number }; + } + >(); + + for (const file of files) { + for (const pred of file.predictions ?? []) { + const { canonical_entity_id, aymurai_label } = pred.attrs; + if (!canonical_entity_id) continue; + + const renderBase = stripSuffix(String(aymurai_label)); + const paragraphIndex = + paragraphIndexByParagraphId.get(pred.paragraphId) ?? 0; + + if (!byCanonicalId.has(canonical_entity_id)) { + byCanonicalId.set(canonical_entity_id, { + mentions: [], + renderBase, + firstAppearance: { + paragraphIndex, + start_char: pred.start_char, + }, + }); + } + + const entry = byCanonicalId.get(canonical_entity_id); + if (!entry) continue; + entry.mentions.push(pred); + + // Keep the earliest appearance + const fa = entry.firstAppearance; + if ( + paragraphIndex < fa.paragraphIndex || + (paragraphIndex === fa.paragraphIndex && + pred.start_char < fa.start_char) + ) { + fa.paragraphIndex = paragraphIndex; + fa.start_char = pred.start_char; + } + } + } + + // Sort canonicalIds by first appearance so suffix numbering is stable and + // matches the document reading order (same as backend behaviour). + const sorted = [...byCanonicalId.entries()].sort(([, a], [, b]) => { + const aPara = a.firstAppearance.paragraphIndex; + const bPara = b.firstAppearance.paragraphIndex; + if (aPara !== bPara) return aPara - bPara; + return a.firstAppearance.start_char - b.firstAppearance.start_char; + }); + + // Assign suffix indices per renderBase. + const suffixCounter = new Map(); + const suffixByCanonicalId = new Map(); + for (const [canonicalId, { renderBase }] of sorted) { + const next = (suffixCounter.get(renderBase) ?? 0) + 1; + suffixCounter.set(renderBase, next); + suffixByCanonicalId.set(canonicalId, next); + } + + // Build EntityGroup objects. + const groups: EntityGroup[] = sorted.map( + ([canonicalId, { mentions, renderBase, firstAppearance }]) => { + // Build normalised → first distinct verbatim form seen for that normalisation. + // We intentionally keep only ONE display representative per normalised bucket: + // multiple document spans may share the same alias and we don't want to show + // the same alias chip multiple times. Verbatim comparison uses NFC so that + // Unicode-composed and decomposed forms of the same visible character are + // treated as identical. + const normalizedToVerbatims = new Map(); + for (const m of mentions) { + const norm = normalizeEntityText(m.text); + if (!norm) continue; + const existing = normalizedToVerbatims.get(norm); + if (!existing) { + normalizedToVerbatims.set(norm, [m.text]); + } else if ( + !existing.some( + (v) => + v.normalize("NFC") === m.text.normalize("NFC"), + ) + ) { + existing.push(m.text); + } + } + const uniqueTexts = [...normalizedToVerbatims.keys()].sort(); + const displayTexts = uniqueTexts.map( + (t) => normalizedToVerbatims.get(t) ?? [], + ); + + const anonymizeCount = mentions.filter( + (m) => m.attrs.aymurai_anonymize !== false, + ).length; + const anonymize = anonymizeCount >= mentions.length / 2; + + const suffixIndex = suffixByCanonicalId.get(canonicalId) ?? 1; + + return { + canonicalId, + renderBase, + suffixIndex, + renderToken: `${renderBase}_${suffixIndex}`, + mentions, + uniqueTexts, + displayTexts, + firstAppearance, + anonymize, + isDuplicate: false, + duplicateOf: null, + }; + }, + ); + + // Duplicate / overlap detection: any two groups under the same renderBase + // that share at least one normalised mention text are flagged as merge + // candidates. + // + // The detection key uses a SORTED-TOKEN fingerprint of the normalised text + // so that name variants differing only in token order + // (e.g. "Pérez, Laura Beatriz" vs "Laura Beatriz Pérez") are recognised as + // the same alias and trigger a merge suggestion. + // + // Primary rule: the group with MORE unique texts is primary (it's more + // "established"). Ties are broken by first-appearance order (already the + // iteration order). When a later group turns out to have more texts than + // the registered primary, they swap roles. + + /** Sorted-token fingerprint — collapses token-order variants of a name. */ + const sortedFingerprint = (normText: string): string => + [...new Set(normText.split(" "))].sort().join(" "); + + const textToGroup = new Map(); // key → primary canonicalId + const groupById = new Map(groups.map((g) => [g.canonicalId, g])); + + for (const group of groups) { + let conflictPrimaryId: string | null = null; + + for (const normText of group.uniqueTexts) { + const key = `${group.renderBase}\x01${sortedFingerprint(normText)}`; + const existing = textToGroup.get(key); + if (existing && existing !== group.canonicalId) { + conflictPrimaryId = existing; + break; + } + } + + if (conflictPrimaryId !== null) { + const primaryGroup = groupById.get(conflictPrimaryId); + if (!primaryGroup) continue; + + if (group.uniqueTexts.length > primaryGroup.uniqueTexts.length) { + // Current group has more texts → it becomes the new primary; + // old primary is demoted to duplicate. + primaryGroup.isDuplicate = true; + primaryGroup.duplicateOf = group.canonicalId; + // Re-register all previously-registered keys under new primary. + for (const normText of primaryGroup.uniqueTexts) { + textToGroup.set( + `${primaryGroup.renderBase}\x01${sortedFingerprint(normText)}`, + group.canonicalId, + ); + } + for (const normText of group.uniqueTexts) { + textToGroup.set( + `${group.renderBase}\x01${sortedFingerprint(normText)}`, + group.canonicalId, + ); + } + } else { + // Existing primary has equal or more texts → current is duplicate. + group.isDuplicate = true; + group.duplicateOf = conflictPrimaryId; + // Register any new texts under the existing primary. + for (const normText of group.uniqueTexts) { + const key = `${group.renderBase}\x01${sortedFingerprint(normText)}`; + if (!textToGroup.has(key)) textToGroup.set(key, conflictPrimaryId); + } + } + } else { + // No conflict — register all own texts as primary. + for (const normText of group.uniqueTexts) { + textToGroup.set( + `${group.renderBase}\x01${sortedFingerprint(normText)}`, + group.canonicalId, + ); + } + } + } + + return groups; + }, [files]); +} diff --git a/frontend/src/renderer/src/hooks/useFileParse.ts b/frontend/src/renderer/src/hooks/useFileParse.ts new file mode 100644 index 00000000..a45da857 --- /dev/null +++ b/frontend/src/renderer/src/hooks/useFileParse.ts @@ -0,0 +1,69 @@ +import { useEffect, useState } from "react"; + +import { useFileDispatch } from "@/hooks"; +import { addParagraphs } from "@/reducers/file/actions"; +import { fileParser } from "@/services/aymurai/queries"; +import type { DocFile } from "@/types/file"; +import { useQueries, useQueryClient } from "@tanstack/react-query"; + +import type { PredictStatus } from "./usePredict"; + +export function useFileParse( + files: DocFile[], +): Record void }> { + const dispatch = useFileDispatch(); + const queryClient = useQueryClient(); + const [abortedFiles, setAbortedFiles] = useState>(new Set()); + + const queries = useQueries({ + queries: files.map((file) => ({ + ...fileParser(file.data), + enabled: !abortedFiles.has(file.data.name), + })), + }); + + useEffect(() => { + queries.forEach((query, fileIndex) => { + const file = files[fileIndex]; + // Use the Redux state as the guard: if paragraphs are already set, skip. + // This correctly re-dispatches when the same file is reloaded after a replace. + if (!query.isSuccess || !query.data || file.paragraphs !== undefined) + return; + dispatch( + addParagraphs( + query.data.document.map((p, paragraphIndex) => ({ + value: p, + document_id: query.data.document_id, + id: `${query.data.document_id}:${paragraphIndex}`, + })), + file.data.name, + ), + ); + }); + }); + + const result: Record void }> = + {}; + files.forEach((file, i) => { + const q = queries[i]; + const fileName = file.data.name; + const isAborted = abortedFiles.has(fileName); + result[fileName] = { + status: isAborted + ? "stopped" + : q.isError + ? "error" + : q.isSuccess + ? "completed" + : "processing", + abort: () => { + queryClient.cancelQueries({ + queryKey: ["file-parser", fileName], + exact: false, + }); + setAbortedFiles((prev) => new Set([...prev, fileName])); + }, + }; + }); + return result; +} diff --git a/frontend/src/renderer/src/hooks/useFiles.ts b/frontend/src/renderer/src/hooks/useFiles.ts new file mode 100644 index 00000000..280012e0 --- /dev/null +++ b/frontend/src/renderer/src/hooks/useFiles.ts @@ -0,0 +1,17 @@ +import { useContext } from "react"; + +import { FileContext, FileDispatchContext } from "@/context/File"; + +/** + * Hook used to view the files in the state + */ +export function useFiles() { + return useContext(FileContext); +} + +/** + * Hook used to dispatch actions that modify the state + */ +export function useFileDispatch() { + return useContext(FileDispatchContext); +} diff --git a/frontend/src/renderer/src/hooks/useForm/index.ts b/frontend/src/renderer/src/hooks/useForm/index.ts new file mode 100644 index 00000000..5dacc409 --- /dev/null +++ b/frontend/src/renderer/src/hooks/useForm/index.ts @@ -0,0 +1,83 @@ +import { LabelDecisiones, type LabelType } from "@/types/aymurai"; +import nArray from "@/utils/nArray"; +import { useRef, useState } from "react"; +import type { FormData, RegisterFunction, SubmitFunction } from "./types"; + +/** + * Creates a group of component references and a function to handle + * @param initialDecisiones Initial amount of decisiones + * @returns `register()` and `submit()` functions + */ +export default function useForm(initialDecisiones = 1) { + // Create an n-array of empty objects + const refs = useRef({ DECISIONES: nArray(initialDecisiones, {}) }); + // State containing decisionAmounts. This is done in this way to make React perform a re-render + // in case we want to add a decision + const [decisionAmount, setDecisionAmount] = useState(initialDecisiones); + + /** + * Adds a reference to a components value to the 'state' + * @param name Name of the reference + * @returns A `(ref) => void` function that should be applied to the `ref={...}` prop of a component + */ + const register: RegisterFunction = (name, decision) => (ref) => { + if (ref) { + // We have to alter the DECISIONES array + if (name in LabelDecisiones) { + // In case we already have an array, modify the label + if (refs.current.DECISIONES) { + const arr = refs.current.DECISIONES; + const i = decision ?? 0; + + arr[i][name as LabelDecisiones] = ref.value; + } else { + // We have no array, create it + refs.current.DECISIONES = [{ [name]: ref.value }]; + } + } else { + // Just modify the label in the object + refs.current[name as LabelType] = ref.value; + } + } + }; + + /** + * Collects all the data from the referrences and creates a submit function with them + * @param callback Callback that is called with all the data collected from the references as an argument + * @returns A `(event) => void` function that should be applied to the `onSubmit={...}` prop of a form + */ + const submit = (callback: SubmitFunction) => () => { + callback(refs.current); + }; + + const addDecision = () => { + const arr = refs.current.DECISIONES; + + if (arr) { + setDecisionAmount((dec) => dec + 1); + refs.current.DECISIONES = [...arr, {}]; + } else { + setDecisionAmount(1); + refs.current.DECISIONES = [{}]; + } + }; + + const getDecisionValue = (n: number) => (field: LabelDecisiones) => { + const arr = refs.current.DECISIONES; + + if (arr && n in arr && field in arr[n]) { + return arr[n][field]; + } + return ""; + }; + + return { + register, + submit, + addDecision, + decisionAmount, + getDecisionValue, + }; +} + +export * from "./types"; diff --git a/frontend/src/renderer/src/hooks/useForm/types.ts b/frontend/src/renderer/src/hooks/useForm/types.ts new file mode 100644 index 00000000..3832a118 --- /dev/null +++ b/frontend/src/renderer/src/hooks/useForm/types.ts @@ -0,0 +1,36 @@ +import type { + AllLabels, + AllLabelsWithSufix, + LabelDecisiones, + LabelType, +} from "@/types/aymurai"; + +/** + * Any value the form can take + */ +export type FormValue = string | boolean | undefined; +/** + * Data structure of the whole form + */ +export type FormData = Partial< + Record & { + DECISIONES: Partial>[]; + } +>; +/** + * Flat form of the `FormData` structure + */ +export type FlatFormData = Partial< + Record +>; + +/** + * Type of the reference for any componente + */ +export type ComponentRef = { value: string | boolean | undefined } | null; + +export type RegisterFunction = ( + name: AllLabels | AllLabelsWithSufix, + decision?: number, +) => (ref: ComponentRef) => void; +export type SubmitFunction = (data: FormData) => void; diff --git a/frontend/src/renderer/src/hooks/usePredict.ts b/frontend/src/renderer/src/hooks/usePredict.ts new file mode 100644 index 00000000..9ab803e2 --- /dev/null +++ b/frontend/src/renderer/src/hooks/usePredict.ts @@ -0,0 +1,171 @@ +import { useRef, useState } from "react"; + +import { useFileDispatch } from "@/hooks"; +import { addPredictions, removePredictions } from "@/reducers/file/actions"; +import predict from "@/services/aymurai/predict"; +import { predictParagraph } from "@/services/aymurai/queries"; +import getStoredValidation from "@/services/aymurai/validation"; +import type { Workflows } from "@/types/aymurai"; +import type { DocFile } from "@/types/file"; +import { useQueries, useQueryClient } from "@tanstack/react-query"; + +// Limit concurrent in-flight predict requests to avoid browser connection exhaustion +const MAX_CONCURRENT = 100; +const semaphore = (() => { + let running = 0; + const queue: Array<() => void> = []; + return { + acquire(): Promise { + return new Promise((resolve) => { + if (running < MAX_CONCURRENT) { + running++; + resolve(); + } else queue.push(resolve); + }); + }, + release() { + const next = queue.shift(); + if (next) next(); + else running = Math.max(0, running - 1); + }, + }; +})(); + +export type PredictStatus = "processing" | "error" | "stopped" | "completed"; + +type FilePredict = { + progress: number; + status: PredictStatus; + abort: () => void; + /** + * True when every paragraph in this file was loaded from the backend's stored + * validation (`anonymization_paragraph.validation`) instead of running the + * model. When true, the disambiguation step must be skipped. + */ + fromValidation: boolean; +}; + +/** + * Runs predictions for all paragraphs across all given files in parallel via + * React Query. Dispatches results to the Redux file store as each paragraph + * resolves. Returns a per-filename map of `{ progress, status, abort }`. + * + * Abort uses `queryClient.cancelQueries` so there are no manual AbortController + * references to track or clean up. + */ +export function usePredict( + files: DocFile[], + workflow: Workflows, +): Record { + const dispatch = useFileDispatch(); + const queryClient = useQueryClient(); + const [abortedFiles, setAbortedFiles] = useState>(new Set()); + + // Paragraph IDs whose labels were loaded from DB validation (not from predict). + // Used to gate the disambiguation step. + const fromValidationRef = useRef>(new Set()); + + // Flatten all (file, paragraph) pairs — one React Query entry each + const pairs = files.flatMap((file) => + (file.paragraphs ?? []).map((paragraph) => ({ file, paragraph })), + ); + + const queries = useQueries({ + queries: pairs.map(({ file, paragraph }) => ({ + // Use the factory for the query key and shared defaults (staleTime, retry) + ...predictParagraph(paragraph, workflow, file.data.name), + enabled: !abortedFiles.has(file.data.name), + // Override queryFn to dispatch to Redux as each paragraph arrives. + // Defined inline to avoid TS's `queryFn?: ...` optionality on the factory type. + queryFn: async ({ signal }: { signal?: AbortSignal }) => { + const controller = new AbortController(); + signal?.addEventListener("abort", () => controller.abort()); + await semaphore.acquire(); + try { + if (!controller.signal.aborted) { + // For anonymizer: check stored DB validation before running the model. + // null → no stored validation; fall through to predict + // [] → explicitly validated with no entities; respect the empty state + // [...] → stored manual annotations; restore them + if (workflow === "anonymizer") { + const stored = await getStoredValidation(paragraph, controller); + if (stored !== null) { + console.debug( + `[predict] Restored ${stored.length} labels from DB validation`, + { paragraphId: paragraph.id.slice(0, 60) }, + ); + fromValidationRef.current.add(paragraph.id); + dispatch(addPredictions(file.data.name, stored)); + return stored; + } + console.debug("[predict] No stored validation — running model predict", { + paragraphId: paragraph.id.slice(0, 60), + }); + } + const predictions = await predict(paragraph, controller, workflow); + dispatch(addPredictions(file.data.name, predictions)); + return predictions; + } + return []; + } finally { + semaphore.release(); + } + }, + })), + }); + + // Build per-file { progress, status, abort } from the flat query results + const result: Record = {}; + + for (const file of files) { + const fileName = file.data.name; + const total = (file.paragraphs ?? []).length; + + // Collect only the queries that belong to this file + const fileQueries = pairs.reduce<(typeof queries)[number][]>( + (acc, pair, i) => { + if (pair.file.data.name === fileName) acc.push(queries[i]); + return acc; + }, + [], + ); + + const successCount = fileQueries.filter((q) => q.isSuccess).length; + const errorCount = fileQueries.filter((q) => q.isError).length; + const progress = total > 0 ? successCount / total : 0; + const isAborted = abortedFiles.has(fileName); + + const status: PredictStatus = isAborted + ? "stopped" + : errorCount > 0 + ? "error" + : total === 0 || successCount === total + ? "completed" + : "processing"; + + // A file is "from validation" when every one of its paragraphs returned + // stored annotations from the backend (none went through model predict). + const fromValidation = + workflow === "anonymizer" && + total > 0 && + (file.paragraphs ?? []).every((p) => fromValidationRef.current.has(p.id)); + + result[fileName] = { + progress, + status, + fromValidation, + abort: () => { + // Cancel all in-flight paragraph queries for this file via RQ's own + // cancellation mechanism — no manual controller refs to clean up + queryClient.cancelQueries({ + queryKey: ["predict", workflow, fileName], + exact: false, + }); + dispatch(removePredictions(fileName)); + setAbortedFiles((prev) => new Set([...prev, fileName])); + }, + }; + } + + return result; +} diff --git a/frontend/src/renderer/src/index.css b/frontend/src/renderer/src/index.css new file mode 100644 index 00000000..e27a23b7 --- /dev/null +++ b/frontend/src/renderer/src/index.css @@ -0,0 +1 @@ +@layer reset, base, tokens, recipes, utilities; diff --git a/frontend/src/renderer/src/layout/home.tsx b/frontend/src/renderer/src/layout/home.tsx new file mode 100644 index 00000000..563d8f80 --- /dev/null +++ b/frontend/src/renderer/src/layout/home.tsx @@ -0,0 +1,50 @@ +import BuiltBy from "@/components/brand/built-by"; +import { css } from "@/styled/css"; + +const background = css({ + display: "flex", + + bg: "bg.primary-highlight", + height: "screen", + width: "screen", + + p: "8", +}); + +const inner = css({ + display: "flex", + flexDirection: "column", + alignItems: "center", + + pos: "relative", + + bg: "bg.secondary", + border: "primary", + + width: "full", + height: "full", + + overflowY: "auto", + pb: "8", +}); + +const childrenArea = css({ + flex: "1", + display: "flex", + alignItems: "center", + justifyContent: "center", +}); + +interface HomeLayoutProps { + children?: React.ReactNode; +} +export default function HomeLayout({ children }: HomeLayoutProps) { + return ( +
    +
    +
    {children}
    + +
    +
    + ); +} diff --git a/frontend/src/renderer/src/layout/loading.tsx b/frontend/src/renderer/src/layout/loading.tsx new file mode 100644 index 00000000..1f1a3d39 --- /dev/null +++ b/frontend/src/renderer/src/layout/loading.tsx @@ -0,0 +1,31 @@ +import { css } from "@/styled/css"; +import { stack } from "@/styled/patterns"; + +const background = css( + stack.raw({ + align: "center", + justify: "center", + }), + { + width: "screen", + height: "screen", + + bgGradient: "primary", + }, +); +const image = css({ + animation: "pulse", +}); + +export default function Loading() { + return ( +
    + AymurAI iso white +
    + ); +} diff --git a/frontend/src/renderer/src/layout/section-title.tsx b/frontend/src/renderer/src/layout/section-title.tsx new file mode 100644 index 00000000..26731e61 --- /dev/null +++ b/frontend/src/renderer/src/layout/section-title.tsx @@ -0,0 +1,13 @@ +import { styled } from "@/styled/jsx"; + +interface SectionTitleProps { + children: React.ReactNode; + className?: string; +} +export function SectionTitle({ children, className }: SectionTitleProps) { + return ( + + {children} + + ); +} diff --git a/frontend/src/renderer/src/main.tsx b/frontend/src/renderer/src/main.tsx new file mode 100644 index 00000000..9f8c88be --- /dev/null +++ b/frontend/src/renderer/src/main.tsx @@ -0,0 +1,12 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; + +import "./index.css"; +import "./constants/i18n"; +import App from "./app"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/frontend/src/renderer/src/reducers/file/actions.ts b/frontend/src/renderer/src/reducers/file/actions.ts new file mode 100644 index 00000000..331a2edb --- /dev/null +++ b/frontend/src/renderer/src/reducers/file/actions.ts @@ -0,0 +1,454 @@ +import type { FormData } from "@/hooks/useForm"; +import type { + AllLabels, + AllLabelsWithSufix, + PredictLabel, +} from "@/types/aymurai"; +import type { Paragraph } from "@/types/file"; + +/** + * List of action types. + */ +export enum ActionTypes { + ADD = "ADD", + ADD_PREDICTIONS = "ADD_PREDICTIONS", + ADD_PARAGRAPHS = "ADD_PARAGRAPHS", + FILTER_UNSELECTED = "FILTER_UNSELECTED", + FILTER_UNPROCESSED = "FILTER_UNPROCESSED", + TOGGLE_SELECTED = "TOGGLE_SELECTED", + REMOVE_ALL_PREDICTIONS = "REMOVE_ALL_PREDICTIONS", + REMOVE_PREDICTIONS = "REMOVE_PREDICTIONS", + REMOVE_ALL_FILES = "REMOVE_ALL_FILES", + REMOVE_FILE = "REMOVE_FILE", + REPLACE_FILE = "REPLACE_FILE", + VALIDATE = "VALIDATE", + APPEND_VALIDATION = "APPEND_VALIDATION", + APPEND_PREDICTION = "APPEND_PREDICTION", + REMOVE_PREDICTION = "REMOVE_PREDICTION", + REMOVE_PREDICTIONS_BY_TEXT = "REMOVE_PREDICTIONS_BY_TEXT", + UPDATE_PREDICTION_LABEL = "UPDATE_PREDICTION_LABEL", + UPDATE_PREDICTIONS_BY_TEXT = "UPDATE_PREDICTIONS_BY_TEXT", + REMOVE_PREDICTIONS_BY_CANONICAL_ID = "REMOVE_PREDICTIONS_BY_CANONICAL_ID", + REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID = "REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID", + UPDATE_PREDICTIONS_BY_CANONICAL_ID = "UPDATE_PREDICTIONS_BY_CANONICAL_ID", + MOVE_MENTION_TO_GROUP = "MOVE_MENTION_TO_GROUP", + MERGE_GROUPS = "MERGE_GROUPS", +} + +/** + * Generic action + */ +type Action> = { + type: Type; + payload: Payload; +}; + +export type ToggleSelectedAction = Action< + ActionTypes.TOGGLE_SELECTED, + { fileName: string } +>; +/** + * Toggles the `selected` property of the given file + * @param fileName Name of the file to be toggled + */ +export function toggleSelected(fileName: string): ToggleSelectedAction { + return { + type: ActionTypes.TOGGLE_SELECTED, + payload: { fileName }, + }; +} + +export type RemoveAllPredictionsAction = + Action; +/** + * Removes all the predictions for all the files in the state + */ +export function removeAllPredictions(): RemoveAllPredictionsAction { + return { + type: ActionTypes.REMOVE_ALL_PREDICTIONS, + payload: {}, + }; +} + +export type FilterUnselectedAction = Action; +/** + * Removes files from the state whose `selected` property is set on `false` + */ +export function filterUnselected(): FilterUnselectedAction { + return { + type: ActionTypes.FILTER_UNSELECTED, + payload: {}, + }; +} + +export type AddFilesAction = Action; +/** + * Adds a new set of `File[]` to the end of the state + * @param newFiles `File[]` to be added to the state + */ +export function addFiles(newFiles: File[]): AddFilesAction { + return { + type: ActionTypes.ADD, + payload: { newFiles }, + }; +} + +export type RemoveAllFilesAction = Action; +/** + * Removes all the files from the state + */ +export function removeAllFiles(): RemoveAllFilesAction { + return { + type: ActionTypes.REMOVE_ALL_FILES, + payload: {}, + }; +} + +export type RemoveFileAction = Action< + ActionTypes.REMOVE_FILE, + { fileName: string } +>; +/** + * Removes a single file from the array + */ +export function removeFile(fileName: string): RemoveFileAction { + return { + type: ActionTypes.REMOVE_FILE, + payload: { fileName }, + }; +} + +export type AddPredictionsAction = Action< + ActionTypes.ADD_PREDICTIONS, + { fileName: string; predictions: PredictLabel[] } +>; +/** + * Adds predictions to a specific file + * @param fileName File to be modified + * @param predictions `PredictLabel[]` received from the `/predict` API request + */ +export function addPredictions( + fileName: string, + predictions: PredictLabel[], +): AddPredictionsAction { + return { + type: ActionTypes.ADD_PREDICTIONS, + payload: { fileName, predictions }, + }; +} + +export type RemovePredictionsAction = Action< + ActionTypes.REMOVE_PREDICTIONS, + { fileName: string } +>; +/** + * Removes all the predictions from a given file + */ +export function removePredictions(fileName: string): RemovePredictionsAction { + return { + type: ActionTypes.REMOVE_PREDICTIONS, + payload: { fileName }, + }; +} + +export type ReplaceFileAction = Action< + ActionTypes.REPLACE_FILE, + { fileName: string; file: File } +>; +/** + * Replaces a file data with the given `fileName` + * @param fileName File to be replaced on the state + * @param file File data to be inserted in place of the given `fileName` + */ +export function replaceFile(fileName: string, file: File): ReplaceFileAction { + return { + type: ActionTypes.REPLACE_FILE, + payload: { fileName, file }, + }; +} + +export type ValidateAction = Action; +/** + * Sets the validated status to the given file to `true` + * @param fileName Name of the file to be toggled + */ +export function validate(fileName: string): ValidateAction { + return { + type: ActionTypes.VALIDATE, + payload: { fileName }, + }; +} + +export type AppendValidationAction = Action< + ActionTypes.APPEND_VALIDATION, + { fileName: string; validation: FormData } +>; +/** + * Builds the `validation` progressively + * @param fileName Name of the file to be modified + * @param validation Validation object to be appended + */ +export function appendValidation( + fileName: string, + validation: FormData, +): AppendValidationAction { + return { + type: ActionTypes.APPEND_VALIDATION, + payload: { fileName, validation }, + }; +} + +export type FilterUnprocessedAction = Action; +/** + * Removes files from the state whose `predictions` property is set on `undefined` + */ +export function filterUnprocessed(): FilterUnprocessedAction { + return { + type: ActionTypes.FILTER_UNPROCESSED, + payload: {}, + }; +} + +export type AddParagraphsAction = Action< + ActionTypes.ADD_PARAGRAPHS, + { + paragraphs: Paragraph[]; + fileName: string; + } +>; +/** + * Adds paragraphs to the state from the endpoint `/document-extract` + * @param paragraphs List of paragraphs to be added + * @param fileName Name of the file to be modified + */ +export function addParagraphs( + paragraphs: Paragraph[], + fileName: string, +): AddParagraphsAction { + return { + type: ActionTypes.ADD_PARAGRAPHS, + payload: { paragraphs, fileName }, + }; +} + +export type AppendPrediction = Action< + ActionTypes.APPEND_PREDICTION, + { + prediction: PredictLabel; + fileName: string; + } +>; +/** + * Appends a new user made prediction to the file + * @param prediction User made prediction on the file. Should only be used when anonymizing. + * @param fileName Name of the file to be modified + */ +export function appendPrediction( + fileName: string, + prediction: PredictLabel, +): AppendPrediction { + return { + type: ActionTypes.APPEND_PREDICTION, + payload: { prediction, fileName }, + }; +} + +export type RemovePrediction = Action< + ActionTypes.REMOVE_PREDICTION, + { + prediction: PredictLabel; + fileName: string; + } +>; +/** + * Removes a user made prediction from the file + * @param predictionId ID of the prediction to be removed + * @param fileName Name of the file to be modified + */ +export function removePrediction( + fileName: string, + prediction: PredictLabel, +): RemovePrediction { + return { + type: ActionTypes.REMOVE_PREDICTION, + payload: { prediction, fileName }, + }; +} + +export type RemovePredictionsByText = Action< + ActionTypes.REMOVE_PREDICTIONS_BY_TEXT, + { + text: string; + fileName: string; + } +>; +/** + * Removes all predictions with the same text from the file + * @param text Text of the predictions to be removed + * @param fileName Name of the file to be modified + */ +export function removePredictionsByText( + fileName: string, + text: string, +): RemovePredictionsByText { + return { + type: ActionTypes.REMOVE_PREDICTIONS_BY_TEXT, + payload: { text, fileName }, + }; +} + +export type UpdatePredictionLabel = Action< + ActionTypes.UPDATE_PREDICTION_LABEL, + { + fileName: string; + prediction: PredictLabel; + newLabel: string; + } +>; + +/** + * Updates the label of a prediction in a file + * @param fileName Name of the file containing the prediction + * @param prediction The prediction to update + * @param newLabel The new label to set + */ +export function updatePredictionLabel( + fileName: string, + prediction: PredictLabel, + newLabel: string, +): UpdatePredictionLabel { + return { + type: ActionTypes.UPDATE_PREDICTION_LABEL, + payload: { fileName, prediction, newLabel }, + }; +} + +export type UpdatePredictionsByText = Action< + ActionTypes.UPDATE_PREDICTIONS_BY_TEXT, + { + text: string; + fileName: string; + newLabel: AllLabels | AllLabelsWithSufix; + canonicalId?: string; + } +>; + +/** + * Updates all predictions with the same text to a new label + * @param fileName Name of the file containing the predictions + * @param text Text of the predictions to update + * @param newLabel The new label to set + */ +export function updatePredictionsByText( + fileName: string, + text: string, + newLabel: AllLabels | AllLabelsWithSufix, + canonicalId?: string, +): UpdatePredictionsByText { + return { + type: ActionTypes.UPDATE_PREDICTIONS_BY_TEXT, + payload: { fileName, text, newLabel, canonicalId }, + }; +} + +export type RemovePredictionsByCanonicalId = Action< + ActionTypes.REMOVE_PREDICTIONS_BY_CANONICAL_ID, + { canonicalId: string } +>; +/** + * Removes all predictions across all files that share the given canonical_entity_id + * @param canonicalId The canonical entity id to match + */ +export function removePredictionsByCanonicalId( + canonicalId: string, +): RemovePredictionsByCanonicalId { + return { + type: ActionTypes.REMOVE_PREDICTIONS_BY_CANONICAL_ID, + payload: { canonicalId }, + }; +} + +export type RemovePredictionValueByCanonicalId = Action< + ActionTypes.REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID, + { canonicalId: string; value: string } +>; +/** + * Removes predictions across all files matching the given canonical_entity_id and text value + * @param canonicalId The canonical entity id to match + * @param value The prediction text to remove + */ +export function removePredictionValueByCanonicalId( + canonicalId: string, + value: string, +): RemovePredictionValueByCanonicalId { + return { + type: ActionTypes.REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID, + payload: { canonicalId, value }, + }; +} + +export type UpdatePredictionsByCanonicalId = Action< + ActionTypes.UPDATE_PREDICTIONS_BY_CANONICAL_ID, + { canonicalId: string; newLabel: AllLabels | AllLabelsWithSufix } +>; +/** + * Updates the label of all predictions across all files sharing the given canonical_entity_id + * @param canonicalId The canonical entity id to match + * @param newLabel The new label to set + */ +export function updatePredictionsByCanonicalId( + canonicalId: string, + newLabel: AllLabels | AllLabelsWithSufix, +): UpdatePredictionsByCanonicalId { + return { + type: ActionTypes.UPDATE_PREDICTIONS_BY_CANONICAL_ID, + payload: { canonicalId, newLabel }, + }; +} + +export type MoveMentionToGroupAction = Action< + ActionTypes.MOVE_MENTION_TO_GROUP, + { + mentionId: string; + targetCanonicalId: string; + targetLabel: AllLabels | AllLabelsWithSufix; + } +>; +/** + * Moves a single mention (identified by its stable mentionId) to a different + * canonical entity group, updating both `canonical_entity_id` and `aymurai_label`. + */ +export function moveMentionToGroup( + mentionId: string, + targetCanonicalId: string, + targetLabel: AllLabels | AllLabelsWithSufix, +): MoveMentionToGroupAction { + return { + type: ActionTypes.MOVE_MENTION_TO_GROUP, + payload: { mentionId, targetCanonicalId, targetLabel }, + }; +} + +export type MergeGroupsAction = Action< + ActionTypes.MERGE_GROUPS, + { + sourceCanonicalId: string; + targetCanonicalId: string; + targetLabel: AllLabels | AllLabelsWithSufix; + } +>; +/** + * Moves all mentions from `sourceCanonicalId` into `targetCanonicalId`, + * updating their label to `targetLabel`. The source group disappears naturally + * once it has no more mentions. + */ +export function mergeGroups( + sourceCanonicalId: string, + targetCanonicalId: string, + targetLabel: AllLabels | AllLabelsWithSufix, +): MergeGroupsAction { + return { + type: ActionTypes.MERGE_GROUPS, + payload: { sourceCanonicalId, targetCanonicalId, targetLabel }, + }; +} diff --git a/frontend/src/renderer/src/reducers/file/index.ts b/frontend/src/renderer/src/reducers/file/index.ts new file mode 100644 index 00000000..d92c80bb --- /dev/null +++ b/frontend/src/renderer/src/reducers/file/index.ts @@ -0,0 +1,415 @@ +import { + ActionTypes, + type AddFilesAction, + type AddParagraphsAction, + type AddPredictionsAction, + type AppendPrediction, + type AppendValidationAction, + type FilterUnprocessedAction, + type FilterUnselectedAction, + type MergeGroupsAction, + type MoveMentionToGroupAction, + type RemoveAllFilesAction, + type RemoveAllPredictionsAction, + type RemoveFileAction, + type RemovePrediction, + type RemovePredictionValueByCanonicalId, + type RemovePredictionsAction, + type RemovePredictionsByCanonicalId, + type RemovePredictionsByText, + type ReplaceFileAction, + type ToggleSelectedAction, + type UpdatePredictionLabel, + type UpdatePredictionsByCanonicalId, + type UpdatePredictionsByText, + type ValidateAction, +} from "./actions"; +import { + addFiles, + comparePrediction, + replaceFile, + updateFromState, +} from "./utils"; + +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; +import type { DocFile } from "@/types/file"; +import { + normalizeEntityText, + stripEntityLabelSuffix, +} from "@/utils/anonymizer/entity-similarity"; + +type State = DocFile[]; + +export type Action = + | AddFilesAction + | AddPredictionsAction + | ToggleSelectedAction + | RemoveAllPredictionsAction + | RemoveAllFilesAction + | RemoveFileAction + | RemovePredictionsAction + | ReplaceFileAction + | FilterUnselectedAction + | ValidateAction + | AppendValidationAction + | FilterUnprocessedAction + | AddParagraphsAction + | AppendPrediction + | RemovePrediction + | RemovePredictionsByText + | UpdatePredictionLabel + | UpdatePredictionsByText + | RemovePredictionsByCanonicalId + | RemovePredictionValueByCanonicalId + | UpdatePredictionsByCanonicalId + | MoveMentionToGroupAction + | MergeGroupsAction; + +/** + * Reducer function for `DocFile[]` state + * @param state Current state + * @param action Action to perform + * @returns A new state + */ +export default function reducer(state: State, action: Action): State { + const { type, payload } = action; + + // Update/replace/delete utility function + const update = updateFromState(state); + + switch (type) { + // ---------------- + // ADD + // ---------------- + case ActionTypes.ADD: { + const { newFiles } = payload; + + // Performs some checkings on the file + return addFiles(newFiles, state); + } + // ---------------- + // ADD PREDICTIONS + // ---------------- + case ActionTypes.ADD_PREDICTIONS: { + const { fileName, predictions } = payload; + + return update(fileName, (current) => ({ + ...current, + // Appends the predictions to the already created array + predictions: [...(current.predictions ?? []), ...predictions], + })); + } + // ---------------- + // TOGGLE SELECTED + // ---------------- + case ActionTypes.TOGGLE_SELECTED: { + const { fileName } = payload; + + return update(fileName, (current) => ({ + ...current, + selected: !current.selected, + })); + } + // ---------------- + // REMOVE ALL PREDICTIONS + // ---------------- + case ActionTypes.REMOVE_ALL_PREDICTIONS: { + return state.map((file) => ({ ...file, predictions: undefined })); + } + // ---------------- + // REMOVE PREDICTIONS + // ---------------- + case ActionTypes.REMOVE_PREDICTIONS: { + const { fileName } = payload; + + return update(fileName, (current) => ({ + ...current, + predictions: undefined, + })); + } + // ---------------- + // REMOVE ALL FILES + // ---------------- + case ActionTypes.REMOVE_ALL_FILES: { + return []; + } + case ActionTypes.REMOVE_FILE: { + const { fileName } = payload; + + return state.filter((file) => file.data.name !== fileName); + } + // ---------------- + // REPLACE FILE + // ---------------- + case ActionTypes.REPLACE_FILE: { + const { fileName, file } = payload; + return replaceFile(fileName, file, state); + } + // ---------------- + // FILTER UNSELECTED + // ---------------- + case ActionTypes.FILTER_UNSELECTED: { + return state.filter((file) => file.selected); + } + + // ---------------- + // FILTER UNSELECTED + // ---------------- + case ActionTypes.FILTER_UNPROCESSED: { + return state.filter((file) => file.predictions); + } + // ---------------- + // VALIDATE + // ---------------- + case ActionTypes.VALIDATE: { + const { fileName } = payload; + return update(fileName, (cur) => ({ ...cur, validated: true })); + } + // ---------------- + // APPEND VALIDATION + // ---------------- + case ActionTypes.APPEND_VALIDATION: { + const { fileName, validation } = payload; + + return update(fileName, (cur) => ({ + ...cur, + // Append to the already created object + validationObject: { ...cur.validationObject, ...validation }, + })); + } + + // ---------------- + // ADD PARAGRAPHS + // ---------------- + case ActionTypes.ADD_PARAGRAPHS: { + const { fileName, paragraphs } = payload; + + return update(fileName, (cur) => ({ + ...cur, + paragraphs: paragraphs, + })); + } + + // ---------------- + // APPEND PREDICTION + // ---------------- + case ActionTypes.APPEND_PREDICTION: { + const { fileName, prediction } = payload; + + return update(fileName, (cur) => ({ + ...cur, + predictions: [...(cur.predictions ?? []), prediction], + })); + } + + // ---------------- + // REMOVE PREDICTION + // ---------------- + case ActionTypes.REMOVE_PREDICTION: { + const { fileName, prediction } = payload; + + return update(fileName, (cur) => ({ + ...cur, + predictions: cur.predictions?.filter( + (p) => !comparePrediction(prediction, p), + ), + })); + } + + // ---------------- + // REMOVE PREDICTIONS BY TEXT + // ---------------- + case ActionTypes.REMOVE_PREDICTIONS_BY_TEXT: { + const { fileName, text } = payload; + const normalizedText = normalizeEntityText(text); + + return update(fileName, (cur) => ({ + ...cur, + predictions: cur.predictions?.filter( + (p) => normalizeEntityText(p.text) !== normalizedText, + ), + })); + } + + // ---------------- + // UPDATE PREDICTION LABEL + // ---------------- + case ActionTypes.UPDATE_PREDICTION_LABEL: { + const { fileName, prediction, newLabel } = action.payload; + return state.map((file) => { + if (file.data.name !== fileName) return file; + + return { + ...file, + predictions: file.predictions?.map((p) => { + const isSamePrediction = prediction.mentionId + ? p.mentionId === prediction.mentionId + : p.paragraphId === prediction.paragraphId && + p.text === prediction.text && + p.start_char === prediction.start_char && + p.end_char === prediction.end_char; + + if (isSamePrediction) { + const currentBaseLabel = stripEntityLabelSuffix( + String(p.attrs.aymurai_label), + ); + const nextBaseLabel = stripEntityLabelSuffix(String(newLabel)); + const canonicalPatch = + currentBaseLabel === nextBaseLabel + ? {} + : { canonical_entity_id: crypto.randomUUID() }; + + return { + ...p, + attrs: { + ...p.attrs, + aymurai_label: newLabel as AllLabels | AllLabelsWithSufix, + ...canonicalPatch, + }, + }; + } + return p; + }), + }; + }); + } + + // ---------------- + // UPDATE PREDICTIONS BY TEXT + // ---------------- + case ActionTypes.UPDATE_PREDICTIONS_BY_TEXT: { + const { fileName, text, newLabel, canonicalId } = action.payload; + const normalizedText = normalizeEntityText(text); + const fallbackCanonicalId = crypto.randomUUID(); + const nextBaseLabel = stripEntityLabelSuffix(String(newLabel)); + + return state.map((file) => { + if (file.data.name !== fileName) return file; + + return { + ...file, + predictions: file.predictions?.map((p) => { + if (normalizeEntityText(p.text) === normalizedText) { + const currentBaseLabel = stripEntityLabelSuffix( + String(p.attrs.aymurai_label), + ); + const canonicalPatch = + canonicalId !== undefined + ? { canonical_entity_id: canonicalId } + : currentBaseLabel === nextBaseLabel + ? {} + : { canonical_entity_id: fallbackCanonicalId }; + + return { + ...p, + attrs: { + ...p.attrs, + aymurai_label: newLabel, + ...canonicalPatch, + }, + }; + } + return p; + }), + }; + }); + } + + // ---------------------------------------- + // REMOVE PREDICTIONS BY CANONICAL ID + // ---------------------------------------- + case ActionTypes.REMOVE_PREDICTIONS_BY_CANONICAL_ID: { + const { canonicalId } = action.payload; + return state.map((file) => ({ + ...file, + predictions: file.predictions?.filter( + (p) => p.attrs.canonical_entity_id !== canonicalId, + ), + })); + } + + // ------------------------------------------------ + // REMOVE PREDICTION VALUE BY CANONICAL ID + // ------------------------------------------------ + case ActionTypes.REMOVE_PREDICTION_VALUE_BY_CANONICAL_ID: { + const { canonicalId, value } = action.payload; + const norm = normalizeEntityText(value); + return state.map((file) => ({ + ...file, + predictions: file.predictions?.filter( + (p) => + !( + p.attrs.canonical_entity_id === canonicalId && + normalizeEntityText(p.text) === norm + ), + ), + })); + } + + // ---------------------------------------- + // UPDATE PREDICTIONS BY CANONICAL ID + // ---------------------------------------- + case ActionTypes.UPDATE_PREDICTIONS_BY_CANONICAL_ID: { + const { canonicalId, newLabel } = action.payload; + return state.map((file) => ({ + ...file, + predictions: file.predictions?.map((p) => + p.attrs.canonical_entity_id === canonicalId + ? { ...p, attrs: { ...p.attrs, aymurai_label: newLabel } } + : p, + ), + })); + } + + // ---------------------------------------- + // MOVE MENTION TO GROUP + // ---------------------------------------- + case ActionTypes.MOVE_MENTION_TO_GROUP: { + const { mentionId, targetCanonicalId, targetLabel } = action.payload; + return state.map((file) => ({ + ...file, + predictions: file.predictions?.map((p) => + p.mentionId === mentionId + ? { + ...p, + attrs: { + ...p.attrs, + canonical_entity_id: targetCanonicalId, + aymurai_label: targetLabel, + }, + } + : p, + ), + })); + } + + // ---------------------------------------- + // MERGE GROUPS + // ---------------------------------------- + case ActionTypes.MERGE_GROUPS: { + const { sourceCanonicalId, targetCanonicalId, targetLabel } = + action.payload; + return state.map((file) => ({ + ...file, + predictions: file.predictions?.map((p) => + p.attrs.canonical_entity_id === sourceCanonicalId + ? { + ...p, + attrs: { + ...p.attrs, + canonical_entity_id: targetCanonicalId, + aymurai_label: targetLabel, + }, + } + : p, + ), + })); + } + + // ---------------- + // ADD PARAGRAPHS + // ---------------- + default: + return state; + } +} diff --git a/frontend/src/renderer/src/reducers/file/utils.ts b/frontend/src/renderer/src/reducers/file/utils.ts new file mode 100644 index 00000000..22d7e6b0 --- /dev/null +++ b/frontend/src/renderer/src/reducers/file/utils.ts @@ -0,0 +1,101 @@ +import type { PredictLabel } from "@/types/aymurai"; +import type { DocFile } from "@/types/file"; +import { isAllowed, isAlreadyLoaded } from "@/utils/file"; + +/** + * Util function used along with `filter()` array function to mantain the types + * @param file File to check + * @returns `true` if the file is defined, `false` otherwise + */ +function removeUndefined(file: DocFile | undefined): file is DocFile { + return !!file; +} + +type ModifyFunction = (file: DocFile) => DocFile | undefined; +/** + * Updates/replaces/deletes a file content in the array. The function was created + * in a way that is not necessary to pass the `state` on every call. + * @param state Current `DocFile[]` state + * @param fileName Identifier of the file to replace + * @param modify Modify function that alters the content of the affected `DocFile` + * @returns A new function which accepts as parameters `fileName` and `modify` + */ +export function updateFromState(state: DocFile[]) { + return (fileName: string, modify: ModifyFunction) => { + // Modify/update the desired file + const newState = state.map((file) => { + if (file.data.name === fileName) return modify(file); + return file; + }); + + // Remove any `undefined` value inserted into the array + // This way we can remove a file from the array more easely + const filtered: DocFile[] = newState.filter(removeUndefined); + + return filtered; + }; +} + +/** + * Adds an array of `File` to the current files state + * @param files Files to be added + * @param state Current files state + * @returns A new state with the files added + */ +export function addFiles(files: File[], state: DocFile[]) { + // Check for whitelisted extensions and already loaded files + const filtered = files.filter( + (file) => isAllowed(file) && !isAlreadyLoaded(file.name, state), + ); + + // Add necessary fields to the object + const newFiles: DocFile[] = filtered.map((file) => ({ + data: file, + selected: true, + validationObject: {}, + })); + + return [...state, ...newFiles]; +} + +/** + * Replaces a file by the given name on the files state + * @param fileName Name of the file to be replaced + * @param newFile File to be inserted into the state + * @param state Current files state + * @returns A new array containing the file replaced + */ +export function replaceFile(fileName: string, newFile: File, state: DocFile[]) { + if (isAllowed(newFile) && !isAlreadyLoaded(newFile.name, state)) { + const replaced = state.map((file) => + file.data.name === fileName + ? { + data: newFile, + selected: true, + predictions: undefined, + validationObject: {}, + } + : file, + ); + return replaced; + } + return state; +} + +/** + * Compares two predictions to check if they are equal + * @param a First prediction to compare + * @param b Second prediction to compare + * @returns `true` if the predictions are equal, `false` otherwise. + */ +export function comparePrediction(a: PredictLabel, b: PredictLabel) { + if (a.mentionId && b.mentionId) return a.mentionId === b.mentionId; + + return ( + a.paragraphId === b.paragraphId && + a.start_char === b.start_char && + a.end_char === b.end_char && + a.text === b.text && + a.attrs.aymurai_label === b.attrs.aymurai_label + ); +} diff --git a/frontend/src/renderer/src/routeTree.gen.ts b/frontend/src/renderer/src/routeTree.gen.ts new file mode 100644 index 00000000..18dad6e9 --- /dev/null +++ b/frontend/src/renderer/src/routeTree.gen.ts @@ -0,0 +1,231 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Route as rootRouteImport } from './routes/__root' +import { Route as IndexRouteImport } from './routes/index' +import { Route as HomeIndexRouteImport } from './routes/home/index' +import { Route as HomeHostRouteImport } from './routes/home/host' +import { Route as HomeFeaturesRouteImport } from './routes/home/features' +import { Route as FeatureValidationRouteImport } from './routes/$feature/validation' +import { Route as FeatureProcessRouteImport } from './routes/$feature/process' +import { Route as FeaturePreviewRouteImport } from './routes/$feature/preview' +import { Route as FeatureOnboardingRouteImport } from './routes/$feature/onboarding' +import { Route as FeatureFinishRouteImport } from './routes/$feature/finish' + +const IndexRoute = IndexRouteImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRouteImport, +} as any) +const HomeIndexRoute = HomeIndexRouteImport.update({ + id: '/home/', + path: '/home/', + getParentRoute: () => rootRouteImport, +} as any) +const HomeHostRoute = HomeHostRouteImport.update({ + id: '/home/host', + path: '/home/host', + getParentRoute: () => rootRouteImport, +} as any) +const HomeFeaturesRoute = HomeFeaturesRouteImport.update({ + id: '/home/features', + path: '/home/features', + getParentRoute: () => rootRouteImport, +} as any) +const FeatureValidationRoute = FeatureValidationRouteImport.update({ + id: '/$feature/validation', + path: '/$feature/validation', + getParentRoute: () => rootRouteImport, +} as any) +const FeatureProcessRoute = FeatureProcessRouteImport.update({ + id: '/$feature/process', + path: '/$feature/process', + getParentRoute: () => rootRouteImport, +} as any) +const FeaturePreviewRoute = FeaturePreviewRouteImport.update({ + id: '/$feature/preview', + path: '/$feature/preview', + getParentRoute: () => rootRouteImport, +} as any) +const FeatureOnboardingRoute = FeatureOnboardingRouteImport.update({ + id: '/$feature/onboarding', + path: '/$feature/onboarding', + getParentRoute: () => rootRouteImport, +} as any) +const FeatureFinishRoute = FeatureFinishRouteImport.update({ + id: '/$feature/finish', + path: '/$feature/finish', + getParentRoute: () => rootRouteImport, +} as any) + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute + '/$feature/finish': typeof FeatureFinishRoute + '/$feature/onboarding': typeof FeatureOnboardingRoute + '/$feature/preview': typeof FeaturePreviewRoute + '/$feature/process': typeof FeatureProcessRoute + '/$feature/validation': typeof FeatureValidationRoute + '/home/features': typeof HomeFeaturesRoute + '/home/host': typeof HomeHostRoute + '/home': typeof HomeIndexRoute +} +export interface FileRoutesByTo { + '/': typeof IndexRoute + '/$feature/finish': typeof FeatureFinishRoute + '/$feature/onboarding': typeof FeatureOnboardingRoute + '/$feature/preview': typeof FeaturePreviewRoute + '/$feature/process': typeof FeatureProcessRoute + '/$feature/validation': typeof FeatureValidationRoute + '/home/features': typeof HomeFeaturesRoute + '/home/host': typeof HomeHostRoute + '/home': typeof HomeIndexRoute +} +export interface FileRoutesById { + __root__: typeof rootRouteImport + '/': typeof IndexRoute + '/$feature/finish': typeof FeatureFinishRoute + '/$feature/onboarding': typeof FeatureOnboardingRoute + '/$feature/preview': typeof FeaturePreviewRoute + '/$feature/process': typeof FeatureProcessRoute + '/$feature/validation': typeof FeatureValidationRoute + '/home/features': typeof HomeFeaturesRoute + '/home/host': typeof HomeHostRoute + '/home/': typeof HomeIndexRoute +} +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: + | '/' + | '/$feature/finish' + | '/$feature/onboarding' + | '/$feature/preview' + | '/$feature/process' + | '/$feature/validation' + | '/home/features' + | '/home/host' + | '/home' + fileRoutesByTo: FileRoutesByTo + to: + | '/' + | '/$feature/finish' + | '/$feature/onboarding' + | '/$feature/preview' + | '/$feature/process' + | '/$feature/validation' + | '/home/features' + | '/home/host' + | '/home' + id: + | '__root__' + | '/' + | '/$feature/finish' + | '/$feature/onboarding' + | '/$feature/preview' + | '/$feature/process' + | '/$feature/validation' + | '/home/features' + | '/home/host' + | '/home/' + fileRoutesById: FileRoutesById +} +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute + FeatureFinishRoute: typeof FeatureFinishRoute + FeatureOnboardingRoute: typeof FeatureOnboardingRoute + FeaturePreviewRoute: typeof FeaturePreviewRoute + FeatureProcessRoute: typeof FeatureProcessRoute + FeatureValidationRoute: typeof FeatureValidationRoute + HomeFeaturesRoute: typeof HomeFeaturesRoute + HomeHostRoute: typeof HomeHostRoute + HomeIndexRoute: typeof HomeIndexRoute +} + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexRouteImport + parentRoute: typeof rootRouteImport + } + '/home/': { + id: '/home/' + path: '/home' + fullPath: '/home' + preLoaderRoute: typeof HomeIndexRouteImport + parentRoute: typeof rootRouteImport + } + '/home/host': { + id: '/home/host' + path: '/home/host' + fullPath: '/home/host' + preLoaderRoute: typeof HomeHostRouteImport + parentRoute: typeof rootRouteImport + } + '/home/features': { + id: '/home/features' + path: '/home/features' + fullPath: '/home/features' + preLoaderRoute: typeof HomeFeaturesRouteImport + parentRoute: typeof rootRouteImport + } + '/$feature/validation': { + id: '/$feature/validation' + path: '/$feature/validation' + fullPath: '/$feature/validation' + preLoaderRoute: typeof FeatureValidationRouteImport + parentRoute: typeof rootRouteImport + } + '/$feature/process': { + id: '/$feature/process' + path: '/$feature/process' + fullPath: '/$feature/process' + preLoaderRoute: typeof FeatureProcessRouteImport + parentRoute: typeof rootRouteImport + } + '/$feature/preview': { + id: '/$feature/preview' + path: '/$feature/preview' + fullPath: '/$feature/preview' + preLoaderRoute: typeof FeaturePreviewRouteImport + parentRoute: typeof rootRouteImport + } + '/$feature/onboarding': { + id: '/$feature/onboarding' + path: '/$feature/onboarding' + fullPath: '/$feature/onboarding' + preLoaderRoute: typeof FeatureOnboardingRouteImport + parentRoute: typeof rootRouteImport + } + '/$feature/finish': { + id: '/$feature/finish' + path: '/$feature/finish' + fullPath: '/$feature/finish' + preLoaderRoute: typeof FeatureFinishRouteImport + parentRoute: typeof rootRouteImport + } + } +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, + FeatureFinishRoute: FeatureFinishRoute, + FeatureOnboardingRoute: FeatureOnboardingRoute, + FeaturePreviewRoute: FeaturePreviewRoute, + FeatureProcessRoute: FeatureProcessRoute, + FeatureValidationRoute: FeatureValidationRoute, + HomeFeaturesRoute: HomeFeaturesRoute, + HomeHostRoute: HomeHostRoute, + HomeIndexRoute: HomeIndexRoute, +} +export const routeTree = rootRouteImport + ._addFileChildren(rootRouteChildren) + ._addFileTypes() diff --git a/frontend/src/renderer/src/routes/$feature/finish.tsx b/frontend/src/renderer/src/routes/$feature/finish.tsx new file mode 100644 index 00000000..a79380e4 --- /dev/null +++ b/frontend/src/renderer/src/routes/$feature/finish.tsx @@ -0,0 +1,59 @@ +import FinishAnonymizer from "@/components/finish/finish-anonymizer"; +import FinishDataset from "@/components/finish/finish-dataset"; +import Stepper from "@/components/home/stepper"; +import Header from "@/components/layout/header"; +import HomeButton from "@/components/layout/home-button"; +import RequireFile from "@/features/RequireFile"; +import { useFileDispatch } from "@/hooks"; +import { Stack } from "@/styled/jsx"; +import { removeAllFiles } from "@/reducers/file/actions"; +import { FeatureFlowEnum, featureNamespace, getFeatureRouteSlug, parseFeatureRouteSlug } from "@/types/features"; +import { + Navigate, + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; + +export const Route = createFileRoute("/$feature/finish")({ + component: RouteComponent, +}); + +function RouteComponent() { + const navigate = useNavigate(); + const { feature: featureSlug } = useParams({ from: "/$feature/finish" }); + const feature = parseFeatureRouteSlug(featureSlug); + + if (!feature) return ; + + const { t } = useTranslation(featureNamespace[feature]); + const dispatch = useFileDispatch(); + + const handleRestart = () => { + dispatch(removeAllFiles()); + navigate({ to: "/$feature/onboarding", params: { feature: getFeatureRouteSlug(feature) } }); + }; + + return ( + + +
    + ) : undefined + } + right={} + /> + + {feature === FeatureFlowEnum.Dataset ? ( + + ) : ( + + )} + + + ); +} diff --git a/frontend/src/renderer/src/routes/$feature/onboarding.tsx b/frontend/src/renderer/src/routes/$feature/onboarding.tsx new file mode 100644 index 00000000..3f6e76f8 --- /dev/null +++ b/frontend/src/renderer/src/routes/$feature/onboarding.tsx @@ -0,0 +1,120 @@ +import { + Navigate, + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; + +import DropArea from "@/components/drop-area"; +import HiddenInput from "@/components/hidden-input"; +import HowItWorks from "@/components/how-it-works"; +import Footer from "@/components/layout/footer"; +import Header from "@/components/layout/header"; +import HomeButton from "@/components/layout/home-button"; +import MainContent from "@/components/layout/main-content"; +import BackButton from "@/components/ui/back-button"; +import Button from "@/components/ui/button"; +import { useFileDispatch } from "@/hooks"; +import { SectionTitle } from "@/layout/section-title"; +import { addFiles, removeAllFiles } from "@/reducers/file/actions"; +import { useSetTutorialSeen, useTutorialSeen } from "@/store/useLocal"; +import { HStack, Stack, styled } from "@/styled/jsx"; +import { + FeatureFlowEnum, + featureNamespace, + getFeatureRouteSlug, + parseFeatureRouteSlug, +} from "@/types/features"; +import { filesForFeatureLoad } from "@/utils/file/preview-files"; +import { useQueryClient } from "@tanstack/react-query"; +import { useEffect, useRef } from "react"; +import { flushSync } from "react-dom"; +import { useTranslation } from "react-i18next"; + +// FIRST step of the processing workflow +export const Route = createFileRoute("/$feature/onboarding")({ + component: RouteComponent, +}); + +function RouteComponent() { + const queryClient = useQueryClient(); + const { feature: featureSlug } = useParams({ + from: "/$feature/onboarding", + }); + const feature = parseFeatureRouteSlug(featureSlug); + const navigate = useNavigate(); + + if (!feature) return ; + + const { t } = useTranslation(featureNamespace[feature]); + + const inputRef = useRef(null); + + const dispatch = useFileDispatch(); + const tutorialSeen = useTutorialSeen(feature); + const toggleTutorialSeen = useSetTutorialSeen(); + + const handleAddFiles = async (files: File[]) => { + const filesToAdd = filesForFeatureLoad(feature, files); + flushSync(() => { + if (feature === FeatureFlowEnum.Anonymizer) dispatch(removeAllFiles()); + dispatch(addFiles(filesToAdd)); + }); + await navigate({ + to: "/$feature/preview", + params: { feature: getFeatureRouteSlug(feature) }, + }); + toggleTutorialSeen(feature); + }; + + const handleInputChange: React.ChangeEventHandler = (e) => { + const rawFiles = e.target.files; + if (rawFiles) handleAddFiles(Array.from(rawFiles)); + }; + + const handleOpenInput = () => { + inputRef.current?.click(); + }; + + useEffect(() => { + queryClient.removeQueries({ queryKey: ["predict"] }); + queryClient.removeQueries({ queryKey: ["file-parser"] }); + }, [queryClient]); + + return ( + +
    } /> + + {tutorialSeen ? ( + + + + {t("onboarding.sectionTitle")} + + + + ) : ( + + )} + +
    + + {!tutorialSeen && ( + + {t("onboarding.validFormats")} + + )} + + +
    + + + ); +} diff --git a/frontend/src/renderer/src/routes/$feature/preview.tsx b/frontend/src/renderer/src/routes/$feature/preview.tsx new file mode 100644 index 00000000..0c924e87 --- /dev/null +++ b/frontend/src/renderer/src/routes/$feature/preview.tsx @@ -0,0 +1,134 @@ +import { Button, FilePreview } from "@/components"; +import HiddenInput from "@/components/hidden-input"; +import Stepper from "@/components/home/stepper"; +import Footer from "@/components/layout/footer"; +import Header from "@/components/layout/header"; +import HomeButton from "@/components/layout/home-button"; +import MainContent from "@/components/layout/main-content"; +import BackButton from "@/components/ui/back-button"; +import Card from "@/components/ui/card"; +import RequireFile from "@/features/RequireFile"; +import { useFileDispatch, useFiles } from "@/hooks"; +import { useFileParse } from "@/hooks/useFileParse"; +import { SectionTitle } from "@/layout/section-title"; +import { addFiles, filterUnselected } from "@/reducers/file/actions"; +import { css } from "@/styled/css"; +import { Grid, HStack, Stack, styled } from "@/styled/jsx"; +import { FeatureFlowEnum, featureNamespace, getFeatureRouteSlug, parseFeatureRouteSlug } from "@/types/features"; +import { + Navigate, + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; +import { useRef } from "react"; +import { useTranslation } from "react-i18next"; + +export const Route = createFileRoute("/$feature/preview")({ + component: RouteComponent, +}); + +function RouteComponent() { + const { feature: featureSlug } = useParams({ + from: "/$feature/preview", + }); + const feature = parseFeatureRouteSlug(featureSlug); + const navigate = useNavigate(); + + if (!feature) return ; + + const { t } = useTranslation(featureNamespace[feature]); + + const inputRef = useRef(null); + + const files = useFiles(); + const dispatch = useFileDispatch(); + const parseStatuses = useFileParse(files); + + const isProcessing = files.some((file) => !file.paragraphs); + + const handleAddFiles: React.ChangeEventHandler = async ( + e, + ) => { + const rawFiles = e.target.files; + if (rawFiles) { + dispatch(addFiles([...rawFiles])); + await navigate({ + to: "/$feature/preview", + params: { feature: getFeatureRouteSlug(feature) }, + }); + } + }; + const handleOpenInput = () => { + inputRef.current?.click(); + }; + + const handleConfirmFiles = () => { + dispatch(filterUnselected()); + navigate({ + to: "/$feature/process", + params: { feature: getFeatureRouteSlug(feature) }, + }); + }; + + return ( + + +
    } + feature={feature} + right={} + /> + + + + + {t("preview.sectionTitle")} + + + + + {t("preview.filesLabel")} + + + {files.map((file) => ( + + ))} + + + + + +
    + + {feature === FeatureFlowEnum.Dataset && ( + <> + + {t("preview.validFormats")} + + + + )} + + +
    + + + + ); +} diff --git a/frontend/src/renderer/src/routes/$feature/process.tsx b/frontend/src/renderer/src/routes/$feature/process.tsx new file mode 100644 index 00000000..f573137b --- /dev/null +++ b/frontend/src/renderer/src/routes/$feature/process.tsx @@ -0,0 +1,179 @@ +import { Button, FileProcessing } from "@/components"; +import Stepper from "@/components/home/stepper"; +import Footer from "@/components/layout/footer"; +import Header from "@/components/layout/header"; +import HomeButton from "@/components/layout/home-button"; +import MainContent from "@/components/layout/main-content"; +import BackButton from "@/components/ui/back-button"; +import Callout from "@/components/ui/callout"; +import Card from "@/components/ui/card"; +import RequireFile from "@/features/RequireFile"; +import { useFileDispatch, useFiles } from "@/hooks"; +import { useDisambiguate } from "@/hooks/useDisambiguate"; +import { useFileParse } from "@/hooks/useFileParse"; +import { type PredictStatus, usePredict } from "@/hooks/usePredict"; +import { SectionTitle } from "@/layout/section-title"; +import { filterUnprocessed } from "@/reducers/file/actions"; +import taskbar from "@/services/taskbar"; +import { css } from "@/styled/css"; +import { HStack, Stack, styled } from "@/styled/jsx"; +import type { Workflows } from "@/types/aymurai"; +import { FeatureFlowEnum, featureNamespace, getFeatureRouteSlug, parseFeatureRouteSlug } from "@/types/features"; +import type { DocFile } from "@/types/file"; +import { useQueryClient } from "@tanstack/react-query"; +import { + Navigate, + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; +import { useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; + +export const Route = createFileRoute("/$feature/process")({ + component: RouteComponent, +}); + +function RouteComponent() { + const queryClient = useQueryClient(); + const { feature: featureSlug } = useParams({ + from: "/$feature/process", + }); + const feature = parseFeatureRouteSlug(featureSlug); + if (!feature) return ; + + const { t } = useTranslation(featureNamespace[feature]); + + const dispatch = useFileDispatch(); + const navigate = useNavigate(); + const files = useFiles(); + + const [isDismissed, setIsDismissed] = useState(false); + const hasNotified = useRef(false); + + const workflow: Workflows = + feature === FeatureFlowEnum.Anonymizer ? "anonymizer" : "datapublic"; + const parseStatuses = useFileParse(files); + const fileStatuses = usePredict(files, workflow); + const disambiguateStatuses = useDisambiguate( + files, + fileStatuses, + workflow === "anonymizer", + ); + + const handleNext = () => { + dispatch(filterUnprocessed()); + navigate({ + to: "/$feature/validation", + params: { feature: getFeatureRouteSlug(feature) }, + }); + }; + + const isProcessing = files.some( + (f) => + parseStatuses[f.data.name]?.status === "processing" || + fileStatuses[f.data.name]?.status === "processing" || + disambiguateStatuses[f.data.name]?.status === "processing", + ); + + useEffect(() => { + if (files.length > 0 && !isProcessing && !hasNotified.current) { + hasNotified.current = true; + taskbar.notify(); + } + }, [isProcessing, files.length]); + + // Weighted progress: 10% parse / 70% predict / 20% disambiguate (anonymizer) + // or 10% parse / 90% predict (datapublic). + const getProgress = (fileName: string): number => { + const parseDone = parseStatuses[fileName]?.status === "completed" ? 1 : 0; + const predictProgress = fileStatuses[fileName]?.progress ?? 0; + + if (workflow !== "anonymizer") { + return parseDone * 0.1 + predictProgress * 0.9; + } + const disambiguateDone = + disambiguateStatuses[fileName]?.status === "completed" ? 1 : 0; + return parseDone * 0.1 + predictProgress * 0.7 + disambiguateDone * 0.2; + }; + + // Status accounts for all three stages so "completed" only shows at 100%. + const getCombinedStatus = (fileName: string): PredictStatus => { + const parseStatus = parseStatuses[fileName]?.status ?? "processing"; + if (parseStatus !== "completed") return parseStatus; + + const predictStatus = fileStatuses[fileName]?.status ?? "processing"; + if (workflow !== "anonymizer" || predictStatus !== "completed") + return predictStatus; + + return disambiguateStatuses[fileName]?.status ?? "processing"; + }; + + const handleAbort = (file: DocFile) => () => { + queryClient.removeQueries({ + queryKey: ["file-parser", file.data.name], + exact: false, + }); + queryClient.removeQueries({ + queryKey: ["predict", feature, file.data.name], + exact: false, + }); + fileStatuses[file.data.name]?.abort?.(); + parseStatuses[file.data.name]?.abort?.(); + }; + + return ( + + +
    } + right={} + /> + + + + + {t("process.sectionTitle")} + + + + + + {t("process.processingTitle")} + + + {t("process.processingSubtitle")} + + + {!isProcessing && !isDismissed && ( + setIsDismissed(true)} + /> + )} + {files.map((f) => ( + + ))} + + + + +
    + +
    + + + ); +} diff --git a/frontend/src/renderer/src/routes/$feature/validation.tsx b/frontend/src/renderer/src/routes/$feature/validation.tsx new file mode 100644 index 00000000..9d2fd963 --- /dev/null +++ b/frontend/src/renderer/src/routes/$feature/validation.tsx @@ -0,0 +1,79 @@ +import { Button, FileAnnotator, ValidateDataset } from "@/components"; +import Stepper from "@/components/home/stepper"; +import Footer from "@/components/layout/footer"; +import Header from "@/components/layout/header"; +import HomeButton from "@/components/layout/home-button"; +import RequireFile from "@/features/RequireFile"; +import { useFiles } from "@/hooks"; +import { Grid, Stack } from "@/styled/jsx"; +import { FeatureFlowEnum, featureNamespace, getFeatureRouteSlug, parseFeatureRouteSlug } from "@/types/features"; +import { + Navigate, + createFileRoute, + useNavigate, + useParams, +} from "@tanstack/react-router"; +import { useTranslation } from "react-i18next"; + +export const Route = createFileRoute("/$feature/validation")({ + component: RouteComponent, +}); + +function RouteComponent() { + const { feature: featureSlug } = useParams({ + from: "/$feature/validation", + }); + const feature = parseFeatureRouteSlug(featureSlug); + + const navigate = useNavigate(); + + if (!feature) return ; + + const { t } = useTranslation(featureNamespace[feature]); + + const file = useFiles()[0]!; + + const handleContinue = () => + navigate({ to: "/$feature/finish", params: { feature: getFeatureRouteSlug(feature) } }); + + if (feature === FeatureFlowEnum.Anonymizer) + return ( + + +
    } + feature={feature} + right={} + /> + + + + +
    + +
    + + + ); + return ( + + +
    } + feature={feature} + /> + + + + ); +} diff --git a/frontend/src/renderer/src/routes/__root.tsx b/frontend/src/renderer/src/routes/__root.tsx new file mode 100644 index 00000000..38c4bcbc --- /dev/null +++ b/frontend/src/renderer/src/routes/__root.tsx @@ -0,0 +1,14 @@ +import { Outlet, createRootRouteWithContext } from "@tanstack/react-router"; +import type { QueryClient } from "@tanstack/react-query"; + +export interface RouterContext { + queryClient: QueryClient; +} + +export const Route = createRootRouteWithContext()({ + component: RootLayout, +}); + +function RootLayout() { + return ; +} diff --git a/frontend/src/renderer/src/routes/home/features.tsx b/frontend/src/renderer/src/routes/home/features.tsx new file mode 100644 index 00000000..70ccb60d --- /dev/null +++ b/frontend/src/renderer/src/routes/home/features.tsx @@ -0,0 +1,87 @@ +import FeatureIcon from "@/components/feature-icon"; +import Footer from "@/components/layout/footer"; +import Header from "@/components/layout/header"; +import MainContent from "@/components/layout/main-content"; +import Card from "@/components/ui/card"; +import APIProtected from "@/features/APIProtected"; +import { css } from "@/styled/css"; +import { Grid, Stack, styled } from "@/styled/jsx"; +import { FeatureFlowEnum, getFeatureRouteSlug } from "@/types/features"; +import { FEATURE_ICON } from "@/utils/config"; +import { + Link, + type LinkComponentProps, + createFileRoute, +} from "@tanstack/react-router"; +import type { Icon } from "phosphor-react"; +import { useTranslation } from "react-i18next"; + +interface CardToolProps extends LinkComponentProps { + title: string; + subtitle: string; + icon: Icon; + disabled?: boolean; +} +function CardTool({ + title, + subtitle, + icon: Icon, + disabled = false, + ...props +}: CardToolProps) { + return ( + + + + + + {title} + + {subtitle} + + + + + + ); +} + +export const Route = createFileRoute("/home/features")({ + component: RouteComponent, +}); + +function RouteComponent() { + const { t } = useTranslation(["common", "dataset", "anonymizer"]); + + return ( + + +
    + + + + {t("home.features.greeting")} + + + + + + + +
    + + + ); +} diff --git a/frontend/src/renderer/src/routes/home/host.tsx b/frontend/src/renderer/src/routes/home/host.tsx new file mode 100644 index 00000000..ad3d8bca --- /dev/null +++ b/frontend/src/renderer/src/routes/home/host.tsx @@ -0,0 +1,24 @@ +import ChooseHost from "@/components/home/choose-host"; +import ConnectToHost from "@/components/home/connect-to-host"; +import HomeLayout from "@/layout/home"; +import { createFileRoute } from "@tanstack/react-router"; +import { useState } from "react"; + +export const Route = createFileRoute("/home/host")({ + component: RouteComponent, +}); + +function RouteComponent() { + const [isLocal, setIsLocal] = useState(null); + + return ( + + {isLocal === null && ( + setIsLocal(false)} /> + )} + {isLocal === false && ( + setIsLocal(null)} /> + )} + + ); +} diff --git a/frontend/src/renderer/src/routes/home/index.tsx b/frontend/src/renderer/src/routes/home/index.tsx new file mode 100644 index 00000000..cb8400d0 --- /dev/null +++ b/frontend/src/renderer/src/routes/home/index.tsx @@ -0,0 +1,9 @@ +import { Navigate, createFileRoute } from "@tanstack/react-router"; + +export const Route = createFileRoute("/home/")({ + component: Index, +}); + +function Index() { + return ; +} diff --git a/frontend/src/renderer/src/routes/index.tsx b/frontend/src/renderer/src/routes/index.tsx new file mode 100644 index 00000000..bfcfef2c --- /dev/null +++ b/frontend/src/renderer/src/routes/index.tsx @@ -0,0 +1,22 @@ +import Loading from "@/layout/loading"; +import { createFileRoute, useNavigate } from "@tanstack/react-router"; +import { useEffect } from "react"; + +export const Route = createFileRoute("/")({ + component: RouteComponent, +}); + +const TIMING = 2000; +function RouteComponent() { + const navigate = useNavigate(); + + useEffect(() => { + const timer = setTimeout(() => { + navigate({ to: "/home" }); + }, TIMING); + + return () => clearTimeout(timer); + }, [navigate]); + + return ; +} diff --git a/frontend/src/renderer/src/schema/disambiguate.ts b/frontend/src/renderer/src/schema/disambiguate.ts new file mode 100644 index 00000000..7d3ef5ad --- /dev/null +++ b/frontend/src/renderer/src/schema/disambiguate.ts @@ -0,0 +1,30 @@ +import { z } from "zod"; + +const disambiguateLabelSchema = z.object({ + text: z.string(), + start_char: z.number(), + end_char: z.number(), + attrs: z.object({ + aymurai_label: z.string(), + aymurai_label_subclass: z.array(z.string()).nullable(), + aymurai_alt_text: z.string().nullable(), + aymurai_alt_start_char: z.number().nullable(), + aymurai_alt_end_char: z.number().nullable(), + aymurai_method: z.string().nullish(), + aymurai_score: z.number().nullish(), + aymurai_label_instance: z.number().nullish(), + aymurai_disambiguation: z.string().nullish(), + aymurai_anonymize: z.boolean().nullish(), + canonical_entity_id: z.string().nullish(), + }), +}); + +export const disambiguateSchema = z.object({ + data: z.array( + z.object({ + document: z.string(), + labels: z.array(disambiguateLabelSchema), + }), + ), + // label_policies is intentionally omitted +}); diff --git a/frontend/src/renderer/src/schema/extract.ts b/frontend/src/renderer/src/schema/extract.ts new file mode 100644 index 00000000..93436f00 --- /dev/null +++ b/frontend/src/renderer/src/schema/extract.ts @@ -0,0 +1,24 @@ +import z from "zod"; + +export const documentExtractSchema = z.object({ + document_id: z.uuid(), + footer: z.string().nullable(), + header: z.string().nullable(), + document: z.array(z.string()), + + // Preserving schema for future use + // id: z.string().uuid(), + // name: z.string(), + // paragraphs: z.array( + // z.object({ + // id: z.string().uuid(), + // text: z.string(), + // hash: z.string(), + // index: z.number(), + // created_at: z.string().datetime({ local: true }), + // updated_at: z.string().datetime({ local: true }).nullable(), + // }), + // ), +}); + +export type DocumentExtract = z.infer; diff --git a/frontend/src/renderer/src/schema/predict.ts b/frontend/src/renderer/src/schema/predict.ts new file mode 100644 index 00000000..d8b0ab20 --- /dev/null +++ b/frontend/src/renderer/src/schema/predict.ts @@ -0,0 +1,30 @@ +import { z } from "zod"; + +/** + * Schema for a single label as returned by `/anonymizer/predict` or + * `/anonymizer/validation`. Tolerant to nullish extended fields so it also + * handles already-disambiguated validation data stored in the DB. + */ +export const predictLabelSchema = z.object({ + text: z.string(), + start_char: z.number(), + end_char: z.number(), + attrs: z.object({ + aymurai_alt_start_char: z.number().nullish(), + aymurai_alt_end_char: z.number().nullish(), + aymurai_alt_text: z.string().nullish(), + aymurai_label: z.string(), + aymurai_label_subclass: z.array(z.string()).nullish(), + aymurai_anonymize: z.boolean().nullish(), + canonical_entity_id: z.string().nullish(), + aymurai_label_instance: z.number().nullish(), + aymurai_disambiguation: z.string().nullish(), + }), +}); + +export const predictLabelsSchema = z.array(predictLabelSchema); + +export const predictSchema = z.object({ + document: z.string(), + labels: predictLabelsSchema, +}); diff --git a/frontend/src/renderer/src/services/api.ts b/frontend/src/renderer/src/services/api.ts new file mode 100644 index 00000000..375e8717 --- /dev/null +++ b/frontend/src/renderer/src/services/api.ts @@ -0,0 +1,25 @@ +import axios from "axios"; + +const API_PREFIX = "/api"; + +function trimTrailingSlash(value: string): string { + return value.replace(/\/$/, ""); +} + +export function getApiBaseUrl(host: string = window.location.origin): string { + const origin = trimTrailingSlash(new URL(host).toString()); + if (origin.endsWith(API_PREFIX)) return origin; + return `${origin}${API_PREFIX}`; +} + +export function setApiBaseUrl(host?: string): string { + const baseURL = getApiBaseUrl(host); + api.defaults.baseURL = baseURL; + return baseURL; +} + +const api = axios.create({ + baseURL: getApiBaseUrl(), +}); + +export default api; diff --git a/frontend/src/renderer/src/services/aymurai/__tests__/validation.test.ts b/frontend/src/renderer/src/services/aymurai/__tests__/validation.test.ts new file mode 100644 index 00000000..6cdf9e96 --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/__tests__/validation.test.ts @@ -0,0 +1,225 @@ +import { describe, expect, it, vi } from "vitest"; +import getStoredValidation, { + normalizeValidationLabel, +} from "../validation"; + +// --------------------------------------------------------------------------- +// Shared helpers +// --------------------------------------------------------------------------- + +function makeController() { + return new AbortController(); +} + +function makeParagraph(value: string) { + return { + id: value, + value, + document_id: "doc-1", + }; +} + +function makeRawLabel( + overrides: Partial<{ + text: string; + start_char: number; + end_char: number; + aymurai_anonymize: boolean | null; + aymurai_alt_text: string | null; + aymurai_alt_start_char: number | null; + aymurai_alt_end_char: number | null; + canonical_entity_id: string | null; + }> = {}, +) { + return { + text: overrides.text ?? "Juan", + start_char: overrides.start_char ?? 4, + end_char: overrides.end_char ?? 8, + attrs: { + aymurai_label: "PERSONA", + aymurai_label_subclass: null, + aymurai_alt_text: overrides.aymurai_alt_text ?? null, + aymurai_alt_start_char: overrides.aymurai_alt_start_char ?? null, + aymurai_alt_end_char: overrides.aymurai_alt_end_char ?? null, + aymurai_anonymize: overrides.aymurai_anonymize ?? true, + canonical_entity_id: overrides.canonical_entity_id ?? "canon-1", + aymurai_label_instance: null, + aymurai_disambiguation: null, + }, + }; +} + +describe("normalizeValidationLabel", () => { + const base = { + text: "original", + start_char: 10, + end_char: 18, + attrs: { + aymurai_label: "PERSONA", + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: null, + aymurai_alt_end_char: null, + aymurai_anonymize: null, + canonical_entity_id: null, + aymurai_label_instance: null, + aymurai_disambiguation: null, + }, + }; + + it("assigns a new UUID mentionId", () => { + const result = normalizeValidationLabel(base, "para-1"); + expect(result.mentionId).toMatch( + /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i, + ); + }); + + it("uses alt_text / alt_chars when present", () => { + const label = { + ...base, + attrs: { + ...base.attrs, + aymurai_alt_text: "redacted", + aymurai_alt_start_char: 5, + aymurai_alt_end_char: 13, + }, + }; + const result = normalizeValidationLabel(label, "para-1"); + expect(result.text).toBe("redacted"); + expect(result.start_char).toBe(5); + expect(result.end_char).toBe(13); + }); + + it("falls back to original text / chars when alt fields are absent", () => { + const result = normalizeValidationLabel(base, "para-1"); + expect(result.text).toBe("original"); + expect(result.start_char).toBe(10); + expect(result.end_char).toBe(18); + }); + + it("sets paragraphId from parameter", () => { + const result = normalizeValidationLabel(base, "para-42"); + expect(result.paragraphId).toBe("para-42"); + }); + + it("preserves canonical_entity_id from stored validation", () => { + const label = { + ...base, + attrs: { ...base.attrs, canonical_entity_id: "abc-123" }, + }; + const result = normalizeValidationLabel(label, "para-1"); + expect(result.attrs.canonical_entity_id).toBe("abc-123"); + }); + + it("preserves aymurai_anonymize flag when false", () => { + const label = { + ...base, + attrs: { ...base.attrs, aymurai_anonymize: false }, + }; + const result = normalizeValidationLabel(label, "para-1"); + expect(result.attrs.aymurai_anonymize).toBe(false); + }); + + it("preserves aymurai_anonymize flag when true", () => { + const label = { + ...base, + attrs: { ...base.attrs, aymurai_anonymize: true }, + }; + const result = normalizeValidationLabel(label, "para-1"); + expect(result.attrs.aymurai_anonymize).toBe(true); + }); + + it("maps null aymurai_anonymize to null (not treated as false)", () => { + const result = normalizeValidationLabel(base, "para-1"); + expect(result.attrs.aymurai_anonymize).toBeNull(); + }); + + it("maps nullish optional attrs to null", () => { + const result = normalizeValidationLabel(base, "para-1"); + expect(result.attrs.aymurai_disambiguation).toBeNull(); + expect(result.attrs.aymurai_label_instance).toBeNull(); + }); +}); + +// --------------------------------------------------------------------------- +// getStoredValidation — offset integrity guard +// --------------------------------------------------------------------------- + +vi.mock("@/services/api", () => ({ + default: { + post: vi.fn(), + defaults: { baseURL: "http://localhost" }, + }, +})); + +describe("getStoredValidation — offset integrity guard", () => { + // The paragraph text is "Sr. Juan fue aquí" (18 chars). + // "Juan" sits at [4, 8]. + const PARA_TEXT = "Sr. Juan fue aquí"; + const paragraph = makeParagraph(PARA_TEXT); + + async function setupApiResponse(labels: ReturnType[]) { + const { default: api } = await import("@/services/api"); + vi.mocked(api.post).mockResolvedValueOnce({ data: labels }); + } + + it("returns normalized labels when all active offsets match paragraph text", async () => { + await setupApiResponse([makeRawLabel()]); + + const result = await getStoredValidation(paragraph, makeController()); + expect(result).not.toBeNull(); + expect(result).toHaveLength(1); + expect(result![0].text).toBe("Juan"); + expect(result![0].start_char).toBe(4); + expect(result![0].end_char).toBe(8); + }); + + it("returns null when an active label has a text mismatch (PDF drift scenario)", async () => { + // offset [4,8] would slice "Juan" from the original text, but the stored + // label says "Jüan" — simulates the backend having a slightly different PDF + // extraction that caused the stored text to drift. + await setupApiResponse([makeRawLabel({ text: "Jüan" })]); + + const result = await getStoredValidation(paragraph, makeController()); + expect(result).toBeNull(); + }); + + it("returns null when an active label has out-of-bounds end_char", async () => { + await setupApiResponse([ + makeRawLabel({ end_char: PARA_TEXT.length + 5 }), + ]); + const result = await getStoredValidation(paragraph, makeController()); + expect(result).toBeNull(); + }); + + it("returns null when an active label has start_char >= end_char", async () => { + await setupApiResponse([makeRawLabel({ start_char: 8, end_char: 4 })]); + const result = await getStoredValidation(paragraph, makeController()); + expect(result).toBeNull(); + }); + + it("does NOT apply the offset check to excluded labels (aymurai_anonymize: false)", async () => { + // An excluded label whose text slice would not match — but since it's + // excluded it should not block the stored validation from being returned. + await setupApiResponse([ + makeRawLabel({ aymurai_anonymize: false, text: "ghost" }), + ]); + const result = await getStoredValidation(paragraph, makeController()); + // No active labels → every() vacuously true → return the labels + expect(result).not.toBeNull(); + }); + + it("returns [] when the backend returns an empty array (no entities stored)", async () => { + await setupApiResponse([]); + const result = await getStoredValidation(paragraph, makeController()); + expect(result).toEqual([]); + }); + + it("returns null on network error (graceful fallback)", async () => { + const { default: api } = await import("@/services/api"); + vi.mocked(api.post).mockRejectedValueOnce(new Error("Network error")); + + const result = await getStoredValidation(paragraph, makeController()); + expect(result).toBeNull(); + }); +}); diff --git a/frontend/src/renderer/src/services/aymurai/index.ts b/frontend/src/renderer/src/services/aymurai/index.ts new file mode 100644 index 00000000..35a0de7d --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/index.ts @@ -0,0 +1,7 @@ +import predict from "./predict"; +export { predict }; + +export * from "./useConnectToHost"; +export * from "./useRunLocalServer"; + +export * as aymuraiService from "./queries"; diff --git a/frontend/src/renderer/src/services/aymurai/predict.ts b/frontend/src/renderer/src/services/aymurai/predict.ts new file mode 100644 index 00000000..1ad7fa10 --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/predict.ts @@ -0,0 +1,66 @@ +import { CanceledError } from "axios"; + +import { predictSchema } from "@/schema/predict"; +import type { PredictLabel, Workflows } from "@/types/aymurai"; +import type { Paragraph } from "@/types/file"; +import api from "../api"; + +/** + * Realiza una petición a la AI para poder obtener predicciones en base a un párrafo + * @param paragraph Párrafo a analizar + * @param controller `AbortController` encargado de mandar una señal de cancelación a `axios` + * @param serverUrl String with the URL of the AyMurAI api + * @returns Una lista de `PredictLabel` con las predicciones + */ +export default async function predict( + paragraph: Paragraph, + controller: AbortController, + route: Workflows = "datapublic", +): Promise { + try { + const path = + route === "datapublic" + ? `/datapublic/predict/${paragraph.document_id}` + : "/anonymizer/predict"; + + const response = await api.post( + path, + { + text: paragraph.value, + }, + { + signal: controller.signal, + }, + ); + const parsed = predictSchema.parse(response.data); + + const data = parsed.labels.map((l) => { + const altStart = l.attrs.aymurai_alt_start_char; + const altEnd = l.attrs.aymurai_alt_end_char; + // Only apply alt offsets when both are present and form a valid range. + // The NER pipeline can emit inverted alt offsets (altStart > altEnd) for + // non-alphanumeric entities like "∙" — using them would produce an + // invalid_range error at export time. + const useAlt = altStart != null && altEnd != null && altStart < altEnd; + return { + ...l, + mentionId: crypto.randomUUID(), + start_char: useAlt ? altStart : l.start_char, + end_char: useAlt ? altEnd : l.end_char, + text: useAlt && l.attrs.aymurai_alt_text ? l.attrs.aymurai_alt_text : l.text, + paragraphId: paragraph.id, + } as PredictLabel; + }); + + return data; + } catch (e) { + // If the POST is cancelled by the controller, just return an empty prediction + if (e instanceof CanceledError) { + return []; + } + + // Otherwise, throw again the same error + console.error(e); + throw e; + } +} diff --git a/frontend/src/renderer/src/services/aymurai/queries.ts b/frontend/src/renderer/src/services/aymurai/queries.ts new file mode 100644 index 00000000..972966a9 --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/queries.ts @@ -0,0 +1,292 @@ +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; +import { disambiguateSchema } from "@/schema/disambiguate"; +import { documentExtractSchema } from "@/schema/extract"; +import type { + AnonymizerLabels, + PredictLabel, + Workflows, +} from "@/types/aymurai"; +import type { DocFile, Paragraph } from "@/types/file"; +import { assertValidAnonymizerExportState } from "@/utils/anonymizer/export-validation"; +import { + anonymizeQuerySignature, + filterActivePredictions, + isPredictionActive, +} from "@/utils/anonymizer/predictions"; +import { mutationOptions, queryOptions } from "@tanstack/react-query"; +import api from "../api"; +import predict from "./predict"; + +export type SuffixMode = "always" | "when_multiple" | "never"; + +interface Body { + data: { + document: string; + labels: PredictLabel[]; + }[]; + label_policies?: Record; + render_policy?: { suffix_mode: SuffixMode }; +} + +/** + * Query factory for a single paragraph prediction. + * Uses React Query's native cancellation signal — no manual AbortController needed. + */ +export const predictParagraph = ( + paragraph: Paragraph, + workflow: Workflows, + fileName: string, +) => + queryOptions({ + queryKey: ["predict", api.defaults.baseURL, workflow, fileName, paragraph.id], + queryFn: ({ signal }) => { + const controller = new AbortController(); + signal?.addEventListener("abort", () => controller.abort()); + return predict(paragraph, controller, workflow); + }, + staleTime: Number.POSITIVE_INFINITY, + retry: false, + }); + +const body = ( + file: DocFile, + excludedTags: Record | null, + excludedWords: string[], + suffixMode: SuffixMode = "always", +): Body => { + const effectiveTags = excludedTags ?? EXCLUDED_TAGS; + const paragraphs = file.paragraphs ?? []; + + // Run the pre-flight validation only on active (to-be-anonymized) predictions + // so the validator doesn't complain about excluded entities. + const activeLabels = filterActivePredictions( + file.predictions, + excludedTags, + excludedWords, + ); + assertValidAnonymizerExportState(file, activeLabels); + + // Send ALL predictions to the backend — excluded ones are marked with + // aymurai_anonymize: false so they are persisted in + // anonymization_paragraph.validation and can be recovered if the exclusion + // is reversed in a future session. + const allLabels = (file.predictions ?? []).map((l) => ({ + ...l, + attrs: { + ...l.attrs, + aymurai_anonymize: isPredictionActive(l, excludedTags, excludedWords), + }, + })); + + const label_policies = Object.fromEntries( + Object.entries(effectiveTags) + .filter(([, enabled]) => !enabled) + .map(([id]) => [id, { anonymize: false }]), + ) as Record; + + return { + data: paragraphs.map((p) => ({ + document: p.value, + labels: allLabels.filter((l) => l.paragraphId === p.id), + })), + ...(Object.keys(label_policies).length > 0 && { label_policies }), + render_policy: { suffix_mode: suffixMode }, + }; +}; + +export const anonymize = ( + file: DocFile, + excludedTags: Record | null, + excludedWords: string[], + suffixMode: SuffixMode = "always", +) => + queryOptions({ + // Normalise null → EXCLUDED_TAGS so the key is stable when the user hasn't + // touched the config (both resolve to "all tags enabled"). + queryKey: [ + "anonymize", + file.data.name, + file.data.size, + (file.paragraphs ?? []).map((p) => [p.id, p.value].join("\u001f")), + anonymizeQuerySignature(file.predictions, excludedTags, excludedWords), + excludedTags ?? EXCLUDED_TAGS, + excludedWords, + suffixMode, + ], + queryFn: async () => { + const formData = new FormData(); + formData.append("file", file.data); + formData.append( + "annotations", + JSON.stringify(body(file, excludedTags, excludedWords, suffixMode)), + ); + + const response = await api.post( + "/anonymizer/anonymize-document", + formData, + { + headers: { + "Content-Type": "multipart/form-data", + Accept: "application/octet-stream", + }, + responseType: "blob", + }, + ); + + return response.data; + }, + // select: (data) => URL.createObjectURL(data), + }); + +export const disambiguate = (file: DocFile) => + queryOptions({ + queryKey: ["disambiguate", api.defaults.baseURL, file.data.name], + queryFn: async (): Promise => { + if (!file.paragraphs) + throw new Error("File with no paragraphs tried to disambiguate"); + if (!file.predictions) + throw new Error("File with no predictions tried to disambiguate"); + + const { paragraphs, predictions } = file; + + // Build a lookup from paragraphId → list of original predictions so we + // can reuse the stable mentionId even after the backend round-trip. + const byParagraphId = new Map(); + for (const p of predictions) { + const list = byParagraphId.get(p.paragraphId) ?? []; + list.push(p); + byParagraphId.set(p.paragraphId, list); + } + + const response = await api.post("/anonymizer/disambiguate", { + paragraphs: paragraphs.map((p) => ({ + document: p.value, + labels: predictions.filter((l) => l.paragraphId === p.id), + })), + }); + + const parsed = disambiguateSchema.parse(response.data); + + // Build a consumption queue per paragraph text so we can match response + // items by content instead of array index. This tolerates backend + // reordering and count drops. Duplicate paragraph texts are matched in + // the order they appear in the original paragraphs array. + const paragraphQueue = new Map(); + for (const p of paragraphs) { + const q = paragraphQueue.get(p.value) ?? []; + q.push(p); + paragraphQueue.set(p.value, q); + } + const consumed = new Map(); + const matchedParagraphIds = new Set(); + + const disambiguated = parsed.data.flatMap((item) => { + const queue = paragraphQueue.get(item.document) ?? []; + const nextIdx = consumed.get(item.document) ?? 0; + const paragraph = queue[nextIdx]; + consumed.set(item.document, nextIdx + 1); + + if (!paragraph) return []; + + matchedParagraphIds.add(paragraph.id); + + // Build a lookup from (start_char, end_char) → original mention so we + // can reuse the stable mentionId. + const origByPos = new Map(); + for (const orig of byParagraphId.get(paragraph.id) ?? []) { + origByPos.set(`${orig.start_char}:${orig.end_char}`, orig); + } + + return item.labels.map((l) => { + const altStart = l.attrs.aymurai_alt_start_char; + const altEnd = l.attrs.aymurai_alt_end_char; + const useAlt = altStart !== null && altEnd !== null && altStart < altEnd; + const resolvedText = useAlt && l.attrs.aymurai_alt_text ? l.attrs.aymurai_alt_text : l.text; + const resolvedStart = useAlt ? altStart : l.start_char; + const resolvedEnd = useAlt ? altEnd : l.end_char; + + // Prefer original mentionId so downstream D&D state stays stable. + const orig = origByPos.get(`${l.start_char}:${l.end_char}`); + + return { + mentionId: orig?.mentionId ?? crypto.randomUUID(), + text: resolvedText, + start_char: resolvedStart, + end_char: resolvedEnd, + attrs: { + aymurai_label: l.attrs + .aymurai_label as PredictLabel["attrs"]["aymurai_label"], + aymurai_label_subclass: l.attrs.aymurai_label_subclass, + aymurai_alt_text: l.attrs.aymurai_alt_text ?? null, + aymurai_alt_start_char: l.attrs.aymurai_alt_start_char ?? null, + aymurai_alt_end_char: l.attrs.aymurai_alt_end_char ?? null, + canonical_entity_id: l.attrs.canonical_entity_id ?? null, + aymurai_anonymize: l.attrs.aymurai_anonymize ?? null, + aymurai_label_instance: l.attrs.aymurai_label_instance ?? null, + aymurai_disambiguation: l.attrs.aymurai_disambiguation ?? null, + }, + paragraphId: paragraph.id, + } satisfies PredictLabel; + }); + }); + + // Preserve raw predictions for any paragraph the backend did not return, + // so a backend count drop never silently erases annotations. + const unmatched = predictions.filter( + (p) => !matchedParagraphIds.has(p.paragraphId), + ); + + return [...disambiguated, ...unmatched]; + }, + }); + +export const fileParser = (file: File) => + queryOptions({ + queryKey: ["file-parser", file.name, file.size], + queryFn: async () => { + const formData = new FormData(); + formData.append("file", file); + const response = await api.post("/misc/document-extract", formData, { + headers: { "Content-Type": "multipart/form-data" }, + }); + return documentExtractSchema.parse(response.data); + }, + retry: false, + retryOnMount: false, + }); + +export const odtToPdf = () => + mutationOptions({ + mutationFn: async (file: Blob) => { + const formData = new FormData(); + formData.append("file", file, "document.odt"); + + const response = await api.post("/convert/odt/pdf", formData, { + headers: { + "Content-Type": "multipart/form-data", + Accept: "application/octet-stream", + }, + responseType: "blob", + }); + + return response.data; + }, + }); + +export const pdfToOdt = () => + mutationOptions({ + mutationFn: async (file: Blob) => { + const formData = new FormData(); + formData.append("file", file, "document.pdf"); + + const response = await api.post("/convert/pdf/odt", formData, { + headers: { + "Content-Type": "multipart/form-data", + Accept: "application/octet-stream", + }, + responseType: "blob", + }); + + return response.data; + }, + }); diff --git a/frontend/src/renderer/src/services/aymurai/schema.ts b/frontend/src/renderer/src/services/aymurai/schema.ts new file mode 100644 index 00000000..96c806da --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/schema.ts @@ -0,0 +1,5 @@ +import z from "zod"; + +export const healthcheckSchema = z.object({ + status: z.enum(["ok"]), +}); diff --git a/frontend/src/renderer/src/services/aymurai/useConnectToHost.ts b/frontend/src/renderer/src/services/aymurai/useConnectToHost.ts new file mode 100644 index 00000000..ee74363d --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/useConnectToHost.ts @@ -0,0 +1,22 @@ +import api, { getApiBaseUrl, setApiBaseUrl } from "@/services/api"; + +import z from "zod"; + +import { useMutation } from "@tanstack/react-query"; + +export const useConnectToHost = () => { + return useMutation({ + mutationKey: ["healthcheck"], + mutationFn: async (host: string) => { + const url = getApiBaseUrl(host); + const response = await api + .get(`${url}/server/healthcheck`) + .then((r) => r.data); + + return z.object({ status: z.string() }).parse(response); + }, + onSuccess: (_data, host) => { + setApiBaseUrl(host); + }, + }); +}; diff --git a/frontend/src/renderer/src/services/aymurai/useRunLocalServer.ts b/frontend/src/renderer/src/services/aymurai/useRunLocalServer.ts new file mode 100644 index 00000000..b2bf9df5 --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/useRunLocalServer.ts @@ -0,0 +1,56 @@ +import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useCallback } from "react"; +import api, { setApiBaseUrl } from "../api"; +import { healthcheckSchema } from "./schema"; + +interface UseRunLocalServerProps { + onSuccess?: () => void; +} +export const useRunLocalServer = ({ onSuccess }: UseRunLocalServerProps) => { + const queryClient = useQueryClient(); + const serverStatus = queryClient.getQueryData(["run-local-server"]); + + const { + mutateAsync: checkServerStatus, + isPending: isRunning, + isSuccess, + } = useMutation({ + mutationFn: () => + api + .get("/server/healthcheck") + .then((r) => r.data) + .then(healthcheckSchema.parse), + retryDelay: 1000, + retry: 10, + onMutate: () => { + queryClient.setQueryData(["run-local-server"], false); + }, + onSuccess: () => { + queryClient.setQueryData(["run-local-server"], true); + onSuccess?.(); + }, + }); + + const run = useCallback(async () => { + setApiBaseUrl(); + if (serverStatus === undefined) { + console.log("Running local server"); + if (!window.electronAPI) + throw new Error( + "Electron API not available. Check your preload script.", + ); + await window.electronAPI.runBatch(); + } else if (serverStatus === true) { + console.log("Server is already running"); + } else { + console.log("Server is not running yet"); + } + await checkServerStatus(undefined); + }, [serverStatus]); + + return { + isRunning, + isSuccess, + run, + }; +}; diff --git a/frontend/src/renderer/src/services/aymurai/utils.ts b/frontend/src/renderer/src/services/aymurai/utils.ts new file mode 100644 index 00000000..1d08c0a2 --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/utils.ts @@ -0,0 +1,6 @@ +import { getApiBaseUrl } from "@/services/api"; +import axios from "axios"; + +export const fetcher = axios.create({ + baseURL: getApiBaseUrl(), +}); diff --git a/frontend/src/renderer/src/services/aymurai/validation.ts b/frontend/src/renderer/src/services/aymurai/validation.ts new file mode 100644 index 00000000..bb227a40 --- /dev/null +++ b/frontend/src/renderer/src/services/aymurai/validation.ts @@ -0,0 +1,109 @@ +import { CanceledError } from "axios"; +import { z } from "zod"; + +import { predictLabelSchema } from "@/schema/predict"; +import type { PredictLabel } from "@/types/aymurai"; +import type { Paragraph } from "@/types/file"; +import api from "../api"; + +const validationResponseSchema = z.array(predictLabelSchema); + +/** + * Normalizes a backend DocLabel (from `/anonymizer/validation`) to a frontend + * `PredictLabel`, applying alt-offset resolution and assigning a new `mentionId`. + * Exported for testability. + */ +export function normalizeValidationLabel( + l: z.infer, + paragraphId: string, +): PredictLabel { + return { + mentionId: crypto.randomUUID(), + text: l.attrs.aymurai_alt_text ?? l.text, + start_char: l.attrs.aymurai_alt_start_char ?? l.start_char, + end_char: l.attrs.aymurai_alt_end_char ?? l.end_char, + attrs: { + aymurai_label: l.attrs + .aymurai_label as PredictLabel["attrs"]["aymurai_label"], + aymurai_label_subclass: l.attrs.aymurai_label_subclass ?? null, + aymurai_alt_text: l.attrs.aymurai_alt_text ?? null, + aymurai_alt_start_char: l.attrs.aymurai_alt_start_char ?? null, + aymurai_alt_end_char: l.attrs.aymurai_alt_end_char ?? null, + canonical_entity_id: l.attrs.canonical_entity_id ?? null, + aymurai_anonymize: l.attrs.aymurai_anonymize ?? null, + aymurai_label_instance: l.attrs.aymurai_label_instance ?? null, + aymurai_disambiguation: l.attrs.aymurai_disambiguation ?? null, + }, + paragraphId, + }; +} + +/** + * Retrieves manually-validated annotations for a paragraph from the backend DB + * (`anonymization_paragraph.validation`). + * + * Return values: + * - `null` → no stored validation exists; caller should fall back to model predict + * - `[]` → paragraph was explicitly validated with no entities; respect the empty state + * - `[...]` → stored manual annotations; use them as the initial UI state + * + * On any non-abort error (network failure, 404, etc.) the function returns `null` + * so the workflow degrades gracefully to model predictions. + * + * @param paragraph Paragraph to look up. + * @param controller AbortController tied to the parent React Query signal. + */ +export default async function getStoredValidation( + paragraph: Paragraph, + controller: AbortController, +): Promise { + try { + const response = await api.post( + "/anonymizer/validation", + { text: paragraph.value }, + { signal: controller.signal }, + ); + + // Backend returns a plain labels array. + // - 404 / error → caught below → null (fall back to predict) + // - [] → paragraph validated with no entities + // - [...] → restore stored annotations + const labels = validationResponseSchema.parse(response.data); + const normalized = labels.map((l) => normalizeValidationLabel(l, paragraph.id)); + + // Defensive: validate that stored offsets are still consistent with the + // current paragraph text. + const active = normalized.filter((l) => l.attrs.aymurai_anonymize !== false); + const isValid = active.every( + (l) => + Number.isFinite(l.start_char) && + Number.isFinite(l.end_char) && + l.start_char >= 0 && + l.end_char <= paragraph.value.length && + l.start_char < l.end_char && + paragraph.value.slice(l.start_char, l.end_char) === l.text, + ); + // If any active label fails basic offset checks, discard the stored data + // and fall back to fresh model predict + disambiguation. + if (!isValid) { + console.warn( + "[validation] Stored offsets do not match paragraph text — falling back to predict.", + { paragraphId: paragraph.id }, + ); + return null; + } + + return normalized; + } catch (e) { + // Propagate request cancellations so React Query can clean up properly + if (e instanceof CanceledError) throw e; + + // Any other error (endpoint unavailable, unexpected schema, etc.): fail open + // and let the caller fall back to model predict. + console.warn( + "[validation] Could not load stored validation, falling back to predict:", + e, + ); + return null; + } +} diff --git a/frontend/src/renderer/src/services/filesystem/browser/download.ts b/frontend/src/renderer/src/services/filesystem/browser/download.ts new file mode 100644 index 00000000..5a240195 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/browser/download.ts @@ -0,0 +1,13 @@ +export function downloadBlob(blob: Blob, filename: string) { + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + link.download = filename; + link.style.display = "none"; + + document.body.appendChild(link); + link.click(); + link.remove(); + + URL.revokeObjectURL(url); +} diff --git a/frontend/src/renderer/src/services/filesystem/excel/__tests__/write.test.ts b/frontend/src/renderer/src/services/filesystem/excel/__tests__/write.test.ts new file mode 100644 index 00000000..3c616bcb --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/excel/__tests__/write.test.ts @@ -0,0 +1,34 @@ +import { Workbook } from "exceljs"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const downloadBlob = vi.fn(); + +vi.mock("../../browser/download", () => ({ + downloadBlob, +})); + +describe("excel write", () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.stubGlobal("window", { filesystem: undefined }); + }); + + it("downloads the workbook in browser mode when the Electron filesystem API is unavailable", async () => { + const { default: write } = await import("../write"); + const workbook = new Workbook(); + workbook.addWorksheet("set_de_datos").addRow(["ok"]); + + await write(workbook); + + expect(downloadBlob).toHaveBeenCalledTimes(1); + expect(downloadBlob).toHaveBeenCalledWith( + expect.any(Blob), + "set_de_datos.xlsx", + ); + }); + it("returns null without logging an error when reading in browser mode", async () => { + const { default: read } = await import("../read"); + + await expect(read()).resolves.toBeNull(); + }); +}); diff --git a/frontend/src/renderer/src/services/filesystem/excel/create.ts b/frontend/src/renderer/src/services/filesystem/excel/create.ts new file mode 100644 index 00000000..afb453d0 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/excel/create.ts @@ -0,0 +1,56 @@ +import { excelStructure } from "@/utils/file"; +import { Workbook, type Worksheet } from "exceljs"; + +function setMetadata(workbook: Workbook) { + workbook.creator = "AymurAI"; + workbook.company = "DataGenero"; + workbook.description = "Set de datos con perspectiva de genero"; + + workbook.created = new Date(); + workbook.modified = new Date(); +} + +function addWorksheet(workbook: Workbook) { + const worksheet = workbook.addWorksheet("set_de_datos", { + properties: { + tabColor: { argb: "B7E1CD" }, + }, + }); + + return worksheet; +} + +function addHeader(worksheet: Worksheet) { + worksheet.columns = excelStructure.map((label) => ({ + header: label, + key: label, + })); + + // Paint first row + const row = worksheet.getRow(1); + row.eachCell((cell) => { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "B7E1CD" }, + }; + }); + + // Freeze first row + worksheet.views = [{ state: "frozen", ySplit: 1 }]; +} + +/** + * Creates a new and empty Workbook with one Worksheet to start working with the dataset + * @returns A formatted Workbook + */ +export default function create() { + const workbook = new Workbook(); + + setMetadata(workbook); + const worksheet = addWorksheet(workbook); + + addHeader(worksheet); + + return workbook; +} diff --git a/frontend/src/renderer/src/services/filesystem/excel/index.ts b/frontend/src/renderer/src/services/filesystem/excel/index.ts new file mode 100644 index 00000000..b67fef0e --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/excel/index.ts @@ -0,0 +1,12 @@ +import create from "./create"; +import open from "./open"; +import read from "./read"; +import write from "./write"; + +const excel = { + read, + create, + open, + write, +}; +export default excel; diff --git a/frontend/src/renderer/src/services/filesystem/excel/open.ts b/frontend/src/renderer/src/services/filesystem/excel/open.ts new file mode 100644 index 00000000..880afe2a --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/excel/open.ts @@ -0,0 +1,19 @@ +import { DATASET_URL } from "@/utils/config"; +import logger from "@/utils/logger"; +import filesystemAPI from "../utils"; + +/** + * Opens the Excel file + */ +export default async function open() { + if (!window.filesystem) { + window.open(DATASET_URL, "_blank", "noopener,noreferrer"); + return; + } + + const result = await filesystemAPI().excel.open(); + + // If we get some string as a result from opening the file, we have an error + if (result !== "") + logger.error("There was an error while opening the XLSX file!: ", result); +} diff --git a/frontend/src/renderer/src/services/filesystem/excel/read.ts b/frontend/src/renderer/src/services/filesystem/excel/read.ts new file mode 100644 index 00000000..e382e7e4 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/excel/read.ts @@ -0,0 +1,24 @@ +import { Workbook } from "exceljs"; + +import logger from "@/utils/logger"; +import filesystemAPI from "../utils"; + +/** + * Read the `.xlsx` and loads its data into a Workbook instance + * @returns A ExcelJS `Workbook` instance if the `.xlsx` file can be opened, `null` otherwise + */ +export default async function read() { + if (!window.filesystem) return null; + + try { + const buffer = await filesystemAPI().excel.read(); + + const workbook = new Workbook(); + const loaded = await workbook.xlsx.load(buffer); + + return loaded; + } catch (e) { + logger.error("An error ocurred while trying to read the XLSX file: ", e); + return null; + } +} diff --git a/frontend/src/renderer/src/services/filesystem/excel/write.ts b/frontend/src/renderer/src/services/filesystem/excel/write.ts new file mode 100644 index 00000000..a3765b3d --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/excel/write.ts @@ -0,0 +1,24 @@ +import type { Workbook } from "exceljs"; +import { downloadBlob } from "../browser/download"; +import filesystemAPI from "../utils"; + +const DATASET_FILENAME = "set_de_datos.xlsx"; + +/** + * Writes the `.xlsx` in Buffer format to the filesystem + * @param buffer Data buffer representing the `.xlsx` file + */ +export default async function write(workbook: Workbook) { + const buffer = await workbook.xlsx.writeBuffer(); + + if (window.filesystem) { + return filesystemAPI().excel.write(buffer); + } + + downloadBlob( + new Blob([buffer], { + type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + }), + DATASET_FILENAME, + ); +} diff --git a/frontend/src/renderer/src/services/filesystem/feedback/export.ts b/frontend/src/renderer/src/services/filesystem/feedback/export.ts new file mode 100644 index 00000000..8756f644 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/feedback/export.ts @@ -0,0 +1,42 @@ +import type { DocFile } from "@/types/file"; +import { downloadBlob } from "../browser/download"; +import filesystemAPI from "../utils"; +import { joinValidation } from "./utils"; + +function getDate() { + const now = new Date(Date.now()); + const [date, time] = now.toISOString().split("T"); + + return `${date}-${time.split(".")[0].replace(/:/g, "_")}`; +} + +function formatName(fileName: string) { + const formattedName = fileName.replace(/\.docx/g, "").replace(/\s/g, "_"); + + return `aymurai--${formattedName}`; +} + +function exportFeedbackFromBrowser(fileName: string, content: object) { + const json = JSON.stringify(content); + const filename = `${formatName(fileName)}--${getDate()}.json`; + + downloadBlob(new Blob([json], { type: "application/json" }), filename); +} + +/** + * Exports the file validation and predictions as a JSON file + * @param file File to be exported + */ +export default async function exportFeedback(files: DocFile[]) { + for (const file of files) { + const { name } = file.data; + + const feedback = joinValidation(file); + + if (window.filesystem) { + await filesystemAPI().feedback.export(name, feedback); + } else { + exportFeedbackFromBrowser(name, feedback); + } + } +} diff --git a/frontend/src/renderer/src/services/filesystem/feedback/index.ts b/frontend/src/renderer/src/services/filesystem/feedback/index.ts new file mode 100644 index 00000000..8543b420 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/feedback/index.ts @@ -0,0 +1,6 @@ +import exportFeedback from "./export"; + +const feedback = { + export: exportFeedback, +}; +export default feedback; diff --git a/frontend/src/renderer/src/services/filesystem/feedback/utils.ts b/frontend/src/renderer/src/services/filesystem/feedback/utils.ts new file mode 100644 index 00000000..a1834196 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/feedback/utils.ts @@ -0,0 +1,68 @@ +import type { AllLabels } from "@/types/aymurai"; +import type { PredictionFeedback } from "@/types/feedback"; +import type { DocFile } from "@/types/file"; +import { flatValidation } from "@/utils/file"; + +/** + * Creates a new Feedback object with a specific name and value + * @param name Name of the entity's label + * @param value Feedbakc value for that specific label + * @returns A new feedback object containing the specified feedback value + */ +function newLabel( + name: AllLabels, + value: PredictionFeedback["validationText"], +): PredictionFeedback { + return { + mentionId: null, + paragraphId: "", + text: null, + start_char: null, + end_char: null, + validationText: value, + attrs: { + aymurai_label: name, + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: null, + aymurai_alt_end_char: null, + }, + }; +} + +/** + * Creates a `PredictionFeedback` array containing the AI response and the validated content + * @param predictions Predictions made by the AI + * @param validationObject Validated information + * @returns An array of objects with the predictions and the validations + */ +export function joinValidation({ + predictions, + validationObject, +}: DocFile): PredictionFeedback[] { + const result: PredictionFeedback[] = []; + const predictionList = predictions ?? []; + + const flat = flatValidation(validationObject); + + flat.forEach((val) => { + // First, add the predictions to the result array + predictionList.forEach((pred) => { + result.push({ + ...pred, + validationText: val[pred.attrs.aymurai_label] ?? null, + }); + }); + + // Get the labels from `validationObject` that aren't present on `predictions` + const filtered = (Object.keys(flat) as AllLabels[]).filter((key) => { + return !predictionList.find((pred) => pred.attrs.aymurai_label === key); + }); + + filtered.forEach((label) => + result.push(newLabel(label, val[label] ?? null)), + ); + }); + + return result; +} diff --git a/frontend/src/renderer/src/services/filesystem/index.ts b/frontend/src/renderer/src/services/filesystem/index.ts new file mode 100644 index 00000000..5bb45f10 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/index.ts @@ -0,0 +1,8 @@ +import excel from "./excel"; +import feedback from "./feedback"; + +const filesystem = { + feedback, + excel, +}; +export default filesystem; diff --git a/frontend/src/renderer/src/services/filesystem/utils.ts b/frontend/src/renderer/src/services/filesystem/utils.ts new file mode 100644 index 00000000..32771eb9 --- /dev/null +++ b/frontend/src/renderer/src/services/filesystem/utils.ts @@ -0,0 +1,13 @@ +/** + * Interface for the filesystem preloaded script on the main process + * @returns FileSystem functionalities + */ +export default function filesystemAPI() { + if (window.filesystem) { + return window.filesystem; + } + + throw new Error( + 'There was an error trying to use the "filesystem" API, check your preload script', + ); +} diff --git a/frontend/src/renderer/src/services/taskbar/index.ts b/frontend/src/renderer/src/services/taskbar/index.ts new file mode 100644 index 00000000..ce6d0404 --- /dev/null +++ b/frontend/src/renderer/src/services/taskbar/index.ts @@ -0,0 +1,16 @@ +import taskbarAPI from "./utils"; + +/** + * Notify the user with a sound and an action on the taskbar/dock + */ +function notify() { + taskbarAPI()?.notify?.(); + const audio = new Audio(`${import.meta.env.BASE_URL}audio/notification.mp3`); + audio.play(); +} + +const taskbar = { + notify, +}; + +export default taskbar; diff --git a/frontend/src/renderer/src/services/taskbar/utils.ts b/frontend/src/renderer/src/services/taskbar/utils.ts new file mode 100644 index 00000000..f7e23bad --- /dev/null +++ b/frontend/src/renderer/src/services/taskbar/utils.ts @@ -0,0 +1,7 @@ +/** + * Interface for the taskbar API + * @returns Taskbar functionalities + */ +export default function taskbar() { + if (window.taskbar) return window.taskbar; +} diff --git a/frontend/src/renderer/src/store/useHoverState.ts b/frontend/src/renderer/src/store/useHoverState.ts new file mode 100644 index 00000000..f6102326 --- /dev/null +++ b/frontend/src/renderer/src/store/useHoverState.ts @@ -0,0 +1,21 @@ +import { create } from "zustand"; + +interface HoverState { + hoveredCanonicalId: string | null; + lastEditedCanonicalId: string | null; + setHoveredCanonicalId: (id: string | null) => void; + setLastEditedCanonicalId: (id: string | null) => void; +} + +/** + * Transient (non-persisted) store for sidebar hover state. + * Used to synchronise which entity group is hovered in the sidebar + * with the corresponding text highlights in the document. + */ +export const useHoverState = create()((set) => ({ + hoveredCanonicalId: null, + lastEditedCanonicalId: null, + setHoveredCanonicalId: (hoveredCanonicalId) => set({ hoveredCanonicalId }), + setLastEditedCanonicalId: (lastEditedCanonicalId) => + set({ lastEditedCanonicalId }), +})); diff --git a/frontend/src/renderer/src/store/useLocal.ts b/frontend/src/renderer/src/store/useLocal.ts new file mode 100644 index 00000000..16fca1a4 --- /dev/null +++ b/frontend/src/renderer/src/store/useLocal.ts @@ -0,0 +1,96 @@ +import { create } from "zustand"; +import { useShallow } from "zustand/react/shallow"; +import { devtools, persist } from "zustand/middleware"; +import type { AnonymizerLabels } from "../types/aymurai"; +import { FeatureFlowEnum } from "../types/features"; + +type TutorialsSeen = Record; + +interface LocalStorageStore { + serverHost: string | null; + setServerHost: (serverUrl: string) => void; + clearServerHost: () => void; + tutorialsSeen: TutorialsSeen; + hasSeenTutorial: (feature: FeatureFlowEnum) => boolean; + setTutorialSeen: (feature: FeatureFlowEnum) => void; + excludedTags: Record | null; + setExcludedTags: (tags: Record) => void; + excludedWords: string[]; + setExcludedWords: (words: string[]) => void; + groupOrder: Record | null; + setGroupOrder: (order: Record) => void; +} + +const useLocalStore = create()( + devtools( + persist( + (set, get) => ({ + serverHost: null, + setServerHost: (serverHost: string) => set({ serverHost }), + clearServerHost: () => set({ serverHost: null }), + tutorialsSeen: { + [FeatureFlowEnum.Anonymizer]: false, + [FeatureFlowEnum.Dataset]: false, + }, + hasSeenTutorial: (feature: FeatureFlowEnum) => + get().tutorialsSeen[feature], + setTutorialSeen: (feature: FeatureFlowEnum) => + set((state) => ({ + tutorialsSeen: { ...state.tutorialsSeen, [feature]: true }, + })), + excludedTags: null, + setExcludedTags: (tags) => set({ excludedTags: tags }), + excludedWords: [], + setExcludedWords: (words) => set({ excludedWords: words }), + groupOrder: null, + setGroupOrder: (groupOrder) => set({ groupOrder }), + }), + { + name: "local-storage", + // groupOrder holds canonical UUIDs regenerated each session, so + // persisting it would only accumulate stale data across sessions. + partialize: (state) => ({ + serverHost: state.serverHost, + tutorialsSeen: state.tutorialsSeen, + excludedTags: state.excludedTags, + excludedWords: state.excludedWords, + }), + }, + ), + ), +); + +// TODO: in the future, we should export all of these hooks under a single named exports +// usage will be like the following: `localStore.useServerHost` +export const useServerHost = () => useLocalStore((state) => state.serverHost); +export const useServerHostActions = () => { + const setServerHost = useLocalStore((state) => state.setServerHost); + const clearServerHost = useLocalStore((state) => state.clearServerHost); + + return { + setServerHost, + clearServerHost, + }; +}; + +export const useTutorialSeen = (feature: FeatureFlowEnum) => + useLocalStore((state) => state.tutorialsSeen[feature]); +export const useSetTutorialSeen = () => + useLocalStore((state) => state.setTutorialSeen); + +export const useExcludedTagsConfig = () => + useLocalStore(useShallow((s) => ({ tags: s.excludedTags, words: s.excludedWords }))); +export const useExcludedTagsConfigActions = () => + useLocalStore(useShallow((s) => ({ + setTags: s.setExcludedTags, + setWords: s.setExcludedWords, + }))); + +export const useGroupOrder = () => + useLocalStore(useShallow((s) => ({ + groupOrder: s.groupOrder, + }))); +export const useGroupOrderActions = () => + useLocalStore(useShallow((s) => ({ + setGroupOrder: s.setGroupOrder, + }))); diff --git a/frontend/src/renderer/src/styles/globalStyles.ts b/frontend/src/renderer/src/styles/globalStyles.ts new file mode 100644 index 00000000..653b594b --- /dev/null +++ b/frontend/src/renderer/src/styles/globalStyles.ts @@ -0,0 +1,87 @@ +import { globalCss } from "./stitches.config"; + +/** @deprecated Global styles have been migrated to Panda CSS in `panda.config.ts`. */ +export const globalStyles = globalCss({ + "@import": + 'url("https://fonts.googleapis.com/css2?family=Archivo:wght@400;600;800&display=swap")', + + "html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, main, menu, nav, output, ruby, section, summary, time, mark, audio, video": + { + margin: "0", + padding: "0", + border: "0", + verticalAlign: "baseline", + boxSizing: "border-box", + color: "$tertiary", + }, + + "*": { + fontFamily: "$primary", + }, + + "mark.predicted-word": { + backgroundColor: "$primaryAlt", + + fontFamily: "$file", + + padding: "0px 0px 0px 2px", + + borderRadius: 8, + "& strong": { + fontSize: "12px", + padding: "0px", + margin: "0px", + }, + "& button.remove-tag": { + visibility: "hidden", + position: "relative", + backgroundColor: "$errorPrimary", + color: "$white", + padding: "3px 5px", + borderRadius: 8, + cursor: "pointer", + fontSize: "10px", + fontWeight: "heavy", + textAlign: "center", + top: "-10px", + right: "-5px", + border: "none", + }, + + "&:hover": { + cursor: "pointer", + "& button.remove-tag": { + visibility: "visible", + }, + }, + }, + + "mark.searched-word": { + backgroundColor: "$bgSecondaryAlt", + + fontFamily: "$file", + + padding: "0px 2px", + + borderRadius: 8, + + "&:hover": { + cursor: "pointer", + }, + + "& button.add-tag": { + position: "relative", + backgroundColor: "$successPrimary", + color: "$white", + padding: "2px 5px", + borderRadius: 8, + cursor: "pointer", + fontSize: "12px", + fontWeight: "heavy", + textAlign: "center", + top: "-10px", + right: "-5px", + border: "none", + }, + }, +}); diff --git a/frontend/src/renderer/src/styles/index.ts b/frontend/src/renderer/src/styles/index.ts new file mode 100644 index 00000000..91fd335d --- /dev/null +++ b/frontend/src/renderer/src/styles/index.ts @@ -0,0 +1,4 @@ +/** @deprecated Use Panda CSS instead. Import from `@/styled/css` or `@/styled/jsx`. */ +export * from "./stitches.config"; +/** @deprecated Global styles have been migrated to Panda CSS in `panda.config.ts`. */ +export * from "./globalStyles"; diff --git a/frontend/src/renderer/src/styles/stitches.config.ts b/frontend/src/renderer/src/styles/stitches.config.ts new file mode 100644 index 00000000..c4f34ce7 --- /dev/null +++ b/frontend/src/renderer/src/styles/stitches.config.ts @@ -0,0 +1,124 @@ +import { type CSS as CSSProp, createStitches } from "@stitches/react"; + +import * as tokens from "./tokens"; + +/** @deprecated Use Panda CSS instead. Import from `@/styled/css` or `@/styled/jsx`. */ +export const defaultTheme = createStitches({ + theme: { + colors: { + ...tokens.colors, + }, + fonts: tokens.fonts, + fontSizes: tokens.fontSizes, + fontWeights: tokens.fontWeights, + letterSpacings: {}, + lineHeights: tokens.lineHeights, + radii: tokens.radii, + shadows: {}, + sizes: tokens.sizes, + space: tokens.spaces, + transitions: tokens.transitions, + }, + utils: { + // ---------------- + // PADDINGS + // ---------------- + p: (value: number | string) => ({ + padding: value, + }), + pt: (value: number | string) => ({ + paddingTop: value, + }), + pr: (value: number | string) => ({ + paddingRight: value, + }), + pb: (value: number | string) => ({ + paddingBottom: value, + }), + pl: (value: number | string) => ({ + paddingLeft: value, + }), + px: (value: number | string) => ({ + paddingLeft: value, + paddingRight: value, + }), + py: (value: number | string) => ({ + paddingTop: value, + paddingBottom: value, + }), + + // ---------------- + // MARGINS + // ---------------- + m: (value: number | string) => ({ + margin: value, + }), + mt: (value: number | string) => ({ + marginTop: value, + }), + mr: (value: number | string) => ({ + marginRight: value, + }), + mb: (value: number | string) => ({ + marginBottom: value, + }), + ml: (value: number | string) => ({ + marginLeft: value, + }), + mx: (value: number | string) => ({ + marginLeft: value, + marginRight: value, + }), + my: (value: number | string) => ({ + marginTop: value, + marginBottom: value, + }), + + // ---------------- + // BORDER + // ---------------- + b: (value: string) => ({ + border: value, + }), + bt: (value: string) => ({ + borderTop: value, + }), + br: (value: string) => ({ + borderRight: value, + }), + bb: (value: string) => ({ + borderBottom: value, + }), + bl: (value: string) => ({ + borderLeft: value, + }), + bx: (value: string) => ({ + borderLeft: value, + borderRight: value, + }), + by: (value: string) => ({ + borderTop: value, + borderBottom: value, + }), + + // ---------------- + // BACKGROUND + // ---------------- + bg: (value: string) => ({ + backgroundColor: value, + }), + }, + media: { + sm: "(min-width: 640px)", + md: "(min-width: 768px)", + lg: "(min-width: 1024px)", + xl: "(min-width: 1280px)", + }, +}); + +/** @deprecated Use Panda CSS instead. Import from `@/styled/css` or `@/styled/jsx`. */ +export type CSS = CSSProp; + +/** @deprecated Use `styled` from `@/styled/jsx`. */ +export const { styled, globalCss, createTheme, theme, keyframes } = + defaultTheme; diff --git a/frontend/src/renderer/src/styles/tokens.ts b/frontend/src/renderer/src/styles/tokens.ts new file mode 100644 index 00000000..4adfa5c0 --- /dev/null +++ b/frontend/src/renderer/src/styles/tokens.ts @@ -0,0 +1,141 @@ +export const colors = { + // ---------------- + // BRAND + // + // Brand colors are used as base color of other elements or as color in image vectors + // ---------------- + primary: "#3F479D", + primaryAlt: "#E6E8FF", + secondary: "#C5CAFF", + tertiary: "#4A5568", + + // ---------------- + // ACTIONS + // ---------------- + actionDefault: "#C5CAFF", + actionDefaultAlt: "#3F479D", + actionHover: "#110041", + actionPressed: "#3F479D", + actionFocus: "#C5CAFF", + actionDisabled: "#E0DDE2", + + // ---------------- + // UI ELEMENTS + // ---------------- + textDefault: "#110041", + textLighter: "#625C68", + textOnButtonDefault: "#110041", + textOnButtonDisabled: "#2D3748", + textOnButtonAlternative: "#FFFFFF", + + bgPrimary: "#F6F5F7", + bgSecondary: "#FFFFFF", + bgSecondaryAlt: "#E0DDE2", + + borderPrimary: "#BCBAB8", + borderPrimaryAlt: "#110041", + borderSecondary: "#9F99A5", + bgSearch: "#FDFB00", + + // ---------------- + // FEEDBACK + // ---------------- + successPrimary: "#1B834E", + successSecondary: "#E0FAED", + + errorPrimary: "#DC582E", + errorSecondary: "#FFECE6", + + warningPrimary: "#F2BA2C", + warningSecondary: "#FFF7DB", + + infoPrimary: "#3F479D", + infoSecondary: "#F6F5F7", + + // ---------------- + // OTHERS + // ---------------- + white: "#FFFFFF", +}; + +export const fonts = { + primary: + '"Archivo", -apple-system, Helvetica Neue, Helvetica, Roboto, sans-serif', + file: '"Times New Roman", Times, serif', +}; + +export const fontSizes = { + titleMain: "64px", + titleMd: "32px", + + subtitleMd: "20px", + subtitleSm: "14px", + + paragraphsMd: "18px", + paragraphsSm: "16px", + paragraphsXsm: "10px", + + ctaMd: "16px", + ctaSm: "14px", + + labelMd: "16px", + labelSm: "12px", +}; + +export const fontWeights = { + default: 400, + strong: 600, + heavy: 800, +}; + +export const lineHeights = { + titleMain: "70px", + titleMd: "38px", + + subtitleMd: "24px", + subtitleSm: "17px", + + paragraphsMd: "27px", + paragraphsSm: "22px", + paragraphsXsm: "14px", + + ctaMd: "16px", + ctaSm: "16px", + + labelMd: "19px", + labelSm: "14px", +}; + +export const radii = { + xxl: "64px", + xl: "32px", + l: "24px", + m: "16px", + s: "8px", + xs: "4px", + xxs: "2px", +}; + +export const sizes = { + xxl: "64px", + xl: "32px", + l: "24px", + m: "16px", + s: "8px", + xs: "4px", + xxs: "2px", +}; + +export const spaces = { + xxl: "64px", + xl: "32px", + l: "24px", + m: "16px", + s: "8px", + xs: "4px", + xxs: "2px", +}; + +export const transitions = { + s: "250ms", +}; diff --git a/frontend/src/renderer/src/types/aymurai.ts b/frontend/src/renderer/src/types/aymurai.ts new file mode 100644 index 00000000..7289fe8f --- /dev/null +++ b/frontend/src/renderer/src/types/aymurai.ts @@ -0,0 +1,169 @@ +import type { SelectOption } from "@/components/ui/select"; + +// ------------ +// PREDICTION +// ------------ + +export type Workflows = "datapublic" | "anonymizer"; + +type LabelAttributes = { + aymurai_label: AllLabels | AllLabelsWithSufix; + aymurai_label_subclass: string[] | null; + aymurai_alt_text: string | null; + aymurai_alt_start_char: number | null; + aymurai_alt_end_char: number | null; + canonical_entity_id?: string | null; + aymurai_anonymize?: boolean | null; + aymurai_label_instance?: number | null; + aymurai_disambiguation?: string | null; +}; + +export type PredictLabel = { + /** Stable unique identifier assigned when the prediction is first created. */ + mentionId: string; + text: string; + aymurai_alt_text?: string; + start_char: number; + end_char: number; + attrs: LabelAttributes; + paragraphId: string; +}; + +export enum LabelType { + // INFO GRAL + N = "N", + NRO_REGISTRO = "NRO_REGISTRO", + TOMO = "TOMO", + FECHA_RESOLUCION = "FECHA_RESOLUCION", + N_EXPTE_EJE = "N_EXPTE_EJE", + FIRMA = "FIRMA", + + // DATOS DENUNCIANTE + GENERO_DENUNCIANTE = "GENERO_DENUNCIANTE", + NACIONALIDAD_DENUNCIANTE = "NACIONALIDAD_DENUNCIANTE", + EDAD_DENUNCIANTE = "EDAD_DENUNCIANTE", + NIVEL_INSTRUCCION_DENUNCIANTE = "NIVEL_INSTRUCCION_DENUNCIANTE", + + // DATOS ACUSADO + GENERO_ACUSADO = "GENERO_ACUSADO", + PERSONA_ACUSADA_NO_DETERMINADA = "PERSONA_ACUSADA_NO_DETERMINADA", + NACIONALIDAD_ACUSADO = "NACIONALIDAD_ACUSADO", + EDAD_ACUSADO = "EDAD_ACUSADO", + NIVEL_INSTRUCCION_ACUSADO = "NIVEL_INSTRUCCION_ACUSADO", +} +export enum LabelDecisiones { + // INFO HECHO + MATERIA = "MATERIA", + ART_INFRINGIDO = "ART_INFRINGIDO", + CODIGO_O_LEY = "CODIGO_O_LEY", + CONDUCTA = "CONDUCTA", + CONDUCTA_DESCRIPCION = "CONDUCTA_DESCRIPCION", + VIOLENCIA_DE_GENERO = "VIOLENCIA_DE_GENERO", + VIOLENCIA_DE_GENERO_SI = "VIOLENCIA_DE_GENERO_SI", + VIOLENCIA_DE_GENERO_NO = "VIOLENCIA_DE_GENERO_NO", + V_FISICA = "V_FISICA", + V_PSIC = "V_PSIC", + V_ECON = "V_ECON", + V_SEX = "V_SEX", + V_SOC = "V_SOC", + V_AMB = "V_AMB", + V_SIMB = "V_SIMB", + V_POLIT = "V_POLIT", + MODALIDAD_DE_LA_VIOLENCIA = "MODALIDAD_DE_LA_VIOLENCIA", + FRASES_AGRESION = "FRASES_AGRESION", + FRECUENCIA_EPISODIOS = "FRECUENCIA_EPISODIOS", + ZONA_DEL_HECHO = "ZONA_DEL_HECHO", + LUGAR_DEL_HECHO = "LUGAR_DEL_HECHO", + "RELACION_Y_TIPO_ENTRE_ACUSADO/A_Y_DENUNCIANTE" = "RELACION_Y_TIPO_ENTRE_ACUSADO/A_Y_DENUNCIANTE", + HIJOS_HIJAS_EN_COMUN = "HIJOS_HIJAS_EN_COMUN", + MEDIDAS_DE_PROTECCION_VIGENTES_AL_MOMENTO_DEL_HECHO = "MEDIDAS_DE_PROTECCION_VIGENTES_AL_MOMENTO_DEL_HECHO", + + // DECISION + TIPO_DE_RESOLUCION = "TIPO_DE_RESOLUCION", + OBJETO_DE_LA_RESOLUCION = "OBJETO_DE_LA_RESOLUCION", + DETALLE = "DETALLE", + DECISION = "DECISION", + TIPO_DE_AUDIENCIA_ORAL = "TIPO_DE_AUDIENCIA_ORAL", + TIPO_DE_AUDIENCIA_ESCRITA = "TIPO_DE_AUDIENCIA_ESCRITA", + HORA_DE_INICIO = "HORA_DE_INICIO", + HORA_DE_CIERRE = "HORA_DE_CIERRE", + DURACION = "DURACION", +} +export enum LabelAnonimizer { + PER = "PER", + USUARIX = "USUARIX", +} + +export type AllLabels = + | LabelType + | LabelDecisiones + | LabelAnonimizer + | AnonymizerLabels; +export type AllLabelsWithSufix = `${AllLabels}_${number}`; + +export const anonymizerLabels = [ + { id: "DNI", text: "DNI" }, + { id: "PER", text: "Persona" }, + { id: "TELEFONO", text: "Número de teléfono" }, + { id: "USUARIX", text: "Usuarix" }, + { id: "CORREO_ELECTRONICO", text: "Correo electrónico" }, + { id: "DENUNCIANTE", text: "Denunciante" }, + { id: "ACUSADO/A", text: "Acusado/a" }, + { id: "TESTIGO/A", text: "Testigo/a" }, + { id: "NIÑO/A_ADOSLECENTE", text: "Niño/a adolescente" }, + { id: "AFILIADO", text: "N° de afiliado" }, + { id: "CAUSA", text: "N° de causa" }, + { id: "INSTITUCION", text: "Nombre de institución" }, + { id: "BANCO", text: "Banco" }, + { id: "CBU", text: "Clave Bancaria Uniforme " }, + { + id: "CUIJ", + text: "Clave única de identificación judicial", + shortText: "CUIJ", + }, + { + id: "CUIT_CUIL", + text: "Código único de identificación laboral", + shortText: "CUIT/CUIL", + }, + { id: "DIRECCION", text: "Dirección" }, + { id: "LOC", text: "Localidad" }, + { id: "EDAD", text: "Edad" }, + { id: "ESTUDIOS", text: "Estudios" }, + { id: "FECHA", text: "Fecha" }, + { id: "IP", text: "Dirección IP" }, + { id: "LINK", text: "Link" }, + { id: "MARCA_AUTOMOVIL", text: "Marca automóvil" }, + { id: "NACIONALIDAD", text: "Nacionalidad" }, + { id: "NOMBRE_ARCHIVO", text: "Nombre de archivo" }, + { id: "NUM_ACTUACION", text: "Número actuación" }, + { id: "NUM_CAJA_AHORRO", text: "Número caja ahorro" }, + { id: "NUM_EXPEDIENTE", text: "Número expediente" }, + { id: "NUM_MATRICULA", text: "Número matrícula" }, + { id: "PATENTE_DOMINIO", text: "Patente dominio" }, + { id: "TEXTO_ANONIMIZAR", text: "Texto anonimizar" }, +] as const satisfies SelectOption[]; + +export type AnonymizerLabels = (typeof anonymizerLabels)[number]["id"]; + +// -------------------- +// DOCUMENT EXTRACTION +// -------------------- + +// TODO: wait for backend to define if the XML metadata property is required +// interface DocumentMetadata { +// start: number; +// end: number; +// fragments: { +// text: string; +// normalized_text: string; +// start: number; +// end: number; +// fragment_index: number; +// paragraph_index: number; +// }[]; +// } +// export interface DocumentParagraph { +// plain_text: string; +// // metadata?: DocumentMetadata; +// } diff --git a/frontend/src/renderer/src/types/component.ts b/frontend/src/renderer/src/types/component.ts new file mode 100644 index 00000000..28fa4280 --- /dev/null +++ b/frontend/src/renderer/src/types/component.ts @@ -0,0 +1,11 @@ +import type { ComponentPropsWithoutRef, ElementType } from "react"; + +/** + * Props for any 'native' component. 'style' prop is removed by default to enforce the use of Stitches + * @param T 'Tag' of the element + * @param K Any prop that should be omitted from the base tag + */ +export type NativeComponent< + T extends ElementType = "div", + K extends string = "", +> = Omit, "style" | K>; diff --git a/frontend/src/renderer/src/types/features.ts b/frontend/src/renderer/src/types/features.ts new file mode 100644 index 00000000..4d0471a1 --- /dev/null +++ b/frontend/src/renderer/src/types/features.ts @@ -0,0 +1,26 @@ +export enum FeatureFlowEnum { + Dataset = "DATA_SET", + Anonymizer = "ANONYMIZER", +} + +export const featureNamespace = { + [FeatureFlowEnum.Dataset]: "dataset", + [FeatureFlowEnum.Anonymizer]: "anonymizer", +} as const satisfies Record; + +export const featureRouteSlug = { + [FeatureFlowEnum.Dataset]: "data_set", + [FeatureFlowEnum.Anonymizer]: "anonymizer", +} as const satisfies Record; + +const FEATURE_BY_ROUTE_SLUG = Object.fromEntries( + Object.entries(featureRouteSlug).map(([feature, slug]) => [slug, feature]), +) as Record; + +export function parseFeatureRouteSlug(slug: string): FeatureFlowEnum | null { + return FEATURE_BY_ROUTE_SLUG[slug.toLowerCase()] ?? null; +} + +export function getFeatureRouteSlug(feature: FeatureFlowEnum): string { + return featureRouteSlug[feature]; +} diff --git a/frontend/src/renderer/src/types/feedback.ts b/frontend/src/renderer/src/types/feedback.ts new file mode 100644 index 00000000..36066444 --- /dev/null +++ b/frontend/src/renderer/src/types/feedback.ts @@ -0,0 +1,11 @@ +import type { PredictLabel } from "./aymurai"; +import type { Nullable } from "./utils"; + +/** + * Type for the object stored into the exported JSON file + */ +export type PredictionFeedback = Nullable< + PredictLabel & { + validationText: string | boolean; + } +>; diff --git a/frontend/src/renderer/src/types/file.ts b/frontend/src/renderer/src/types/file.ts new file mode 100644 index 00000000..d8bff845 --- /dev/null +++ b/frontend/src/renderer/src/types/file.ts @@ -0,0 +1,38 @@ +import type { FormData } from "@/hooks/useForm"; +import type { PredictLabel } from "./aymurai"; + +export interface Paragraph { + value: string; + id: string; + document_id: string; +} + +/** + * Type that defines the properties of a processed file + */ +export type DocFile = { + /** + * File contents + */ + data: File; + /** + * File paragraph data and their metadate + */ + paragraphs?: Paragraph[]; + /** + * Used on the 'preview' page to detect which files have to be processed + */ + selected: boolean; + /** + * Predictions made by the AI + */ + predictions?: PredictLabel[]; + /** + * Is the file validated by the validation form? This is toggled when the user clicks on the 'Validar documento' button + */ + validated?: boolean; + /** + * Data from the form + */ + validationObject: FormData; +}; diff --git a/frontend/src/renderer/src/types/react-query.d.ts b/frontend/src/renderer/src/types/react-query.d.ts new file mode 100644 index 00000000..4d996c21 --- /dev/null +++ b/frontend/src/renderer/src/types/react-query.d.ts @@ -0,0 +1,10 @@ +import "@tanstack/react-query"; + +declare module "@tanstack/react-query" { + interface Register { + mutationMeta: { + invalidates?: Array; + awaits?: boolean; + }; + } +} diff --git a/frontend/src/renderer/src/types/spreadsheet.ts b/frontend/src/renderer/src/types/spreadsheet.ts new file mode 100644 index 00000000..2634c8bd --- /dev/null +++ b/frontend/src/renderer/src/types/spreadsheet.ts @@ -0,0 +1,68 @@ +import type { FormValue } from "@/hooks/useForm"; + +/** + * Spreadsheet's unique identifier + */ +export type SpreadsheetId = string; + +/** + * Type of data that can be written to the dataset + */ +export type WriteValue = FormValue | null; + +/** + * Properties of the whole spreadsheet extracted from the metadata + */ +export type SpreadsheetProperties = { + title: string; + locale: string; + timeZone: string; +}; +/** + * Properties of a single sheet extracted from the metadata + */ +export type SheetProperties = { + properties: { + index: number; + sheetId: number; + sheetType: string; + title: string; + gridProperties: { + columnCount: number; + rowCount: number; + }; + }; +}; +/** + * Spreadsheet metadata + */ +export type SpreadsheetMetadata = { + spreadsheetId: SpreadsheetId; + spreadsheetUrl: string; + properties: SpreadsheetProperties; + sheets: SheetProperties[]; +}; + +/** + * Response from the `read` endpoint + */ +export type SpreadsheetRange = { + range: string; + majorDimension: string; + values?: string[][]; +}; + +/** + * Response from the `append` endpoint + */ +export type SpreadsheetAppend = { + spreadsheetId: SpreadsheetId; + tableRange: string; + updates: { + spreadsheetId: SpreadsheetId; + updatedRange: string; + updatedRows: number; + updatedColumns: number; + updatedCells: number; + }; +}; diff --git a/frontend/src/renderer/src/types/utils.ts b/frontend/src/renderer/src/types/utils.ts new file mode 100644 index 00000000..5cbe5fd3 --- /dev/null +++ b/frontend/src/renderer/src/types/utils.ts @@ -0,0 +1,32 @@ +/** + * ORs every type to a `null` recursively + */ +export type Nullable = T extends object + ? { + [K in keyof T]: Nullable; + } + : T; + +type Without = { + [P in Exclude]?: never; +}; +/** + * XOR + */ +export type XOR = T | U extends object + ? (Without & U) | (Without & T) + : T | U; + +/** + * Makes a single property of T optional + * @param T Type to analyze + * @param K keys of T that must be optional + */ +export type Optional = Omit & Partial>; + +/** + * The opposite of Optional. Makes a single property of T required + * @param T Type to analyze + * @param K keys of T that must be required + */ +export type Necessary = Omit & Required>; diff --git a/frontend/src/renderer/src/utils/anonymizer/__tests__/predictions.test.ts b/frontend/src/renderer/src/utils/anonymizer/__tests__/predictions.test.ts new file mode 100644 index 00000000..61c0ded7 --- /dev/null +++ b/frontend/src/renderer/src/utils/anonymizer/__tests__/predictions.test.ts @@ -0,0 +1,191 @@ +import type { AnonymizerLabels, PredictLabel } from "@/types/aymurai"; +import { describe, expect, it } from "vitest"; +import { + anonymizeQuerySignature, + filterActivePredictions, + isPredictionActive, +} from "../predictions"; + +// Minimal factory — only the fields the tested functions inspect +function makeLabel( + overrides: Partial & { label?: string; text?: string } = {}, +): PredictLabel { + const { label = "PERSONA", text = "Juan", ...rest } = overrides; + return { + mentionId: "mention-1", + paragraphId: "para-1", + text, + start_char: 0, + end_char: text.length, + attrs: { + aymurai_label: label as PredictLabel["attrs"]["aymurai_label"], + aymurai_label_subclass: null, + aymurai_alt_text: null, + aymurai_alt_start_char: null, + aymurai_alt_end_char: null, + canonical_entity_id: null, + aymurai_anonymize: null, + aymurai_label_instance: null, + aymurai_disambiguation: null, + }, + ...rest, + }; +} + +// A tag map where every label is enabled except FECHA +function tagsWithout(...excluded: AnonymizerLabels[]): Record { + // We only need to express the keys relevant to each test; cast is fine here + return Object.fromEntries( + excluded.map((tag) => [tag, false]), + ) as unknown as Record; +} + +// ──────────────────────────────────────────────────────────────────────────── +// isPredictionActive +// ──────────────────────────────────────────────────────────────────────────── +describe("isPredictionActive", () => { + it("returns false when the prediction's label is excluded", () => { + const label = makeLabel({ label: "FECHA" }); + expect( + isPredictionActive(label, tagsWithout("FECHA"), []), + ).toBe(false); + }); + + it("returns true when the prediction's label is not excluded", () => { + const label = makeLabel({ label: "PERSONA" }); + expect( + isPredictionActive(label, tagsWithout("FECHA"), []), + ).toBe(true); + }); + + it("returns false when the prediction's text is in excludedWords", () => { + const label = makeLabel({ text: "Juan" }); + expect( + isPredictionActive(label, null, ["Juan"]), + ).toBe(false); + }); + + it("returns true when neither label nor text is excluded", () => { + const label = makeLabel({ label: "PERSONA", text: "Maria" }); + expect(isPredictionActive(label, null, [])).toBe(true); + }); + + it("does NOT consider attrs.aymurai_anonymize — only excludedTags matters", () => { + // An entity stored with aymurai_anonymize: false from a previous session + // should be considered active once its tag is re-enabled. + const label = makeLabel({ + label: "FECHA", + ...{ attrs: { ...makeLabel({ label: "FECHA" }).attrs, aymurai_anonymize: false } }, + }); + // With FECHA now enabled (not in tagsWithout), the entity is active + expect(isPredictionActive(label, null, [])).toBe(true); + }); +}); + +// ──────────────────────────────────────────────────────────────────────────── +// filterActivePredictions +// ──────────────────────────────────────────────────────────────────────────── +describe("filterActivePredictions", () => { + it("keeps active predictions and removes excluded-label ones", () => { + const persona = makeLabel({ label: "PERSONA", mentionId: "m-1" }); + const fecha = makeLabel({ label: "FECHA", mentionId: "m-2" }); + + const result = filterActivePredictions( + [persona, fecha], + tagsWithout("FECHA"), + [], + ); + + expect(result).toHaveLength(1); + expect(result[0].mentionId).toBe("m-1"); + }); + + it("returns all predictions when excludedTags is null (default config)", () => { + const labels = [ + makeLabel({ label: "PERSONA", mentionId: "m-1" }), + makeLabel({ label: "FECHA", mentionId: "m-2" }), + ]; + + // null means "use defaults" — in tests we just check the count is ≤ total + const result = filterActivePredictions(labels, null, []); + expect(result.length).toBeGreaterThanOrEqual(0); + expect(result.length).toBeLessThanOrEqual(labels.length); + }); + + it("treats undefined predictions as empty array", () => { + expect(filterActivePredictions(undefined, null, [])).toEqual([]); + }); +}); + +// ──────────────────────────────────────────────────────────────────────────── +// anonymizeQuerySignature +// ──────────────────────────────────────────────────────────────────────────── +describe("anonymizeQuerySignature", () => { + const persona = makeLabel({ label: "PERSONA", mentionId: "m-1" }); + const fecha = makeLabel({ + label: "FECHA", + mentionId: "m-2", + // attrs with aymurai_anonymize already set to false from a previous session + ...{ + attrs: { + ...makeLabel({ label: "FECHA" }).attrs, + canonical_entity_id: "canonical-2", + }, + }, + }); + + it("includes ALL predictions, not just active ones", () => { + const result = anonymizeQuerySignature( + [persona, fecha], + tagsWithout("FECHA"), + [], + ); + expect(result).toHaveLength(2); + }); + + it("fingerprints excluded predictions with false", () => { + const [, fechaFingerprint] = anonymizeQuerySignature( + [persona, fecha], + tagsWithout("FECHA"), + [], + ); + expect(fechaFingerprint).toContain("false"); + expect(fechaFingerprint).not.toContain("true"); + }); + + it("fingerprints active predictions with true", () => { + const [personaFingerprint] = anonymizeQuerySignature( + [persona, fecha], + tagsWithout("FECHA"), + [], + ); + expect(personaFingerprint).toContain("true"); + }); + + it("the signature changes when a tag is excluded vs enabled", () => { + const sigWithFechaEnabled = anonymizeQuerySignature([persona, fecha], null, []); + const sigWithFechaExcluded = anonymizeQuerySignature( + [persona, fecha], + tagsWithout("FECHA"), + [], + ); + expect(sigWithFechaEnabled).not.toEqual(sigWithFechaExcluded); + }); + + it("fingerprints word-excluded predictions with false", () => { + const juan = makeLabel({ text: "Juan", mentionId: "m-juan" }); + const [sig] = anonymizeQuerySignature([juan], null, ["Juan"]); + expect(sig).toContain("false"); + }); + + it("the signature changes when a word is added to excludedWords", () => { + const label = makeLabel({ text: "Juan" }); + const sigBefore = anonymizeQuerySignature([label], null, []); + const sigAfter = anonymizeQuerySignature([label], null, ["Juan"]); + expect(sigBefore).not.toEqual(sigAfter); + }); + + it("returns empty array for undefined predictions", () => { + expect(anonymizeQuerySignature(undefined, null, [])).toEqual([]); + }); +}); diff --git a/frontend/src/renderer/src/utils/anonymizer/entity-similarity.ts b/frontend/src/renderer/src/utils/anonymizer/entity-similarity.ts new file mode 100644 index 00000000..91ddefcd --- /dev/null +++ b/frontend/src/renderer/src/utils/anonymizer/entity-similarity.ts @@ -0,0 +1,227 @@ +export interface EntityMentionDraft { + text: string; + normalizedText?: string; + label: string; + paragraphId?: string; + start_char?: number; + end_char?: number; +} + +export interface SimilarityOptions { + threshold?: number; + maxCandidates?: number; +} + +export interface EntityGroupForSimilarity { + canonicalId: string; + renderBase: string; + renderToken: string; + uniqueTexts: string[]; + displayTexts: string[][]; + firstAppearance: { paragraphIndex: number; start_char: number }; +} + +export interface SimilarEntityGroupCandidate { + group: EntityGroupForSimilarity; + score: number; + labelMatches: boolean; + matchedText: string; +} + +export type ManualEntityResolution = + | { type: "existing"; candidate: SimilarEntityGroupCandidate } + | { type: "new" }; + +const DEFAULT_THRESHOLD = 80; +const DEFAULT_MAX_CANDIDATES = 5; +const FIRST_COMBINING_MARK = 0x0300; +const LAST_COMBINING_MARK = 0x036f; + +export function stripEntityLabelSuffix(label: string): string { + return label.replace(/_\d+$/, ""); +} + +export function normalizeEntityText(text: string): string { + const withoutDiacritics = Array.from(text.normalize("NFD")) + .filter((char) => { + const code = char.charCodeAt(0); + return code < FIRST_COMBINING_MARK || code > LAST_COMBINING_MARK; + }) + .join(""); + + return withoutDiacritics + .normalize("NFD") + .toLowerCase() + .replace(/[^a-z0-9]+/g, " ") + .trim() + .replace(/\s+/g, " "); +} + +function tokenize(text: string): string[] { + const normalized = normalizeEntityText(text); + if (!normalized) return []; + return [...new Set(normalized.split(" "))].sort(); +} + +function levenshteinRatio(a: string, b: string): number { + if (a === b) return 100; + if (!a || !b) return 0; + + const previous = Array.from({ length: b.length + 1 }, (_, i) => i); + const current = new Array(b.length + 1); + + for (let i = 1; i <= a.length; i += 1) { + current[0] = i; + for (let j = 1; j <= b.length; j += 1) { + const cost = a[i - 1] === b[j - 1] ? 0 : 1; + current[j] = Math.min( + current[j - 1] + 1, + previous[j] + 1, + previous[j - 1] + cost, + ); + } + previous.splice(0, previous.length, ...current); + } + + const distance = previous[b.length] ?? 0; + return Math.round((1 - distance / Math.max(a.length, b.length)) * 100); +} + +function bigrams(text: string): string[] { + if (text.length <= 1) return text ? [text] : []; + const result: string[] = []; + for (let i = 0; i < text.length - 1; i += 1) { + result.push(text.slice(i, i + 2)); + } + return result; +} + +function bigramRatio(a: string, b: string): number { + if (a === b) return 100; + if (!a || !b) return 0; + + const aBigrams = bigrams(a); + const bBigrams = bigrams(b); + const counts = new Map(); + for (const gram of aBigrams) counts.set(gram, (counts.get(gram) ?? 0) + 1); + + let overlap = 0; + for (const gram of bBigrams) { + const count = counts.get(gram) ?? 0; + if (count > 0) { + overlap += 1; + counts.set(gram, count - 1); + } + } + + return Math.round((2 * overlap * 100) / (aBigrams.length + bBigrams.length)); +} + +function stringRatio(a: string, b: string): number { + return Math.max(levenshteinRatio(a, b), bigramRatio(a, b)); +} + +function sortedTokenText(tokens: string[]): string { + return tokens.join(" "); +} + +export function computeEntitySimilarity(a: string, b: string): number { + const aTokens = tokenize(a); + const bTokens = tokenize(b); + + if (aTokens.length === 0 || bTokens.length === 0) return 0; + + const aSet = new Set(aTokens); + const bSet = new Set(bTokens); + const intersection = aTokens.filter((token) => bSet.has(token)); + const diffA = aTokens.filter((token) => !bSet.has(token)); + const diffB = bTokens.filter((token) => !aSet.has(token)); + + const intersectionText = sortedTokenText(intersection); + const combinedA = sortedTokenText([...intersection, ...diffA].sort()); + const combinedB = sortedTokenText([...intersection, ...diffB].sort()); + + if (!intersectionText) return stringRatio(combinedA, combinedB); + + return Math.max( + stringRatio(intersectionText, combinedA), + stringRatio(intersectionText, combinedB), + stringRatio(combinedA, combinedB), + ); +} + +interface GroupCandidateText { + comparisonText: string; + displayText: string; +} + +function groupCandidateTexts( + group: EntityGroupForSimilarity, +): GroupCandidateText[] { + const texts: GroupCandidateText[] = []; + const seenDisplayTexts = new Set(); + + group.uniqueTexts.forEach((uniqueText, index) => { + const verbatims = group.displayTexts[index] ?? []; + + if (verbatims.length === 0) { + texts.push({ comparisonText: uniqueText, displayText: uniqueText }); + return; + } + + for (const verbatim of verbatims) { + if (seenDisplayTexts.has(verbatim)) continue; + seenDisplayTexts.add(verbatim); + texts.push({ comparisonText: verbatim, displayText: verbatim }); + } + }); + + return texts; +} + +export function findSimilarEntityGroups( + newMention: EntityMentionDraft, + groups: EntityGroupForSimilarity[], + options: SimilarityOptions = {}, +): SimilarEntityGroupCandidate[] { + const threshold = options.threshold ?? DEFAULT_THRESHOLD; + const maxCandidates = options.maxCandidates ?? DEFAULT_MAX_CANDIDATES; + const selectedLabel = stripEntityLabelSuffix(newMention.label); + const mentionText = newMention.normalizedText ?? newMention.text; + + const candidates = groups + .map((group) => { + let bestScore = 0; + let bestText = ""; + + for (const text of groupCandidateTexts(group)) { + const score = computeEntitySimilarity(mentionText, text.comparisonText); + if (score > bestScore) { + bestScore = score; + bestText = text.displayText; + } + } + + return { + group, + score: bestScore, + labelMatches: + selectedLabel === stripEntityLabelSuffix(String(group.renderBase)), + matchedText: bestText, + } satisfies SimilarEntityGroupCandidate; + }) + .filter((candidate) => candidate.score >= threshold); + + return candidates + .sort((a, b) => { + if (b.score !== a.score) return b.score - a.score; + if (a.labelMatches !== b.labelMatches) return a.labelMatches ? -1 : 1; + const aFirst = a.group.firstAppearance; + const bFirst = b.group.firstAppearance; + if (aFirst.paragraphIndex !== bFirst.paragraphIndex) { + return aFirst.paragraphIndex - bFirst.paragraphIndex; + } + return aFirst.start_char - bFirst.start_char; + }) + .slice(0, maxCandidates); +} diff --git a/frontend/src/renderer/src/utils/anonymizer/export-validation.ts b/frontend/src/renderer/src/utils/anonymizer/export-validation.ts new file mode 100644 index 00000000..ee042f80 --- /dev/null +++ b/frontend/src/renderer/src/utils/anonymizer/export-validation.ts @@ -0,0 +1,285 @@ +import type { PredictLabel } from "@/types/aymurai"; +import type { DocFile, Paragraph } from "@/types/file"; +import { stripEntityLabelSuffix } from "./entity-similarity"; + +type ExportValidationIssueCode = + | "missing_offsets" + | "invalid_range" + | "paragraph_not_found" + | "range_out_of_bounds" + | "text_mismatch" + | "missing_canonical_entity_id" + | "duplicate_range" + | "overlapping_range" + | "mixed_group_labels"; + +export interface ExportEntityDebugInfo { + entityId: string; + canonicalEntityId: string | null; + label: string; + start: number | null; + end: number | null; + text: string; + source: "manual" | "automatic"; + groupId: string | null; + isDeleted: boolean; + isManual: boolean; + paragraphId: string; +} + +export interface ExportValidationIssue { + code: ExportValidationIssueCode; + message: string; + entity: ExportEntityDebugInfo; + relatedEntity?: ExportEntityDebugInfo; +} + +export class AnonymizerExportValidationError extends Error { + issues: ExportValidationIssue[]; + + constructor(issues: ExportValidationIssue[]) { + super( + "No se puede exportar: hay entidades con offsets inválidos, duplicados o solapados.", + ); + this.name = "AnonymizerExportValidationError"; + this.issues = issues; + } +} + +function buildDebugInfo(prediction: PredictLabel): ExportEntityDebugInfo { + const isManual = !prediction.attrs.aymurai_disambiguation; + return { + entityId: prediction.mentionId, + canonicalEntityId: prediction.attrs.canonical_entity_id ?? null, + label: String(prediction.attrs.aymurai_label), + start: Number.isFinite(prediction.start_char) + ? prediction.start_char + : null, + end: Number.isFinite(prediction.end_char) ? prediction.end_char : null, + text: prediction.text, + source: isManual ? "manual" : "automatic", + groupId: prediction.attrs.canonical_entity_id ?? null, + isDeleted: false, + isManual, + paragraphId: prediction.paragraphId, + }; +} + +function issue( + code: ExportValidationIssueCode, + message: string, + entity: PredictLabel, + relatedEntity?: PredictLabel, +): ExportValidationIssue { + return { + code, + message, + entity: buildDebugInfo(entity), + ...(relatedEntity && { relatedEntity: buildDebugInfo(relatedEntity) }), + }; +} + +function paragraphById(file: DocFile): Map { + return new Map( + (file.paragraphs ?? []).map((paragraph) => [paragraph.id, paragraph]), + ); +} + +function validateGroupLabels(labels: PredictLabel[]): ExportValidationIssue[] { + const issues: ExportValidationIssue[] = []; + const groupLabels = new Map(); + + for (const label of labels) { + const canonicalId = label.attrs.canonical_entity_id; + if (!canonicalId) continue; + + const baseLabel = stripEntityLabelSuffix(String(label.attrs.aymurai_label)); + const existing = groupLabels.get(canonicalId); + if (!existing) { + groupLabels.set(canonicalId, { label: baseLabel, first: label }); + continue; + } + + if (existing.label !== baseLabel) { + issues.push( + issue( + "mixed_group_labels", + `El grupo ${canonicalId} contiene labels incompatibles: ${existing.label} y ${baseLabel}.`, + label, + existing.first, + ), + ); + } + } + + return issues; +} + +function validateParagraphRanges( + paragraph: Paragraph, + labels: PredictLabel[], +): ExportValidationIssue[] { + const issues: ExportValidationIssue[] = []; + const sorted = [...labels].sort((a, b) => { + if (a.start_char !== b.start_char) return a.start_char - b.start_char; + return b.end_char - a.end_char; + }); + const rangeOwners = new Map(); + let previous: PredictLabel | null = null; + + for (const label of sorted) { + const key = `${label.start_char}:${label.end_char}`; + const duplicate = rangeOwners.get(key); + if (duplicate) { + issues.push( + issue( + "duplicate_range", + `Hay más de una entidad activa en el rango ${key}.`, + label, + duplicate, + ), + ); + } else { + rangeOwners.set(key, label); + } + + const textAtRange = paragraph.value.slice(label.start_char, label.end_char); + if (textAtRange !== label.text) { + issues.push( + issue( + "text_mismatch", + "El texto de la entidad no coincide con el texto original en sus offsets.", + label, + ), + ); + } + + if (previous && label.start_char < previous.end_char) { + issues.push( + issue( + "overlapping_range", + "Hay entidades activas con rangos solapados.", + label, + previous, + ), + ); + } + + if (!previous || label.end_char > previous.end_char) previous = label; + } + + return issues; +} + +export function validateAnonymizerExportState( + file: DocFile, + labels: PredictLabel[], +): ExportValidationIssue[] { + const issues: ExportValidationIssue[] = []; + const paragraphs = paragraphById(file); + const labelsByParagraph = new Map(); + + for (const label of labels) { + const paragraph = paragraphs.get(label.paragraphId); + + if ( + !Number.isFinite(label.start_char) || + !Number.isFinite(label.end_char) + ) { + issues.push( + issue("missing_offsets", "La entidad no tiene offsets válidos.", label), + ); + continue; + } + + if (label.start_char >= label.end_char) { + issues.push( + issue( + "invalid_range", + "La entidad tiene start mayor o igual a end.", + label, + ), + ); + continue; + } + + if (!paragraph) { + issues.push( + issue( + "paragraph_not_found", + "La entidad apunta a un párrafo inexistente.", + label, + ), + ); + continue; + } + + if (label.start_char < 0 || label.end_char > paragraph.value.length) { + issues.push( + issue( + "range_out_of_bounds", + "La entidad tiene offsets fuera del texto original.", + label, + ), + ); + continue; + } + + if (!label.attrs.canonical_entity_id) { + issues.push( + issue( + "missing_canonical_entity_id", + "La entidad activa no tiene canonical_entity_id.", + label, + ), + ); + } + + const paragraphLabels = labelsByParagraph.get(label.paragraphId) ?? []; + paragraphLabels.push(label); + labelsByParagraph.set(label.paragraphId, paragraphLabels); + } + + for (const [paragraphId, paragraphLabels] of labelsByParagraph) { + const paragraph = paragraphs.get(paragraphId); + if (!paragraph) continue; + issues.push(...validateParagraphRanges(paragraph, paragraphLabels)); + } + + issues.push(...validateGroupLabels(labels)); + + return issues; +} + +export function assertValidAnonymizerExportState( + file: DocFile, + labels: PredictLabel[], +) { + const issues = validateAnonymizerExportState(file, labels); + if (issues.length === 0) return; + + // Group issues by code so a quick console.table() is readable. + const byCode = issues.reduce>((acc, i) => { + acc[i.code] = (acc[i.code] ?? 0) + 1; + return acc; + }, {}); + console.error("Invalid anonymizer export annotations", { + fileName: file.data.name, + issueSummary: byCode, + issues, + }); + console.table( + issues.map((i) => ({ + code: i.code, + paragraphId: + i.entity.paragraphId.length > 40 + ? `${i.entity.paragraphId.slice(0, 40)}…` + : i.entity.paragraphId, + label: i.entity.label, + start: i.entity.start, + end: i.entity.end, + text: i.entity.text, + })), + ); + throw new AnonymizerExportValidationError(issues); +} diff --git a/frontend/src/renderer/src/utils/anonymizer/labels.ts b/frontend/src/renderer/src/utils/anonymizer/labels.ts new file mode 100644 index 00000000..d454502a --- /dev/null +++ b/frontend/src/renderer/src/utils/anonymizer/labels.ts @@ -0,0 +1,10 @@ +import type { SelectOption } from "@/components/ui/select"; +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; +import { type AnonymizerLabels, anonymizerLabels } from "@/types/aymurai"; + +export function getActiveAnonymizerLabelOptions( + excludedTags: Record | null, +): SelectOption[] { + const effectiveTags = excludedTags ?? EXCLUDED_TAGS; + return anonymizerLabels.filter((label) => effectiveTags[label.id] !== false); +} diff --git a/frontend/src/renderer/src/utils/anonymizer/occurrences.ts b/frontend/src/renderer/src/utils/anonymizer/occurrences.ts new file mode 100644 index 00000000..43aa22ed --- /dev/null +++ b/frontend/src/renderer/src/utils/anonymizer/occurrences.ts @@ -0,0 +1,74 @@ +import { normalizeEntityText } from "./entity-similarity"; + +export interface NormalizedOccurrenceRange { + start: number; + end: number; + text: string; + normalizedText: string; +} + +interface NormalizedToken { + start: number; + end: number; + normalizedText: string; +} + +const TOKEN_REGEX = /[\p{L}\p{N}]+/gu; + +function normalizedTokens(text: string): NormalizedToken[] { + const tokens: NormalizedToken[] = []; + + for (const match of text.matchAll(TOKEN_REGEX)) { + const source = match[0]; + const start = match.index ?? 0; + const normalizedText = normalizeEntityText(source); + if (!normalizedText) continue; + + tokens.push({ + start, + end: start + source.length, + normalizedText, + }); + } + + return tokens; +} + +export function isNormalizedTextMatch(a: string, b: string): boolean { + const normalizedA = normalizeEntityText(a); + return normalizedA !== "" && normalizedA === normalizeEntityText(b); +} + +export function findNormalizedOccurrenceRanges( + text: string, + search: string, +): NormalizedOccurrenceRange[] { + const normalizedSearch = normalizeEntityText(search); + if (!normalizedSearch) return []; + + const searchTokens = normalizedSearch.split(" "); + const tokens = normalizedTokens(text); + const ranges: NormalizedOccurrenceRange[] = []; + + for (let i = 0; i <= tokens.length - searchTokens.length; i += 1) { + const candidate = tokens.slice(i, i + searchTokens.length); + const candidateText = candidate + .map((token) => token.normalizedText) + .join(" "); + + if (candidateText !== normalizedSearch) continue; + + const start = candidate[0]?.start; + const end = candidate.at(-1)?.end; + if (start === undefined || end === undefined) continue; + + ranges.push({ + start, + end, + text: text.slice(start, end), + normalizedText: normalizedSearch, + }); + } + + return ranges; +} diff --git a/frontend/src/renderer/src/utils/anonymizer/predictions.ts b/frontend/src/renderer/src/utils/anonymizer/predictions.ts new file mode 100644 index 00000000..2ab3fc84 --- /dev/null +++ b/frontend/src/renderer/src/utils/anonymizer/predictions.ts @@ -0,0 +1,73 @@ +import { EXCLUDED_TAGS } from "@/constants/excluded-tags"; +import { + type AnonymizerLabels, + type PredictLabel, + anonymizerLabels, +} from "@/types/aymurai"; +import { + normalizeEntityText, + stripEntityLabelSuffix, +} from "./entity-similarity"; + +const ANONYMIZER_LABEL_IDS = new Set( + anonymizerLabels.map((label) => label.id), +); + +export function stripLabelSuffix(label: string): string { + return stripEntityLabelSuffix(label); +} + +function getAnonymizerLabelId(label: string): AnonymizerLabels | null { + const baseLabel = stripLabelSuffix(label); + return ANONYMIZER_LABEL_IDS.has(baseLabel) + ? (baseLabel as AnonymizerLabels) + : null; +} + +export function isPredictionActive( + prediction: PredictLabel, + excludedTags: Record | null, + excludedWords: string[], +): boolean { + const effectiveTags = excludedTags ?? EXCLUDED_TAGS; + const labelId = getAnonymizerLabelId(String(prediction.attrs.aymurai_label)); + + if (labelId !== null && effectiveTags[labelId] === false) return false; + + const predictionText = normalizeEntityText(prediction.text); + return !excludedWords.some( + (word) => normalizeEntityText(word) === predictionText, + ); +} + +export function filterActivePredictions( + predictions: PredictLabel[] | undefined, + excludedTags: Record | null, + excludedWords: string[], +): PredictLabel[] { + return (predictions ?? []).filter((prediction) => + isPredictionActive(prediction, excludedTags, excludedWords), + ); +} + +export function anonymizeQuerySignature( + predictions: PredictLabel[] | undefined, + excludedTags: Record | null, + excludedWords: string[], +): string[] { + // Include ALL predictions (active and excluded) so the cache key changes + // whenever an exclusion is toggled, and excluded entities appear in the key + // with aymurai_anonymize: false rather than being silently omitted. + return (predictions ?? []).map((prediction) => + [ + prediction.mentionId, + prediction.paragraphId, + prediction.start_char, + prediction.end_char, + prediction.text, + prediction.attrs.aymurai_label, + prediction.attrs.canonical_entity_id ?? "", + isPredictionActive(prediction, excludedTags, excludedWords), + ].join("\u001f"), + ); +} diff --git a/frontend/src/renderer/src/utils/config.ts b/frontend/src/renderer/src/utils/config.ts new file mode 100644 index 00000000..6c076073 --- /dev/null +++ b/frontend/src/renderer/src/utils/config.ts @@ -0,0 +1,13 @@ +import { FeatureFlowEnum } from "@/types/features"; +import { Database, Detective, type Icon } from "phosphor-react"; + +/** + * Dataset Spreadsheet + */ +export const DATASET_URL = + "https://docs.google.com/spreadsheets/d/1pzaGNM5BzRAOlj8p0NYtxnkU4VI_X5UcQsnIMOtLSVY/edit#gid=257379348"; + +export const FEATURE_ICON: Record = { + [FeatureFlowEnum.Dataset]: Database, + [FeatureFlowEnum.Anonymizer]: Detective, +}; diff --git a/frontend/src/renderer/src/utils/file/__tests__/preview-files.test.ts b/frontend/src/renderer/src/utils/file/__tests__/preview-files.test.ts new file mode 100644 index 00000000..2c6ee85d --- /dev/null +++ b/frontend/src/renderer/src/utils/file/__tests__/preview-files.test.ts @@ -0,0 +1,25 @@ +import { FeatureFlowEnum } from "@/types/features"; +import { describe, expect, it } from "vitest"; +import { filesForFeatureLoad } from "../preview-files"; + +function makeFile(name: string): File { + return new File(["content"], name, { + type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + }); +} + +describe("filesForFeatureLoad", () => { + it("keeps only the newest file for anonymizer", () => { + const files = [makeFile("old.docx"), makeFile("new.docx")]; + + expect(filesForFeatureLoad(FeatureFlowEnum.Anonymizer, files)).toEqual([ + files[1], + ]); + }); + + it("keeps all files for dataset", () => { + const files = [makeFile("first.docx"), makeFile("second.docx")]; + + expect(filesForFeatureLoad(FeatureFlowEnum.Dataset, files)).toEqual(files); + }); +}); diff --git a/frontend/src/renderer/src/utils/file/excelStructure.ts b/frontend/src/renderer/src/utils/file/excelStructure.ts new file mode 100644 index 00000000..9a36334c --- /dev/null +++ b/frontend/src/renderer/src/utils/file/excelStructure.ts @@ -0,0 +1,72 @@ +/** + * Columns order extracted from the original dataset spreadsheet + */ +const excelStructure = [ + "N", + "NRO_REGISTRO", + "TOMO", + "FECHA_RESOLUCION", + "N_EXPTE_EJE", + "FIRMA", + "MATERIA", + "ART_INFRINGIDO", + "CODIGO_O_LEY", + "CONDUCTA", + "CONDUCTA_DESCRIPCION", + "VIOLENCIA_DE_GENERO", + "V_FISICA", + "V_PSIC", + "V_ECON", + "V_SEX", + "V_SOC", + "V_AMB", + "V_SIMB", + "V_POLIT", + "MODALIDAD_DE_LA_VIOLENCIA", + "FRASES_AGRESION", + "GENERO_ACUSADO", + "PERSONA_ACUSADA_NO_DETERMINADA", + "NACIONALIDAD_ACUSADO", + "EDAD_ACUSADO", + "NIVEL_INSTRUCCION_ACUSADO", + "GENERO_DENUNCIANTE", + "NACIONALIDAD_DENUNCIANTE", + "EDAD_DENUNCIANTE", + "NIVEL_INSTRUCCION_DENUNCIANTE", + "FRECUENCIA_EPISODIOS", + "RELACION_Y_TIPO_ENTRE_ACUSADO_Y_DENUNCIANTE", + "HIJOS_HIJAS_EN_COMUN", + "MEDIDAS_DE_PROTECCION_VIGENTES_AL_MOMENTO_DEL_HECHO", + "ZONA_DEL_HECHO", + "LUGAR_DEL_HECHO", + "TIPO_DE_RESOLUCION", + "OBJETO_DE_LA_RESOLUCION", + "DETALLE", + "DECISION", + "ORAL_ESCRITA", + "HORA_DE_INICIO", + "HORA_DE_CIERRE", + "DURACION", + "LINK", + "SI_NO_RECURRENTE", + "DECISION_CAMARA_DE_APELACIONES", + "N_REGISTRO_Y_TOMO_CAMARA", + "LINK_CAMARA", + "SI_NO_RECURRENTE_CAMARA", + "DECISION_DE_ADMISIBILIDAD_CAMARA", + "N_REGISTRO_Y_TOMO_CAMARA_1", + "LINK_CAMARA_1", + "QUEJA_Y_RECURRENTE", + "DECISION_DE_ADMISIBILIDAD_TSJ", + "N_REGISTRO_Y_TOMO_TSJ", + "LINK_TSJ", + "DECISION_DE_FONDO_TSJ", + "N_REGISTRO_Y_TOMO_TSJ_1", + "LINK_TSJ_1", + "RECURSO_EXTRAORDINARIO_Y_RECURRENTE", + "DECISION_CSJN", + "N_REGISTRO_Y_TOMO_CSJN", + "LINK_CSJN", +] as const; + +export default excelStructure; diff --git a/frontend/src/renderer/src/utils/file/filterEmptyDecisions.ts b/frontend/src/renderer/src/utils/file/filterEmptyDecisions.ts new file mode 100644 index 00000000..4e6f0255 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/filterEmptyDecisions.ts @@ -0,0 +1,31 @@ +import type { FormData } from "@/hooks/useForm"; + +type Decision = Exclude[number]; + +/** + * Checks for the contents of a `Decision` + * @param decision Decision to analyze + * @returns `true` if the decision is empty, `false otherwise` + */ +function isDecisionEmpty(decision: Decision) { + const copy = { ...decision }; + + // Loop through the object, deleting undefined entries + for (const key in copy) { + if (!copy[key as keyof typeof copy]) delete copy[key as keyof typeof copy]; + } + + return !Object.keys(copy).length; +} + +/** + * Filters the decisions array to remove any empty decision + * @param decisions `Decision[]` to analyze + * @returns A filtered array of the original `Decision[]` + */ +export default function filterEmptyDecisions( + decisions: Decision[] | undefined, +) { + if (decisions) return decisions.filter((dec) => !isDecisionEmpty(dec)); + return []; +} diff --git a/frontend/src/renderer/src/utils/file/flatValidation.ts b/frontend/src/renderer/src/utils/file/flatValidation.ts new file mode 100644 index 00000000..e6bc96f7 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/flatValidation.ts @@ -0,0 +1,43 @@ +import type { FlatFormData } from "@/hooks/useForm"; +import type { DocFile } from "@/types/file"; +import filterEmptyDecisions from "./filterEmptyDecisions"; + +/** + * This method flattens the `DECISIONES` array inside the `validationObject` so we have as result an array of `FormData` + * @example + * // BEFORE: + * // validation = { + * // ..., + * // DECISIONES: [{...}], + * // } + * + * flatValidation(object); + * // AFTER: + * // validation = [ + * // {...}, + * // ] + * + * @param validation Object to flatten + * @returns An array of flat formatted `FormData` + */ +export default function flatValidation( + validation: DocFile["validationObject"], +): FlatFormData[] { + // Set a default value for the `DECISIONES` array + const decisiones = filterEmptyDecisions(validation.DECISIONES); + + // Make a copy of the whole object, removing the `DECISIONES` key + const copy = { ...validation }; + delete copy.DECISIONES; + + if (decisiones.length > 0) { + // For each decision made, return the whole validation object plus the current decision + return decisiones.map((dec) => ({ + ...dec, + ...copy, + })); + } + + // We have no decision, just return the copy (without the `DECISIONES` array) + return [copy]; +} diff --git a/frontend/src/renderer/src/utils/file/getByName.ts b/frontend/src/renderer/src/utils/file/getByName.ts new file mode 100644 index 00000000..32832afe --- /dev/null +++ b/frontend/src/renderer/src/utils/file/getByName.ts @@ -0,0 +1,11 @@ +import type { DocFile } from "@/types/file"; + +/** + * Searches for a specific `DocFile` into an array or state of files + * @param fileName File to be searched into the array + * @param files Array or state of `DocFiles` + * @returns The `DocFile` with the given name + */ +export default function getByName(fileName: string, files: DocFile[]) { + return files.find(({ data }) => data.name === fileName); +} diff --git a/frontend/src/renderer/src/utils/file/getExtension.ts b/frontend/src/renderer/src/utils/file/getExtension.ts new file mode 100644 index 00000000..e06f786f --- /dev/null +++ b/frontend/src/renderer/src/utils/file/getExtension.ts @@ -0,0 +1,8 @@ +/** + * Extracts the extension of the given file + * @param file File to extract its extension + * @returns Extension string of the file (formatted as `doc | docx`) + */ +export default function getExtension(file: File) { + return file.name.split(".").at(-1); +} diff --git a/frontend/src/renderer/src/utils/file/getParagraphId.ts b/frontend/src/renderer/src/utils/file/getParagraphId.ts new file mode 100644 index 00000000..1e71975d --- /dev/null +++ b/frontend/src/renderer/src/utils/file/getParagraphId.ts @@ -0,0 +1,27 @@ +import RegexEscape from "regex-escape"; +/** + * Hashes a word using _base64_ encoding. + * @param word The word to be hashed. + * @returns A `string` representing the hashed word. + */ +const hash = (word: string) => { + try { + return window.btoa(RegexEscape(word)); + } catch (e) { + console.error("Error parsing word:", word); + console.error(e); + return "err"; + } +}; + +/** + * Generates a string ready to be used as an ID by splitting and hashing the paragraph. + * @param paragraph Paragraph to be hashed. + * @param index Index of the paragraph in the array. + * @returns A `string` representing the hashed paragraph. + */ +export const getParagraphId = (paragraph: string, index: number) => { + const start = paragraph.slice(0, 15); + const end = paragraph.slice(-15); + return `${index}-${hash(start + end).slice(0, 30)}`; +}; diff --git a/frontend/src/renderer/src/utils/file/index.ts b/frontend/src/renderer/src/utils/file/index.ts new file mode 100644 index 00000000..a5e2c42f --- /dev/null +++ b/frontend/src/renderer/src/utils/file/index.ts @@ -0,0 +1,21 @@ +import excelStructure from "./excelStructure"; +import flatValidation from "./flatValidation"; +import getByName from "./getByName"; +import getExtension from "./getExtension"; +import isAllowed from "./isAllowed"; +import isAlreadyLoaded from "./isAlreadyLoaded"; +import isFileValidated from "./isFileValidated"; +import isValidationCompleted from "./isValidationCompleted"; +import submitValidations from "./submitValidations"; + +export { + excelStructure, + flatValidation, + getByName, + getExtension, + isAllowed, + isAlreadyLoaded, + isFileValidated, + isValidationCompleted, + submitValidations, +}; diff --git a/frontend/src/renderer/src/utils/file/isAllowed.ts b/frontend/src/renderer/src/utils/file/isAllowed.ts new file mode 100644 index 00000000..ddc35d93 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/isAllowed.ts @@ -0,0 +1,11 @@ +import { WHITELISTED_EXTENSIONS } from "@/constants/config"; +import getExtension from "./getExtension"; + +/** + * Runs a check on a file, validating its extension + * @param file `File` to check + * @returns `true` if the file is allowed, `false` otherwise + */ +export default function isAllowed(file: File) { + return !!WHITELISTED_EXTENSIONS.find((ext) => ext === getExtension(file)); +} diff --git a/frontend/src/renderer/src/utils/file/isAlreadyLoaded.ts b/frontend/src/renderer/src/utils/file/isAlreadyLoaded.ts new file mode 100644 index 00000000..d6441000 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/isAlreadyLoaded.ts @@ -0,0 +1,11 @@ +import type { DocFile } from "@/types/file"; + +/** + * Looks in the file state if an specific file is already loaded + * @param fileName Name of the file to analyze + * @param state State to check + * @returns `true` if the file is already in the state, `false` otherwise + */ +export default function isAlreadyLoaded(fileName: string, state: DocFile[]) { + return !!state.find((file) => file.data.name === fileName); +} diff --git a/frontend/src/renderer/src/utils/file/isFileValidated.ts b/frontend/src/renderer/src/utils/file/isFileValidated.ts new file mode 100644 index 00000000..7afd55c2 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/isFileValidated.ts @@ -0,0 +1,10 @@ +import type { DocFile } from "@/types/file"; + +/** + * Checks if a file has been at least partially validated + * @param selectedFile Current selected file + * @returns `true` if the file has any validation made, `false` otherwise + */ +export default function isFileValidated(selectedFile: DocFile) { + return Object.keys(selectedFile.validationObject).length > 0; +} diff --git a/frontend/src/renderer/src/utils/file/isValidationCompleted.ts b/frontend/src/renderer/src/utils/file/isValidationCompleted.ts new file mode 100644 index 00000000..3f8cc437 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/isValidationCompleted.ts @@ -0,0 +1,13 @@ +import type { DocFile } from "@/types/file"; + +/** + * Checks if the file validation process is completed + * @param state Current files state + * @returns `true` if the validation process is completed, `false` otherwise + */ +export default function isValidationCompleted(state: DocFile[]) { + // If we find any file with no predictions, return false + const uncompleted = state.find((file) => !file.validated); + + return !uncompleted; +} diff --git a/frontend/src/renderer/src/utils/file/preview-files.ts b/frontend/src/renderer/src/utils/file/preview-files.ts new file mode 100644 index 00000000..8468f1fd --- /dev/null +++ b/frontend/src/renderer/src/utils/file/preview-files.ts @@ -0,0 +1,9 @@ +import { FeatureFlowEnum } from "@/types/features"; + +export function filesForFeatureLoad(feature: FeatureFlowEnum, files: File[]) { + if (feature === FeatureFlowEnum.Anonymizer) { + return files.slice(-1); + } + + return files; +} diff --git a/frontend/src/renderer/src/utils/file/submitValidations/__tests__/offline.test.ts b/frontend/src/renderer/src/utils/file/submitValidations/__tests__/offline.test.ts new file mode 100644 index 00000000..e7d93774 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/submitValidations/__tests__/offline.test.ts @@ -0,0 +1,37 @@ +import { Workbook } from "exceljs"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const filesystemMock = { + excel: { + create: vi.fn(), + read: vi.fn(), + write: vi.fn(), + }, +}; + +vi.mock("@/services/filesystem", () => ({ + default: filesystemMock, +})); + +describe("offline validation export", () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("creates a new dataset workbook when the existing workbook has no worksheets", async () => { + const emptyWorkbook = new Workbook(); + const createdWorkbook = new Workbook(); + createdWorkbook.addWorksheet("set_de_datos"); + + filesystemMock.excel.read.mockResolvedValueOnce(emptyWorkbook); + filesystemMock.excel.create.mockReturnValueOnce(createdWorkbook); + + const { default: offline } = await import("../offline"); + const result = await offline([["value"]]); + + expect(filesystemMock.excel.create).toHaveBeenCalledTimes(1); + expect(result).toBe(createdWorkbook); + expect(createdWorkbook.worksheets[0].getCell("A1").value).toBe("value"); + expect(filesystemMock.excel.write).toHaveBeenCalledWith(createdWorkbook); + }); +}); diff --git a/frontend/src/renderer/src/utils/file/submitValidations/index.ts b/frontend/src/renderer/src/utils/file/submitValidations/index.ts new file mode 100644 index 00000000..551e865f --- /dev/null +++ b/frontend/src/renderer/src/utils/file/submitValidations/index.ts @@ -0,0 +1,27 @@ +import type { DocFile } from "@/types/file"; +import { validationToArray } from "@/utils/google"; +import offline from "./offline"; + +interface Props { + isOnline: boolean | undefined; + validations: DocFile["validationObject"]; +} +/** + * Submits the data through the appropiate way. Saves into the filesystem when + * `online=false` and to the cloud when `online=true` + * @param isOnline Has the user authenticated through Google OAuth? + * @param validations All the validated data for a single file + */ +export default async function submitValidations({ + isOnline, + validations, +}: Props) { + const validationArray = validationToArray(validations); + + // This validation was left here for future use if we support online submissions + if (isOnline) { + console.warn("Online submissions were disabled."); + } else { + await offline(validationArray); + } +} diff --git a/frontend/src/renderer/src/utils/file/submitValidations/offline.ts b/frontend/src/renderer/src/utils/file/submitValidations/offline.ts new file mode 100644 index 00000000..35da5ed5 --- /dev/null +++ b/frontend/src/renderer/src/utils/file/submitValidations/offline.ts @@ -0,0 +1,29 @@ +import type { FormValue } from "@/hooks/useForm"; +import filesystem from "@/services/filesystem"; +import type { Workbook } from "exceljs"; + +/** + * Writes the validated data to the filesystem, creating new rows on the already existent dataset + * In case there is no dataset, we create a new empty one + * @param validations Validations to write to the filesystem + * @returns Returns the recently submitted Workbook + */ +function getWritableWorkbook(workbook: Workbook | null) { + if (!workbook || workbook.worksheets.length === 0) { + return filesystem.excel.create(); + } + + return workbook; +} + +export default async function offline(validations: FormValue[][]) { + // Opens an already existent Workbook or creates a new one + const workbook = getWritableWorkbook(await filesystem.excel.read()); + + const worksheet = workbook.worksheets[0]; + worksheet.addRows(validations); + + await filesystem.excel.write(workbook); + + return workbook; +} diff --git a/frontend/src/renderer/src/utils/filtering.ts b/frontend/src/renderer/src/utils/filtering.ts new file mode 100644 index 00000000..f157a4c0 --- /dev/null +++ b/frontend/src/renderer/src/utils/filtering.ts @@ -0,0 +1,9 @@ +/** + * Checks the type of an object. This util function is meant to be used along the `.filter()` array function + * @example array.filter(removeUndefined); + * @param obj Object to analyze + * @returns `true` if the object is not undefined, `false` otherwise + */ +export function removeUndefined(obj: T | undefined): obj is T { + return obj !== undefined; +} diff --git a/frontend/src/renderer/src/utils/google/index.ts b/frontend/src/renderer/src/utils/google/index.ts new file mode 100644 index 00000000..d6d71d11 --- /dev/null +++ b/frontend/src/renderer/src/utils/google/index.ts @@ -0,0 +1,4 @@ +import spreadsheetURLToId from "./spreadsheetURLToId"; +import validationToArray from "./validationToArray"; + +export { spreadsheetURLToId, validationToArray }; diff --git a/frontend/src/renderer/src/utils/google/spreadsheetURLToId.ts b/frontend/src/renderer/src/utils/google/spreadsheetURLToId.ts new file mode 100644 index 00000000..c05efd53 --- /dev/null +++ b/frontend/src/renderer/src/utils/google/spreadsheetURLToId.ts @@ -0,0 +1,17 @@ +import type { SpreadsheetId } from "@/types/spreadsheet"; + +/** + * Converts an spreadsheet URL into an `SpreadsheetId` + * @param url DataSet URL + * @returns The `SpreadsheetId` of the dataset + */ +export default function spreadsheetURLToId(url: string): SpreadsheetId { + const split = url.split("/"); + const pageIndex = split.indexOf("spreadsheets"); + + // + 1 equals to the '/d/' in the url + // + 2 equals to the id we are looking for + const id = split[pageIndex + 2]; + + return id; +} diff --git a/frontend/src/renderer/src/utils/google/utils.ts b/frontend/src/renderer/src/utils/google/utils.ts new file mode 100644 index 00000000..a11a9580 --- /dev/null +++ b/frontend/src/renderer/src/utils/google/utils.ts @@ -0,0 +1,62 @@ +import type { FlatFormData } from "@/hooks/useForm"; +import { LabelDecisiones } from "@/types/aymurai"; + +/** + * Treats the special case to return the correct value + * @param obj Current `FlatFormData` to analyze + * @returns The value for the current label + */ +export function treatVIOLENCIA_FISICA(obj: FlatFormData) { + const si = obj[LabelDecisiones.VIOLENCIA_DE_GENERO_SI]; + const no = obj[LabelDecisiones.VIOLENCIA_DE_GENERO_NO]; + + if (si) return "si"; + if (no) return "no"; + return undefined; +} + +/** + * Treats the special case to return the correct value + * @param obj Current `FlatFormData` to analyze + * @returns The value for the current label + */ +export function treateV_X( + obj: FlatFormData, + key: keyof typeof LabelDecisiones, +) { + if (obj[key] === true) return "si"; + if (obj[key] === false) return "no"; + return undefined; +} + +/** + * Treats the special case to return the correct value + * @param obj Current `FlatFormData` to analyze + * @returns The value for the current label + */ +export function treatFRASES_AGRESION(obj: FlatFormData) { + // Find related fields. This retrieves any field named in the format `FRASES_AGRESIONx` + const frases = Object.keys(obj).filter((objectKey) => + objectKey.includes(LabelDecisiones.FRASES_AGRESION), + ); + // Join the phrases by commas + const joined = frases + .map((frase) => obj[frase as LabelDecisiones.FRASES_AGRESION]) + .join(", "); + + return joined; +} + +/** + * Treats the special case to return the correct value + * @param obj Current `FlatFormData` to analyze + * @returns The value for the current label + */ +export function treatORAL_ESCRITA(obj: FlatFormData) { + const oral = obj[LabelDecisiones.TIPO_DE_AUDIENCIA_ORAL]; + const escrita = obj[LabelDecisiones.TIPO_DE_AUDIENCIA_ESCRITA]; + + if (oral) return "oral"; + if (escrita) return "escrita"; + return "no_corresponde"; +} diff --git a/frontend/src/renderer/src/utils/google/validationToArray.ts b/frontend/src/renderer/src/utils/google/validationToArray.ts new file mode 100644 index 00000000..9a0acc02 --- /dev/null +++ b/frontend/src/renderer/src/utils/google/validationToArray.ts @@ -0,0 +1,47 @@ +import type { AllLabels, AllLabelsWithSufix } from "@/types/aymurai"; +import type { DocFile } from "@/types/file"; +import { excelStructure, flatValidation } from "@/utils/file"; +import { + treatFRASES_AGRESION, + treatORAL_ESCRITA, + treatVIOLENCIA_FISICA, + treateV_X, +} from "./utils"; + +/** + * Converts the validation object into an ordered array + * @param object Validation object containing all the validations made in the `/validation` page + * @returns An ordered array with the values from the `validationObject` + */ +export default function validationToArray(object: DocFile["validationObject"]) { + const flat = flatValidation(object); + + return flat.map((obj) => { + return excelStructure.map((key) => { + // Special cases + + switch (key) { + case "VIOLENCIA_DE_GENERO": + return treatVIOLENCIA_FISICA(obj); + case "V_AMB": + case "V_ECON": + case "V_FISICA": + case "V_POLIT": + case "V_PSIC": + case "V_SEX": + case "V_SIMB": + case "V_SOC": + return treateV_X(obj, key); + case "FRASES_AGRESION": + return treatFRASES_AGRESION(obj); + case "ORAL_ESCRITA": + return treatORAL_ESCRITA(obj); + default: + // Generic case, just return the value + // Treat the case as a defined LabelType | LabelDecisiones. In case its not, just return the undefined + // as this case won't create a value on the dataset as expected + return obj[key as AllLabels | AllLabelsWithSufix]; + } + }); + }); +} diff --git a/frontend/src/renderer/src/utils/logger.ts b/frontend/src/renderer/src/utils/logger.ts new file mode 100644 index 00000000..e4f29a4a --- /dev/null +++ b/frontend/src/renderer/src/utils/logger.ts @@ -0,0 +1,38 @@ +/** + * Interface for `console.log`. Won't print on 'production' mode + * @param args Same arguments as `console.log` + */ +// biome-ignore lint/suspicious/noExplicitAny: No need to specify the type +function info(...args: any[]) { + if (!import.meta.env.PROD) { + console.log(...args); + } +} + +/** + * Interface for `console.error`. Won't print on 'test' mode + * @param args Same arguments as `console.error` + */ +// biome-ignore lint/suspicious/noExplicitAny: No need to specify the type +function error(...args: any[]) { + if (!import.meta.env.PROD) { + console.error(...args); + } +} + +/** + * Interface for `console.warn` + * @param args Same arguments as `console.warn` + */ +// biome-ignore lint/suspicious/noExplicitAny: No need to specify the type +function warn(...args: any[]) { + console.warn(...args); +} + +const logger = { + info, + error, + warn, +}; + +export default logger; diff --git a/frontend/src/renderer/src/utils/nArray.ts b/frontend/src/renderer/src/utils/nArray.ts new file mode 100644 index 00000000..580fd981 --- /dev/null +++ b/frontend/src/renderer/src/utils/nArray.ts @@ -0,0 +1,15 @@ +/** + * Creates an ordered array with a length of `n` + * @param n Amount of values + * @param base Value to store on each element of the array + * @returns A `number[]` of `n` length + */ + +export default function nArray(n: number, value: T) { + const array = Array.from(Array(n).keys()).map(() => { + if (typeof value === "object") return Object.create(value); + return value; + }); + + return array; +} diff --git a/frontend/src/renderer/src/utils/predictions/countDecisiones.ts b/frontend/src/renderer/src/utils/predictions/countDecisiones.ts new file mode 100644 index 00000000..353a0e93 --- /dev/null +++ b/frontend/src/renderer/src/utils/predictions/countDecisiones.ts @@ -0,0 +1,19 @@ +import type { PredictLabel } from "@/types/aymurai"; + +export default function countDecisiones( + predictions: PredictLabel[] | undefined, +) { + if (!predictions) return 0; + + const amount = predictions.reduce((prev, label) => { + const subclass = label.attrs.aymurai_label_subclass ?? []; + + // If we found this subclass, it means we are facing a decision + if (subclass.some((text) => text === "hace_lugar")) return prev + 1; + return prev; + }, 0); + + // Default the decisions to 1 if no decision was found + // This is because we always have at least 1 decision active per file, no matter the predictions array + return amount === 0 ? 1 : amount; +} diff --git a/frontend/src/renderer/src/utils/predictions/index.ts b/frontend/src/renderer/src/utils/predictions/index.ts new file mode 100644 index 00000000..8180988f --- /dev/null +++ b/frontend/src/renderer/src/utils/predictions/index.ts @@ -0,0 +1,4 @@ +import countDecisiones from "./countDecisiones"; +import Suggester from "./suggestions"; + +export { countDecisiones, Suggester }; diff --git a/frontend/src/renderer/src/utils/predictions/suggestions/index.ts b/frontend/src/renderer/src/utils/predictions/suggestions/index.ts new file mode 100644 index 00000000..30ac006f --- /dev/null +++ b/frontend/src/renderer/src/utils/predictions/suggestions/index.ts @@ -0,0 +1,207 @@ +import type { SelectOption } from "@/components/ui/select"; +import { + type AllLabels, + type AllLabelsWithSufix, + LabelDecisiones, + type PredictLabel, +} from "@/types/aymurai"; +import type { + BooleanSuggestion, + InputSuggestion, + Prediction, + PropertyCallback, + SelectSuggestion, +} from "./types"; + +export default class Suggester { + constructor(predictions: PredictLabel[] | undefined) { + this.predictions = predictions ?? []; + } + + // ------------ + // FIELDS + // ------------ + private predictions: PredictLabel[]; + + // ------------ + // PRIVATE METHODS + // ------------ + /** + * Transforms the predictions array into a { [label]: T } form to be used on the getters methods + * @param propertyCallback This function is used to define which property is added when reducing + * @returns A predictions array transformed into { [label]: T } + */ + private reducePredictions( + propertyCallback: PropertyCallback, + ): Prediction { + const reduced = this.predictions.reduce( + (prev, pred) => ({ + ...prev, + // Append the next value + [pred.attrs.aymurai_label]: propertyCallback(pred), + }), + {}, + ); + + return reduced; + } + + // ------------ + // PUBLIC METHODS + // ------------ + /** + * Searches for a suggestion for the given label + * @param label Label to check + * @returns The suggestion in `string | undefined` format + */ + public text(label: AllLabels | AllLabelsWithSufix): InputSuggestion { + const reduced = this.reducePredictions((pred) => pred.text); + + return { + suggestion: reduced[label], + }; + } + + /** + * Searches for a suggestion option for the given label + * @param label Label to check + * @returns The suggestion as a `SelectOption` object + */ + public select(label: AllLabels | AllLabelsWithSufix): SelectSuggestion { + const reduced = this.reducePredictions((pred) => ({ + subclass: pred.attrs.aymurai_label_subclass ?? [], + text: pred.text, + })); + + const { subclass, text } = reduced[label] ?? {}; + + const hasElements = !!subclass && !!subclass.length; + const suggestion: SelectOption | undefined = + hasElements && text ? { id: subclass[0], text } : undefined; + + return { + priorityOrder: subclass, + suggestion, + }; + } + + /** + * @example + *[{ + ... + "text": "violencia de género", + "attrs": { + ... + "aymurai_label": "VIOLENCIA_DE_GENERO", + "aymurai_label_subclass": [], + } + }] + */ + violencia_genero(type: "si" | "no"): BooleanSuggestion { + const reduced = this.reducePredictions((pred) => pred.text); + + const value = reduced[LabelDecisiones.VIOLENCIA_DE_GENERO]; + + if (value !== undefined) { + // Return true or false + return { checked: type === "si" ? !!value : !value }; + } + return { checked: undefined }; + } + + /** + * @example + * [{ + * ... + "text": "violencia económica y física", + "attrs": { + "aymurai_label": "VIOLENCIA_DE_GENERO", + "aymurai_label_subclass": [ + "economica", + "fisica" + ], + } + }] + */ + violencia_tipo(label: LabelDecisiones): BooleanSuggestion { + // Reduce the predictions, merging VIOLENCIA_DE_GENERO subclasses + const subclasses = this.predictions.reduce((prev, pred) => { + const label = pred.attrs.aymurai_label; + const subclass = pred.attrs.aymurai_label_subclass; + + if (label === LabelDecisiones.VIOLENCIA_DE_GENERO && subclass) { + return [...prev, ...subclass]; + } + return prev; + }, []); + + const values: Partial> = { + [LabelDecisiones.V_AMB]: "ambiental", + [LabelDecisiones.V_ECON]: "economica", + [LabelDecisiones.V_SIMB]: "simbolica", + [LabelDecisiones.V_SEX]: "sexual", + [LabelDecisiones.V_PSIC]: "psicologica", + [LabelDecisiones.V_POLIT]: "politica", + [LabelDecisiones.V_FISICA]: "fisica", + [LabelDecisiones.V_SOC]: "social", + }; + + // Type of VIOLENCIA_TIPO + const labelValue = values[label]; + + return { + // Find the desired type on the subclass array + checked: !!subclasses.find((s) => s === labelValue), + }; + } + + art_infringido(): SelectSuggestion { + const reduced = this.reducePredictions(({ text }) => ({ id: text, text })); + + const suggestion = reduced[LabelDecisiones.ART_INFRINGIDO]; + + if (suggestion) { + return { + priorityOrder: [suggestion.id], + suggestion, + }; + } + + return { + suggestion: undefined, + priorityOrder: undefined, + }; + } + codigo_o_ley(): SelectSuggestion { + const reduced = this.reducePredictions( + (pred) => pred.attrs.aymurai_label_subclass, + ); + + const suggestion = reduced[LabelDecisiones.ART_INFRINGIDO]; + + if (suggestion) { + return { + suggestion: { id: suggestion[0] }, + priorityOrder: [suggestion[0]], + }; + } + + return { + suggestion: undefined, + priorityOrder: undefined, + }; + } + + decision(): SelectSuggestion { + const reduced = this.reducePredictions( + ({ attrs }) => attrs.aymurai_label_subclass ?? [], + ); + + const suggestion = reduced[LabelDecisiones.DECISION]; + + return { + priorityOrder: undefined, + suggestion: suggestion ? { id: suggestion[0] } : undefined, + }; + } +} diff --git a/frontend/src/renderer/src/utils/predictions/suggestions/types.ts b/frontend/src/renderer/src/utils/predictions/suggestions/types.ts new file mode 100644 index 00000000..787a2532 --- /dev/null +++ b/frontend/src/renderer/src/utils/predictions/suggestions/types.ts @@ -0,0 +1,16 @@ +import type { SelectSuggestion as Suggestion } from "@/components/ui/select"; +import type { + AllLabels, + AllLabelsWithSufix, + PredictLabel, +} from "@/types/aymurai"; + +export type Prediction = Partial>; +export type PropertyCallback = (prediction: PredictLabel) => T; + +type TextSuggestion = Partial<{ suggestion: T }>; +export type InputSuggestion = TextSuggestion; +export type SelectSuggestion = TextSuggestion & + Partial<{ priorityOrder: string[] }>; + +export type BooleanSuggestion = Partial<{ checked: boolean }>; diff --git a/frontend/src/renderer/src/utils/process/canContinue.ts b/frontend/src/renderer/src/utils/process/canContinue.ts new file mode 100644 index 00000000..019e44b5 --- /dev/null +++ b/frontend/src/renderer/src/utils/process/canContinue.ts @@ -0,0 +1,12 @@ +import type { ProcessState } from "./initProcessState"; + +export function canContinue(state: ProcessState[]) { + const atLeastOneCompleted = state.some( + ({ status }) => status === "completed", + ); + const hasFinishedProcessing = !state.some( + ({ status }) => status === "processing", + ); + + return hasFinishedProcessing && atLeastOneCompleted; +} diff --git a/frontend/src/renderer/src/utils/process/initProcessState.ts b/frontend/src/renderer/src/utils/process/initProcessState.ts new file mode 100644 index 00000000..f6d5bb91 --- /dev/null +++ b/frontend/src/renderer/src/utils/process/initProcessState.ts @@ -0,0 +1,13 @@ +import type { PredictStatus } from "@/hooks/usePredict"; +import type { DocFile } from "@/types/file"; + +export type ProcessState = { name: string; status: PredictStatus }; + +/** + * Creates the initial state for the `/process` page + * @param files `DocFile[]` state + * @returns An `ProcessState[]` array containing the name of each file and its processing state + */ +export function initProcessState(files: DocFile[]): ProcessState[] { + return files.map(({ data }) => ({ name: data.name, status: "processing" })); +} diff --git a/frontend/src/renderer/src/utils/regex.ts b/frontend/src/renderer/src/utils/regex.ts new file mode 100644 index 00000000..4ab20526 --- /dev/null +++ b/frontend/src/renderer/src/utils/regex.ts @@ -0,0 +1,50 @@ +import RegexEscape from "regex-escape"; + +/** + * Given a vowel, returns a 'regex' that matches the vowel with or without accent + */ +const getVowel = (vowel: string) => { + switch (vowel) { + case "a": + case "á": + return "[aá]"; + case "e": + case "é": + return "[eé]"; + case "i": + case "í": + return "[ií]"; + case "o": + case "ó": + return "[oó]"; + case "u": + case "ú": + case "ü": + return "[uúü]"; + default: + return vowel; + } +}; + +/** + * Replaces all the vowels with or without accent with a regex that matches the two options + */ +const replaceVowels = (char: string) => { + let parsed = ""; + + for (const vowel of char) { + parsed = `${parsed}${getVowel(vowel)}`; + } + + return parsed; +}; + +/** + * Using the two replace functions, returns a sanitized word that can be used in a regex + */ +const sanitize = (word: string) => replaceVowels(RegexEscape(word)); + +/** + * Matches all the text that contains the word + */ +export const includes = (word: string) => new RegExp(sanitize(word), "gi"); diff --git a/frontend/src/renderer/src/vite-env.d.ts b/frontend/src/renderer/src/vite-env.d.ts new file mode 100644 index 00000000..7ea578b0 --- /dev/null +++ b/frontend/src/renderer/src/vite-env.d.ts @@ -0,0 +1,9 @@ +/// + +interface ImportMetaEnv { + readonly VITE_APP_MODE: 'electron' | 'web' +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 00000000..155ebaa6 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.node.json" }, + { "path": "./tsconfig.web.json" } + ] +} diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 00000000..414dff54 --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "extends": "@electron-toolkit/tsconfig/tsconfig.node.json", + "include": ["electron.vite.config.*", "src/main/**/*", "src/preload/**/*"], + "compilerOptions": { + "composite": true, + "moduleResolution": "bundler", + "types": ["electron-vite/node"] + } +} diff --git a/frontend/tsconfig.web.json b/frontend/tsconfig.web.json new file mode 100644 index 00000000..4a1a9b0a --- /dev/null +++ b/frontend/tsconfig.web.json @@ -0,0 +1,21 @@ +{ + "extends": "@electron-toolkit/tsconfig/tsconfig.web.json", + "compilerOptions": { + "composite": true, + "jsx": "react-jsx", + "baseUrl": ".", + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": false, + + "paths": { + "@/*": ["./src/renderer/src/*"] + } + }, + "include": [ + "src/renderer/src/env.d.ts", + "src/renderer/src/**/*", + "src/renderer/src/**/*.tsx", + "src/preload/*.d.ts", + "src/renderer/src/styled/**/*" + ] +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 00000000..9375df6b --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,34 @@ +/** + * Vite config for building the renderer as a standalone web app (no Electron). + * Used by the `dev:web` and `build:web` scripts. + * + * Since `root` is set to `src/renderer`, `envDir` points back to the project + * root so that `.env` files are resolved from there. + */ +import { resolve } from "node:path"; +import { tanstackRouter } from "@tanstack/router-plugin/vite"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +export default defineConfig({ + plugins: [ + tanstackRouter({ + target: "react", + autoCodeSplitting: true, + }), + react(), + ], + root: "src/renderer", + envDir: resolve("."), + server: { + port: 3000, + }, + build: { + outDir: "../../out/renderer", + }, + resolve: { + alias: { + "@": resolve("src/renderer/src"), + }, + }, +}); diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts new file mode 100644 index 00000000..5d495d28 --- /dev/null +++ b/frontend/vitest.config.ts @@ -0,0 +1,14 @@ +import path from "node:path"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: true, + environment: "node", + }, + resolve: { + alias: { + "@": path.resolve(__dirname, "src/renderer/src"), + }, + }, +}); diff --git a/tests/api/conftest.py b/tests/api/conftest.py index 22dd7a69..4bdd54a1 100644 --- a/tests/api/conftest.py +++ b/tests/api/conftest.py @@ -14,6 +14,7 @@ from aymurai.api.endpoints.routers.anonymizer import anonymizer from aymurai.api.endpoints.routers.datapublic import datapublic from aymurai.api.endpoints.routers.misc import document_extract +from aymurai.api.endpoints.routers.misc import convert from aymurai.database.meta.anonymization.paragraph import AnonymizationParagraphCreate from aymurai.database.meta.datapublic.paragraph import DataPublicParagraphCreate from aymurai.database.session import get_session @@ -27,16 +28,21 @@ def app() -> FastAPI: test_app = FastAPI() test_app.include_router( anonymizer.router, - prefix="/anonymizer", + prefix="/api/anonymizer", tags=["anonymization/model"], ) test_app.include_router( datapublic.router, - prefix="/datapublic", + prefix="/api/datapublic", tags=["datapublic/model"], ) - test_app.include_router(document_extract.router, tags=["document"], deprecated=True) - test_app.include_router(document_extract.router, prefix="/misc", tags=["document"]) + test_app.include_router( + document_extract.router, prefix="/api", tags=["document"], deprecated=True + ) + test_app.include_router( + document_extract.router, prefix="/api/misc", tags=["document"] + ) + test_app.include_router(convert.router, prefix="/api", tags=["Document conversion"]) return test_app diff --git a/tests/api/routers/anonymizer/test_anonymizer.py b/tests/api/routers/anonymizer/test_anonymizer.py index 4480e05f..7337566a 100644 --- a/tests/api/routers/anonymizer/test_anonymizer.py +++ b/tests/api/routers/anonymizer/test_anonymizer.py @@ -11,9 +11,11 @@ import pytest from docx import Document +from aymurai.api.endpoints.routers.anonymizer import anonymizer as anonymizer_module from aymurai.database.schema import AnonymizationParagraph from aymurai.database.utils import text_to_uuid from aymurai.meta.api_interfaces import LabelPolicy, RenderPolicy +from aymurai.settings import Settings from aymurai.text.anonymization import DocxAnonymizer, PdfAnonymizer, get_anonymizer from aymurai.text.anonymization.alignment import index_paragraphs from aymurai.text.anonymization.pdf.ops import _refine_signature_text_rect @@ -697,7 +699,7 @@ def test_should_return_prediction_when_text_provided(mock_load_pipeline, client) mock_load_pipeline.return_value = mock_pipeline response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": "Sample anonymization text"}, ) @@ -727,7 +729,7 @@ def test_should_return_cached_prediction_when_text_in_cache( db_session.commit() response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, params={"use_cache": True}, ) @@ -749,7 +751,7 @@ def test_should_store_prediction_in_db_when_use_cache_true( text = "New prediction to cache" response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, params={"use_cache": True}, ) @@ -772,14 +774,14 @@ def test_should_return_cached_result_when_calling_twice(mock_load_pipeline, clie text = "Repeated query text" response1 = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, params={"use_cache": True}, ) data1 = response1.json() response2 = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, params={"use_cache": True}, ) @@ -801,7 +803,7 @@ def test_should_return_prediction_without_storing_when_use_cache_false( text = "No cache storage text" response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, params={"use_cache": False}, ) @@ -819,7 +821,7 @@ def test_should_return_prediction_without_storing_when_use_cache_false( @pytest.mark.integration def test_should_return_422_when_payload_is_invalid_json(client): response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", content="not json", headers={"Content-Type": "application/json"}, ) @@ -837,7 +839,7 @@ def test_should_use_cache_by_default_when_param_omitted( text = "Default cache behavior" response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, ) @@ -873,13 +875,13 @@ def test_should_isolate_cache_when_different_texts( db_session.commit() response1 = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text1}, params={"use_cache": True}, ) response2 = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text2}, params={"use_cache": True}, ) @@ -923,7 +925,7 @@ def test_should_dedupe_duplicate_labels_when_returning_cached_prediction( db_session.commit() response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, params={"use_cache": True}, ) @@ -975,7 +977,7 @@ def test_should_merge_cached_duplicate_labels_for_same_span_and_label( db_session.commit() response = client.post( - "/anonymizer/predict", + "/api/anonymizer/predict", json={"text": text}, params={"use_cache": True}, ) @@ -1019,7 +1021,7 @@ def test_should_disambiguate_and_persist_paragraphs( }, } - response = client.post("/anonymizer/disambiguate", json=body) + response = client.post("/api/anonymizer/disambiguate", json=body) assert response.status_code == 200 payload = response.json() @@ -1070,7 +1072,7 @@ def test_should_dedupe_duplicate_labels_when_disambiguating_and_persisting( }, } - response = client.post("/anonymizer/disambiguate", json=body) + response = client.post("/api/anonymizer/disambiguate", json=body) assert response.status_code == 200 labels = response.json()["data"][0]["labels"] @@ -1097,7 +1099,7 @@ def test_should_dedupe_duplicate_labels_when_disambiguating_and_persisting( @pytest.mark.integration def test_should_return_null_validation_when_paragraph_not_found(client): response = client.post( - "/anonymizer/validation", + "/api/anonymizer/validation", json={"text": "Paragraph without validation"}, ) @@ -1118,7 +1120,7 @@ def test_should_return_validation_when_paragraph_exists(client, db_session): ) db_session.commit() - response = client.post("/anonymizer/validation", json={"text": text}) + response = client.post("/api/anonymizer/validation", json={"text": text}) assert response.status_code == 200 assert response.json() == labels @@ -1149,7 +1151,7 @@ def test_should_return_application_pdf_when_pdf_document_is_anonymized( } response = client.post( - "/anonymizer/anonymize-document", + "/api/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, files={"file": ("sample.pdf", b"%PDF-1.4 fake", "application/pdf")}, ) @@ -1159,6 +1161,54 @@ def test_should_return_application_pdf_when_pdf_document_is_anonymized( assert len(response.content) > 0 +@pytest.mark.integration +@patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_anonymizer") +def test_should_pass_resolved_default_policies_to_document_anonymizer( + mock_get_anonymizer, + client, + tmp_path, + monkeypatch, +): + monkeypatch.delenv("DISAMBIGUATION_LABEL_POLICIES", raising=False) + monkeypatch.delenv("RENDER_POLICY", raising=False) + monkeypatch.setattr(anonymizer_module, "settings", Settings()) + + anonymized_path = _write_pdf( + tmp_path / "output.pdf", + lambda _doc, page: page.insert_text((72, 72), "Anonymized PDF output"), + ) + mock_anonymizer = MagicMock(return_value=str(anonymized_path)) + mock_get_anonymizer.return_value = mock_anonymizer + + annotations = { + "data": [ + { + "document": "Ana Perez presento el escrito", + "labels": [build_label("PER", "Ana Perez").model_dump(mode="json")], + } + ], + "label_policies": None, + "render_policy": None, + } + + response = client.post( + "/api/anonymizer/anonymize-document", + data={"annotations": json.dumps(annotations)}, + files={"file": ("sample.pdf", b"%PDF-1.4 fake", "application/pdf")}, + ) + + assert response.status_code == 200 + render_context = mock_anonymizer.call_args.kwargs["render_context"] + assert render_context["render_policy"] == RenderPolicy( + suffix_mode="auto", suffix_threshold=1 + ) + assert render_context["label_policies"]["PER"] == LabelPolicy( + disambiguation="fuzzy", + anonymize=True, + use_subclass_when_available=True, + ) + + @patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.subprocess.check_output") @patch("aymurai.api.endpoints.routers.anonymizer.anonymizer.get_anonymizer") def test_should_anonymize_document_when_annotations_are_valid( @@ -1193,7 +1243,7 @@ def fake_convert(*args, **kwargs): } response = client.post( - "/anonymizer/anonymize-document", + "/api/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, files={ "file": ( @@ -1243,7 +1293,7 @@ def fake_convert(*args, **kwargs): } response = client.post( - "/anonymizer/anonymize-document", + "/api/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, files={ "file": ( @@ -1290,7 +1340,7 @@ def test_should_return_500_when_anonymize_document_conversion_fails( } response = client.post( - "/anonymizer/anonymize-document", + "/api/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, files={ "file": ( diff --git a/tests/api/routers/datapublic/test_datapublic.py b/tests/api/routers/datapublic/test_datapublic.py index 69be0111..49385e6b 100644 --- a/tests/api/routers/datapublic/test_datapublic.py +++ b/tests/api/routers/datapublic/test_datapublic.py @@ -23,7 +23,7 @@ def test_should_return_prediction_when_valid_document_id_and_text( document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-predict-valid") response = client.post( - f"/datapublic/predict/{document_id}", + f"/api/datapublic/predict/{document_id}", json={"text": "Sample datapublic text"}, params={"use_cache": False}, ) @@ -55,7 +55,7 @@ def test_should_return_cached_prediction_when_text_in_cache( document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-cached-text") response = client.post( - f"/datapublic/predict/{document_id}", + f"/api/datapublic/predict/{document_id}", json={"text": text}, params={"use_cache": True}, ) @@ -79,7 +79,7 @@ def test_should_store_paragraph_and_document_when_use_cache_true( text = "New datapublic paragraph" response = client.post( - f"/datapublic/predict/{document_id}", + f"/api/datapublic/predict/{document_id}", json={"text": text}, params={"use_cache": True}, ) @@ -118,7 +118,7 @@ def test_should_return_prediction_without_storing_when_use_cache_false( text = "No datapublic storage text" response = client.post( - f"/datapublic/predict/{document_id}", + f"/api/datapublic/predict/{document_id}", json={"text": text}, params={"use_cache": False}, ) @@ -136,7 +136,7 @@ def test_should_return_prediction_without_storing_when_use_cache_false( @pytest.mark.integration def test_should_return_422_when_document_id_not_uuid(client): response = client.post( - "/datapublic/predict/not-a-uuid", + "/api/datapublic/predict/not-a-uuid", json={"text": "Sample text"}, ) @@ -156,13 +156,13 @@ def test_should_associate_multiple_paragraphs_with_same_document( text2 = "Second paragraph for association" response1 = client.post( - f"/datapublic/predict/{document_id}", + f"/api/datapublic/predict/{document_id}", json={"text": text1}, params={"use_cache": True}, ) response2 = client.post( - f"/datapublic/predict/{document_id}", + f"/api/datapublic/predict/{document_id}", json={"text": text2}, params={"use_cache": True}, ) @@ -192,7 +192,7 @@ def test_should_associate_multiple_paragraphs_with_same_document( def test_should_return_404_when_validation_document_not_found(client): document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-validation-missing") - response = client.get(f"/datapublic/validation/document/{document_id}") + response = client.get(f"/api/datapublic/validation/document/{document_id}") assert response.status_code == 404 @@ -203,7 +203,7 @@ def test_should_return_none_when_validation_not_set(client, db_session): db_session.add(DataPublicDocument(id=document_id)) db_session.commit() - response = client.get(f"/datapublic/validation/document/{document_id}") + response = client.get(f"/api/datapublic/validation/document/{document_id}") assert response.status_code == 200 assert response.json() is None @@ -219,7 +219,7 @@ def test_should_upsert_and_read_document_validation(client, db_session): } post_response = client.post( - f"/datapublic/validation/document/{document_id}", + f"/api/datapublic/validation/document/{document_id}", json=payload, ) assert post_response.status_code == 200 @@ -228,6 +228,6 @@ def test_should_upsert_and_read_document_validation(client, db_session): assert stored_doc is not None assert stored_doc.validation == payload - get_response = client.get(f"/datapublic/validation/document/{document_id}") + get_response = client.get(f"/api/datapublic/validation/document/{document_id}") assert get_response.status_code == 200 assert get_response.json() == payload diff --git a/tests/api/routers/misc/test_document_extract.py b/tests/api/routers/misc/test_document_extract.py index 124c4b9c..0521649a 100644 --- a/tests/api/routers/misc/test_document_extract.py +++ b/tests/api/routers/misc/test_document_extract.py @@ -62,7 +62,7 @@ def test_should_extract_real_text_from_sample_docx_without_mocking(client): ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 200 data = response.json() @@ -96,7 +96,7 @@ def test_should_extract_real_text_from_pdf_without_mocking(client): ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 200 data = response.json() @@ -122,7 +122,7 @@ def test_should_return_document_with_paragraphs_when_uploading_docx( "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 200 data = response.json() @@ -146,7 +146,7 @@ def test_should_return_document_via_misc_prefix_when_uploading(mock_extraction, "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/misc/document-extract", files=files) + response = client.post("/api/misc/document-extract", files=files) assert response.status_code == 200 data = response.json() @@ -168,7 +168,7 @@ def test_should_return_document_via_deprecated_alias_when_uploading( "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 200 assert response.json()["document"] == ["Alias text"] @@ -191,11 +191,11 @@ def test_should_return_deterministic_id_when_uploading_same_file_twice( ) } - response1 = client.post("/document-extract", files=files) + response1 = client.post("/api/document-extract", files=files) data1 = response1.json() # Reset mock and upload same file again - response2 = client.post("/document-extract", files=files) + response2 = client.post("/api/document-extract", files=files) data2 = response2.json() assert response1.status_code == 200 @@ -206,7 +206,7 @@ def test_should_return_deterministic_id_when_uploading_same_file_twice( @pytest.mark.integration def test_should_return_422_when_no_file_provided(client): """Test that missing file returns 422 Unprocessable Entity.""" - response = client.post("/document-extract", files={}) + response = client.post("/api/document-extract", files={}) assert response.status_code == 422 @@ -224,7 +224,7 @@ def test_should_return_empty_document_when_file_is_empty(mock_extraction, client "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 200 data = response.json() @@ -246,7 +246,7 @@ def test_should_collapse_consecutive_duplicates_when_extracting( "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 200 data = response.json() @@ -266,7 +266,7 @@ def test_should_normalize_whitespace_when_extracting(mock_extraction, client): "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 200 data = response.json() @@ -286,7 +286,7 @@ def test_should_return_504_when_extraction_times_out(mock_extraction, client): "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 504 @@ -304,6 +304,6 @@ def test_should_return_500_when_extraction_fails(mock_extraction, client): "application/vnd.openxmlformats-officedocument.wordprocessingml.document", ) } - response = client.post("/document-extract", files=files) + response = client.post("/api/document-extract", files=files) assert response.status_code == 500 diff --git a/tests/api/routers/server/test_frontend.py b/tests/api/routers/server/test_frontend.py new file mode 100644 index 00000000..f88ea03f --- /dev/null +++ b/tests/api/routers/server/test_frontend.py @@ -0,0 +1,96 @@ +import pytest +from fastapi.testclient import TestClient + +from aymurai.api.main import api +from aymurai.settings import settings + + +@pytest.fixture(scope="function") +def client(tmp_path, monkeypatch): + # Setup a fake frontend build + frontend_dir = tmp_path / "frontend-dist" + frontend_dir.mkdir() + (frontend_dir / "index.html").write_text("SPA") + (frontend_dir / "logo.png").write_bytes(b"fakeimg") + monkeypatch.setattr(settings, "FRONTEND_DIST_DIR", str(frontend_dir)) + with TestClient(api) as c: + yield c + + +def test_serves_index_html(client): + r = client.get("/") + assert r.status_code == 200 + assert "SPA" in r.text + assert r.headers["content-type"].startswith("text/html") + + +def test_serves_static_asset(client): + r = client.get("/logo.png") + assert r.status_code == 200 + assert r.content == b"fakeimg" + assert ( + "image" in r.headers["content-type"] + or r.headers["content-type"] == "application/octet-stream" + ) + + +def test_fallback_to_index_for_spa_route(client): + r = client.get("/some/spa/route") + assert r.status_code == 200 + assert "SPA" in r.text + + +def test_redirects_legacy_app_prefix_to_lowercase_feature_route(client): + r = client.get("/app/ANONYMIZER/validation", follow_redirects=False) + assert r.status_code == 307 + assert r.headers["location"] == "/anonymizer/validation" + + +def test_redirects_uppercase_feature_route_to_lowercase(client): + r = client.get("/DATA_SET/onboarding", follow_redirects=False) + assert r.status_code == 307 + assert r.headers["location"] == "/data_set/onboarding" + + +def test_api_healthcheck_is_available_under_api_prefix(client): + r = client.get("/api/server/healthcheck") + assert r.status_code == 200 + assert r.json() == {"status": "ok"} + + +def test_unknown_api_route_does_not_fallback_to_spa(client): + r = client.get("/api/no-existe") + assert r.status_code == 404 + assert r.json()["detail"] == "API route not found." + + +def test_404_for_missing_asset(client): + r = client.get("/missing.png") + assert r.status_code == 404 + assert r.json()["detail"] == "Frontend asset not found." + + +def test_404_for_path_traversal(client): + r = client.get("/%2e%2e/%2e%2e/etc/passwd") + assert r.status_code == 404 + assert r.json()["detail"] == "Frontend asset not found." + + +@pytest.mark.parametrize( + "path", + [ + "/anonymizer/no-existe", + "/datapublic/no-existe", + "/database/no-existe", + "/docs", + "/document-extract", + "/misc/no-existe", + "/openapi.json", + "/redoc", + "/server/no-existe", + ], +) +def test_does_not_fallback_to_spa_for_api_prefixes(client, path): + r = client.get(path) + assert r.status_code == 404 + assert r.json()["detail"] == "API route not found." diff --git a/tests/api/routers/test_pipeline_flows.py b/tests/api/routers/test_pipeline_flows.py index 8d53952d..5684d0f5 100644 --- a/tests/api/routers/test_pipeline_flows.py +++ b/tests/api/routers/test_pipeline_flows.py @@ -57,7 +57,7 @@ def test_should_run_anonymizer_flow_end_to_end( mock_check_output.side_effect = _fake_libreoffice_convert extract_response = client.post( - "/misc/document-extract", + "/api/misc/document-extract", files={ "file": ( "sample.docx", @@ -72,12 +72,14 @@ def test_should_run_anonymizer_flow_end_to_end( predictions = [] for paragraph in paragraphs: - predict_response = client.post("/anonymizer/predict", json={"text": paragraph}) + predict_response = client.post( + "/api/anonymizer/predict", json={"text": paragraph} + ) assert predict_response.status_code == 200 predictions.append(predict_response.json()) disambiguate_response = client.post( - "/anonymizer/disambiguate", + "/api/anonymizer/disambiguate", json={ "paragraphs": predictions, "label_policies": { @@ -90,7 +92,7 @@ def test_should_run_anonymizer_flow_end_to_end( assert len(annotations["data"]) == len(paragraphs) compile_response = client.post( - "/anonymizer/anonymize-document", + "/api/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, files={ "file": ( @@ -104,7 +106,7 @@ def test_should_run_anonymizer_flow_end_to_end( assert compile_response.headers["content-type"] == "application/octet-stream" validation_response = client.post( - "/anonymizer/validation", + "/api/anonymizer/validation", json={"text": paragraphs[0]}, ) assert validation_response.status_code == 200 @@ -124,7 +126,7 @@ def test_should_run_datapublic_flow_end_to_end( mock_load_pipeline.return_value = build_mock_pipeline() extract_response = client.post( - "/misc/document-extract", + "/api/misc/document-extract", files={ "file": ( "sample.docx", @@ -140,7 +142,7 @@ def test_should_run_datapublic_flow_end_to_end( document_id = uuid.uuid5(uuid.NAMESPACE_URL, "datapublic-e2e-flow") for paragraph in paragraphs: predict_response = client.post( - f"/datapublic/predict/{document_id}", + f"/api/datapublic/predict/{document_id}", json={"text": paragraph}, ) assert predict_response.status_code == 200 @@ -154,12 +156,12 @@ def test_should_run_datapublic_flow_end_to_end( validation_payload = {"materia": "penal", "violencia_de_genero": "si"} save_response = client.post( - f"/datapublic/validation/document/{document_id}", + f"/api/datapublic/validation/document/{document_id}", json=validation_payload, ) assert save_response.status_code == 200 - read_response = client.get(f"/datapublic/validation/document/{document_id}") + read_response = client.get(f"/api/datapublic/validation/document/{document_id}") assert read_response.status_code == 200 assert read_response.json() == validation_payload @@ -186,7 +188,7 @@ def test_should_compile_anonymized_document_with_real_libreoffice_when_available docx_bytes = buf.getvalue() response = client.post( - "/anonymizer/anonymize-document", + "/api/anonymizer/anonymize-document", data={"annotations": json.dumps(annotations)}, files={ "file": ( diff --git a/tests/api/test_utils.py b/tests/api/test_utils.py new file mode 100644 index 00000000..05795669 --- /dev/null +++ b/tests/api/test_utils.py @@ -0,0 +1,18 @@ +import torch + +from aymurai.api import utils +from aymurai.settings import settings + + +def test_pipeline_memory_cache_uses_configured_ttl(): + assert utils.mem_cache.ttl == settings.MEMORY_CACHE_TTL + + +def test_configure_torch_threads_calls_torch_api(monkeypatch): + calls = [] + monkeypatch.setattr(settings, "TORCH_NUM_THREADS", 3) + monkeypatch.setattr(torch, "set_num_threads", calls.append) + + utils.configure_torch_threads() + + assert calls == [3] diff --git a/tests/test_settings.py b/tests/test_settings.py new file mode 100644 index 00000000..ab2b0fb8 --- /dev/null +++ b/tests/test_settings.py @@ -0,0 +1,63 @@ +import pytest +from pydantic_core import ValidationError + +from aymurai.settings import ( + DEFAULT_DISAMBIGUATION_LABEL_POLICIES, + DEFAULT_RENDER_POLICY, + Settings, +) + + +def test_anonymization_policy_defaults_are_used_when_env_vars_are_absent(monkeypatch): + monkeypatch.delenv("DISAMBIGUATION_LABEL_POLICIES", raising=False) + monkeypatch.delenv("RENDER_POLICY", raising=False) + + settings = Settings() + + assert ( + settings.DISAMBIGUATION_LABEL_POLICIES == DEFAULT_DISAMBIGUATION_LABEL_POLICIES + ) + assert settings.DISAMBIGUATION_LABEL_POLICIES["PER"] == { + "disambiguation": "fuzzy", + "anonymize": True, + "use_subclass_when_available": True, + } + assert settings.DISAMBIGUATION_LABEL_POLICIES["DNI"] == { + "disambiguation": "fuzzy", + "anonymize": True, + "use_subclass_when_available": False, + } + assert settings.RENDER_POLICY == DEFAULT_RENDER_POLICY + + +def test_anonymization_policy_env_vars_override_defaults(monkeypatch): + label_policies = ( + '{"PER": {"disambiguation": "none", "anonymize": false, ' + '"use_subclass_when_available": false}}' + ) + render_policy = '{"suffix_mode": "always", "suffix_threshold": 0}' + monkeypatch.setenv("DISAMBIGUATION_LABEL_POLICIES", label_policies) + monkeypatch.setenv("RENDER_POLICY", render_policy) + + settings = Settings() + + assert settings.DISAMBIGUATION_LABEL_POLICIES == { + "PER": { + "disambiguation": "none", + "anonymize": False, + "use_subclass_when_available": False, + } + } + assert settings.RENDER_POLICY == {"suffix_mode": "always", "suffix_threshold": 0} + + +@pytest.mark.parametrize("env_name", ["DISAMBIGUATION_LABEL_POLICIES", "RENDER_POLICY"]) +def test_malformed_anonymization_policy_env_vars_raise_validation_error( + monkeypatch, env_name +): + monkeypatch.delenv("DISAMBIGUATION_LABEL_POLICIES", raising=False) + monkeypatch.delenv("RENDER_POLICY", raising=False) + monkeypatch.setenv(env_name, "{") + + with pytest.raises(ValidationError): + Settings() From efa62969c43dfb573701ce31359fde2739325a02 Mon Sep 17 00:00:00 2001 From: jansaldo Date: Wed, 10 Jun 2026 17:47:10 +0000 Subject: [PATCH 103/104] =?UTF-8?q?=F0=9F=94=A5=20Remove=20TensorFlow=20re?= =?UTF-8?q?lated=20environment=20variables=20in=20Dockerfile?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker/api/Dockerfile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/docker/api/Dockerfile b/docker/api/Dockerfile index 9d1b4a0d..1ac9d054 100644 --- a/docker/api/Dockerfile +++ b/docker/api/Dockerfile @@ -111,10 +111,8 @@ CMD uv run fastapi run --port 8899 .venv/lib/python3.10/site-packages/aymurai/ap # ----------------------------- FROM aymurai-api AS aymurai-api-full -# Configure TensorFlow and resources -ENV TF_CPP_MIN_LOG_LEVEL=3 \ - TFHUB_CACHE_DIR=resources/cache/tfhub_modules \ - RESOURCES_BASEPATH=resources +# Configure resources base path +ENV RESOURCES_BASEPATH=resources # Copy additional resources COPY ./resources/pipelines/production resources/pipelines/production From 61b6a57f132242acb2f979daeefe00cb83d89e1a Mon Sep 17 00:00:00 2001 From: jansaldo Date: Wed, 10 Jun 2026 19:08:26 +0000 Subject: [PATCH 104/104] =?UTF-8?q?=F0=9F=93=9D=20Update=20documentation?= =?UTF-8?q?=20for=20AymurAI=20v1.5.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.es.md | 44 ++++++++++++++++--------- README.md | 16 +++++---- docs/CONTRIBUTING.md | 27 +++++++++++++-- docs/README.md | 1 + docs/api/README.md | 30 ++++++++--------- docs/database/README.md | 16 ++++----- docs/es/README.md | 1 + docs/es/api/README.md | 30 ++++++++--------- docs/es/database/README.md | 16 ++++----- docs/es/models/README.md | 2 +- docs/es/models/anonymizer-model-card.md | 6 ++-- docs/es/pipelines/README.md | 4 +-- docs/es/pipelines/anonymizer/README.md | 20 ++++++----- docs/es/pipelines/datapublic/README.md | 16 ++++----- docs/models/README.md | 2 +- docs/models/anonymizer-model-card.md | 6 ++-- docs/pipelines/README.md | 4 +-- docs/pipelines/anonymizer/README.md | 20 ++++++----- docs/pipelines/datapublic/README.md | 16 ++++----- 19 files changed, 161 insertions(+), 116 deletions(-) diff --git a/README.es.md b/README.es.md index 90e939c0..46d6072d 100644 --- a/README.es.md +++ b/README.es.md @@ -1,17 +1,17 @@ -# AymurAI Backend +# AymurAI Idioma: [English](README.md) | **Español** -AymurAI Backend provee la API y los pipelines de ML usados para procesar resoluciones judiciales en dos flujos principales: +AymurAI provee una aplicación integrada, una API y pipelines de ML para procesar resoluciones judiciales mediante dos flujos principales: - `anonymizer`: extracción de entidades y generación de documentos anonimizados. - `data-public`: extracción de información estructurada para curación de dataset público. -Este repositorio contiene el servicio FastAPI, configuraciones de pipelines de producción y persistencia en base de datos para ambos flujos. +Este repositorio contiene el frontend React/Electron, el servicio FastAPI, las configuraciones de pipelines de producción y la persistencia en base de datos para ambos flujos. ## Qué es AymurAI -AymurAI es un proyecto orientado a facilitar la generación de datos judiciales anonimizados y estructurados para casos de violencia de género (VG) en América Latina. El backend orquesta la ingesta de documentos, la inferencia de modelos, la persistencia de validaciones y la exportación de resultados para usos operativos y de investigación. +AymurAI es un proyecto orientado a facilitar la generación de datos judiciales anonimizados y estructurados para casos de violencia de género (VG) en América Latina. La aplicación guía la ingesta de documentos, la inferencia de modelos, la revisión manual, la validación y la exportación de resultados para usos operativos y de investigación. -Este repositorio está enfocado en el backend: expone APIs consumidas por el frontend y ejecuta los pipelines de producción de `anonymizer` y `data-public`. +El frontend puede ejecutarse como aplicación web servida por FastAPI o como aplicación de escritorio Electron. Permite cargar y previsualizar documentos, revisar anotaciones, configurar políticas de entidades, exportar documentos anonimizados y validar datasets estructurados. ## Documentación - Índice técnico: [docs/es/README.md](docs/es/README.md) @@ -20,6 +20,7 @@ Este repositorio está enfocado en el backend: expone APIs consumidas por el fro - Flujo anonymizer: [docs/es/pipelines/anonymizer/README.md](docs/es/pipelines/anonymizer/README.md) - Flujo datapublic: [docs/es/pipelines/datapublic/README.md](docs/es/pipelines/datapublic/README.md) - Esquema de base de datos interna: [docs/es/database/README.md](docs/es/database/README.md) +- Desarrollo y empaquetado del frontend: [frontend/README.md](frontend/README.md) ## Inicio Rápido (imagen Docker) Ejecutar la imagen full de la API (incluye recursos de producción): @@ -50,7 +51,13 @@ docker run -d --name aymurai-backend-gpu --gpus all \ Abrir Swagger UI: ```text -http://localhost:8899/docs +http://localhost:8899/api/docs +``` + +Abrir el frontend integrado: + +```text +http://localhost:8899/ ``` ## Inicio Rápido (Docker Compose) @@ -80,6 +87,8 @@ make api-logs ## Resumen de runtime - Framework: `FastAPI` - Puerto por defecto: `8899` +- Ruta del frontend integrado: `GET /` +- Implementaciones del frontend: navegador y Electron - Motor de DB: `SQLModel` + migraciones Alembic al iniciar - URI de DB por defecto: `sqlite:////resources/cache/sqlite/database.db` - Configs de pipeline de producción: @@ -87,16 +96,16 @@ make api-logs - `resources/pipelines/production/datapublic/pipeline.json` ## Endpoints públicos principales -- `GET /server/healthcheck` -- `GET /server/stats/summary` -- `POST /misc/document-extract` (y alias deprecado `POST /document-extract`) -- `POST /anonymizer/predict` -- `POST /anonymizer/disambiguate` -- `POST /anonymizer/validation` -- `POST /anonymizer/anonymize-document` -- `POST /datapublic/predict/{document_id}` -- `GET /datapublic/validation/document/{document_id}` -- `POST /datapublic/validation/document/{document_id}` +- `GET /api/server/healthcheck` +- `GET /api/server/stats/summary` +- `POST /api/misc/document-extract` (y alias deprecado `POST /api/document-extract`) +- `POST /api/anonymizer/predict` +- `POST /api/anonymizer/disambiguate` +- `POST /api/anonymizer/validation` +- `POST /api/anonymizer/anonymize-document` +- `POST /api/datapublic/predict/{document_id}` +- `GET /api/datapublic/validation/document/{document_id}` +- `POST /api/datapublic/validation/document/{document_id}` Para contratos request/response y ejemplos completos, ver [docs/es/api/README.md](docs/es/api/README.md). @@ -121,6 +130,9 @@ Las contribuciones son bienvenidas en documentación, API y mejoras de pipelines - **Sofía del Pozo** - [@sofiadelpozo](https://github.com/sofiadelpozo) at [collective.ai](https://collectiveai.io) ([email](mailto:sofia.delpozo@collectiveai.io)) - **Paolo Donizetti** - [@padonizetti](https://github.com/padonizetti) at [collective.ai](https://collectiveai.io) ([email](mailto:paolo@collectiveai.io)) - **Conrado Beatriz** - [@conrabeatriz](https://github.com/conrabeatriz) at [collective.ai](https://collectiveai.io) ([email](mailto:conrado@collectiveai.io)) +- **Lionel Chamorro** - [@lionelchamorro](https://github.com/lionelchamorro) at [collective.ai](https://collectiveai.io) ([email](mailto:lio@collectiveai.io)) +- **Damián Mazzini** - [@ +dmazzini](https://github.com/dmazzini) at [collective.ai](https://collectiveai.io) ([email](mailto:dami@collectiveai.io)) ## Citar AymurAI Si usás AymurAI en investigación o publicaciones, por favor citá: diff --git a/README.md b/README.md index 573196fe..a8c335f1 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@ -# AymurAI Backend +# AymurAI Language: **English** | [Español](README.es.md) -AymurAI Backend provides the API and ML pipelines used to process judicial rulings for two main workflows: +AymurAI provides an integrated application, API, and ML pipelines for processing judicial rulings through two main workflows: - `anonymizer`: extract named entities and produce anonymized documents. - `data-public`: extract structured information for public dataset curation. -This repository contains the FastAPI service, production pipeline configs, and database persistence used by both workflows. +This repository contains the React/Electron frontend, FastAPI service, production pipeline configurations, and database persistence used by both workflows. ## About AymurAI -AymurAI is a project focused on supporting the generation of anonymized and structured judicial data for gender-based violence (GBV) cases in Latin America. The backend service orchestrates document ingestion, ML inference, validation persistence, and document export for downstream operational and research uses. +AymurAI is a project focused on supporting the generation of anonymized and structured judicial data for gender-based violence (GBV) cases in Latin America. The application guides users through document ingestion, ML inference, manual review, validation, and export for operational and research uses. -This repository is backend-focused: it exposes APIs consumed by the frontend and runs the production pipelines for `anonymizer` and `data-public`. +The frontend can run as a web application served by FastAPI or as an Electron desktop application. It supports document upload and preview, interactive annotation review, entity policy configuration, anonymized document export, and structured dataset validation. ## Documentation - Technical docs index: [docs/README.md](docs/README.md) @@ -20,6 +20,7 @@ This repository is backend-focused: it exposes APIs consumed by the frontend and - Anonymizer flow: [docs/pipelines/anonymizer/README.md](docs/pipelines/anonymizer/README.md) - Datapublic flow: [docs/pipelines/datapublic/README.md](docs/pipelines/datapublic/README.md) - Internal database schema: [docs/database/README.md](docs/database/README.md) +- Frontend development and packaging: [frontend/README.md](frontend/README.md) ## Quick Start (Docker Image) Run the full API image (includes production resources): @@ -87,6 +88,7 @@ make api-logs - Framework: `FastAPI` - Default API port: `8899` - Bundled frontend path: `GET /` +- Frontend implementations: browser and Electron - DB engine: `SQLModel` + Alembic migrations on startup - Default DB URI: `sqlite:////resources/cache/sqlite/database.db` - Production pipeline configs: @@ -128,7 +130,9 @@ Contributions are welcome across documentation, API, and pipeline improvements. - **Sofía del Pozo** - [@sofiadelpozo](https://github.com/sofiadelpozo) at [collective.ai](https://collectiveai.io) ([email](mailto:sofia.delpozo@collectiveai.io)) - **Paolo Donizetti** - [@padonizetti](https://github.com/padonizetti) at [collective.ai](https://collectiveai.io) ([email](mailto:paolo@collectiveai.io)) - **Conrado Beatriz** - [@conrabeatriz](https://github.com/conrabeatriz) at [collective.ai](https://collectiveai.io) ([email](mailto:conrado@collectiveai.io)) - +- **Lionel Chamorro** - [@lionelchamorro](https://github.com/lionelchamorro) at [collective.ai](https://collectiveai.io) ([email](mailto:lio@collectiveai.io)) +- **Damián Mazzini** - [@ +dmazzini](https://github.com/dmazzini) at [collective.ai](https://collectiveai.io) ([email](mailto:dami@collectiveai.io)) ## Citing AymurAI If you use AymurAI in research or publications, please cite: diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index c9b462da..0d55d3f7 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -22,7 +22,9 @@ make api-up # or make api-full-up ``` -Swagger UI: `http://localhost:8899/docs` +Bundled frontend: `http://localhost:8899/` + +Swagger UI: `http://localhost:8899/api/docs` If you prefer working from VS Code, the repository also includes a `.devcontainer/` setup. @@ -39,6 +41,26 @@ pip install -e . For most contributors, Docker is the easiest way to get a working API with the expected runtime dependencies. +### Frontend development +The frontend supports browser and Electron development. Install its dependencies and run the desired target: + +```bash +cd frontend +pnpm install +pnpm run dev:web # browser +pnpm run dev # Electron +``` + +Before submitting frontend changes, run: + +```bash +pnpm run lint +pnpm run typecheck +pnpm test +``` + +See [the frontend README](../frontend/README.md) for build and packaging commands. + ## Pre-commit hooks After installing dependencies, enable the hooks: @@ -61,8 +83,9 @@ ruff format aymurai/ ``` ## Documentation policy -When behavior changes in API, pipelines, or DB persistence, update the corresponding docs in the same PR: +When behavior changes in the frontend, API, pipelines, or DB persistence, update the corresponding docs in the same PR: - `README.md` +- `frontend/README.md` - `docs/api/README.md` - `docs/pipelines/README.md` - `docs/pipelines/anonymizer/README.md` diff --git a/docs/README.md b/docs/README.md index 5a05e53e..fa347452 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,6 +10,7 @@ This index covers operational documentation for `v1.5.0`. - Anonymizer flow: [pipelines/anonymizer/README.md](pipelines/anonymizer/README.md) - Datapublic flow: [pipelines/datapublic/README.md](pipelines/datapublic/README.md) - Internal database schema: [database/README.md](database/README.md) +- Frontend development and packaging: [../frontend/README.md](../frontend/README.md) ## Entities - Entities index: [entities/README.md](entities/README.md) diff --git a/docs/api/README.md b/docs/api/README.md index 4b3957c5..2c676c12 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -128,7 +128,7 @@ Note: the JSON snippets below are minimal valid examples. Real payloads may incl ### Server -#### `GET /server/healthcheck` +#### `GET /api/server/healthcheck` - Response `200`: ```json @@ -139,7 +139,7 @@ Note: the JSON snippets below are minimal valid examples. Real payloads may incl curl -s http://localhost:8899/api/server/healthcheck ``` -#### `GET /server/stats/summary` +#### `GET /api/server/stats/summary` - Response `200` (shape): ```json @@ -158,8 +158,8 @@ curl -s http://localhost:8899/api/server/stats/summary ### Document Extraction -#### `POST /misc/document-extract` -#### `POST /document-extract` (deprecated alias) +#### `POST /api/misc/document-extract` +#### `POST /api/document-extract` (deprecated alias) - Request: `multipart/form-data` with `file` - Supported MIME types in extraction flow: DOCX, ODT, PDF - Response `200`: @@ -183,7 +183,7 @@ Common errors: ### Anonymizer -#### `POST /anonymizer/predict` +#### `POST /api/anonymizer/predict` - Request body: `TextRequest` - Query param: `use_cache=true|false` (default `true`) - Response `200`: `DocumentInformation` @@ -194,7 +194,7 @@ curl -s -X POST "http://localhost:8899/api/anonymizer/predict?use_cache=true" \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` -#### `POST /anonymizer/disambiguate` +#### `POST /api/anonymizer/disambiguate` - Request body: ```json @@ -223,7 +223,7 @@ curl -s -X POST http://localhost:8899/api/anonymizer/disambiguate \ -d '{"paragraphs":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}}}' ``` -#### `POST /anonymizer/validation` +#### `POST /api/anonymizer/validation` - Request body: `TextRequest` - Response `200`: `list[DocLabel] | null` @@ -233,11 +233,11 @@ curl -s -X POST http://localhost:8899/api/anonymizer/validation \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` -#### `POST /anonymizer/anonymize-document` +#### `POST /api/anonymizer/anonymize-document` - Request: `multipart/form-data` - - `file`: original document (`.docx`, `.pdf`, `.odt`) + - `file`: original document (`.docx` or `.pdf`) - `annotations`: JSON string serialized from `DocumentAnnotations` -- Response `200`: binary anonymized `.odt` file +- Response `200`: anonymized `.odt` for DOCX input or anonymized `.pdf` for PDF input ```bash curl -X POST http://localhost:8899/api/anonymizer/anonymize-document \ @@ -246,12 +246,12 @@ curl -X POST http://localhost:8899/api/anonymizer/anonymize-document \ ``` Common errors: -- `400` invalid form payload +- `400` invalid form payload, unsupported input format, or invalid document - `500` conversion/anonymization failures ### Data-Public -#### `POST /datapublic/predict/{document_id}` +#### `POST /api/datapublic/predict/{document_id}` - Path param: `document_id` (`UUID5`) - Request body: `TextRequest` - Query param: `use_cache=true|false` (default `true`) @@ -263,7 +263,7 @@ curl -s -X POST "http://localhost:8899/api/datapublic/predict/7e6b6f35-2f29-58f7 -d '{"text":"Buenos Aires, 17 de noviembre de 2024"}' ``` -#### `GET /datapublic/validation/document/{document_id}` +#### `GET /api/datapublic/validation/document/{document_id}` - Response `200`: object or `null` - Response `404`: document not found @@ -271,7 +271,7 @@ curl -s -X POST "http://localhost:8899/api/datapublic/predict/7e6b6f35-2f29-58f7 curl -s http://localhost:8899/api/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc ``` -#### `POST /datapublic/validation/document/{document_id}` +#### `POST /api/datapublic/validation/document/{document_id}` - Request body: free-form JSON object (stored as document-level validation) - Response `200`: empty body @@ -300,7 +300,7 @@ For PDF input endpoints, optional query param: Example: ```bash -curl -X POST "http://localhost:8899/convert/pdf/docx?backend=libreoffice" \ +curl -X POST "http://localhost:8899/api/convert/pdf/docx?backend=libreoffice" \ -F "file=@input.pdf" -o output.docx ``` diff --git a/docs/database/README.md b/docs/database/README.md index 64cf5212..555524e4 100644 --- a/docs/database/README.md +++ b/docs/database/README.md @@ -86,28 +86,28 @@ Primary key is composite over `id`, `document_id`, `paragraph_id`. ## Endpoint to Persistence Mapping ### Anonymizer -- `POST /anonymizer/predict` +- `POST /api/anonymizer/predict` - Reads `anonymization_paragraph` by paragraph UUID. - Writes `anonymization_paragraph.prediction` when cache is enabled. -- `POST /anonymizer/disambiguate` +- `POST /api/anonymizer/disambiguate` - Writes disambiguated predictions to `anonymization_paragraph.prediction`. -- `POST /anonymizer/validation` +- `POST /api/anonymizer/validation` - Reads `anonymization_paragraph.validation`. -- `POST /anonymizer/anonymize-document` +- `POST /api/anonymizer/anonymize-document` - Writes `anonymization_paragraph.validation`. - Creates `anonymization_document` keyed by uploaded file content hash. - Creates link rows in `anonymization_document_paragraph`. ### Data-public -- `POST /datapublic/predict/{document_id}` +- `POST /api/datapublic/predict/{document_id}` - Uses caller-provided `document_id` as the document primary key. - Ensures `datapublic_document` exists when `use_cache=true`. - Writes `datapublic_paragraph.prediction` when `use_cache=true`. - Writes link row in `datapublic_document_paragraph` when `use_cache=true`. -- `GET /datapublic/validation/document/{document_id}` +- `GET /api/datapublic/validation/document/{document_id}` - Reads `datapublic_document.validation`. -- `POST /datapublic/validation/document/{document_id}` +- `POST /api/datapublic/validation/document/{document_id}` - Upserts `datapublic_document.validation`. ## Legacy Note -Route modules for dataset CRUD (`/datapublic/dataset/*`) exist in code but are not mounted in the public router. Do not treat them as active public API until exposed in `core.router`. +Route modules for dataset CRUD (`/api/datapublic/dataset/*`) exist in code but are not mounted in the public router. Do not treat them as active public API until exposed in `core.router`. diff --git a/docs/es/README.md b/docs/es/README.md index 5998d7cc..7d3c2710 100644 --- a/docs/es/README.md +++ b/docs/es/README.md @@ -10,6 +10,7 @@ Este índice cubre la documentación operativa para `v1.5.0`. - Flujo anonymizer: [pipelines/anonymizer/README.md](pipelines/anonymizer/README.md) - Flujo datapublic: [pipelines/datapublic/README.md](pipelines/datapublic/README.md) - Esquema de base de datos interna: [database/README.md](database/README.md) +- Desarrollo y empaquetado del frontend: [../../frontend/README.md](../../frontend/README.md) ## Entidades - Índice de entidades: [entities/README.md](entities/README.md) diff --git a/docs/es/api/README.md b/docs/es/api/README.md index d51ec974..afb84e97 100644 --- a/docs/es/api/README.md +++ b/docs/es/api/README.md @@ -128,7 +128,7 @@ Nota: los snippets JSON de abajo son ejemplos mínimos válidos. Los payloads re ### Server -#### `GET /server/healthcheck` +#### `GET /api/server/healthcheck` - Respuesta `200`: ```json @@ -139,7 +139,7 @@ Nota: los snippets JSON de abajo son ejemplos mínimos válidos. Los payloads re curl -s http://localhost:8899/api/server/healthcheck ``` -#### `GET /server/stats/summary` +#### `GET /api/server/stats/summary` - Respuesta `200` (forma): ```json @@ -158,8 +158,8 @@ curl -s http://localhost:8899/api/server/stats/summary ### Extracción de documentos -#### `POST /misc/document-extract` -#### `POST /document-extract` (alias deprecado) +#### `POST /api/misc/document-extract` +#### `POST /api/document-extract` (alias deprecado) - Request: `multipart/form-data` con `file` - MIME types soportados en extracción: DOCX, ODT, PDF - Respuesta `200`: @@ -183,7 +183,7 @@ Errores comunes: ### Anonymizer -#### `POST /anonymizer/predict` +#### `POST /api/anonymizer/predict` - Body: `TextRequest` - Query param: `use_cache=true|false` (default `true`) - Respuesta `200`: `DocumentInformation` @@ -194,7 +194,7 @@ curl -s -X POST "http://localhost:8899/api/anonymizer/predict?use_cache=true" \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` -#### `POST /anonymizer/disambiguate` +#### `POST /api/anonymizer/disambiguate` - Body request: ```json @@ -223,7 +223,7 @@ curl -s -X POST http://localhost:8899/api/anonymizer/disambiguate \ -d '{"paragraphs":[{"document":"Acusado: Ramiro Marrón DNI 34.555.666.","labels":[]}],"label_policies":{"PER":{"anonymize":true,"disambiguation":"fuzzy"}}}' ``` -#### `POST /anonymizer/validation` +#### `POST /api/anonymizer/validation` - Body: `TextRequest` - Respuesta `200`: `list[DocLabel] | null` @@ -233,11 +233,11 @@ curl -s -X POST http://localhost:8899/api/anonymizer/validation \ -d '{"text":"Acusado: Ramiro Marrón DNI 34.555.666."}' ``` -#### `POST /anonymizer/anonymize-document` +#### `POST /api/anonymizer/anonymize-document` - Request: `multipart/form-data` - - `file`: documento original (`.docx`, `.pdf`, `.odt`) + - `file`: documento original (`.docx` o `.pdf`) - `annotations`: string JSON serializado de `DocumentAnnotations` -- Respuesta `200`: archivo `.odt` anonimizado (binario) +- Respuesta `200`: `.odt` anonimizado para entrada DOCX o `.pdf` anonimizado para entrada PDF ```bash curl -X POST http://localhost:8899/api/anonymizer/anonymize-document \ @@ -246,12 +246,12 @@ curl -X POST http://localhost:8899/api/anonymizer/anonymize-document \ ``` Errores comunes: -- `400` payload multipart inválido +- `400` payload multipart inválido, formato no soportado o documento inválido - `500` errores de anonimización/conversión ### Data-Public -#### `POST /datapublic/predict/{document_id}` +#### `POST /api/datapublic/predict/{document_id}` - Path param: `document_id` (`UUID5`) - Body: `TextRequest` - Query param: `use_cache=true|false` (default `true`) @@ -263,7 +263,7 @@ curl -s -X POST "http://localhost:8899/api/datapublic/predict/7e6b6f35-2f29-58f7 -d '{"text":"Buenos Aires, 17 de noviembre de 2024"}' ``` -#### `GET /datapublic/validation/document/{document_id}` +#### `GET /api/datapublic/validation/document/{document_id}` - Respuesta `200`: objeto o `null` - Respuesta `404`: documento inexistente @@ -271,7 +271,7 @@ curl -s -X POST "http://localhost:8899/api/datapublic/predict/7e6b6f35-2f29-58f7 curl -s http://localhost:8899/api/datapublic/validation/document/7e6b6f35-2f29-58f7-9f8e-fd1d9026a6bc ``` -#### `POST /datapublic/validation/document/{document_id}` +#### `POST /api/datapublic/validation/document/{document_id}` - Body: objeto JSON libre (se persiste como validación a nivel documento) - Respuesta `200`: body vacío @@ -300,7 +300,7 @@ Para endpoints con input PDF, query param opcional: Ejemplo: ```bash -curl -X POST "http://localhost:8899/convert/pdf/docx?backend=libreoffice" \ +curl -X POST "http://localhost:8899/api/convert/pdf/docx?backend=libreoffice" \ -F "file=@input.pdf" -o output.docx ``` diff --git a/docs/es/database/README.md b/docs/es/database/README.md index 7fee93a5..b263ac1d 100644 --- a/docs/es/database/README.md +++ b/docs/es/database/README.md @@ -86,28 +86,28 @@ La clave primaria es compuesta por `id`, `document_id`, `paragraph_id`. ## Mapeo endpoint -> persistencia ### Anonymizer -- `POST /anonymizer/predict` +- `POST /api/anonymizer/predict` - Lee `anonymization_paragraph` por UUID de párrafo. - Escribe `anonymization_paragraph.prediction` cuando el cache está activo. -- `POST /anonymizer/disambiguate` +- `POST /api/anonymizer/disambiguate` - Escribe predicciones desambiguadas en `anonymization_paragraph.prediction`. -- `POST /anonymizer/validation` +- `POST /api/anonymizer/validation` - Lee `anonymization_paragraph.validation`. -- `POST /anonymizer/anonymize-document` +- `POST /api/anonymizer/anonymize-document` - Escribe `anonymization_paragraph.validation`. - Crea `anonymization_document` con clave derivada del hash del contenido binario subido. - Crea vínculos en `anonymization_document_paragraph`. ### Data-public -- `POST /datapublic/predict/{document_id}` +- `POST /api/datapublic/predict/{document_id}` - Usa el `document_id` provisto por el cliente como primary key del documento. - Asegura existencia de `datapublic_document` cuando `use_cache=true`. - Escribe `datapublic_paragraph.prediction` cuando `use_cache=true`. - Escribe vínculo en `datapublic_document_paragraph` cuando `use_cache=true`. -- `GET /datapublic/validation/document/{document_id}` +- `GET /api/datapublic/validation/document/{document_id}` - Lee `datapublic_document.validation`. -- `POST /datapublic/validation/document/{document_id}` +- `POST /api/datapublic/validation/document/{document_id}` - Hace upsert de `datapublic_document.validation`. ## Nota legacy -Los módulos de rutas para CRUD de dataset (`/datapublic/dataset/*`) existen en código pero no están montados en el router público. No deben tratarse como API pública activa hasta su exposición en `core.router`. +Los módulos de rutas para CRUD de dataset (`/api/datapublic/dataset/*`) existen en código pero no están montados en el router público. No deben tratarse como API pública activa hasta su exposición en `core.router`. diff --git a/docs/es/models/README.md b/docs/es/models/README.md index a843aee4..a4bcd14f 100644 --- a/docs/es/models/README.md +++ b/docs/es/models/README.md @@ -10,7 +10,7 @@ Esta sección documenta los modelos individuales utilizados por el backend. ## Uso actual en producción - `flair-anonymizer` usa la model card del NER de anonymizer documentada aquí. -- `datapublic` usa el modelo Flair NER y el clasificador de decisiones. +- `datapublic` usa el modelo Flair NER, el clasificador de decisiones y encoders sentence-transformer multilingües para subcategorización basada en embeddings. ## Documentación relacionada - Índice de documentación: [../README.md](../README.md) diff --git a/docs/es/models/anonymizer-model-card.md b/docs/es/models/anonymizer-model-card.md index 8ab878d8..0f934578 100644 --- a/docs/es/models/anonymizer-model-card.md +++ b/docs/es/models/anonymizer-model-card.md @@ -53,10 +53,10 @@ Sus predicciones de spans se postprocesan luego con: Esas predicciones alimentan el resto del flujo de anonimización: -1. `POST /anonymizer/predict` ejecuta la extracción de spans. -2. `POST /anonymizer/disambiguate` asigna IDs canónicos y metadatos efectivos por label. +1. `POST /api/anonymizer/predict` ejecuta la extracción de spans. +2. `POST /api/anonymizer/disambiguate` asigna IDs canónicos y metadatos efectivos por label. 3. La revisión manual puede editar labels, `label_policies` y `render_policy`. -4. `POST /anonymizer/anonymize-document` aplica los reemplazos sobre el documento de salida. +4. `POST /api/anonymizer/anonymize-document` aplica los reemplazos sobre el documento de salida. # Uso diff --git a/docs/es/pipelines/README.md b/docs/es/pipelines/README.md index c6ff29fa..3eb62157 100644 --- a/docs/es/pipelines/README.md +++ b/docs/es/pipelines/README.md @@ -17,8 +17,8 @@ Esta sección documenta los pipelines de producción del backend por flujo. - Config datapublic: `resources/pipelines/production/datapublic/pipeline.json` ## Mapeo con API -- `POST /anonymizer/predict` -> `flair-anonymizer` -- `POST /datapublic/predict/{document_id}` -> `datapublic` +- `POST /api/anonymizer/predict` -> `flair-anonymizer` +- `POST /api/datapublic/predict/{document_id}` -> `datapublic` ## Documentación relacionada - Referencia API: [../api/README.md](../api/README.md) diff --git a/docs/es/pipelines/anonymizer/README.md b/docs/es/pipelines/anonymizer/README.md index f7f71857..0c910e6d 100644 --- a/docs/es/pipelines/anonymizer/README.md +++ b/docs/es/pipelines/anonymizer/README.md @@ -12,18 +12,18 @@ Este flujo extrae entidades del texto judicial y compila documentos anonimizados Fuente editable: [../../../pipelines/anonymizer/pipeline.excalidraw](../../../pipelines/anonymizer/pipeline.excalidraw) ## Entrypoints de runtime -- `POST /misc/document-extract` -- `POST /anonymizer/predict` -- `POST /anonymizer/disambiguate` -- `POST /anonymizer/validation` -- `POST /anonymizer/anonymize-document` +- `POST /api/misc/document-extract` +- `POST /api/anonymizer/predict` +- `POST /api/anonymizer/disambiguate` +- `POST /api/anonymizer/validation` +- `POST /api/anonymizer/anonymize-document` ## Flujo paso a paso -1. Extracción de texto (`/misc/document-extract`) divide el documento fuente en párrafos normalizados. -2. Predicción (`/anonymizer/predict`) ejecuta NER por párrafo. -3. Desambiguación (`/anonymizer/disambiguate`) asigna IDs canónicos y metadatos efectivos para la desambiguación/anonimización. +1. Extracción de texto (`/api/misc/document-extract`) divide el documento fuente en párrafos normalizados. +2. Predicción (`/api/anonymizer/predict`) ejecuta NER por párrafo. +3. Desambiguación (`/api/anonymizer/disambiguate`) asigna IDs canónicos y metadatos efectivos para la desambiguación/anonimización. 4. Revisión manual en UI para editar etiquetas/políticas. -5. Compilación (`/anonymizer/anonymize-document`) aplica reemplazos y exporta `.odt` anonimizado. +5. Compilación (`/api/anonymizer/anonymize-document`) aplica reemplazos preservando el formato de origen: una entrada PDF devuelve PDF y una entrada DOCX se exporta como ODT. ## Componentes técnicos @@ -57,6 +57,8 @@ Tablas usadas por este flujo: - `anonymization_document_paragraph` ## Notas +- La anonimización de PDF redacta el texto en el documento y preserva el layout no afectado, las anotaciones, los metadatos y el watermark. +- La anonimización de DOCX procesa reemplazos antes de convertir el resultado a ODT. - Las políticas por label se mergean desde entorno y request. - `render_policy` controla el comportamiento de sufijos (`auto`, `always`, `never`). diff --git a/docs/es/pipelines/datapublic/README.md b/docs/es/pipelines/datapublic/README.md index aec3291c..2abdd047 100644 --- a/docs/es/pipelines/datapublic/README.md +++ b/docs/es/pipelines/datapublic/README.md @@ -10,14 +10,14 @@ Este flujo extrae información estructurada a partir de párrafos y soporta pers ![Diagrama del pipeline de datapublic](../../../pipelines/datapublic/pipeline.png) ## Entrypoints de runtime -- `POST /misc/document-extract` -- `POST /datapublic/predict/{document_id}` -- `GET /datapublic/validation/document/{document_id}` -- `POST /datapublic/validation/document/{document_id}` +- `POST /api/misc/document-extract` +- `POST /api/datapublic/predict/{document_id}` +- `GET /api/datapublic/validation/document/{document_id}` +- `POST /api/datapublic/validation/document/{document_id}` ## Flujo paso a paso -1. Extracción de texto (`/misc/document-extract`) divide el documento fuente en párrafos normalizados. -2. Predicción (`/datapublic/predict/{document_id}`) procesa cada párrafo y devuelve predicciones; la persistencia en caché ocurre solo cuando `use_cache=true` (default). +1. Extracción de texto (`/api/misc/document-extract`) divide el documento fuente en párrafos normalizados. +2. Predicción (`/api/datapublic/predict/{document_id}`) procesa cada párrafo y devuelve predicciones; la persistencia en caché ocurre solo cuando `use_cache=true` (default). 3. Revisión en UI agrega la salida validada a nivel documento. 4. Los endpoints de validación leen/escriben payload de validación de documento. @@ -61,8 +61,8 @@ Tablas usadas por este flujo: - El directorio de pipeline en producción sigue llamándose `datapublic`. - `document_id` es la clave de agrupamiento a nivel documento para asociar predicciones por párrafo y el payload de validación. - La persistencia de validación es a nivel documento y acepta intencionalmente un objeto JSON libre. -- `GET /datapublic/validation/document/{document_id}` devuelve `404` cuando el documento no existe; `POST` crea o actualiza el payload de validación. -- El router público no monta actualmente `/datapublic/dataset/*`. +- `GET /api/datapublic/validation/document/{document_id}` devuelve `404` cuando el documento no existe; `POST` crea o actualiza el payload de validación. +- El router público no monta actualmente `/api/datapublic/dataset/*`. - La validación a nivel párrafo aparece en código como lógica legacy comentada y no forma parte del flujo público. ## Modelos usados por este flujo diff --git a/docs/models/README.md b/docs/models/README.md index 8893a1e4..2d7885e9 100644 --- a/docs/models/README.md +++ b/docs/models/README.md @@ -10,7 +10,7 @@ This section documents the individual models used by the backend. ## Current production usage - `flair-anonymizer` uses the anonymizer NER model card documented here. -- `datapublic` uses the Flair NER model and the decision classifier. +- `datapublic` uses the Flair NER model, the decision classifier, and multilingual sentence-transformer encoders for embedding-based subcategorization. ## Related docs - Documentation index: [../README.md](../README.md) diff --git a/docs/models/anonymizer-model-card.md b/docs/models/anonymizer-model-card.md index 53a46813..e50b2e69 100644 --- a/docs/models/anonymizer-model-card.md +++ b/docs/models/anonymizer-model-card.md @@ -53,10 +53,10 @@ Its raw span predictions are then post-processed by: Those predictions feed the rest of the anonymization flow: -1. `POST /anonymizer/predict` runs span extraction. -2. `POST /anonymizer/disambiguate` assigns canonical entity IDs and effective per-label metadata. +1. `POST /api/anonymizer/predict` runs span extraction. +2. `POST /api/anonymizer/disambiguate` assigns canonical entity IDs and effective per-label metadata. 3. Manual review may edit labels, `label_policies`, and `render_policy`. -4. `POST /anonymizer/anonymize-document` applies replacements in the output document. +4. `POST /api/anonymizer/anonymize-document` applies replacements in the output document. # Usage diff --git a/docs/pipelines/README.md b/docs/pipelines/README.md index e62edfe0..a2b2605a 100644 --- a/docs/pipelines/README.md +++ b/docs/pipelines/README.md @@ -17,8 +17,8 @@ This section documents AymurAI backend production pipelines by workflow. - Datapublic config: `resources/pipelines/production/datapublic/pipeline.json` ## API mapping -- `POST /anonymizer/predict` -> `flair-anonymizer` -- `POST /datapublic/predict/{document_id}` -> `datapublic` +- `POST /api/anonymizer/predict` -> `flair-anonymizer` +- `POST /api/datapublic/predict/{document_id}` -> `datapublic` ## Related docs - API reference: [../api/README.md](../api/README.md) diff --git a/docs/pipelines/anonymizer/README.md b/docs/pipelines/anonymizer/README.md index 67880ba0..5b724b05 100644 --- a/docs/pipelines/anonymizer/README.md +++ b/docs/pipelines/anonymizer/README.md @@ -12,18 +12,18 @@ This flow extracts entities from judicial text and compiles anonymized output do Editable source: [pipeline.excalidraw](pipeline.excalidraw) ## Runtime entrypoints -- `POST /misc/document-extract` -- `POST /anonymizer/predict` -- `POST /anonymizer/disambiguate` -- `POST /anonymizer/validation` -- `POST /anonymizer/anonymize-document` +- `POST /api/misc/document-extract` +- `POST /api/anonymizer/predict` +- `POST /api/anonymizer/disambiguate` +- `POST /api/anonymizer/validation` +- `POST /api/anonymizer/anonymize-document` ## Step-by-step flow -1. Text extraction (`/misc/document-extract`) splits source document into normalized paragraphs. -2. Prediction (`/anonymizer/predict`) runs NER on each paragraph. -3. Disambiguation (`/anonymizer/disambiguate`) assigns canonical entity IDs and effective anonymization/disambiguation metadata. +1. Text extraction (`/api/misc/document-extract`) splits source document into normalized paragraphs. +2. Prediction (`/api/anonymizer/predict`) runs NER on each paragraph. +3. Disambiguation (`/api/anonymizer/disambiguate`) assigns canonical entity IDs and effective anonymization/disambiguation metadata. 4. Manual review in UI edits labels and optional policies. -5. Compilation (`/anonymizer/anonymize-document`) applies replacements and exports anonymized `.odt`. +5. Compilation (`/api/anonymizer/anonymize-document`) applies replacements while preserving the source format: PDF input returns PDF, while DOCX input is exported as ODT. ## Technical components @@ -57,6 +57,8 @@ Tables touched by this flow: - `anonymization_document_paragraph` ## Notes +- PDF anonymization redacts text in place and preserves unaffected layout, annotations, metadata, and watermark behavior. +- DOCX anonymization handles replacements before conversion to ODT. - Label policies are merged from environment and request payload. - Render policy controls suffix behavior (`auto`, `always`, `never`) during replacement. diff --git a/docs/pipelines/datapublic/README.md b/docs/pipelines/datapublic/README.md index 53b4199c..0bcadad2 100644 --- a/docs/pipelines/datapublic/README.md +++ b/docs/pipelines/datapublic/README.md @@ -10,14 +10,14 @@ This flow extracts structured information from paragraphs and supports document- ![Datapublic pipeline diagram](pipeline.png) ## Runtime entrypoints -- `POST /misc/document-extract` -- `POST /datapublic/predict/{document_id}` -- `GET /datapublic/validation/document/{document_id}` -- `POST /datapublic/validation/document/{document_id}` +- `POST /api/misc/document-extract` +- `POST /api/datapublic/predict/{document_id}` +- `GET /api/datapublic/validation/document/{document_id}` +- `POST /api/datapublic/validation/document/{document_id}` ## Step-by-step flow -1. Text extraction (`/misc/document-extract`) splits source document into normalized paragraphs. -2. Prediction (`/datapublic/predict/{document_id}`) processes each paragraph and returns predictions; cache persistence happens only when `use_cache=true` (default). +1. Text extraction (`/api/misc/document-extract`) splits source document into normalized paragraphs. +2. Prediction (`/api/datapublic/predict/{document_id}`) processes each paragraph and returns predictions; cache persistence happens only when `use_cache=true` (default). 3. UI review aggregates document-level validated output. 4. Validation read/write endpoints persist and retrieve document-level validation payload. @@ -61,8 +61,8 @@ Tables touched by this flow: - Current production pipeline directory name is `datapublic`. - `document_id` is the document-level grouping key used to associate paragraph predictions and validation payloads. - Validation persistence is document-level and intentionally accepts a free-form JSON object. -- `GET /datapublic/validation/document/{document_id}` returns `404` when the document does not exist; `POST` upserts the validation payload. -- Public router currently does not mount `/datapublic/dataset/*` routes. +- `GET /api/datapublic/validation/document/{document_id}` returns `404` when the document does not exist; `POST` upserts the validation payload. +- Public router currently does not mount `/api/datapublic/dataset/*` routes. - Paragraph-level validation route exists in code as commented legacy logic and is not part of the public flow. ## Models used by this flow

    KcND*yD>OJ!^X3$!qdA@2kLq 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�H{N!3$2 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ӞPH{rbwYk0pP|NjQCU`1X3OyMS}`m3+TM4in0o zdiEw@$1bO&Iu`zSS8%o#IC%gh(62J})t7y)GL2QuB{ggrlFcd-rTTb;@eXKW0(XPo zkd&)jarm^+8o#Z|p3;rwiv7@%j%^Pi6&iySgFBgnFJ&p*uqgKs!Dy3rSR9HFtngpn z#b71TU@^*2-3yvjt`vTv1f5XkND67`C2aqJvAKYwcI2P9| z8Phx-(+A0nVO3RtZnq9Ny*OIJ0DtzkcA%mH@agtKDQr8~+c5AUorsj|4%SjkWT^wd z@1<%fwO|2w;LoHRSX@jWh}g2S0(1#OHhYiM7N{XyC6ozhfJXIu^Q!x9A4qbD-l%3| zBEqmgT+Ve(FbYV6IjObh?vz8P#90sRXxt&yt5?5|)b*b6f5fA4(5>Tf=iby8XXP&o zL%v{!cS4#3SB}E1j`on%6N&r3>E1SJ*1WC?Y%xF>)%Y1O>98-8dPdW6|F)}nk#kDSxo=b^(r55uj)0^C%RDC<)2zr=>a}i zsdf28KdS*faiZx}9$;Q2>#a|8#>&idAlhf?Fuzdp+RP`~S*hrb5IwK5WadIQru2!% zSP?n-ME5K;&nC+8ngXK57Ne&AspZw$E5>qn!&6@@Vut|ptP#Kj3srpTu=U^8p_?x1 z&VOqG{BPH}e>?R5x%=tgOZM+2``_dxDe%xF?^PW6bz2E@-+LpFuH0vjJ=D3#e~m$V z3z03|Shr?g1KqQ{fkBmgw=W0kp6u6A3-CcC%)EYQi0DF`)Kgtu*XoCB-Bz-CXrLw6zpGzaktT>MF9s#;?#Aa3E$j}X zRPHK?v3yn2cCiN>?m7kr-0_ZY+s=!xuJUUVZS1x|5wAk+S!g z>g?NP!XMW4#yLj5cU#J=&v0HIp9@F=5R-ETEcY%O`AW&Z<#|#VJE=0$PZc~XrTw}5x{ZL>MAA6`mg_{=S$`S63mUS)$X$>-6FUqBKl90IF~VIPC> zhnPZ>1fK1`B3;#aAG}O!F>xk15ZLB+;*{K3F;V;>-QXk!;?H?0FI~*f=1AXs&Ud=U z3|qdp3^KW#2o)2(rK`+uJTkTqls3M-)Cal#A<3PCClM-27?kP6O~#W5UYht%RqQ3K zM=jqg2Af>Q;xZG@CbBsUn|*0>_SAxZUvJH%a6vMm0iBJr%4u{CG^e^61fOceZf|IV^ zc=_^PwGq{+&DIW<7Y4>)0b%$~7(vQ^xet!TfJ-inuXrW)fv`AMj3P^FC=4cK_K)M? z#6o|6h{E6)tSk(^j$xG-SO&^qRPneVP+=(ag?VYgiPD!AgF6^B|% z<2QPX+?WhaeJhy^Wt|j0`<1RSOb2%gE50?FAbriicF|dvLV4#EsZAtoyARv$`v4Wh zPs?{jRQbwO&W*QAXDJ_sliTZE>As@)BKg^^k7Qy(!U9>36@`>8G&{Wydce}()LI>_ zLefle^}=^$}OrrQ!v8PkXx`m96c1_#zPokIt@JwgB6Fibn!F$RIdHzoNU-e44N%H+DYEf)j%Lvxt^BlB}#8nXGGE`TYW~RMcV=cjdWsW3rIa)eWbc@>Q2J%-TS_ zQV+FD(PB1!+fYcikpk%yOHaXVUjl=HMZ#>3~2*K>&;@*#*Z|^dYZ2l-x)={RnZph+tZ0 z(^zQKn2~aPx`Z1W(^vdbjY$ix7wJlSqRFHe-^F8~dA|ImROOxECpS{~b?Zx43X01c z`_r=JHb%6kb#5Q)@CHg4RPnrVXo%%pEUP?sm4I99+uR~4l=w=yeg;GlsUkdp-OY+~ zBeOh0|F}*mQWcn)u6BeW-ululgT*Utc`VwUkX$ zJTI+qze)A>B8&*x`4Zw%=4gTuUoX>po*G--k}DxD;(%BHCTi&d?1rgIC+^2pBQYrf z<3F{;~AwW!oV1w_$C1VZUUTaebWby#LAlh>Q zy&x{Uw22qQu>s_<;^^gyL?7KQ}N>{fAI)EC9 ztwK64DF|1G=l^{sEtrWiz)=Ul_UP@(fdKs&VH-yC1+R0>ui;!#Z7cuF~iBm*Y zc2!Pu-c?XKMWNaC;-|>%=LIrc91Ov&L-P1EF5p=s9e4XV;&ubSC0}JJmOk@ST4i}C z2Gh>)PNDx-vYfO0**tGos_JXKOmK6O$oH*Iw|oFost@eZe)OnU$=m2mj-$I0pltY_MqW9DYB_>D2RW6>@{GD z_5H!Q)9M)r3dR}K7XSw==a>sR=mn-1qWHiHWza>y+-i#LQWnsyIUC%u-8+RVfNxdx z{c8^zKDama93Bi@3;ef3|Fsc17zYuGBxmks2a{X>4&`?fA%9c(Hn!W8T@9KRv6rA~ zOsH`V?Ty#kjT3~hk`$7Aln3Brk9(r!An5$&js>g;Fz zP0EZBO15;gPPgJ{#AgNC`woG9+8#>ejpBKQr&n0MiBc*&aJng8*&MqrNCfe}-vd0T z$V0b2r`m5RIt+cyqf8^dgxyYRXaPefh|rt%jfcV1I>{=UPFqVy2w=+v_+tTvRCXV78j$&6G=f? z5)nxgbDcm+$^j_i*9IR zu`$P_e0 z1)pMg#rdC$5li+mYsJK%i?x_H3gL??0p*4sJm{I7cu z3nw78=;z`iB`KX)d~}bLtJ)IZRYrN+4Zyo8uP9<7+LpX``-J1$*6!1w;z4xLrL(2O zqZu>6*O8jt)5%{7cKsdio#Csje9XA>yt(XMjlZZz+)EeDi?6b)Bpj5|_@w~rCYR9v zD5~Pr@r|UNb9u9;U;n5SJ^ty2vQwd(NioEMsOOc*O!`{#{Ix%h38}@>B<=mC#T_1Ig=O9pKZ=im}SqJ(44dQtIz*- z?%$F7_n!Orf%x}T@?Uug>ksru&fH3=p5z5c7FXxQRcG>sM$%amMOn%?Iqz%4I z%EH(|19@hp7@pfo%K-VI69vb|)9ex_YgG_n!FalHRd@5~yLNec2D^g|e$Bdl%4Nxl zqe-juagJvF)sh(|AfACd2}^iP-29r*e^}Bp<2^kbuhbmv^Jwaxsg&0S5kWT`8~6pV zUV4a={)?(^A{zr>ThwS*+g=KBMh6^)EAsE4!5r7Op9G(a>w{o1E}Gm}oH$cZ0ABg% z^l&K!7`V}6k=}k=D`5mjV$eu{-P%h?iHXd@yZ<=Kb6e>T;J3&YELB%B{_Z{F{uaGs z-B&o_p-q4FiRR0~IsbIRcE&SjHJCx=@%hz8ulTwvxw}7SE#khcJkgjuzIt21Yw^2a zsW~(C*>=FC$PP8D#iC5l<@oIGy>!w3jL^`>wVZ2Pp-d2GaRqj|hH&_FD8B-!8(!^> zsoe7!4~y3el*DD~KxP{3nnWOx#F7Ul{e=^X#v0z6UwFEnbDrk9%U}D>8R#9`hqxO+ zt{4#wFpLkG7NK0iguQ9`nd!eF1SIxSo{~`h;{)Q={`D3SQ5PkC#100@i`?u$xm*hQ zpbAs?qW!3z^)I{}gH8T;zmcHSRw(j6AI{K$(k33BAg`I4?(?Gzil5>kDb%&*r!C#N z--?<2)_@;eU_MhcQ;hdGdB~0NxFq27)8Xh`0bQwEd~)sjOif5g2v$T^V-}K{!KUkQ z=V!wd*-2s!^VKEAAcYZi8IlsOUbWY(Jia$}+Pr20gxBj=T1#|{a2MKwJCHs$ZLn$A zZ%inpp}BrkH8Y&K;A}?6GQ~N4l)Q@+6k26>Ht!+aB{03gmGTw(&)0Ua#qUyQ6&zg%lB>ZKn1#lriyAtK}Pe>rqq z3%ELL&U&7nTYmTRYTO?-XW!m>LR<}2n%iQ!0(b4`;+mM5?U6gGfs8&UHzCff?rUoW zUH+O_dLX}^^>hwJP;*Ina+yexQ>wuNy31%hTl|}ckl1e`2&ho0&*NWG{jsshm^!u3 zP(qdrwIib@jp(dvW$Cdg;(^sGC>3!PibuzjU0qtu|NK+(aVw- zkJ#_^f-jM>jR`2Xft8!iy{S-8v{?OKJLIpVGqf)dX#7m~*pc0b#i7{uh9(Bd+D5Tt0Ta(U{ZN;`4t6Q0*v~s)X zqlS-Gx9%P6dVXyQQ=(*LnQ!YI8nv{L4kypzw%qgckGD$o>g*c84FJN3`xp*K0?bNB z&G@~qzb|4_)}Q(&%r853q|m;#ZTU?hMJQ&y5uIu>yzKZD^^W+B^h3gM)@%oAI_IL zJVVq+AI_=X=s)8+Ftq^m1E|aAQ>*B_SLmM$8NN*ST}MS4K$SDu(=L4%B~}15Blf*I zPNd6M1`~C?REKo|U{|I+*h|+HVGeP8=dy-9lhXr8@P#ga#w%+sXj6j^=wN?VWgdRp}>jPdGJ zi*8V5DV0U^xNj`e2p#?$uY`h)?4_0ls+m`opB$Vjz`(wIt?>K#gVbFa9{`_ifqcC$ z5cf0u%umrp7zV&>Ol7N-j{=6)Gh0oenP19369EDM<^Btu_9g6nzyISzvtms39Tq2i zljj4&SvKoaAXXAnqD>xp%svPd?S>PJUIk{g16Tkd84a)V9*bu?`p0iTnPY7{E*4Bc z_Cc{2zz7TF@*(s%*{&q&8U~d}dwQwBizKWHqBj^aQq3urSDs;Xoye0z(p8!kEP zAwMmu{=|PU-gw9B+3+6*@SZ8JahIN=*83nfIo2w1bn0` zNB4o^SvZ6p+`3VMN%UCUW5APy&_(18SL{li-3m~n3h8aK`pV{;&<7~yClWu@-T?~& zetGq0!%Lt4d^u}$1&d4Vo5kWHMufPx12kEHLeEbN0pFeepa~R$|0yJOglpJqTMw!7 zx=mX;*oJ<9-Bxb?1}Hs`zD{Xd*n^2WV)b&nd~qbB$b?ZktD5y0C31Inj5QiBliBf; z@!9RqD)Sk-+|H$frI-0P*uS2q+tff?a`oos&JfrsssIwGgo?LMI(5Hd~omDsh(;A>8U34zYTco{x=WN zuU3~kSdb?uN!EypIb|pTunnEuEnh7U7~d%mz`BjC-C=DD@#x7sy;K)WKf?scsC(kD zHA>cLy^6EA0dm!Iyat8omJk)E2am(l$26GQ{?9LJ$FA>t%+!?W_;(jjPfReLmZv9z z)_O$!=$l{V`Z#dyrRQ{FZ%h4q?f?JycnsYe_gkdgiL3|=8j0a;Ef`*YOn%^5KMGkp zhRF2(7={*`C^7l@2H>Ru|L?@s*W|`X@1*`g69iauaTn3jTOX$c+Hk4FQZxFNUb= zi(7{(c6X^pm;r5Jua`X{Quo$}jQO0em3XZANdW4pj`2*h?Jf6fTF#^0=eJVya@&2uk z8;PF{u!wEC`ylC5r?pyAqiwc*!6y}J`q?M?{Wb56Uyt`UCd`(XU{ivh?ER>#{Cd{P zU!JI0FNQ{VxO>}L_BRQ`@p3y~f{ziF+8cNLZEX=}WyoIQKPN3`Oj;v9>1uJWYZ*i0 zH8qEL8wL^_w#zGq7)ptv$L%;A(#mPLYINeNxQQHtUD^|;^PKw|v)->>`j5sURjKjS za`?l=L1Epz#>8j!Us7C;R*}B8Y25CivoN-a+tU%$5~FudPyc?#6FjyTBI_;BC>Fgq zq~C)gNTDV+zUnHxC5}hZTjI%eU=x5P%m2mUYx}=3d~7HPC@5%!;~VRQWtESd2rkYtPC@5EPi6u=IS?c|y%yI&b1IYqISoby<4R zNVDKXjhp!MDM9ATi8VcCEKo0$rU;(a(2QU8XS!9#(fFPa$q5+NK`0-B}IWw?oorlQ0^`mr_yaBoDvz%YJq zU5m%XZz#E|29;(qTKGgaXZ0r#?aMBK!@#>&dLsP0W}!%4WaIJXkNf=Vqa}hR4O`+! z{gTG?6z>^q<)g!2rcl|7XJ0;yYCZxKpjMt_gN7_i-EgK*4G2_8^s*=~3Z&Yk+F_~8 z{U?gpzKF3k`GUo>&VngycfN#2`eqJ_%8~K{NsWYVLL!0d+kM0pUqUBwL~zqIH?BEa z>-dGXTP&X(jK3f>U^#)c3qtan>jzUQ(@tAJ4YR}{k}$spwjCWrJ<7A&!?_zI5c!x^ zceN=2sv$n(hi)D9V~abQ>Q)XuQjQBG7YxhFVU1N?lp$SWAJ``!J}rOI4K8^p^sBeB zP)-8EfY+9_ek@$`{8g?!E>L@hZxQkmsUN$D*_y9T5opYu-9riH-kGLIA-qYY91Zq~ z^0FQ_VxUIc8;OzG#r^su^y;0v-k>o} z2hKkLHOmF_D}O%QScKaK5yp0E;77^j-UK{=wFQ;i>?OGktPAj}qZQfVEa`~fdT#7EqO`-_r8YGbmBkRR=#kd{_L9=GDSN6_zUF(s2 zT4c8<3^H>tiRLvN0(Zk#GCuGra}8oA)tE^-FeTFH3!e$9uHz9&W8e}vt~&-p08Bf- z-4DDDl^#U0z8a5g@THRa9&>dkg7P;zGVwqAZE=hkxq7PHc) z5GvdU9)m1{3Nw-zl#SwV<$f0(JMQ1_$gbp!UPq6A!%xr~%|7(DY;bi~EYKvY`CMJg zXTSK9WXRPR>YGJeNv|l8VaSoM4U4&x;~{*)pLq~n!>I>M3sGtD)BbB}W1^^pOdqb^ zH2aAj-9$d9u0B5ZRUS-3yXLi*IgfpIjaa&t{apbSC;gTM+R5vcw#Faa_VkG>Y%eZg z?H=>IMhD*XK6B1;aovTH0rwi!xwx2Vt80>8))9nB5T$OI6gsnVPDZkGds4jfG?1S= zuIL_uxbccjl<;s0KqdxTJCCELO~}r~N7r;jAIwTP{ssR!c=emki;$*woZ^(`(!Yw{ zKxdvO4kt3FSVXg;!Tb)yN2u@JOMJGxu4JkNbj7$huDSe2(8m1=dgbP4Zh$?vpL$MkFRCmM2~| zA{<2F>fCx{OSl=e6>9iQs=BQkNL?@6uqrLX;|VKD_0|M@Ad+|2b4L3F1?KUd+5WvV z7YvShk&3MsMHE0VYddwIqv@SBa)`dxbVbdvy$f3{oz1IDD#XdSL8QqfxSpWH=OE-! zR84#S&dx6s#J|3KdzH-^hanP*$$d@G=m(FgC$+mSkum`EWHj`%sxP7M7^*-xe7+{a zncnf&4z4NiN6F{T+(?_|Ya-;pkwAi>P}IwTG;sB+xOG7w$3u%e2%q~i{Q%Mcmor%x z^i;t(95CwZ4wCHm(KFh_$0=Din!f1GFZY!W42qjk-ll(&yIFnQ)Ur$D3G}7htN|r) znEvh>DKnksNiCapVv^WCup|$Q7}^a3C+F*G?KAn{4GKRe{($-j9l;x4(X%82Yym)l z@iH_>e98uQ`Ag=;_b=@q+wxE$m|)8mit}OVbv>vx!2TYidKtp%91ddF>ANxcW& zft*K(Lt7x*HAEj7_ik??wW|2}mppo&tZfm3W~=BQAcnQT$NE`=PcD*HLo5+0b?zcr z7J#H^b?5#eU4<5|ofeHZ({T*YNHR^JG~0u; z1_z%lqAiz~VJm`Y0(|QL5bch_9mApxQbb||Q(Wd$a?P_Cfyd;rsYfJnlmJHCmZ-jw zMTJ`}DrBzhTyUY**J$GV*cu=6Q@AYc53h}JlgB*K2+&$Qpso8eP&+5>%5qWPaPF9h zF~o>*9WViDD9jK!XlZbJ1r~tuU_+TI7`QQ4pHRY=Y-p+?+>hGNtJ_S>G#;oa_eP6_ zys`B<-VT%2d7%EPV778CL3L<91w!W#;UJz@GFq$?#8)}bk|%$Xt5n`=Qu(DM|6BW! z4Cx|zx=jDsJiN(a5mVNGX-<%=J~e8{g{HB$KW|X)`FSdru5D2~fR?)-dd`orEM9`x zt_+((-;Uq4sOSE3OC&-`-3zTAPh(S9s|DN*6hc^_+T}g-*zLl;7u~O zNeWAN(Sd0H74kyR;DPS0h*pV?{6!CuLY9HUhsNr7*%#4`O-DbD5$)h@VE}=ya*{pJ z8!cKCEKM^|I2wqGcPt(dEEULw%7Lim+I+bezsJ&uWl5OOb9wm;ZOh=BgUJwpbhmkN z-KHQSS79$tq|V#riK3v7?Pw7%e6Mkq2MwJ)Mrc6xd9P#kew&h1rl#bA$Jcgp7WZ(I zPwwor^Zmz}%Mt1cs1q=nkRlXd9(`fK>(5Z?oDStFKB>J7(z>A_SUo)C_D<4kNz2KJ zlxgPE-*_&u*jAoR|5%Kye$of0rg_ajSSJ8gezr8dwj-U%k)ZNlXiUahhs_Rp)go5Yp5!aj zwhDL{2y(b{1$dHfF(>PD6*mIV?s zN8rO!eM?8l9SR-HJ@Yi-?TJwKbLUwVDMs!e|G7^pKDFE-BHcT9#<4ecCzOEj(^$^= zoO*)YqvxZmuyaDvnb`B>!uQ0s`l6sLo<%cLjhBCU`fe~;h z#FyZ(E;X)HJ@efK`nd1#-@lRh1tkKE5{0=Lqj8A@QNnkQpLZ~XZ)}9y39CODA9$VT ztnjVHL^0_`f)h=+Dl=VTSl?|Z^=ClR{FBc})hy8~h6K3oD8jD~)^ zG~K%yfW@_6Vnah?``%(Pl0U5$ntkU&*FdH6#R#XSH(_p`1NaMxP!oVkoGM0NYOYxD zzAv(hhnr=OBPF%9{#RDp-f5Ylx6l$n#Fj@MyS1Vnv?zva@H33=* zkI(X+WH-?op5(Jsq|hoUJeoM{cT5ygn#or+^DJRu<=yqSe^A$aUqk6pzyjp%i$x~L zy*sQU)#^7)tVHnF$Ri?JdAjdcc9@@2txJIl+@V|s6c=K#W3wYZPC!^%Bw6qTl+}{g&g}Ro++nKjveC@ z%9Feu_+`2dK`pJCpilU-Zom~8+1J0G#e1-$Hc($O^k%IHzq!~1;eI#hzq=-rOk{%9 z6^UmQrHh0ipT1_FMdKE1^IpGf#|_>xVd3+y^bk|f*%rD2(o#Bf^&0+R3juM2>py5D zUp=0D9Dho5wJl1=oNgQntLyI7G{6$>CLo}U6txJPYTFlfdxCpXZrdN*LF1`*nGyw@ z-HohWg)90`*~A^ro*=PoSxk(KahAb@Ko{0++KeV*gT~0SKPy0>$Pa9~RP7!(53XJC z<#Kp%?%UQSnBH|S%e|(%PzB?=d6;A0?zh44A($C}Ml5*{(hBBEyA`a!4Z%BT4<~}Y z-*`PBz7*dTCg}6geIN2ndpRv0@WFpnw_r8A*Mh=CTz}inh_t<|?t9AJ+V$Z!-U!%0 zcDeNf<@ui%?JJMER>oV-?*8F#$hxhOrwW=L(3_!F^yQSK``UL@lD=ryWWK3vqwAgc zuI0pINoA>0HGJFt-&p`q<+N43I#1k3@Q|WScw&JEempbhs=r9cbu$&+t9^I;3&M}P|+4X8wzlDRN9{RVLs&!1>_5x8O=9H9I;k9NgiV<603uK4;4p{=NVt z+VH1r#8afnISHy}XLc3OM*ltAd&U{b#fEpPUrS#UD10SXuML!z5YxJAePX!|Pd62a zb`KTcBJ<#9plSG?lJpah9r6^06Q30?F@>b?o1`H7@0auLW4amUZG_pV4vA(~L^ZarO*rdpBWdss?E5mCNaK%G)RGxhI61r!?W&iH!s}d0*n(_U9lz@rM zd-KS$r&u}dmBLcZmvvmF{+lTef{t$XO|8#{z}^S{m-f!#8q5!sh3hj4I8p4})79TdN&)L~RjgI%2SSu>i8xMLGRF9(=dqKdH)GzEO8tr0+y%maPSG`9UIrjzaEynKv9 zqgjg6X>mH!)c{wDM5{tC6Mpp5{ngVEo)(&}Cgj;?O9dHbhVhbWACVBr3P&7XTlI?v z0aG+(|ATJGeOd62p77v?y~)0=se!egnaNt&yX`bEPE!>aMsZfO@k;rXnccu&T_t}r zk%m%b9C5!MzE1=Wr@U8kARIg$xgR$5z3X%BA5;A)7H{4rn_t6)jJ87ERYSS*8cl#gVy_&E-w&f1+vJa3l~Ka6S?~jL*Ak@6~-7R@r!( z%%Zm=0Q{G=_4U%rZ1>1E>To5p3f()iwGbCYuh*Eq*P#1~K%BLDtK3r75Lj{*<1)a9 zSfu2_NsR~k{SAB2?FHh2ORI5-351T{#OY?iN3meMAI>~_od!@K8?$G=f{MR}Eu9UP zX525#4Ah+dPROr#xw9n#b}DE7VmFKE*21F|lh;q<_)P?a`Ay6C_%|4}Js&zC(H zl-%dv+=|ul1-hz52(}oAFe{Xb{^!u(NaXd^Cr%Ed56cTer|919Ky-xp$((fuc4tk! z6$rl58g_d*E6;Yn8T0owc%ir_0*9EfCy%LehwlqYDCFvBHz;85XIDD#!l=@Tm6er8 zCGBEbZ(dD~_`SA*XRqyOc)T(cb3}mxdZffZ%o)!*;d0Ja&JQzJP;KsJ8tWCd7)|NO zFfwOgc5G0S=n;dH<|1)8ksu4ZrtiMgjw*SglDl`T#INJ4^9x5e}E5 z-q%j0co+2nUf%R-`mOZg!1`EvAY~R?nWVfFs*z3Q_~lNP)Rl_Ul@&%}E)sO(D#@SH zB?9JDSb=Dfn-K966<(V<``zOgrFZp-t~$UwGi4-6!E~!XE~Kz+XS4(GSWDAC)g!s` z{DI><`)Vgv;NSud{dz*6(W{CnRk7}<+CPfr-?s68gireu1cy7bSBCn?SZ-w=7@l`y9-$ihUmozve1*Nt*zqsSG2QpI=miF1n?p9QJ z!Sgy<%-4UILd+kg&iIvah)Yi6io|m}66ITQJ4X#BcO_RWOc|rjM?b~?{Q6(WVsu`0 zftkS+kw_Nx52^sQYNfTOz-F3^6K9sMqi8|f;1E&E3|jeZ_>A1hE9u`TUC@I`CnT<< zQq3`PyZw=K(#!wgeL3L7DeDOi|NAg3poZiBVGbDxU@<)|JT$61qord}AZ*wnc@^;t zc#ON>Mowh@lQ@c_x_1fiC+AI~P}3m=>^6FCT>)Yfq;qqx5SawU+1Kxi5)GrTudl83 zTky#RvCw^Qfl!z!;yA8x!}TiPY5IPBlM=m`ovYGL21X~Llh}xLxX*;`0!~B_mTK5{ z%)s97oS_gxKL*QE4C`7sU<=xQ$~P5Iy8Xr0^#1i#5@r9VXSj8Fh?HZpxKVsB=zJA~ zt%|%R#TI;&fc_oFn!h~gcfTCD0?hq@;3^S3|VUtsWR_HC=^x{uKp5pstE70zQX_Ylf03;^zgl?H^X{#x{hKn*&ZY0M;v&qE)ckt#uveNP!gAgv+F!LU%URPOY4tP=gBq{pQrUMtfzsL0<1=M!Mr)Uv~ zVS*EjlPyj)uqD6|*|6V)xgU#vpdl2##;HZ1v*I@`Pt2Vj)01tMgOpDmW}h~pnT0Cy zg%^biU3fgh_1;U$bC6INT?qJ&`@BYu&=F!xaZ&F6*_kZ-#ZxL}x#A<>LUcVLw%wr1 zYj(dm4R<4B-s*h~)mlUQ9i9OKebV7djs@=9Pc=z}?pTT#KUW1^yZykW!+_NU^*+N! z?_MuUwe?!>7lL%&*%rEr_#<>+G-_=yqp$aEu$5JF<^*C&LjCYLFCC*N?o_{RFIWcT zH{IXOE?njHNifeZ_Mr5E zB#@Hw9Fo3e_^oJy#D>p5J9qgdE77U8y%Q?@{td~GSdssL-pw5&0Nvvc?r+5TC-y&4 z{q*zrA6^Uj=K2pl-wMpV=dAyK6$B7bfjRxkqXP6sn`rloC00fatpGLeDtVS1Tqud&?T947@m65h z111Y2-K={8XP0H0mxRRPZ$~BSNO*0T(P1A>9lecH#IBk!5Yha=GAQtxDih*k)FB(E z?#vqt<|Y8+{QE3+<0IYL83QpB+!Ss_NVDQmO|2>YO9PV~85T>ZPr-nt#L)JCs~$ix z?64?$$_}l6(t{OVPWgk10CH4$^?BUUy<&-qM1UiKSYAhj89g}tl_c9g*>Z44J z(3a&~h>wxSVA4Td?gxzY#O5;y$ZFwyqBa%Mw91X7#?-$%7KH+}!3GDba?R>vBoi^4 z6s3DYY`MbUJ)Y+ZKXVwm$Y%g()No6}5(*?t+^+`TQ^d6?rbZS`z5Nu;i|H>OSckcw zP49w~J3ZWj50S`aE#ZO{tQuymw#B^VFl&!I60X??QVpVDLBMSAB}hMnqG8J&{|_xM z&Ra=m`^#z5UH>5^##OlfY!vMR*W5eZxV%9{JRn0hpvp@?C;7RSe6DhP zDKG&T7|&ExbaHIKES>Of3C|W+Pr6^#{6KX0{ z_d66l6C=b2tKS!Q!26#Y+@q^I!9W&wc72zl(34=iq?jooCy*GhSO_UMx~?^uxpKPe z)2uZV2A{)@!-+5Jfp^0cI3lhVcMmg5m#;Gd36M!>0hl>+1J^nnL=8 z8cQ=ZI!k%o=I(Wm?$!AQep=h|X~7Fd5lLrj#(pR&d*zf-C)@peyo!sMl!R{%B7aU= z-J3*GfX-AfXh_SSkjuBsZVhN})N4Jj`_nmsf$tg8Cj}7e z=pe;Oh#g8`6S5v~Qbl5-;2z{W@U9USX4FBnnKC_&PV*6WD(D~K2tU7N7If^S5&pYB z?bn3I*fZSGC%8IL``4Gs5Bo++6$cDc`{r-o9Ql?lQrQ4ZPz|D1pP}^D=Ur2hl|Y^e zJ_uXtKkHx3eekg*erEziQIyNrwlJ5uZ;!iql^4K!;_@OAP{M~)I$=w+8cC|mVGB(} zLy14!NvURArn`R%Ahl??{`8Iig`E7ORi5$u0Z9^M85ulqBy(U)f4tS1q&oacpg7&R zyD|^G@JnSL1k=ntN*w7*zk;m|p+pY)l`NunA3tV{z-76qx~EKf3{1=Q+T)nV70ux*p^fD-?>U2+0`h}G} zrX9P>55jLv_PwrMFlfQz_aM+Q(--x3QV=OI0)Pkjp83h|eQ-5SD;UEKBxOPRF; zpDFxAyuKVKKCfQXdU&BTvwLl2B^HqeH~8*9zE$zO{R$s#@N;Qm=wbeaV{v*LGaKIt z^N4lIQ-0Z(YOv}}RBl|dA|^@kzU0DNyL!BAZU3ZIy;B<8_ndGFes}G$u)tzT=P<5Q zKl`*&&d2%HX4FvHI^q7&_$YnT{$*f=Z(~&RYFY(!D~OAQEXX|dJerAZkCx7njZYTp zZ*a{6u5q|yX=HyMw@6gSSnRW=m*64{vSph#IrKCh9$Q$r6^{A`^a>L_q=~r0uOE)* zJP|3&c9>fw5((aNu(Ozwz(EDSooXcZ?L4dB(Q_H~^BF-{gbeYv(?Y3DWkb`kpqn5p zzeU18d7B|-NBhz7yBm;1;lS>un1WZ-==}O>JCi2NgZJ_+&*5^M0%%+4`U`%c=$0ubVM+Y=2BbbJo{$#PKI3Ijg_?svDzhS`A zFFv~B*!>VpXi5XJ3_fMmOt3FpGXInM>c{QBAkE+Z0+<*R3)#pzWlcVvKFTN)$cah% zDW>Dlbd1kQFX|M-^9r|N8a&8ICw-!41cwvcTLI)NU1LQof#o_|b?SrxS%+%X9!|LvfhNiQjm3|;{x zJzs~D;Ag#XU7R?~FE-FTfdaG7xyepftDqe5UUELr69X{j9FL60W{dTA99Ih=+PLhi zj}3kaUIQWVcbbg?2!|m3A=$k-wAwl6YOLg(QbbYh(>9b1;jtRpVIZbx>Zo}ySPwHC zxdN2bP4+H=iB$biBBrqahNOY=axL8Y%(Mu_6V`Wzt2ShX5?6?bKl+5h`8Q;UD%sZu zhmDJPRu-D(l029V8m3NUr|Tn>fR97aqmU+}mJ0##zCMdU_&j(-13e25#8lC_ZxtVW zzVm|(t_VJ+zkh`=2|o=$vh3k>_+)|v>FjG%Vb`t80HH_$1ud2I5s$%yMS~B$o&C2UGfN!N2XU;pAAy&TJi*vngYe!61arVb zzJB5-&>H0?+9q`f=pZP(?S_zF`H1%5`-Frwp-o?a_CwbVmqa?Ng5M>BA{37fBfpYk zD8Q!?=$*Yl%bBt-u%MxV()(`UZdnIcD=_{TNx%j_0jUM4bSTWq+}K@SVo zlU>UFeEb&O;IO9EPPo;C;X}cZ*)GFR*Y%zr>`?`u#Ub4kPcdjy@UiKU!{p9UMyt0m zYcuhyU59DX>RVrQe}IF$w2-#~CON6UafAPd)&2lT)w@y%FKvZ&%2mcc_~pwq}-p!*dWT?lx6c2QuqMsfHav*l*3#FqkKh7n)T zjT6(pNJZRp=_^8k*18cJcff3A-Ri}@7@6}>G$0b}pwCv~M&ud`nl{mr8V?Vk_&8!5 zkP~#lFwm(U(%VdCRkZ{j<*}ux%!m$2l?7&(_X-}REJYUgoZUEz_zlGUS;%@skgK^m zD4_GWu&p6B4wkLRG0x0=Cv%y7>c1y~`(NJqznypfFF#p?Ge6Mfn~|9oYq}NCa=xIs z=oMOqo;Lco>O@TVdjDmZnGR50GkN;vNa4-aU$Egqa5db8zL|Lyl76>`->q3n>d}aW z;Wbt=nv5pa6-f1=p+h$4ZM(98&0&I$#Lc?v%lU+ip@?$kH=8(yJ7C06#^w|~ur4cl zSDo!6#ULN^eKOB&ojOyh^VxR&AI>ksjQZpID;@ui0hY2KP8QM4{5MMQbuP7k9sIxJ zC18L#IeSVa(E`?i)^!jHE03W!H}#DYbKjX?6pgOGF~9c9t>Lxf_1C9Z>?vwwSJG|! z_5=1V2{P&j)Q>JE6xsLQlU~nUs5Qwlu6_yiWLV6S%qsBiFL#UhHWRS(Z6ZZU5ZVKeRk%);{2;9LCjeSgskWWHLqy}pl?o>hwGk$_hN#`fb%p6#gIg;&%%L;MheQ~h zz$a)?MV_Wu+cmG8NKm?tTjk?liHOT!J&6Rmsqpxpm8X zO!TMs2>IWc=3LK#0cH8n>~p-K3g@`?m(lO8=w2bY z`-4wJXY0pnthYsl{nh5Ph*k3=y_eONu`@)`^F%bA|CbZvJ}M%E~>iSyWY*teG&9D*6LmxK{sK-OM{= z{Z;Al1EI7g|IM$ETiw+rJ0kWXWjtALLPKw$CP%(FUK#0zhPGZyVwC(8wG z+cFycnUe-8w3I&t9S-_9jphqG?`GEbY&DoxR8*MKop}<+A5dxTHTl0Y#;-m~YJBY)PMaFZw5qlNxF!+0Z#Y#7YEvD42lp zO(Rmoccxz5Yxd8&KkY271`U=mS=-t&F4?56pqmsb(V-$9w*SflvQ&^`UmoblM`uH4 zw%shzCXa&266G3&ABO7G(+N7Yt!;YQSSocB8v8g}CkDQCj&*|{b}if`S1Z)7RSlrT z?`3Lre!`@d^7OFY9~OBFiTqF7u*olPgy>|~EGyF41M-#nhpkyX{<+;`6ZZ3;7O(2# z*YnTqL;oAs{&~ae^T>Zaz<;whFjm6#-4+ZP545NRxj618(&)@@%J1X9*$ z%q#K;r;8FF=--r}{gK1pHb(BztL_>WN9=7<5~}z3gz7uz+wWA%aWO!tQdu`8bv<7f zC?8slDxJGyn)J;As-@u3Ma(6fhPL)ulZP0eW8=;d*0-)5C%?3bt{%EQw7}P@)yDBM za(o(#DAw<&HXcnxt+D;t+x67T3Y~Bcd4fHFP+YwhORIkW$&ZQYpVO9?eeX-1nM`-7 zM}wmkyHps#!F)Z*tpgt%ffkv*)m~Y@k_*BNisSCR>gix-!gGOq%zB|pI@r}=IE6FS zwyZLuvi91(!JGXO#@VwcC_M}CgWIF$D}^c+;JH3(7%QLiW?+S*8{Kd2l>!+d%zvE0 zWw`V^M78S0{L5YfhU7ysa;I-Iw}pPx+Gjzd+GX-!n*MZeHf}p@aZF3N`4N;OY^&6~ za_;RiL&SY!mPdmP$6NYIJUS6)7ABS2A{M)|wdxg$u5)!EQW-BFlK;Rah#$2Q!p;~I zxvbHJ^Vp*;oykRCu6dumphTUd$|%;3!ansl*2ipt`#DGT&SN|r?jGIaN_?ePZLMkS zIbY8eaVQwuFu}z>)B3)vc{Lx3=yA&}I}?+mp-KByWN$Qd&$8M7{=BE82#_Qs^V%Mc z>U%kUX=I;TkR;@&QcvM4J;?uQMREh8S(M|pxz_W=n%5cetPF>3t7<$DiANIy73tMV zN~NJ@50;W-SLMS)S7d`lo_ZF!boEk#{`!1Q((2w}Uw5Z-5)!1;mHwcxbnwIft z?+PF1Tt+lVy3SoM`cY~wNI(LUZR}Gy?=VtFDNn6}Jwf3LB_ZT9`ObDP!?jDiP~(wS0;dRQ z^kV2h1}<_B+8d|cBu75*aP5xx>zQ!>6S=VLGo4SZ(c3wJFy?MmcJjkI2Jx3-v3DM3 zO1P=W_B8dGOQt=Tu6xb}j0vD~zdbqAGvjw@XRph#s^(p0qxX&sW?P;{w_Y#!JZulswp|YoyqampTlQL&g>u-{8H&hX^|!mFVM+ zfef$0ct*ZI7rrX()4wM8O6~TqThvwk@ga3|;_5uV)M6R?Gi69@Pfu8869m2G%dFw4 zHEx|#B*jTkIvNi>c_eMa<(0KiilIV7U1{Sk#@cQ~{0ed06aUtJhC8h z*L7-VjZWxeH^_XD(dgQ!K$2sIxC;+{GTas6+Hw2Po=#+Wcdj{!lEad3k>V6FH-{>3 zPAzZV^>5f7)l#}sE-dMP=kD6(SfN(x^3y!Et2vq7cNZ-ohK-{sq~%|}YC%HYD1@X6 zne$Cf7d1wzIDUeyR-~gOQqw{Py8XwG^w#~k{^)tq1lvE(*wDQBkBj6l zDt?F{JdSHmoLHFwE2}I|)dbv^7*P8ug&@4;Q@mi-CPE}k>r`8G8DkVMglVcLoZPH$ zCNaO$?^!L@m`tfwTg)(Sa2-RJpU4ZvMplQy4+66%hfvA-snU9RA?mYNRw# zx9qIwH$4wu-C}LMliH2^Md;=!_#CTujs=}#-OjN@#XdrJxpm_P3I;C#648+he(Qn_ zm^I6dZzWgWF;B6X3u@u8ZlvTzl`n>J6>&>cVs__ZGa>$HORm$FR|~n^Ub}&}vPe}d zx^;Qq^~^9|YUQeOA5)8;P91@Of|V)ggVi$ylQrB^MWvR-w;hmdjWjpLv-zpM0qSwY9CvHQytb~V zOM70ac*%N!Arb587C2;M(d_RPzqZRUBrL@Wc$1AK4n%t(Y1fZ;>$u_N;=|Lf7D&r-m}oRx|9Qq{&s=EKfOw) z&Nk4N8z}Sjg9&2=I(ZH~Vtw{{Se&$hPKNl` z?7}QvIA#Z?jNVqRj^9j+UIY?UnAhLSbH=d@uG25BVteY_3zUNo$|6%RS3}oL#Iazc}x9 zHQ?EgO5>r9Ln>EHg3apJ5eIJ9Mh`LcR!ZwoA6D|(!W9{pu+L3w2=6lc+gaf)x7o)w zp39wbvR;y6eD`DylRtEnv532p->+cA@pW=}JP9|y4uf$y%oTc=^m z3^^u|BO4N%{iE{p#8=20<7AZ(CGDfg__M7 zuZ03x5J%6uQK}Y18e%J)V}C}QNQ}fH-$h;g0_R#jEljx6!Pt7xqXg)(#|iwjRmzWNxG!9FP4pM;YA@VuxYUkws$E|Kwle4VqB zUhYE{#gnaK{L4-2@iu;2>a^zH%G*{-26{WDT6^CpZElA3Y+t6bT_;KOe+jqnH}%?& zzVqmXurIYNef%#&?D%Now=mNVc9DR#u&MfY`PnnD)CJ>zJ<|X0-qMB4tOQZ%-Cuf* z?X?UaA{^Lhx}fr8IX53wRJ%<4PFjS8Jv-+vv-&{-Z6xwGtX62hloec~W~; zb#Bk$;`;bDqInoqz(8Y`R(eWf|E!tpk_jPyWN1fLsnk*vp&}isDy=4^mB8a)qnVqMchDklD@(sHB zVaPFM{Gp8Z8{oool|1*>y6B4?_FbTj=@qmrATW;Cng=j@gX z-m|aYa(wWuemR+Xf?v7#8-+ZZR8KYG(L@t3zM*wr3~O1qI+9Iu5*|NN`pToD^uH+MLY{p+fG zv0))A9fUnk;3OsOUELKg`VcAUt-PmVs9EzW|8c%WUXZL~`_6PFFaA7=H~g1njOh2} zT%dMBJ4X3Y&{~@E(Lpy`|J3Ra(`GfVmyH#_`6*)hx!W_@KMt*5nb zvfzjFSiy}fzb=NOqztzL09Gl{IVC70WXofbnmcvEQ*HJA;qy3w0(8V}`>cNNQ4=Ftm9-ZivqmiDQN1f|54=5e` zGWpw?UE|J@A&`E#Gv<6do>m{}>KN+Av>pXI&xETza;CEHq!y^mql8I|Q=>|6Fi9k@ zv!6yLSy7y~3+Ch3t(c`GJocZhT`+$0$4l!gmwhqO3tqTSaK>#)?Q=aM`|vMk{jX2j zUmt$zb$9mf=rxtW2KuOhARO1eFy;j=OQe+};GQzSrKE$y8JW}+*Y-?(I3pwz$vk~( zY5xp4*ghZd9TlC9hF!@Q0nfx3Pi>@tS-`Z|)pYssppzKcTfDB6cgk(-Q;r4_ZpSz3 zpFCg8yp1jQXxk=CZh)!CO9PJvZ<@`Izjt|IncvTpwe8--RmDxt+e}oc&Ta9aOb|MD zyP};#{=!ShzmzWAFdCi#o_>P4gH&sp89Q6?MRq;?qdoP;=s9+Sjn=wu%w1Yao`6;n z_V=JFkxYWm2fpj&YyHulM$ZkMwv4_|cxq7VI^%UvZWdq)J;;W2l4sQ0O?=XVBDipm zji-%8*pSOm!`-Lifskf}#J z&^v1Xwx^uv60Vm|%mmszUa9*Yi<6sk@(yF!n)KL$_b--NRL>0F?I?R(xyGJ!a;bNh zXN!!}mQ?kT9dEYFz`Io$kZ$H9VYuAKwL!~wdWEo*iRmGz*WP#`gzNi)r*O?+w33RI zIw;KOlvAO1C`~hMzlV14C3~lrn%XFTd0psk6H4giOkI>cZ#9a|(bvIXBV4%Uizz55 zWo(cnBAro-L2sq(%lqAFVKPe#&2be5!Mh6j&4z6P6fuJ z3|YY#MD!HS&+O2>$5+^QO)g50u#Q+HiEfiQzXkm9(P&Kjs^~tGk9o|Cc|Co_zouWXf6t~QLD8^(_f|Er;BoOl@S6%0M){ryF9-ALWN(Nr zPrPrItys75*!=odI@{69zNE~6n_f{)e*uh?H)8GgTpP$S1qB#abnPzeRCIZ~7#`xy zendR#2j}v`>P8a^mJsG1WTGK-_U1eh4Pi_IiQ82WYj5c%uv&dUFbaP&;P1m8fO;RB zcyPQ(IE9DYYce7qd?k3ftyX7N;^@pSF67N@+)U`Jen>6-WCiPV6q)?t_2$bYs4kt1 z_~z62s{TnI){3Tu_busp!aSUZI`to~zwhwB*-hsTmOg}puBu=74Ks|L|p(Z#o) zX z%eOE2J{s2@Eb(6AnSiJFssXi~toPORG*d~uB#fV=`ZN=7)&;$k@aQFzmXeJ(E>D#}BzN>eN`252%UkeVl zw=QB2y!?wJHS~?^WfZ+2F6{sqIAG0V=OtrE_2f-_UP;*_lER}?#n>l={iq3xO2Q|$!>fB@PjB#i z=X^@C$I&OYdM$8YHr5Vx*JlmF44bU4&0;_4Z6;3PCf7iODT2#{6d!1RYqb7z`ny(t zTH;EhV7mNX{G2G*JcgLq%3zG#Kg}XFxI`6jXr->e5)mZk2X`kO<6I>m`r?q-#m2!~W=I})ZYjAVc9Tj9?ZANLn~hO!QY@2q=2Qxc!E7Q_cXdrP5A;@q z2jNwOp7dw*S1NO5e68{hB!XG}0V(ZKs~T4s{NH?*gU)w~F!QG@a^)kwOo~+U)QbFH zk9o@!|Hx2rrB}V5Kj7E20I)LMH$FwB9vlvn9#oDl&Ym|CTZ3mV-w~CWPE24>-Aboc>N}%z?i*?^24<>VG`c!VU@g%y zA+%;G^qjbEG8z^2>ue#2Avn*Yj#&2XgQu6x83Nv-fNrJfowrXHDY%nt>3V0L8gx1z6I?PJ?a=SEx{+|SE4#<(iMqQP zr>EW1y!DMgVI0laz?dc&qwM=@AYIYD1 zQ7{k{1QblOhYu~W1wMhU&>WFb?)tE97+fu#v=ODgG<9MF_rLL^0~CDm)&alRl@8T~ ztktj;1cNqAO?&T=cC^+vj`AtoukHFLOS7WPfsg#cF#0eSYcdg=+%6KxcvEs9s9XW_^VQu zNAMfd!StM52frQ3MzB5a`X1?K3ukUZ))%9Ay;4i7I(tg{@u*Lg+e~%}9@=T_@@#2u z;aFF9*H;JQoR)7ij2n=E%vq?2FYc(e!TXOodgEuSDK44Be@?5yZt;h-S{PWR=#oqa z{B8|7+J~{G`lh_QQ{ppVZkE0wD&1zBYPdAA1mZ%sSD&+3JP2+f47Aw#WEU4N%EiS9LTou3EmIa-^ z`7vR}>!o4gCzcIbdk6WlZs%VOIxgR00+!8;gatc~#}m9hhz?c^DSn=_j$E$m`pv^7 zc=|Soj;aHpNjC@{dqz29ftmR75U^QxR})SAO2Ue}hW4vxDoUOkb!scGae)1IvfcbX z^5kzXH+s(H5^8;CAbRV!du-S2ncqgpnfd*{4H*bm?Ekj&(ew73Qm${bt3E;_SwBEi zM$a?;sN)64rW2PMAAF|kY+GTBtp)5nLxx$huZZ7%C};hCpk7joVn4qgL~{y_GCv@O)O|#8;b;J`)FbCyj(k))Xy^u6 zw6Xa%i`<)u6|C>N7=b!kjPTRxCha3d{n9?$z270gLw3s+9z^Qns=F5%se4|8eCZBv zCV=%S)AI)U4s+V>CBsc^?X2)uQPz!K zUmKOT9@RrUZrn0E%##bZ8K@n*!0YbgiHL0HenVft{U>X##l zVYgVk<;pCY(+k*3w))TJ&K;pa@3)~n3sKfu1e`Byp?O1%nqsg1)P@5QT*82E{M#_`z-31UcaNXo;e7$;RA@M`Q5QS1sFJ#;A2mL|Gb9C5M~P3 z7AOTGC;3zMN+e5dnEqtK%k+WN6aQm1TN2bIYCF@OGnjG7^}CPlpFK7ia)C8|Vw_OD zViJF4=lQH*ljpjweNI;7$9&;YAa@~jNeyzf`m_J(rYb40%HO@508!)uJ(cKF?FsL_ zG)SfVEQkW}zS7m>Ze5(`&|}~#Po*hb8qpraC#f(iW#~u3=LLV%YmSPS5e@9jXx_Cn z+Q7~fQ-5#(TQpT32$-x9$)z^D2lc--End6qVk*SN=a`3l)dYA6EeU7GfzP__@j+h9 z3jA>U16wgyWo5&wrFrVH1!-p;@{&Cr%gc$k{C^X$n=j&38sBb`EW6%l z7EGSAO|Z|$U$G19sZ^!Ti>gO)+mi4*-VQn%QQrhQY;w>vGwn-zc(5 zM^het?jnBfv8G9Tj1n)36DaC=!9Td}8ZG>R?w&pIPWWV5PkIvzLqe_F;%<4A^|NNe z3~J-H{Trlq`Hh5mGb*3z-GPVZ82stcHaqZ>q|P*B<3s4eM{e0q$d|2ez6J1s!@`73 zdZTDxce&%=AHT_|OKAzxOqYb(_pd(XNvd(0R(aA;c)W3O6sq*^;RTFgyOCB9l{>x7p zgIL?~wNB%S4Pn<8FF(TG7EDKRo0!dD9eES7M84S>-&WV<{9~vpWu>(}m-#GHI&-)m z|1rel@e#(R%a=!FE&ivGdmjvCne!iCGpgZ>QPqmhJU&y{%Ggz85=@}Dg!m>vnP9Y9 z+I{+Tk(T(X>X8t&TuFu0BZI$Pi6O3Xbw=}tR;RI`m1QE;# zj%6ZqmtCt+y;G!uo3R}YMY5 z9#N%2Z`EN3i}L#1=glgP4T$x{(O>p`e=da~L&mV4kNqvBPolUNsg?fJe899{g!^uU zusjfXfioL4`}sQ-)sS%9}KvZAytz+MARn9_D zsQ>!&B4U4-wDH*m(|kwCYUj;wU5R7G+=D=rPXG-l5=ze-_gYkeg21HG5@20X0MJ4V z{QLp}J(}dblu~=pXm56NiQWV;ze}v7OV=4_eReMRp%F(XvTkEJq>-By{X$>KSeu|* z<0a}}+2LF6wD#5QkyN87FhR6=AE)0-TTgmde6=zkV1}?WIe^Z0+=3}`?PY(J!Nzf= z``0cEb)2zOd?y^}g*iznJO}T$a%`8fd`%zkFVcf9uyfeNT`xUttGp(nIz*p~Duf2V zzn)!*gh7o&5YHXJ!th6qnS1(#zAz3ukBe33Wxmp$2>G9U`k@hnO zkL8s(Mao2W$7iqa?RYl-6qN2yEt_>dsjXCc#&QL{Y58`Q+RcWQw5@_~7bQZi0lVCb z=4GGR^6YWj=}E{t8aGXHKHI0-1en39Y6J7Gi??<%NevE^>_N>Z=`Ki&CoE7vxyyR! z9hN}WzKOaIiu%+$bc~YtLdIGL1qzWbXOkv{R;q76D`P~I-GB9r903g>#GWclSiF#5 zW7YkNoRdq>(NVm?T;Urt)k@DI6q8b+48Zh(D@ zWVqGeSlz8ru}@XN?MOceIAQi*idc7+Bd?{nEfC)Ski)X()yTC=6Y538PP~JwyYbZI+F8mNza=;GfI-&l-T?Iv8B-& zsX5eoF3^0w#m_Dp*7HfAdHh?7fg5!@tbHo*cNkk(|%nirr9ANzWHE7QPd}Gq%fAC7Oiw z@FA`??;pMzt$SGgYCKxz?ZyS@U{!EC&rF419+dcGLvvo~%ld)jg^r`7_-Y9S9BK48 zXR(gf`Yo**i*r0Q7`z`S%GIGtwf*j5`4fce%dt`8SnfhYEx=I0jNljV0YlAt&`P&C zt@GNV;oFbZw=Xq-iVVQg2Cg3rlgd7S$3I$`F;n%{*sgc;S0d1e3+QHP49huW-ar4V zb&ldhMgQC@{6F6-9sF1Y1WO2IP_{le?-wP`0@iam> zbaq)!>AA3;1>Ls?lB~68$S&w=X%M#Ydg+pf$Ye^CDj_9OoxS|27x^ty+IMniKW|E> zzp+2c30420zO^X$wtoLnTS)w}FwI{g0#IlM(SPTZ^T1Zkt%TOX_KXD*fQ^#=micsdWP1OKq-Q$CEbfh+quQ53ZkUAI#T^ke_CTk#dq-H(n;&?{!jDej#1pvUiy-U` z;DZcxK0k6k0|sl!V7EQv+xCqD-xD77e(6aQbeSmP?hxZ~)ogw9!gk#!=JtrzSs=c! z2Plj(cf9Jp&1X*#xZhPcggHE@UnFL}PEaf%%#^@JD9#4XenwDyRj3{R@>F$eanJS~ z80cEd{-ZikFVgYKx0`Vz0IbpZzDTD6{%CC16Ll6YO~WkBWVg4V{j51*7l_CR>Z>@7 z{9^ARm?Qve+2ZTX^v54hhKQNZ?+C70 zGmAW9RnQz$9>P)E|7v4**(Kpf3-~=Iz0OX`4^&D&2&uOA+x@{t8sb&lfd>#Tv?BK# z>6iSOI4ai>V1j1@E}DO1Ky>Jt_@|$Hpq8O#_V2;CgTfhCQl5*w5J)8JfH2NX#!#lS zMO?XFcP%Z-O$kbGNCRbH$ohN?y;`cxj0^}qrsMw3dhvO6xc})^*mmpWXqY1S-M5sE z(|-Ea!?;SiLpD|lxnMtnaod77T}K6vou z!K&A;4d3?U6ZU@=Xm=+dpD?zEIKqzUl{tARJwWND{}1-wGpMQVZ68&t(vjYqfOG+s zP5?!as?uwaA|OqQbO=Ry2LTZ<(p3UTlTHvR0fEqakq%Nq4}p;Ux6ki+&wDma!L)MWq}9Yzc-Yk{dAjomzWBm-!+gA zd3s$Bsa|H;hoTI@8rQcoFGj6vOg5BmHEAa$wKyu}YAycSR;#*h=JDeTBR(R?wNzwekPDf+vH=&{reh z5~WMwYk$^#3Z}wf4Zj=XWgI7jTSh;IFkCzJY94k`nY4Iq*_~VaD$~jt*-jP~C}*{G zpL<74wsK|AtiHdp&Jj$k(v~NF!kT)@$Zm4D0W)_nnXRoN_++ie6iA5(Bu_5)_cpGm z5!stDx&Bn5jJ%EHe{b{uCr|UJ70}2KNxjlji~dE4cx9TrTV9d6oeFxhNMYZZCC1@C zQpk_Ua+rp8mSw9bU%r@lb+NXp?*u4x5TeZ#Ihv?XxT{NplzpY6Gp_gcJc==olvNntgc5EddNvL{iMWKzXuT@(rrJU8(nmdgC-bJW+Q z)PTJbTx6fGwi5(+f5-O-SWJPM&0B3@wP-{8WTJxo#THbF!hU1Eye~m`eJS6!mz+89 zY(ijRJ#ygwro4UwhLwA>i2oV~%NR@zKYa$UL6wv?ZvcUmSH2NOR+mG!Vect|Tty~W&m4N=7=y5SS*aN9h-5K^eBx=`1j>yJM5Ap$cqW>B zB~?|~b|&9fX&Ijgv$XJwD3J^rjjo{bzp1&Ir|x&~`v!EA8hEbH%(Sm8lV&iLM^o9`i8GHQ$saZMXQ7FE0zNMZ7mZkxv~PL|HNrJaOGVn0uYjG2|1pWp zh%1e0!a-H1AL>P+u*u5Z#s=I&8WFkWoCfk zh^`W-9uaHmbk9uH^*?+U` zFAJXiz`%c9`mOh8-UD^e~h_N^-B0T%x#F<+ozBf#54(1yxLoUx7Q1J>CwYiG5w95lUn$dc*bghUkYj zk#18~W28ujQOy`swMazH+GtJYQ_8+svNrzN-$r!|^v@@8k7ngz)Vg0Vx`} z=RVV%Lqg3e`eC{}N+|pcjhKoi?*wp3tZgUJ#kCnjOw(QGXVgPoL1M~m zpo0(PUqS+c${tUwbBlOCnDtuFic|v6mX=Alp$8KR9FEa#3)oB&<6VOG(z)Y-*Azvq7KGXVIn*T~yTpja_ zBIX*L?rheFtj6uT`^<+wGBCkMj|Dh?MdiRDk_9s*scU zId(e}-b5<^e}62M=b_X1R@yys7SpCLw^AbmT5(4OU|x$IxA96{k-pczB!4FzzlQcY zJ?NQx+U0|7JiG_FPG_2+LL$aUuv3(x`1neq>Aig3Yl0K*Z!5SmeW>`O?U5o4?Z*a_ zOhs@;v0QCz&h3!h8)t={Jc`hHT&;)|zOjSg5~;JhyI7>Kzo(NbuVAn@TmO3Lpc`^F zUGKsq^(|C_$Uxv5U`uUM8Cg4Yw!J`VcWe%n6i7Yc6U84|th|TjArEkXMGGNN6NUH5tPk@m(EHv%Y~PFrvw0jx2!L(weS1*5vbMfzR1J$jPpHtNWCo%_CD(H=M4 zW49j(=^G(z2nZGPyiFOQQRQA3=d?j~Y!Z?+tOs<}E_D zuaGDnh422ZDzw|Mh2?v=lhgcAe901|sn2%Olyq=r+WwG%<&;+mDRyTR`w#Q#7%cx7 z;8$&59dqr$gOxYv65k6O=1YG&lDDwIi@@ND%hOM$z?lVJvs;2A;0%b+RHWbA7JNLW z?2QZ4$cte0a*gai>ETB1M1nM?)W=r0&JG5CNbr4bGMbj9cNcjEM!8F;5e85MmF)79 znuIraIX2yt)Us&(($DZoO&#~e@bEBu2LzCTZ@06z`Bv4(zs6%4(rP`Gz}=B~Lx}b( z3WRrc{5Tvt{+;J=S^E$Tp*%c1Lb@Hz@9XMAkHg~3QdS=#XXEhm7tnB)q(iOcRkPIKDf3 z_|24M!fvq)U(g+8K4^k0>GT=oU|7|>ZcD-5i$f2eELj({=}r?&jhOs&%aotc1?`UT zC+p;=65xhMxo|`!e)isMc5Q}v+~_=>FtJkK{1`;_W^a;%-RQ)~27h|@B+oO`u8YVX zH=u-CKayRpa=Y&``Swp_uvJ7NELf9dk|%O|^;wZ~kIqmB8NsV3)if`;2*OXZ0DS3z zn>in$%bP?*;Tl9U6Da56>3sTJ9#H#?H-JIS*H@c`H5=6Z+bbp73u#OQ_BhoTt&;??kZCU(Zfn@Q zk#UuwzEwxf|_08BFBuWPqQP3n?tY6&1-!*D$HshzdAgB zVR5svK^b7wEwoS{iWHO%e$dWZWaMu3l`Uvftd&abl@sx?f*HA4)R!_=SUk6~_o38? z%}|UzSAV*Ur9Sn(gIa{~PQ@5uNS@<;aZIcb23K~>4KhSRg;DXjcA}eR@X6@8_NoN> z!P)B1$U5AUJ35Nk*1j-Brt<%&h%OPa#g&gsyHKR!DaAUv{!@&0=>5N|U$ zJV*@>E(X{e3nQ4)|=(F`C2O2`j8xqK&T(ln`Ng)pfL|EnB>=7QQF#E(YKCtVz{e0%QvE zwNp82=86Cq@a1NWV?PgN%Oqykr*|tuA5;MJTOpjW?k!At<1TpP(s3^>?r2n7{QCBh zaO(O{@ofEjr|iq#1?HwoxuNLh%u-~Ys>c;Z_XEX|FeEFF^npjt#I^8xnHw;f1tNl- z1@3Q!7s9FfAdTpeDeEB0N1dK(WNQH(EOy9F$Nef5NJB)dDO*=ND|hjq9~J? z(V*iwkL?*A zw1(?#d;QMjD7gexNwzh+fIVpFs6SLU_d(IIglr0@|8LblM5CTS*)$}C10SSnY2EOG zkdp0!Hwkxc_d&+5(!MX##uk4FtGx(gmJh2W^sH%ZWxuW85CJ3p5wKCma?(kT)K

    =jMEd2X0 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

  • Fu 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�Om36J0#9XA;T+uy?+ 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

    2cNtN1h^8{7D2%K!JmU20y@Ek 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�*+u4@c;D>`*r<#1D@AnFo2I;8v&nxR31a*l7wsA@GB?S*3SM~@mB{# zU*PAMy$>o5V)2IYnoovW?4vRpY#v7cpuY2x`I>%wrcso|Oc|;80psySnZ*xt@=s$g zr0pCoI4j9cIZ@8IcX!&?m$B2OX=+$MAW|pki7I|Miq+_ci#{A^L>zszk_%`bPQ=7J4)n)l#w(|?2-`!+02#9yo3a3bMpDv|uh~rHj)V;G|@A?`t zkg7M(qcmLjZK8?1h<=hqN4B3XN1qN!r){e3F2Y;DmAep?nw_b>Dc`P^Yn zw)u2>+Gm~g;uiv28A~ktm5s2EKRngC@;sP>9Va4$f&xoLiGTp}uU|;56UKzv(S?HK zbRG(+V7BYA5z@nzUeubPJ~Z2B2ha7DDqR9f}m;aj)}$e0Nu9*3Dc0f@1`{ zMhm&^O4UE(9<%(fpGtwX%8FTP^v|dK`A9(wtN?eI5JpzN>fY{dE6{(5`2DcHdegfH z(RYMacJ}6l2!D4rx3*vo!|$%x1)Exw8bKrImS7lUyu=dQEcnC=*fz(0nrs08@uzRK zQXX`@xWWs0^P%Jt*|t~qjg5^vySr6E8ShRyB#Z#M_7}B&$I#UQR9`HRiPHcj2;jL- z=UOLxw$zA%R&wb_ay}tmUKM<{0L6k#>+{=G!41!*nq0js@aM*b?nc5vKpy~r;N$(O zCi%5QGrwh;6052v0Q1l&RGer5HM5XlH)N+bSu{4MdK|{wo0-Ntl1>2QLV z*)cwl76?Paep-V${qMk-s$+Hscus$)<&;FBpEXTAP-o`lETSxbK0gGYAz zvDMqG*4gEY80dIUpCMG>|!`RE+l8b%m0LtR{%X0V~i@m*5%jO+V;fK?1 z<2j)^=z-}68lDDJYinyI55HeHUP{oKxAzWXsg<=<8TondgO9_H9Ef6d;CNE z@bbG#oeFWLRJUdO9)DM&d-hHy-S;}Pg6Ku+6$AEr5TRwZC5y6E-Gts@t8OxuRa5ig zH>**VY^}z3iOOpjvUQFaUy{09YrDqD3s*n!8(6R~ez@AJe0rE#*ByK<~mWN2~aAEh%1yveE6C8F#6hF9siD z$>)z`-f3bf2&I0lVvXHq6)7)LKYtIAg&!RB142vF9EnGl*Q@<3gey0Ml&w@*B#LI^kBT>Lkf7YEtcyHA#Fo)Ka@j0!%RDd)Qg()#WN~g`~Fi*-tjn-yeE>>#V_TaQjg}nRv=R z{*Z>u`kLlkZTq;PJ~@8jmCaUF3D;S}=$*VH9=k|O8k3UJ9L)6;{=4g3Ji<6T^8s1f zf%>qA+KDUHHH_($l>{A=kl&PxMPHlHMN$CeEjx^)ddo$?WrSxlChN}&YTy2C9~%;Ltf zf*5E>bw>I$mrDmjQyZ-5jPWZ5WFAqL zN??jzuo>3ZI%)_X#ov;>9NB)IK^`aEUOxW&%ZPrvqR3o^isYG+BptK7?|DTUi47O_ zSc%bUoUh$6UEX60R1~Gz7sV2HQ9Mr#gO_2`i{CGq9_7c+qZ05$p^Q|Tz9S(48?}-{p zyE@hXwR75C34Q+j!tth0Q!7*tS{(pWK(`bH;j42RY4uJMqA!w@AAnk(#@*0N1jseJ zx^D2_tN3QJhv2nXeGJ4$3iUec^&SC9JJs%s3BOdaoJ?F?1kw29^*@-4?|mkkR)l>A zjgl77LrMU$-kg#W3TT3^nzY+}yxN@;k`wGTU+Fs1u)xCC`>pMroNlkdmh}=h zw!US2{rZ*XK59VcvP`wROeT7yIOwg5{i<}Tuq76tPDJ}}*5IQkiW?Y<8&FbUwV7-uF8#g0Va>^X$EPT~`+YI!$lscX|&|ZO>UqJks|=YpQ2lO0c!E z>cD1B0l-t?2g)H3XCp~hL0=ncM7f#SSabf_(J{fE*5{6u*8cP-O5D_Aisd@luCnzF zuAsAFt$C{<5vLxWH|i#XALgV?$0S+Pia4Y{OWv$yAfNW(T)^rbC~QVAnzLSuC{D=5 zF3(AS^ev4LChtq7a+C1_UP9~kHw@lk_wS#_a)S$KM5O8F)8-v+zvC!9Xs1tSD9mtm z_$fV?rhu1n5EEVGK=1Ztgnr~QM(C5k?W8BzIqO{4_8CIkD9kY!^D$Ng!$oq<4Z9v* zr+>tv?oAecRh*&ev9;)(b$a=FMXX*KaV_?sU4%Ki!Z=n^Q7a>T)cas*!k{!Z6UF{EV za(efosiYKkt*y#_j)-+IMNq)5uhAFUUdE^+7e-tv4DDgxaQv-CqDHQGwEX}w7T<*x zU+l}|vC4p$I0cyTQpZ@nnzlN3x@q}F{gC~NJk{WBTZvb~_S2uM<>UznuD9M#vANa6 z_`KG(b<9>@rf#1xLRQ@?^2t)(g*r<;9p)(0VEo4&_{yA_blUZ-Pb5eu!jCwmhjd@w z-`f@vd80-Bc?=XEL*H+)l4)}uiL*`r*ghfH|I8lvP3riOibR0ZV5jC2y$empj!5Pa8|d!*+K4 zx!A`)s#ZlVjPf0|P``RATf|6IZcY$%(srLv{Y4 zGk@yTZ_xhK{h{G@gRF=x5vP|q4xjaykl)&&Z+u;()(}g@>cW7~bo9z?)%UZl+XF9+ z2gF$l_&({99gCB`XbwC(z<8`?lL3 zVx*Ncrjz-mSCDT38tQWFV9oKlzlQhUW#RMPN|(ADP~g4M4I4Y#akA5R%JPc%nY0hV zx7CCX4?g^R`+{pyQds^sS^vGOQeY_xV>Y_2Ud;`hG~wEDVBf~hA1}3v_ArC%;JH-K zd2xApIn-5HCI!J!Nel(e-&@zJV(9DF7jI_C zF+lsqK58Ny4A#>Ctv0!L$Ew%e)ywlItPz=oe%kGRDoYWbKg9$L=OX)vwS(?l5knp10c*L8yx`+Dgaio02E;KUU6{m#c15qBKSJR zX35j7R7?Dz>8}q;-5wc9O-S$bJ@e`7h-Z3Ff3QBLEB)1K)VuDaL_w-Q0Xh`QPX`@s zq$&n0pw-tPQsWI5FuTjU?^2&pc=uCPzN(09wskX@$_i)eSpE5(EU>q?7mR+f z`MQ9~Mlv(v;~BDkFm7k%DSUYJP*z_vIa2^sf>rr9fOfT#gtg(N_X`-u8@- zk{EJ9y(@NT(MlxLoVM(hbJ)Aq{y8?x(;xz(pN8IeIQXsEn^=eeZBh=kr=zq9W#?I-du`=I*3hxUOEUnO1` zP1;YJKDa2|=c(8%uE3W`hl_^?M-+H|e$c;2kRzHN*)5L7$GIrpNv9y87%^m8DtGWH zaF{TDVyi?XTnZ;qzUOQ9Xry}Csd$k2C*!@m^gxTNRb}PRXNA-3Vm0x1NeSQj?TUmW zSX3&H4iDMxrH4dXbK0|NbCGhDzwLDyF#QowdS9-R{odT&bRn!Ocn#tUNDc3hC4L2o zlKafZAK2K27%nW4-y%$Ee_z-a{mPyTXHdan{zk|?X>h6oX})MCkvL1UxKC)K1p0X< zN5$qVU5Z}$k;>CyWT1m~1fBs~?dUyqldM=_Mz$%Yn9bAYds-6dq;geqMHJ6%vVt%%2}pm07o|5c;D086r-0=U_^ME1 zt(#35Gw9*5o)BqhD5kTMUr_y`;Yh{&9_`J={ewLYVkN5sRrc=#w-a!9Rz&de2Brs@ z?b8x4?zt8sUMhVy$7C#!Fds=E(NB4LUJF=uqNO?}-xw~4K46*!?w|x*{$ch#p+R>; zCJ%q4K6&-UI;`wYFDy!_>`LmsF;l-9d;F7BQMTC>BOmsW!=c9IEl13zfPfQ9+6x$& zVosbpw{~^>_;xCI8(v8NbbYsIMo_x@-rZ9s21P`&jqBxkUFG6=5IcX1BH+^3m2T2v z*=qzhjpqkC8m7HMO z^=+8vhX)UFZ3kZGCJHzkC{^)aeWLMh;>pEz1&6#h&Bj_vfd}5B_qd}7{|TTfNUV$O zsx(+C$mq*RpjAGaJ2R6fXd~CEAcx3iz?JW~m6506PsIJ}%et9SNU`CGSimtL-P7E! z$j`AtjpzXStT^R=ogV&Nm?aK+#m4)%%4f@L`L+uX^mmmq%f7ODAB>WUcdc}u_jtKNDm%L93rca!EVPjO;Y)H5u1kGdbugt*Krj5_<;%DzoJ2&YevXQH zwmv*OEd7ueQC6jmq$l)lK}f>Sz~&$y)%Jm=ytg2f<)m~`(L3ymW305xY&}DE;64LX zp@YWbq&y1U>W+^C63B?_gC@SS$(}6+hGg=e96 z9h$RcpxJ$ghvjz+wVsD#E-k|92S{KB23`PmT4@v-)?9wl5esY~-{-FKxRxDX7 z#i(lP|G8q>p&ufZPRKka;oW#wPcMf#M;=TP$Hc}O{6I0gfrNlp9%vY8{3Tz$e97zZ z`Q9DWO#My=6F7(FbF>fxTJ9i=#PrmDJ%a|?RXw*3b)zzdV=jKo0 z#9iIp(kcL<50)`C9UY&Bd&a?js{@%?bXbNhw;O68es~tX59#~65}<-D(lZDQu-<8K z925LHGVeHpOZRWpmH6kkNV(wcAvWj@xnw%$hCnwn3ZZ;X7RQ%_(f^!`-^xT$hGZB$){ zY_h4hu@K|Fnc`)hH)t&tg3+yPa5A2WT+U)i+uoZsW?}!%{{BkZNGK^j{~s4s1pH7} zNu39J9^XJVsGA#z^p^zX{?LbP^$En%w)o*2*mFKZ3fp40!D=(>EUhXCoNm1DpE)Zo zEBrHRf8Tf5%)i0?XvcRLf!!jC_>@xX34_o37-#zL$F~3LBfqg@Qp%1IqNZ!8z|?ui z(wC$WJ*cDrysoJN@)~)io{-KJC|I`OOoQ47_u!3dy4;vSbBVCDd@<;P}&e`2BZ5 zwz}mSkuK?qXD)kFQ&Ychc=F&FqpWa2_)x1PuXf6{i3Q@>(S>J{e8h3C*O{C&-+J@lcn207 zF~-3rd$=g-x-CdTjrY-eahDu8Cx@4jIih+ZX%G4MgG1~;@hzL6KfKVW-g;)mFVEl02YiPnuXXu}M z{dbHq&Bw8x{-3}3*S-I<#;V;2w#)Bm;5FK{Gofc+a$*n48${mY0_UQ?*u28o*GGfOwF! zvACL=nrrtY=3ac_b)cf7(=e%!KDE+#h@wv{*7RrxbFD<>6FpyATRs&x5`lrE;}yv! z{bf{sBFofHZwqul7$+;rFD_oa4nRg0G^?wtpHd~w1NUeekAG-wlOm?cWfgwP)Ga>V z3||Cr0{gTM@UwuT?M`Fx*(o@eWCfr4EnkNPlO!TQ2=WH8tivR}v-A2(7xQ;Sjf+u7 z$aeuv7zpOZ^^B#ZCAa^FvbPS4vhAWr>5!I=0R#z2QKTCI1woLM4hiWlX%LhYr6dFd z>F#F8Q5xwUx=XsxJ-(ms_rBlncdm1t|6nej8J>CWd*6Gnz4ls8Ta%Rv9ozg{CDC?Y zS03z&kdu-+kWus7wj-K9Cg$dDTS!r>uuTyaY{=w&E2UqecrrbkX`24vzYE^rC4}ZRBd=*czA-1u_mfK~dv~sCc_b{3BlRH^3xB zqNJqkl3WGyLb$GZ??1T%Zi7NEk?@(wdou>Me;+hK&~;||^MCL1Kc}PrL8@Q4^540R zKtA?6>6UU&&vt=7huSJWa;X|t@@tgYq~lsT9}DP(U*Jiw7uT-Eo|rWuA>qIvGlLrq z3KJ8PR<$kUcxUDfO>SHMWPfU}nQH8uDVKWNP{qDjL)*q=F@K-J|E`j>SU+oD3KSq` z0|m#A6X3CIS{`j`5$l-u=&2pShOb?Kb$TOY=vjP5$mmpO^kDqfMQUqKe;*Xy`shLhiQ&oFE7#-HkVBt_#QDA5~p9 zmb1Myv6KJ6H)~byRTy73cfKlCix7v1+~2pmLy8FXS4o5`3FmcZmP;gRf)0jVBJ*I z_uA`OijaDx=wPRnovG>a`^Nn?%OWSUX<-G=~O$V0!e$dFHN@0^ND zdG;#`&l3T8-v7~uPrA3@s$dCY7x)qh z3qGwbWs6_k18y8G>X2JoJ)delAS|vq(OCb;xPSM*ktBa7B>($ZC9slj&|U@oz5StY zW#Hk0Bpj@)H6>5FEZ#y-9!ne-?qXLsGot;KoZ0t*a1)@Pp~y_!;ISKsKU){su9U6% z-Xmo)H{81Ep+9gt9~rf*%&TFfF6QV@WWdHx|$rGZ? z5hJg!(6A_LYli}tB9o=>(OuEP!uJfb16EH<+P(g)ZyPjP??V-PLpgq%w;%s|A4+k4 z-%}+~z%Da{d2GGg2B|5wZR3%~vm`z|FPrF;FW^yoccoL^7)}6Q>ZA{rU;ip_V+}4V zd$87gl$7i`!qQs9 zrQ9le_{eqX7$$yAv=y@rup8oqg@u?;{AAXbwTkfiY+~8&Z;)hXeo-q2$NUo`r`tj(t#HA>k9zH|thfOJK@B zFLG+#Mo?}$juArIKZk}!qWDFC1}p+`vF1y1j6taG?8pjsFM2HXm_&(UxNdxRvZlZo zms|vbM=i_XnN4j}JjQ5c<>jR2c6!dv75vyMV{xzJ;SS9}x3>nAU@a%kmzxGR zmYQ!a?{=35jZNImX8Ly);(zeL5BKTc5$nHC3>6i)xuX z)qnHo|MaL5v+iMSJ^29Xe?7_Xq3&>-dbju2Wl7spUgAL$!hxgFp<9YpDW6QRCYA!+>wGj<#vwHS_^go(3QGR|VJPnpmS0^p1+h9XvY|R%lyZ7y8 zMG(1}fF8k;@6e~rKcV>29!;Z2H&-a0PF6X6!nn+(7KNxIGat=spA>^a)-MeQvOR`jtghYt+^s%HG zi`SNYVO<@SbTF<_beoj1@z*YKFc)Nq>A6M!0fJNJB%zcqKMAlYpe!yai2DjNKrNGI zz7hC%u8ri!mqpuLT^{t0M3LBEfr{i|Bxt-98_()`u79(92Bg6SBVBD`AQV7TIln8H zwj0*jxd7y*I)Lf?)SA$J>H{r!!k-uWgAl5@2`xZ? zJu{iF4B|HHk^Qsm&514P!3wBMs~7iyF%U7$K?6Fd6d-uBj@_JKT&vW$)o~Vj-(n9*{@|ld1(X2YcVDr=3hK8wlbq@b1*85 zFcY`1KBZWfeR{$sv?5-726!UWv)7UL+;akUZ-DD&Qdi28>f0Y9{#`qq&SH7hGgeOp zCTbIOv5Bx2^D3*n&A=#PXFo~%`b$}~BbhrpVJb$GA~SGG^_gQq)TUsL5S!JfZ$4d5 zzD(sx2!V@+n^Jtr0;fE?YYWTfKj>0cYI^+C=`>R5iI;Q>s!a{9niJZMTRdDvj5I=ZO+nj>des+-uDubc!E;1KWI&5UB zR@^oDN(Ao7b%4?51aAmA^n7xxTwc{wQ{=tZRn0B@V20>3Y)k7>cbtA!XG6EM-n&>PXXqPXZ9gB_S-oEmuMPU0XlEU;=nU*Mo8Tan2F|!#5)+SfB`{u z7dhL8gC7KbdwAEnz74fY=MN#{(ex*GBAGu2{HtH@k55FHj!$&DDt?3QlTat!$}lVo z2iYB3>JXy7uL0JMlU+=A{v`8W4D@3n{n-;SrN5(Np9#u?3Y;%U!hE1tyjlX_DeIX! zQm^fp;#J1h|1P0)&a_Rj78T7t78iQM1 z0hKgeZ!NX7mH5+$-M>;oow(Ko@aRjE8D~{AlGRKbkWC~yoFCMnlNeIk-VZL z-oX4}Kf6!N3iRs9oL2kPmAIprV9Q&|2b#_2BSt5R_GhIi!gd7(1!^O5MbFh)ssH2@ zf8`+qDk$b!ecQhbH#=>#>dc7wY-fWSeqjitoVwa0$98yVmDxVjPR2;lMDA5|(P}c| zw4_SDYnPUuhctC-W8RU^WHU~2yv&7h)Ot3ccdClMx&|$Ov{3TxNAw?YMl($hK0eCf z98fceP@Hl#Y#W8-*d2fHLEVXC2D&G4T~)?IaS^Nqu3rz~v|V;>quWy@W-!TNjaZ}Y z^GD-SXO)}$=~)x#A&uz5RdyZ6DO2`onThB2#&gFm<8e9#hjFBI&`8t{*6jTP!1R1H zQmIvLOUh?El|>Qr$fLw5FLKIZ%uq()4uw%;i@gI8ZXABjMsRJZ)IlW=Anhf7q%th>6BP50*w<4 z`GaGVK}R;7YHZanbuH2~Fo*)U*djQTp+H7yGAz%_!GQ;#R>WOP(7XmLHe7a% z0(ikKrk zrsFlGryg8goM5gt-eFVg8@zL6Zsv1XCP4fu_vi zTgZQHs5JrPXc822Mt=Z*vBBQFe*GFw=OX-5_WDj0i1c3>$Jky5r(8jD7u`LYI)x0O zev9vutLi|(P|_x@aSDh|Cg5ym+lv~kB+%^}D`^~y7mR%O4sN#hOZjuTVH-ZxnHWk_ zR-Y2qnf4{ZXeC4N&L!7M*{4<@|BJnKxnEx)u9EcO1ECA&&0|MczBx<$Wk$g4<_7H3 zmDr}Elasnz!;1S%PPp}-#O`-Y=E6c*ouuES_9xUtu8O68qKMTo#odfyLF?81l!o*) zVcLB&<)oxJ>q{T;4C{0QmR;X8N|-vPGyk#8%=_HbK8dh=WLs6%uLX~^G${j={Dr8t zsLXtL2%5y0*X}DPG!vAIr()E@{GRfc*snM{D{cnShv8J>;eSNJ4Z};)EDRzV$4{mF)qXL9m=B;_8n*-n8khgz=^zM*xeC8pIyl**_i{o0D@HWDf z^Zs(Ngyg5N^JC}==CDW4yAoc*^|~1>Y+jT3f|pp~I{`s^ge0Tu_RBUB`h^fP_q5j* zCypj3=N$>n?)S(FC;enYAnfFv8fP8~8tDyn0Y4Q=4EJvr%=jP$$(Qn4Jg(<2go?E@ zWa!-O>fThT@)iD)ni9gLC(I~S+$nC5gr1s))$_76Ov_nDVdpl-qyeVybIv%M9y!nI zSI^G+!^RB=c;j|k^qp8Jp-?^pN)fsNV_xubL;bd+4x?n5!`R3F# z+Y_3t0_10vnEQP{z5F1kR1()kobJmrpDi3zWnVuS&@u>_tP>i3H1Wd+Rq=?lX6@^p zcgI7@bK_`DH;ql{M2d>N7LGN!+-KzfE-yhy(A7eFRq>C2L5RX4Cm}BA5G|I9MM6RX zf9y}UC!zvRx&{p|^4G#th(gnu_gNw@b~gL{u!Gk=rW{gm5f=J3Vvr=E+=cS@-GEG} zJ@xvK<JOs3}a1at}0N1$X`goPJa>9Bx(^1I{ zIK2fx&P#iM4BS4TNBA!S*+Uuxu3`rcN7J14h7?a`^ty&J1;`*RS_o<%|-s z0u}R^JP8ECUkuHIz=zWUp=R`AQP5m3a`be6LbH7_UFX6M25*FxE9^lsMj`51aofa) z&B3DW{AKZkwFc8A68h>C!V4)M!J?-4uzZ$v4fMdsfK0Xk!1AvdJDOt6v%_?2fE^WJ z$l3p@KzFVC-qnDQFUa|?_8c6Oi9RJ26K&FWcT&uo7I!>L!N&^_j=jLM01gJom zH;AwQ0SBN2l77AwuRy{n{&?(X_FqYCvM5^n?K}38gm9}W5#^?_h(#Qxl0bg^%M4f0 zyQ@0)Z)#`|v4>mjA!d#y4GdN`=MZ2#pujBkAtGy zBp4y}a{6@`qtA(N**%o3K9@9Mvut}W?f>f0CvmR&6(J7Ya%yICL01iJq7AD6S(leYoKvt6BNLR+m z3MGg=!tj(sChOA4jqLS1k%98IMW{d2mrGd*{2F1fIO3tR|3gRB5Fba*SeG|^#rT;{ z86^*o(dn&yjuzDoXAh@PNR(cZ4G`SQNN6$y78V^;io{`{9nXeFLV6N-OIAAS7z4;F9@DkV6;^m6mcwK&*T zdV$Sy2@oShLqq!mDv&eYz57^@YpExk@}aVdO3PEyQ%$;wQdDz&;PyD}v6}KOBBBEU zY7;!RuWg%$=Wz1!^XEHXGy&4lGiG8N|F}3Z(u2;$efuDQw=E(Z=nfnVib(e`LcVlhM0#KH6 z4%Y#wfw9tMBBUoI6ZMZGm5T%Af%cs}8x#P?0lEQw1JBZk5sIXwq~Yo>6&01P^^53L zZ-~a-fPV#b#4r9s@)9us{IoAa)8!&>z(;3!mSA7j+yD9u)KxF8PU#FZ>3EFWv5WUz zfkqhU=eGkl2VbQqo$#A$tP&^r9nMFOVi~dj^}g8=eyl=_XuNoeF0rTQ`7bFR?3=lZ zP#IF(&v{7DK~i~5ZJS_HHrU|wD9-MO+-kVZhT1wxC=hEa;iI+DQ z?`^Bsc^#7-LxY=>Pv0G*|Dejb!^NbIXH7Jj`#N4@)Oe)xD!~~RJ1%_UbV&UOgFn0v zI!vj9Y%D|lQT%JAnXKar2G66-z%a+wQhTdF$384$wW+Unn0T<`XT8|ZUBaaM{03`W z)M)af|0Mo@4h8@qMxZ^8{l|grqk_x?QuqFC~|}Qt9^2 zt-@K3243kF><)eqc-J$J=6>xVhR+?FOjsj<{k`OOTDvNMeC^dPy#~D9G4QC`f3yXh z$U5eaOlmX%U!2$-U>o2lmh&KlZ|m;;`}dWX0Ue{zc$P!Ifx^_(6ksB->hm*@7lZ@8 z$Snke?qvn1K#EeV27hnPFh6y%Q+tLW$t&|vj`dhdAn*$Gh$d;+s@!zH6J&C{EDP%3 zaoy6go+v}_7rWr#s^5A5@_%tjfV%jc)X!B4n!l1PmTsx2;1#(#92%&wv(+||8{tsZ z*6tcKN^fdv;@mYI*09I8jmSW}e;_3JKEV{uCn!16L5CxUNCFm$#QZ(Tlx``)CMtVAW zVbKv%b^09+2CA3d3<Des? z7xGhmhhF304r{6MHtda1+(qWQyT>^^c_@>6-blgolHM8A=|v0$7U43k#tCI3ie(u0 zR?l7uKheGZQ||r2_G<>Pzn}j5MJP7b8cU8icm71~GbyQ74?#Z4VK)|NWXLN$FE^i` zzknm^fB0O`LG1Pp$W=VWnJk`d`T@6+V?e-I`fRBfK~PZ82aX(=-B4e zTm`$Bo0(N{zj&=^)yUa?e|YNuxdt5hE7@d&yeItShI)q{T=wS1a7bzZmusZl`m24+3q0FCnaisK#5-XsKABL zMt+{8r1B5ak^gR>-=RY~(S1S+Lqp9{98YN`?aPn$ZSRz{sxnB6HfeYI$WATa^cZpSh5VYaxuEGgeykf zaUDfl9eUdAazGX((!D)`iiJ&Xa>MfgR0{Dt{@X(r3!&qdRNclL(^|n`wt&_Jy`G2^ z%S+INt4X^K$M_uioJyArhaLI}UqmQSaon;zoVsPLar`MN6<5l$^ z%&2%})x#_E$Dl-Up<$jblJd)zTMsc?rgbrzzhkNKy)it+kaQcCei%*rUEzNcR)44W ze&hdbr2pQ3O?D{cOZ-2)PzQmU1aux$k8gv_c}%-v${F^OlYe}Oj}KXV3y>C{xr?+z zH>2AhRQ~FwK`EIDA&^2(!;ls>hjv-DNzA89t~KT0anybQYkIpVsNCa`2CeB9LPP!?i8> z?2L@4h-wh@q5ao~vKN7Tsw7DIK3X;Jmksb1dY8(F08&IvRTUW^v9N8=xL*kV#7?ii zc7`1t9ck4%E*nKco}1J440RtnZ;&E-5P!uRDEd;BB7{6_RaOxX* z5ltdq`6CpE`Sf>B`dU-?l^#20tLgH2f)N_SQknUU_u^8`JNLfR*i#lYzQRJ`AVZUL z>re#a%b9Dh!W)-f1WoZ$#3}1~Z!1zH%%bZ(2r=#%Afg!ICuR-|`PT9c(`Y(qlV^TG zf#>*Z_x&=t2f>j|DDhEs6y#BLB;s|K43FDg+FZtF{S;*N!yV!kA6K8=w}_(;&pPie zYD9nOe{||~=2J%ZoznRpv!1tT@X;1ZHTAolp9EtDVr26~r8V<)KPbdkZim;uLOFMf zl5SSfTudyDpZ^*izpybFh-3keM}CN*SVM46rDcG3;p>^v0;k&oOZCj#H+J>tdW$da zdu-XCYG2(y8>JrP?7~&FvZ1D$L+95Mr5e){q$+I@Q!C1_DweES_()W<@KX}2)Dlba zS%;{bZqz2TZorSR2brd=Z`CK-|HmmO z(1!N7@!zprU=@39^%6_T2np0AhN}U$ne)O3ypR_{@I_e6A0)RrMrV=pB2zZ}byczz zn&-(*#NM7gLb4gaKsRw`^=`Wwrd#ySnJn5OPgq-l9haaG2ZvrA$(BWA%CX0?7IgE; zo>n9dLP!(jfZ;Mz0nN?L@|qeNdE@mwxTwHt=*3I^Inj(47WL~ho5}-LP7)G+ANRVd z+ycx?wFv3xiZ=l0^AypQ1BXgT*Fo?UqI<&1!Ld|uOFtx3H~ZG4&E@4K$#br*-rnUL z&XNPEK2RHGR8+)#GUsjBYsE?6eGQaOA?KW{!P%2M{mA|0V^0@yH$ENzcT3jFN^JdR za3t%YfgBcLB2qHs;fm6~KVh1#^=Hx$K8(E=6|#5Y4LgrK8h%5Fhj;^jM(n?OlzUgV z5u_T(ugYaW?TY=qJOBO!1m(#*(Ql0$#heAX{H64(n&5E@dM?=vXlZ0-jA8f=xqpp? z;z-8}n&(F}u#eUp%ZtX&A6NPGDV4u;sig$FGZBo4eKF0|qlxWMp;5R~rC+K}M39i!syN-wmr!Vl4>(h5%WH%MHOv`$q~ z!(bxttQ@ssD_;K^=kWK8K;h!gict~u?&g0lMM9Jiq7UK!`2kKhfPo8&97FfP+cLJYv=;X;ILX;sjxU2})m07tr_zFauM(E{f}Mwd=MvLIztm zQwq`U1?f}XA^0PL@`-|<4U|BNTn-^ugm7nGUh>B|P5`E$=V^_fn%dhR zlL0wA94P)BPzE3@9q2&c9#7wMok@Mnr%ef0aPH^NRw5w5pk`e@p|<71Iv=5a$EK*^ zm;59Of@TLj&cU@A|G_YIly7i#3+Ns3##UUvfuP34$5)fllpYDOE*)>@kCz&0XvDFd z1GX$yNL%{Ph9CX?Fu)BI^q7=VRE+qkuBSKCDMgwb91+hm7w$wg{QlP8N5$WKM}HhY zC}I%!{M-{EqyE7u7RRvF^xf};it_=AFn$IC9Y9JP$NuoaD{#HgV~L>O0Me>}|JIhZ z^X90c9)TDvgkj~sq?O-SKa`W;#qq}p_sc?-!(cnpn23I0Zl#~SU$W2qsc-Ov*1o8T zm-u%5w>vxxa9xQ1_&)?UkP*pYq~DW&zazjiIq3B@-ou%l5+i`+L!Hv@L0p zfe3E{BRJF_G5^fK$QT0AyhqFnSi9oD5{d0M9nW@faF;@r-#W zoebgcmh_ZU_iOULF7-^lss z_8*rt0T?X5bnkRxf9`uUBaipFGZ<-D07$Tj3MpVysZG!R_{t_wu|FCg7e~u>#%!GZ zKKTMrTu3*8aQh zez5#&-3TQ6jaYU7TGjrr>T`(xomzb2(++MQf6y+^Y5OIfNk12O-|N&KkWg1bc%{$( zF>Mc}WTA)rsh<8tf&#iR;>eWg|GSS@Y5gDWDDO>6GmwErV2^_G;?MGcC(}a-%o+fN z*>Kf$Yal8GB{(>kZPlC3YY&-$fdPuY&Ku!NR_^iyu-e)HuR7+Ti0gQ@)2h;4X6A*g zB->U%`5~gEon;%hy#P(m1#|I>2_qL#&qHNXpoFGuGxeU`JP?ebgnu-Lxuas>LIK;- z4|E+D2z*Zi9S>oVNR2jt4L85JnV(GR_|nXbdHg-SFym4~bF=vQ@pf2D3`t)VI#((X zejcBo+g#iq8yyXxM2H+)iU59|&97-O;FYx9J;`>j1)qcUg%Y8lEuA}Vs?Yg7*>DPE z#i1Bt7$B{&uD%yP`|*4-?2DskYY;ZVd(GY2to$tIs8SQ|(#498KBXF6@t@cRMSHdO zd(REY`auGpgO<$#>)O(Xx*6LMdI15gjxxY&`JGMLi`|CPNzFU#N7dVNfYsr@o8ssE zdnf==))laT);V|oINFZas6YGNgGAV>e{P1(=iHq6FBgtsc2sjTDyZ_wyL_-e+eHUiT-f5`QO zbyXXZsk!+gLdggCn3bA#ll3G%!U5JTsYGOCt_jKfVA2Q-1*rfsjlL)almHW<3Zy%l ztIAS5ZnO`gcJb1gKW5cB@Um5n#F=;r2MPs<)m!;v4p`qA!h(TxP#%Y{$xE&hRGFPHn<+4o@{^97+%3UgLIMepYyv@CzbSFFTj^pi zR$HVNbj++?D@jNpYq~m~0!+%lkBdInV6xRO1&@~5oy?qyiYmqhjEZ&D8X#25^=r=u;6MmCyYBN8o`b z>!8v4oEjZ@F95xse$KWIfEEW5eTe)EnSehd0_jD-3Fh~jC~z$e|D4yuWF;1Jrb}Q# z4nwNFNKB-PRJw;?3Imbf?!obKcX`jqk@3a-oV+2U{1wco`Je4c6YEFv z|Le)a4~Yd#@X?<)=YCbe(xpdxmGIXxq(}RG3*uPFu3VHPBxv#7Z-J^4Eg7KIXVN^o zrVoCa{h#&f1IoAG1qv4-0tUBXv`MvPk7;+nE(v@?X2`ONVEnNBn{%10fYz?@pMYhK zg=hsBn#1%1#cwX1I1HL-^f4V~9p5+mqPW)UxokwJuL#@DdaOcRW=@_7ULFX26M6`Rntz zbWy;}3t$h`qbO@=1cOcph>fi6G&1ce(R`+;6u-d+yPd}!Hv;=utZaF_^(q2J`(TBlV?NIdIb8{NMR`^oP+ zMMy{CO0)|0z;U@HUQ(~_O$sPp98>BWXUjAe45=DqXPYu8r7h`x&L+l{o_!eQWGzTk zA32+&#|l@$GGOJ0!d@svehxUht54@^a+7vvEh4%t38pZeWUZf@XaF7GYj1@`+t<(J6cu3z6IV=F z!=f*D)D;yK^Y(Km^I~Ww-N%;Gw+L>R;-RCXi$9s0bIWe<@o1Rd{VYVbHQPwteAa7s zAB;*ZH^f~0I{xwcKOLDpPLvn_x#w-HVSXgi5eW|_Wewz*xXMl@5~n(Ecv&c09yg}I zOjG1gZ02f-<41Oul#tlUp-s-!grm4mBAbGG{zqks-{giAOhwE{BTW|XO-Ok*dY5zR zH)Us*L&S@}$R`TRZE6y3n;jqCrB1@#n=ZMUrpp%G(`qo)?OQDPTB#zXOL~wop1U*| z>vSP+>7*rCxq9^7B_y`mYHZ%|XGc|X9v3Zf)b8UeM{)H>5^}GmoFOpTQP}2CcjAF5 z@0jUu@R06UoiC+DaWUtWUIHWoFDk4FLr^qq1J}Z#&d<`!_qz{wYE>=0S@KG)+Vs1O z(ARXPUy@fm&0r67JB8GmdX!->jZxm_Y0ULSJ{oslWt*qut1ly0!@J#^Y6=3*4>o?q zIW%sBZPehMz_uIwr%G{Qv(N`@ir%GSb{0U3f;HwtFX(7?imXi5X=DeP8-~J8Ho`;=t-%L^)&gJnM5ev?&^vD_+NauE%)PTZHl-7kw2gPrZa zbk{a9`Y%&!H-8jn3nddCPF#Cel<}j4lV*G;VTu*T~HQUZ|i;qF>O9y5q$x9m?pMcW$@e!H!rVKMSQA^22+go;QWBL ztu{QcYsevZi0Rv*&oir0_U>PDI2_%sj$Rd>c9dfW`|nWcHU;b_b^5Q8O;njy{x@9P z;}atS(B6_BMOHU!lnh*|R&rNsG2Zdd!v05q7D&bVuJz}v!SY`u8sNnPv?@6*t?~W# z%zwr%b3tUD=YP|8v146P&QnPys1z?Zi;iAs!UOWG})J5l}v}P4I+R)ipJ< z?*;}2s$c5yKYH|N&t2qQRMbroo6>kuQ6v*ERE&Gh$OioVH zjr#58o;>v6VCCk90sZbsFau2iNDr<_#6!EUEq?wcHpAcCrPuol*n&o*;Zl5`DkUp^ zmJ;R>rUB1Kx5{Zxb0Wc~m4Bn-zW3t|ov}hLHCMIV2z78ZeolJSa_l!!t-4o~8sLmS zQy5F{&<_*DiIW_9N{&sP+3UnQ%F7bhlNh=^jITDT-G`r}m503Ba6^RXP?A zA1YpL$*hd?SQZTqsdz!TZs_DZ^LFB)8GUuud+S4}^fFCNXt4>IE~ zSRi}6izD&+GB0u9#}x8*`62_lNl_=+Ug0v`@kXOxO)cy_b7rNrb44p{VlT4rPDZH0 z`6&BUmb9m$k=u<9%4)|o)Y@(tjm~IQnGy4rOI}rA1oBp{)9cy1w(Rqim@W`wllhn_ z`_QoTMTxyamul|&pF+LrE{_b|l-n4uCw|n1bk1s9Lx)~Oncwh3Twiowd8=aDC-zv7 ze&ZA-=HSk4|EQj1#D}WLM16nx)ARj#z*Cz&Z@ix#8y~WgQ7T0Kyit&#H}(yW_wfVw z@5}`E4nELs+}a*W=Kt=hXV)U9Dkkx*+aifB3KqG(drdGfeHZzbtd-72TUxSQhc3SQ z&dBoXvH0qq2{r$C0}s;c_MYA&675ZiL|m3kj$Wky%m|Fk4rTQx@lS4Ojcz++i1`v% zEs?1*W>n&_K7B#^b9Mfhr2by;U^sc|1p!-nynJIA^BiRLAtI11n)Mkz#%m~)Nq)=+V{(xje=*cJKnWdKV z%KZ7v+OMO-!jyT`CFkyH_lG7IkBq-PT9!5yDrBL_2Li)ck6>jq zTET&BJ1xQLR{N7IIP-V)Xeli2&AoSP(hA22!AWyi+12t_lyTV`CNmrjc&l}PRiQ_# z0oN(M2$mPw z<0Cff=~_CkXL_Q$P8<_un!QFpW-GNy&ybF7blyH+<&e|!z9*J=Oi5O#+F3mF?iNTS)e{W^*JVDUz&aHK=uJCame5zjVeqqdrm6+A|Axp?W zX_xU)j!9V9aR-~wt9e%L(Q=PvsfME;x;@F|NCsTvexAm@_N!(hH=X8edV20isr`EI zQz-l2DAPULyKiu}5G%kH~ZQTy|9 zLnYM>R5DZXMqSyd^PecgjNC@y-Rnc|V7vw5%JN$lTbVj;{Dwz~>Y*yc_wI?;K)U0& zTi9lwuQi&Aj&SOhQOMw72m2N^fIY(xLS@HyBFRw?Wg3mvdV9Zxnka z)GLwAI-a>VdOoqzNgNHyDz}+VO}7+r_OifB#uTZz<}_o8E1JL!JeDM=-2Z^P35Tnk zX}s)nGNk5w#hBg8YakNUpkG+wo5!1!vtNUoV9`|DCuL&f5piDf)2Dx#_T!?XE$YW| z8X^6Jr`4Z-aoBxzt)oK4R;8p9K5Yzh(aMdK9}zEREL!9ff*90%iDDnA2u}EP+p>Dz zK@*aB^lQ|b?T8SQiZLSg!N#0Sr;T#Nm+KDiguWY`!7SY@T_yi1F^Pjg_D8yI(5;L)k5>e>8#4|srogiiHmV%{F=3z zJ{OMsrQ`_rm2b}nB!s4>U`HHoyuxaNg)DZEZb$g9;<-1FFjoy#@enQ5w;LgcZ*ml^ zCZ!jD4Vc&0vf9|IBwAXWym(^4j-lMbGE5#!T#+h zNY+tuM-DlY+wEWySK>>^{ZgM>h0pLu0?)sR)utHH$g5t2ZY%J(%quO~ynOGgIEN9~ zC2|+$?VxSc6WDu|rEGslRYBbnzrd45q4ES*HG?T+i83mqrak-xt5pDW` z-<%7osBOQ^|`WFf_j4j6Uj?)g~CE`Ak$1?e^{4N}sY06!21fQVmc) z4qighG7(MPzYl!mzkh*Wvd}aBe~4B5zKopEA3=$nO?oCRB{lqAT3TA2BPo&yQ4QZt z7Ib13J6~gr6@yTRWQ?@6=3Wn=2$Q^e)7sW1D8$&Z?#$Mh-IksP#6f^WaBLGossS-p zBY&fu1jKt8`T5C#HoG8V;F%OSx?V_scIrGARfVB^=?8e2$@S$~*DKgp|e21YJ4PFs2r1{zyA(Y(#gdFxym8E;fW z0hO0}_%qfR^-psP?@4;7V~~m)Yd*l(*bG(Cc=y?8T>g{SNpwg)K`D1vKN2S&cZwhb42~^ zE0anpVLK5e0>|@XxoSA`vzI#W*HgXU?lfMc&qLYN1QfrojbNhIYwZnch8Yftuuj*b zhH2U{2y0IeF%2*6w$5E&J-EJ_i{J0aOG!AHcyl^-GYb{JIiRYFjWIfzlsO&qHRzCY z8cWN~!m?{PAu1q4?QTj8{w7Qy<;1tpORnF(rHCm}&tL2J0a~? z>ZVKr2?jxC@|q;%49#hTZwTT7OpljhU$C>_FOk6|^u^dV*DoleAaC!gs;OX-7k<9{ zC{IGBnO>VqTU$Z9x$d{*%F8ZVTM;=Ej3e{*Eh}r`9lgREmk25b6RA?WZQP|XUWt-^WSXw8^+>BG8{a6BVa=bfY)Zn* znnFsNfrxZV@^v9`baeW6_JTIU4f7|d`W45$5;jC$0Ssv#;iJn1$YciMr@Zm>R>}t9 zTe#0st7$aEYzY}$frQ-R?aQlH0kDw?)vIi z(rLeNYI<5%I+h(3*og^O8dzDpDFcaI`k7;nsmf+D&KChMgvYF7slW>3M zfpa9TY`G5X(IQvJc=Xl$qGgaE8}TA{E$-*{(em8z)_~W$cPgx?Fjf!!eyD`xDjeKT zh}>L%Z^Sw)LcLRCOCd;4eLYMU_3k3KYbLIAv-4Ue1a_F zH&5^A`&`?^JgSv6$aW~Nf?h}{nA8eg3#>`Jl!g^eCOY!gm({KG%%;&yBrW7r@=!%wcc^`EOubv6#yo6pFEq{(@j(YXYk!=;3si;lT>23 zIX<6_^aeE=&RfPRf+431ftnw52C;-2&964+xD6E?L?H@#Qt)5Fn zX$A3aq9D4p$ z*4R4Dr{DOQUJYrzW-nCSz!SpVAQ*dIgo%r3_WX=)_H#WtRp|`xu8GLW+}QryiI|L} z3+gZoBe+l&O1+?}5sKm2JTyL$2zwh4z!0P1d(Z^6Rz&8Zklt*xT)to(ug7LT9x)k) z+PYr^7Q??*DnULyU}-vEgN)2M-MqoEa#Yy+iBr6AcGKkloV*az`J?5%R^MD}Js(mp zj$Zf0<*|K{!n3HAf=odkXwFk25nFPIL1?srHY(->N#X#+;frTY&QHZ%t21X2cGg_v z=I82harFGf6iSmPIaI;02&r@34j0-)UvmXU2o8?29L%L?bwCPsGacycW$ilnCjHYn zTVR&e;q`*-Ya=4Z0|mqE#n8rdvNKb>4FULk@HUFCEqu{ZUy^BJGtI=12%jvrO&Zn~ zh>7zd=?&rA*g5;dnq;_`iz1^3!B#|OQe=6hB0lf1nxVM2#&qo}eOEVoiMcQGcV{#? z*;ZIVi)1Q#P4U+*46Q3v!Ua1S-5fex?I1B9f2_knBsUyLb(r!C$xXj)wU&&?1I#dX zxMgmJi5F(YaMW9~SLh*E*qFc-$--qO-mdF*O?=0LfRL zv1ZYrsxv!m>j->sADA)FjMtN`^r3!On26v+@30>oF+MndWdCzk;d@Q(Evn^wcAR0J z^shzw5%&b{qS0zg$HvO!HD`(4=((?M}M#YMY!|U^VLW6l+!0l zes<3DNw%lt&zevA`rGhLpZtAGP&XF)lNmR}RJ1&@uh@^iKH2^+qU!p55Jvl(tCPUm z(nI3sBI&fcONY4_uI*%mgh&tHI18YgBD6`4K0A}FyH<-eP>_&ho(sj|MV#HU z-I8~R!GP?qJDF3z&KQM>mYQn!5uz~R6g(&dB6~<*ypLa!(t57lDH1Af1$ge>WKLn> z+o-50{K;T*luF!6AJ$VhHL8$xv`Uv;4>;icck8tpaxXT(rXDk+2!^O>nVnUZcdrO zs*!Q!+3*vwWaM7Gi05WKu;b!6nMPOuNPXVtb$T_Nc4(Yd#K61JyGw1aHL-9BB%dmx zuJcJu8WoR+AL<7ZS#ZnZ9GRy(4J@;dwc5wQ>29vj>W@hmHj7tLG%&BPuD!fYCv*ky zAWX3%1GuP%1eyw*RlDPu$5dI=BkorbZiBmJKPYH)0{OEzp`n7R(c}ZDpJbg|VqP0S zl}x1SGYoG+ns#FZg%@Nr zu#|qZoWl*f&Y~A_@7JsGQs$=_uO`2T3R?{A=9Wv&$K@Ups#`v$yW{)+u=N&hQHNc) zE--YL^w1^J-5r8}fG9|pbV_%3iHMTIFm#us#lIMmp0f{5c$#;~1S{N8l74O)bkG`QR4BwVX4>MHzg zM9OG5=yDyer|)3x{MJP2;>>cWG$}aff9zn-Y10`qQkeU5>ROD3D=bknGO+cUF0&4A z_q+69`lA4qTD;fg=4{`qLD%xf60H>7vDMzb?0NZ*o6|9^Fs3#&Xe+&?5?!pOA7(+0v3GTZJU{P$j>D>d@^b2jNHj-qxKh8jF51P&xE)B9l(?V3`?peYoJ+2p%a)~_x?ky z^IIlMC$6sB9=>W@9g(TB^mvCJoSC)&917+8Ngb((7r(Ck9zP$XKE2dq7xWW%7iCMQ zbk3>6kPNV7H*88+ihXr5CRPg(A~w5S1H3FQ)St5uXB5SSNVJPDWEQ)Yw4?I@wDG*_ zC4JyA$;51yaHAdABSmm6_EQF2qX|^0{xK-Sv5A1`?=tN3T=o@!@Q%nG@(O&95#YA| zi&g)QoP?O4&U1wM_w7-kn|*P&qbTQmte|PnaI3E1x}ES4HSxi+!tpZaC_n6@e$)d~ zN)e}6RL*&201U=r5A2 zADnE8{sc-cVpARlYKMj>ywj}wXtSJM>{a~@hAXe2*y-pAnOa55=s{K!GC8g8((^}% zuj5P$m)YO%_<6XKDS)7p08TVIW%j9Lhy4;ViWe9C&cVrBWz~apz%>`kwO!66L47du zKIAl+IoAi~HaKDjaUYOCx|g)U!{|a19i}Sd=nY&-53R_0;PKrA?5PrXO((qtX*A}O zf7HAJ|BxUP;ceO{pz2ilf-Mg{yKL#j`U^&uAMs`Ag1xrSQcgyP*IWeG!-d)+)G9k$ z#!1Z1ww<7vxOw;F@_Yv~?@FLvhvMw>MnMfmcVv%`ZNhVQ!`spLD?M}vq;JVEn^-`>Kyi*aw4vLk{Jqz)F_Nb`Lg%sVeJ8+XZiJT{M) z;@*3!`(2K`DRN7#w%^j}^CXmO2+ke)3zW`8*o20=I(=9QhL#X~Kk@ubYsNsWUb*~z z>}9fI@{xgEO~LD-_Lue`Q%BiIyF7FVPeH7nHZh?UkwnbM%U@KSnNafyRorc1$najo z`gHzM01Hn+@J$s2>z!@ za+&eI4?_f0>`q}Lmbr~NWEa2gs{8^4N?zHT!ZS`Pi~knu93fO)httyy(&Vg1_7Dcm z6d~{ny=P!$M>Z5KH0$ZDT!Z1@=JoV;Nzqe4>II>z{<|MccJEP&1lUvmtx0LDe>S@) z5wI>Bf`#}|va#(|Ijw7zv7P6*txvn%vxP}X$*68S zas$tE@4GMmtu@=m3_d#z2ue0J*3gh%Cd%?zxr4Ub2`9nY%_pUR1f|yz@+$CBmVngC zdZ>8u4$5C1(B))H6htwBX=&;I*SqvTL6QG=%lf~$ng1iE5PTdi{qZCDGa|N%uNAnt zuCH{4R?XTw_;UdX7TicEM<6p%@BY5LhevnCf3j(Wn~|$_wzk^oLQcO=Q2{(m=ra-r zh$i*|RK~{ZGF$+G`sX>!1_-lgCe%Ibxq(zC?rcXr36P|E{UL0aDtNqFDobQv{w(}; zkkeP-K`rXTE;2&a@BBZWr_b5t+HXOXm0UBkIzB$PA8l7>ZKi;~>_x+~lJl9(%&#W) zNiHKjeZ@`GMKlw^2aE}z?z3wQd$lx-jVnuJWo5PfN-}63c9e9hOc0+z{>zV-4TU8Y z<*mKzGMbtMQx%4>Kxg4sifc$aR=T)1uc-T8*z<)Ks7x3vkeHd9rHhv?It- z5VkyxI9MG=fmQ1f=*`Th;LH1S2mYG<&2hD+6N3bptYR&FMGL2)vYWOa(y zShF8=G{Zt~TB<#)=;}GLA{84DGZJyMu>z%xPpouHhtLZCup##p((+XBAsN083M7-2 z4gEq!86Po+`t3HKR-7LozdI6BKB7Zht17bA@d;OACmdfoi)7Atn$TQslKwJ^Eoc+) zWs0Hj!!OM2*VoYe5Hr`T_-*$TJ--cyq6)Dl><&XDEpfNNyuifO0W9-fmn$h+m%Daoi7MKeWk}@3gYSx>*I9b2(a=j(F*K zjzJ>qh}5K;(eCdbjjk2{Fmz1gHE#t^+JY)GYGPyoz8%(u+7No;+wQGhCumh$v>PI| zr$qhxxi3@%xTQTIbLngyRnRHo_*7b&F}aU*ZG$AQkYMy*fFMptsN87N8x~>8^y(|x zYK9hQ^1GxlUt-BeXH1ohtnTF?b-Otts>Hk#gzHqd4Tt4~^cq>=``nc`=Gz46Eet*;Q^?1-wqWj7$~4(AB*DHS+-EcPv8PO37Gb5 zf~y6QNrjrk)P#WJqUp$pw++ZW|&dL0{`N59VCS9@sq({*5dtn@zSn&9)2Ko!A* zg^&PHvW;<{?C&Ou(^+!#x5Lur-Xdj>kf?YJC7(j;YqaoOI~C$|X+I<+0{BauMZbNG z54tf!^By@Bv$*k>@lmPB*nP^HMrD3*S^s?-w=ytTc}GtQgV%t8SyQ94or-w2Vw>3SO+3-T5vmZGwsRw zNrEDBkY4>G6UFTRSyBTk!j9_wr*>!EYTHM~gAwR+z)5Am1O9vYtuyCXx=4V3t`NwI zf01z=612YL^%M8RqHbZ1ov_Kv+=AQ7$!oK&$@xRl%CxtT`EAvDHAr`P#&5SDG$TwlZ8_1z4>erjl(-;-c}o>lfH8+}`Ax<6$IQ@3#jZ zx*GKyKc4Y47r?KQhb<3gYEa)yJIeBb8xGVyT^~Z*VS}M0*au12EHFCh<1GKjF`B}2v~nzwecLxBZ+*pQI97%SZpV4!TLM8;Wq9o$J%UVK|5JV zP~U-oe0$rWaHr`Q8Y~eW|5{m{HcdJ#d`uMmGWZ=I%5-OlyT2ooQgp&i1+#X6dKHJ+UV}3R?3+czJPRuZ)=?Vfu@)Oxz=l>!YM#6(bNzs()2KTRnrE5ZQ^t{; zb|E#{5(hFLsY9gURj~S@9@8wl(53xy+sXKoEpqWG9c#sB)1~wwGT$CG z>)DoXQ&A}QKR=yf$>WJqzxY0p%qdq~Gfiqbw3k&>WJ4!m88#~3<8h1>I2671Tjg8@ zQ#L!3jCd+FY0EfboAlU<*LLL9Vtb^d6eE4dGFn6_wLYG<`8=-Z@H?9H0=O^MkX1a` zH#U6~fFzMP6w4Owyq+l|5k4H6X>yQ=DcKvXb z{dN^TX#rqpqzz;lza~FaJ62LU8p@d(A;y%JY941JOVNNKtER7G5PGtTu3@E|K)5UVCSC4ZCPAa>kMGJ0hBA0&!A9T40L$}I{R7KTgCv7E`Hc-m? z{3j6wNo3}d2zpK0j%%^v-7>ZPvJN^LczliqRbWpcc%{t%C$+5(eLW)2{9?epaW%Nb zW%<`)mD!om=qQ}c))`q12Kj+1^(2iPDQ~X(fqTGC9Kf%4a0yc#m5*2PRHCB|3?$78 zAWHDoYRG59-F}fEJW_p|V|ekxSFlrv5mRVMn0zre)bz_g!HX|H{wr5I3`UwZ^aMYz zF|nzHPm1X1=n#7`w})AKwCJ1z2uDXoOtUzkgkt~ef%v~e1JAF;{|nbmjrjPU?eU^y zz5n$h-kY5Kd=!BABn^O}b8MCu+AhzspQw(1pABD`87SR~e$N66e3`F30Ax!^$;kk7 zeFh>eCkK+e*&up$G?9sUus;{3p1XZ}1#(Po6weBYoy8U*AVfY<;0`Q#y#R^e{67|z z-$1&35ApzXYSv=_n-kG1oeFVV6KZis%clj`k=2{+Y_vj=ttzk6HKILBu^Ei@YUI+A zl9R0rr;-fx)El4__L&_H{eBjD0Z5uU0d0NJ!QDzI-Y5{5*PcDr^WybCSy%*kIJS>J zefC~*w?i-f+MoUVm+&Ef004|*HO!Zfm4!BC4^mZ~{d#_^KZA@P0WwA?Se5P5p&+H8 z{j+*E!EPOXdFR2#_!7B|6v>Z|z;h#B#QzetTJ^s|;$W64paKDOo1RkDSDq!r?vAGb z-m`UGC6S?j_;fbuE{Xo0dohZDp<{WZuJR7}mzLdb`*1$(Kogzk9U6kOkR$@!|#JBZ}@Qr;uksT~-Y;nB{<&;T4?|2gwgzzH!AY!DFtMy##Ie`iAVIe7rpQ+YT)eWdvN9jdk!b`N$JsIll%J{zKYdnc&`oQL|~XaWm#bh5L~!Z+wqib*gt4n)sec#1{{})e|QR zCry5U)nlTqpXyo+V%|?vnRzv@2~`YkXA%CnkmSC)y1KH$aaG|ooQ+$UR;Ki9!zc_5 z+WB8eZ%gz#egSBHJ~?MCibBg(?%<)UxhvKIF4|1>N4rXD;N$>X(v3%^o6Y@|CBbQ=J$8E8TiYtI0^5&$zSv> zt<>Qh0Z|wiq2r%q!_H{`y%`vtnLsY=4Jz=hvfIba!=s9q0in{(bK&V)@$BLc{G36 z2^-%H**fj$-HMH=A)J^H%9(YLP3?*9yY{juWX?@+6YJmkzNNU+2`Lh-!u#ZXw?agQ zT4)M;%N*Z3+efFqO&+N_S>Ea4m6V~?32IT*!)u@YoUpSW`Djbx+VTw`K431cHt>0yFEd@lk`1= zJi9HjVfleZGQFLIga+iR!=dQtP9&rxrzUbKDn|gemvhAuJ3_?%0pb`^JHf+uE2eYQWDCY z&a~q-D~Box!3^I;E!3#+kNs9~-$Pnl3;mhK{}jB!gw!w|&0I6CY*z&739mxHxk1^S z@y(%5dK5h0O^IMS`_AxcOy!|Ir??p9^pwZ>4h`y=?RE`Q_L#9T%7CvqfA!}e9v2-G zFRJ8F`uK}TIoN|A{1;syebI*o8x4lVV zx1v1#uXp_7s3UmAE@Gzf`{7nk=lqI=e_%(>opN`D7(?8Cas(zLFv@Jz9w{Rql%8Ll zjW&Vz@CzM!4mN~}ThYOfO++ZM%W?vTwST9}m8!Bq#;RHIdzM0nNoJ{C4$D~9U9 z3z=9&Yptdp;=j7w!X%!yCR=RB`(x~Za_OiSD>{efZOH%CpL%Z6Ab}*^e9r3Jl8Utm zRs;v}xb0Z;AAU>#3A{+XyO8Cd3%*W$y@`;JUi45j>!>7`Oj)hT$v&$Qc4Mrjq&mzx zq4UFZcdVx<|6<_IPYsGicbPS#Ve%(Ro5r4G8iE}xzsr0hMg94mUUSWGsV6Gr*MjYQ7z7>gd0VbTspd=kuswM~?P7;*Y zKa5h3Qu@#!JlC7C>g@BaEQ7@GjUmb*rFgHldM}=&y0Ew5Tvk*RPVdr!3RPdJjH;^e z!ta$LPna`|>RZsAQwvhh`A;3=^jHow%qp*2;%lFORqcWZkRyNKa@Kp@i}fUDS`NY; z121{w#|RDeiXHn$&Fa5#QMP2g))hV4qr@N8!l0=I#ZDh9b^d(8TBi@BO97HFXPMrK z$P)DG=N>bQfum5lH;YHPagfkbW`yo7r|ZMl8}69zIo}d+N4Dx*LwmF*X0#P9CQv1aO(3OwI>Y6uv0ZpTBkLoN2bjog(qh zdA|)DkO+^0xGfm3>6(tYkyCN%Vkn#mxONz=_|3Qu8`OQ7+A?qHNVY|}87q*)1{QRG z`5_)8_za4SO8=X@_L)<<_OW9^%@6OgXI49>*3WJr3MMc`ud=D*)bBWU=Um#hR%cj; zRWVc&&U@<6iT1@+9V9if)=>d`fPsXnRI)Oo2D}%O?$$0JM_i=uYjB>Y+_W&3$0l5_+(Fv#6Zz#V44=p>R39&>9ZHPS^TOKNT2^f}z^~ejhD%Dz zTtPLbkDMy;Kf3@l%F7qfyqcf4=-q7(;WO>8@QMlA>H<$rC*v(|{Z=8T*8F8*sT%AH znqhl$%yqgC_^TDU{`G_$b#IZy4&3akVN3Rf)uO98>&krj8P+t8pV4R+3=$>W;!1M; z3&JlCnM>>nu6QJustwFzDJ7ECSO>WjG>bvI(afnu%RATBy4YYtt#JayJ73T*SNJxL zsrkjQMMPlT5UuwzEFW3dw zO~5NqSJEnUCLZ&CdvetV4L3#lcIGdW=rkM>_8Ej9Uf4*dvol(xi2-Bn$OxgRvMI(PQ~U^$j3 z9O#$>-$x9pnZg9USfIpJ>1uzGT9FUJy#+UoTav)u{aL${_=+I~D9;|>49(gsUOA+k zvmpQfPA31C?&V4`CnpDCDfab!)#=q#wc7+8((~gIt>WX%s&f#R?Ps7-ht+g=X2t7Y z)+TDU9etqk=1pj2WhJ4V)D+O3^t+hU8F)!4<_iR!K}&vTYTe!4MQ8_+xZoJzybkW6dM-BQvq;8aiM72K)gF z0G}Sf0>_@TEI+7=u$g25UNEWO^u2L6xqM>$&s>X?cc3nrH!pxmtPU60o z_V>GQ1GR9`n!sWr8zP(L2|~|)0)HZR(~M7IbCC@^S1??L8Pg6R-yH$iEKHVudoS(P zr|v&XKThQ29Ks_B#kYaK4g?*hkI3E_!Q;TuL2&IMbNbXqd%i@a{=ZHo!b8X^Dk>8qxY<}I-djbQ zP;T#k7MpobeHGV=+hb!|b)FMjDXXsGKm+!D7A2?cw*8WRU|C~Z8#Q23keuPs^Cf?L z3?JbGbV~_9vBZC+191b8hk@%#L*z2vmwqUI^j1BvI0V?+z0cT=Z5ltLK?mIEkP-c7 zbKR!>sBcC8wx2j|yG zA=l^HW|@8i?t#W}-CgluR2y-`B?nygP#wRwNq1%TL#FXI8& zTUBWPtBS@oeRYo3!&&83fT`U2@t4%;t%{mj4}eFV8<=OA*`*sn%YHgbUu?ip(kOD`#c)>WopIU*U?+Q(s^+-GPaQ-jQ z();y^fu8<<9#$AJq8k6_svy`kD5xU1g7RiP~@D!YSEb>brB-pCZ1NQE(b zDE(liJZd!;kHI4`JLw^X*@IJTW2yD6%xU{m<#Caur}#op%SENmwJ^$F_)0ZSgr zKZfp1mxlui%aBllvnp8< zN+G25<`ic)tmP;(>RT9ccUZ)Ff!J}+mvdz7#tq8_@d7*_>}I4Z14(>CU+kWd05_44 z2ke>qELNu+<(!YWvHNj$V!t{XlxXsLZ;_a5df{=Vp}aXtZe5AJ9tw_*FPIa+*pyjw zTR*0N!_BR9Axgo%v~E=JUd`w80c9mk1?XprZ&P*%vVMaDlJViP&8GJ&*a!Wkg)SZn zu^a>vq6*OCR6Cm`6?nVxTV2Siv?E4E(?6{lR-B=Te$S=Qn%_une+T8IHK-gZi6ac} zur#Kvm9$1=h+8^u1?+@5j}|dfj-)Nz6T;@HA_x{AxGmQlssz8$Ro3Aq5eOc(9 zeXwaI?>2;O{6%AssziQ>z?OS6s9~X?S9Ku{|Ab<$(u-|6g&t1~@UFdsG0 zirSEwrdt{zrE?*_hPxB>>ET>mW&r zn&1YnSGG|J^q}-nshB%Bo9ikvrc<@0I#0fsX+1+2*gpVTvlQ{`R-Ojx+hsR9X_Fus zp0pjBxwzJ*eBq7I_^Dt#LUSZd!}sC0%q*PE|3n+@2H@r=y4Q`1ujz(|+}{`3*ehD= z^5@c<@z@TM$$x!7xIm<3rNfbGvPI@!M04J6+=aO zBf535VmsXf+#;37Lt1>n@fEX?CpqTjfs%JQSZ7RJ_Z3#OFVh%jdQ_YSDK7Ch_|EmR zv~vz(;yjYEFQ_I`y<;`~6fhSku~hr^rr_yY8)!_V;NRcoM|JjAuX% z^7w)0_`8gSqI4ghm>P9X!8(ou0JWnZxN}-us7eRO&~=SPKy|dL=A<&?)pn#BX(%wy zs+|IPzJ8Va@@0;45oXXQ<%J)h*^dDJ5gAVrBjJl@_O=+Lxe6f*xQXXxi>Y?sWVdIV zgiCZIKjqOi=2=mB91JTs&uMg{-gcPB_Eu$DOia%2l8uvoxpa2$03vyGcuO;Tijl@8IvvtU(39-1zHe(GUAPj*pXH2PN!8|-MveSNLqK2w=`p< zr_Wv4rirF>%tE${ec`$IS;8z7;nm@Kf1SE237Cm#GY@T4KsxatAvo)y%JWG^_nng2 z+Q|_@tChTWddG0Xt+5Z2BPAT=XMvu9BroXFQivaPay5-lKok6ZK#N$X<#fFim7brU z0?yOlxHf=+UZ;ouf&laB3$0J0a1@d+IwyFHw9{f)QdHd{E;EYSa1DR0qO$^&(s(r1 zd2))SnAeUMVc>#gAMYMDKo+NM=6Cj~HOY7^s(SqoUD3ER<8J)unh)W+?i?Qf9AD7r z2K)W>9#2%%Va!v@(+5WP;qLMuIEwPO3fDKGQZfyx$O{1@7TqWrCKn*g`Kb)t_C8_J z2rF~rc$`+K-OET_x~w;Xpnb1b|t8*K|;=tSA6=$>cww3OGTU<{;Ky}#%)jI z{5>YAN4q7uCL)&K*0)9->6au;sCBFH`o(=A>R2_AX&QeaEC?FJH5Lfpi}{+J`QG9JKO&KG0oEgU1y)xWFBVE@MCKhnZ z9iU(z@UXIo?&`yR^IiG1nrhcjch1`~6cVh`G5jk&**^_+mbvX~<+F z^7Fnc>^Yl}Sf6~?Ys{YbDj&YMI94z(LUKz|L6a#T)gJp1l4Q+-Su0lzEW z64ZEoCoYDL{E{N@!fS$RA@X;w?RmRB`&U%~YmCEaqiV#RaV{dxA1Ld+i6IJCUm7Ep zNY#Q$y=c0|?s8r2g^!xOiNQbq@$5zbAHWz`Q5lg5fEC9+{MVwBwM{0^-G693@+XYbeTBpTuqj z8$@7PhtAZ3Ex&0f41)VqaYLC{kx4(HLhpK}83bm6K`1XuvSjoF=afQo*IZmm zDk%!zT`3@JRt}%bWQkz3w*2W(&X%nBeWaep64trPKk78`dSa44*Z6~#PhkEP(i^HZ zd&@YAIW&}%j$bgbV5fGz*X^bG1XGT3tNYGhsfoUdGUY-FP$va0c0`HK#gI8rg+K~IGUGpIAp1FMZfO_D;SDq%jflU)m z5E?;`TlbUR$6Q*EuvN;2`=kGA8M~6>MogPvUNb!Q`J;1gVU7>@E$cq_UPWV=Wuz*!BPa+Xi8%*M$J#t^t@!r~2%5u$@Q8mOK3wN9VYP z^Zyw6nva)S#em*vY4>v{0h^3lI$y|fA!=d4;M=!vw5+V?z`$b?iT?!f*th|dTS_}X zfl3*dnOxzwpAi9-ig=ySdK@kED|>-esct&jOT^92fN=v_QgXq(2*`Tg|HYe2q?XVV zVanvQN~pPeo|Ck+2%mu&fb)5+4{Q9HrQV54)Vc{s)8&Bc7N7{jW%4bHylj&57`O&N zhMx&LJ39d@fmn6RUPY3R+kf$1ArY1dKNJD z;y+JF&orxNQ;Um>OQgUuV4DSyW(}(y>Q6_lS4*%=)_-$GukErZ1Aa(0g2kq;0SH~E zoz30lp@|X-;9gm2n@K|a>jleIi2ah4g`>8vFV~u1UR|+oYp^78+(-31bH-pKCf->V zz5uX$?WX{iD->)BxYK``w3bWMIqH<_g&Vc{{IZ;Lc-#9pp`OJU-tm%Xg)+d);cQ5z zuuPTsztC|j*o3TXY+ATu&x7`f2tsy-vq_=ZGk4e4))sev@h+=R0H7@b`l;*8;1M~I zp>0R1vnE|%tDQi=E1m>s@Tkx~OGE+~WSaK-O|Fz$pZr0 z>Sa~DMm8m{S3oBsfdKliGhyVWz+AF&Lp<6Purt{%_(^s*H+vk$L`9(k*m~sWD#*u; zs*dg7ez>l>t1m5Pf@y>riV77)F4Tl)MNWs4Jcs|pQx=k)-JAeU=n~!e!%HX89O7*t zs;5|WCh{0y0u-1{3h(`XzL|7b7I01v{ZTtBx?n^u248pYO`vY_qsux2 zcvV?@_u11^<8P&gdK`isELpq^I<{+`Ig}~u5|8RZS?UFag{~=>=>@^y+cUC{R={UV zTcnaFMYwY-oYbfT*b$&T;zrM(q*u?{uRP9TtR)RSQ&Ug8ImFC2E?l2If`FaN+Qvq6 z*%dgH(M*Mn6guS`SKHdzOCMsuP13DAJg)g#E^=KIqZrH$?wg(io&7 z^UE{3!M;4U!i5T1P%nqWhDah1KQ7`^kS7}LX03XJhF}y+_~gEGLpN)=kj{H#x zPAmc0w^4+IvcKM40u>vMCoM6N2Rxeg^$&(*JIa1;pt8unlukV7Z}!*-{WCO6%UoQh-y7itmm(K0MbLC}ALr+OSrOG6~Pt_2qnCFY4HRtlHBN>otv5zGxiTBRgR9IVK~ zC&&n?8;(YgJ_?y=WM#~=pfB}BBKD| zln;C+y!t>)77d1WDX$fmb}P6-loY-c4H>;2v5;wBl}k$b8B?bYU-{85gbup9lo!Sk zX6Hfi_qmcsp9QDPV1TT_;kSCaswkxjay}!&WTPx-S?gUkM(%qo$jmqs(~ulcb${{B z+x;p}OFTw*W|Bp*PA*nLknbmkS|tiX^YzhJwJd~P_M>VG>Y+VS-_9=;D$DG> zhqXx5Wx{L6{m~&R5f_v-MlbmCMcU%ms3x_Gv_%f`r0V{@qn~l9c}K60iNhO#r^VX@ zX)gm73#-i>S2tF_5Qb4PsMx)A#X~3qk6QZKnhn znOR^e)zN?YJEa&Y{EL_5lP$;G-PDf5gX;>=@W{fv^hOXNJY=u$ET*qDQXOQvb6AQ* zzS^|ERgP1t%(NFar07~p=B_bj=>TD82oppTw2kU&jKj;Va20WeWh{cos|~f3je!$! z7~>qvJM;T5>UWBm<=GQIB?$JnW#y8S6EKRSaJXg8aC-Y>KK2a&AP9M~h|4#T*(q1? z=yBvC=*6cpK>`S&5xCM%)LGU?ZX4%^@iMK=a-eqpbS|(&O$*dhPuyMx0)%1k!OJM1 znsEZkWegE=!^yTC8j9F}ZZQ$gul9T4Wk*@7c9ZxdSy70suJ{zx@l-tm;>sxou5?2Gu&^ogYeD9(fq9!FNSwxH=L#NEH_4ZSV12@w!*~(Fd(Ly zJM%4EKA$#ojF%s~=TWmR`?1$}4r(ZQyyZ#lXLRJvdGV)Tf?=pQveP@XsZn+YpFPj} zRrA+fg>TRI-aKsNIH@~zBc~_9Ye_e2zb*ZIsX1X3I@ybtHtTQ0@u$lSsri!yUDq;l zeM$kCz$Gh*fD~DcFY1S4Z~W4VIb~&KUZ3;%K?=xtPYCKH=;MhO?pUAesqVSs7-%41 zihg*fQTeUTEsksgEfnosW@MN^yMRu#nD4fbDP%g^@>K4#AMqfa3z;Z)WWw18X=tFD zoVEcODo&rGV7X_8a^!4Tr+syXb8W!x>IsnotP~&{<2MNyat(1tQRwFiS9L$p&#vUI zsDYJ^(zwrVbkqqtg%jR2T5qn>4`S=)_@%R&Q4SuG36TusA>@OFW~@iZ>iMIC?A0J* zRNQV@9H+9i&6M?%s+@|O@F5$#&ghnbi7jjnnKpDPcncAU;VWFMkmhTy?BwGDK=2n- zQ~n^943ysp}GC z{97)#&tLB+>~v$lU#?Ull@CK=Hk5n4)w4rRiu*$!I>JCfs8!2d^p?cOssLu53eQf6 z9&Eih!+eceM^fty@1rB*btVh(1C8eEzqJ_kEX4m><1haA$>;`Jga>NvuL2ZbEWJ$Ze$e1bkqyp@irh?hgc_-KTe_A zeG))^f|uA6G)TPjfzp5ZNBDsw&nWxj&Lm4l!mF1#`K5Dq%&%^7$m3*MYm+7ga3$+C z4EW6untQ`p7Z)Nq_(>QdFO;Td@KbllB>iR(^hiZ^6mJ6LBIrw%*v5#U`1nadJaRs! z&QDZf5eh4p(NL3I5i`D<2b=CFx}9adq}zIWhEkSWOOFDdSHO>0bP;|aHu*$Gf)(>* z7^(%3;J&-P zItcj^MTUJmnSU{3!pjg}p_catl~zOoOU|c|q0s6|jzh+kB#r=v1`SL^mS@Z>8WCu% z^V52gw9jGPd;$2_ zINTZHz$KKKQgmDoJuF_5Xye3%jS;=o=Tg2Q%z1~I#)qa~*5gW@mJh(Tk;JAg(bT?X zCL(wgO|julQX^TEcGf11Q^pF0y#7CMK|p-!8Sc-54M2#yqmiVt;YrTy+cCXt+jq?( z&aJA`P0GMG_t5u>|2*3M>uvu3&HUjbIUxTgt@=&+dyb9KWs1N==`%3Dgqo6>D7m~9 zKSjPqbbCyxRZeDJEiU}2g*$ZJc{Bd$-gEb_-8S&84Y;7X|NLQl0mKg3wj!tA=Poh> zLf88fajE;^VdA;>Sz2GSPyuaCekd48TSv$I*`j^CCFb;gZzrR4)lf*dBGHWMoCu!%y?ekEmNaK%%Qps?GHMvBx_#CArnTba*GQY02y+R6XApf#GHSB(oi#*HNO&J-`i zym-~I-Fsk>Fw!!EC@L1{gcp`I?JD{5Wi+(DW4r5MAs%aOeZ6ygArnYiHgqQJ&qPy* zd99z(J=#A_>KMBS%)Gqs3defybGp`J!g9eTN9j?fL;#dawHGq27|D{sKRi#6j-5y;hnyEuCznK*C3`;x`?V8Z}|W={NU zkZDq-$@DVLB1w3DEF8UY{G-8^@k!{BldWm~5gF!vQ zm91Z!EH3$E8Ts{@170dCD%DY{Ri5#CQ0MSJy8!dqdA+;EdOV49{OkK>f4gIENipRO z$-vWC~oeEwufX*sJ2>pTCLYy_g5zzB+6QbT6x& zq?=AXlUadj@A&{b;bXhJBt~L%?6;JWon0AlAF};BH&<4K`F!B)ig_^fZ;Sgr>XG?G zk*4ioZRi_GJisB^pkwer3kvM*u?Ga`)X(#hi&+NXYsyS_aIhN;t846BDUb_Pdq`oS#D_k8(@&lu%M! z4L%?`7nKP@YEQ>3g3h}pL!mU*@^{>bquPV+qWwF} zu69P#IW|6a=^MqE_hV|z&5uQ$W~hFCswdSuqx|s$swy8sQJuMirrOjpLko6CrNa?k zQ&Bv*bgl5>FlX((tb8~6`U4=$&={;g^{)Av$4fN5+x!`+z*QCToHq?yKFlsEUXYG? zAWRn%P9V(~p8AD(gL)?6gcT<#NmQ3vR7(!KU(rRP|1%XhKXhJE!8(e*sh+>TZp&R> zQ#5_g3_28L37%jUmDLf27ICUfrs2!E!--X}>N`$c7bol?;nu(6@0K?}P!po#WhP|yGNw2!@Xq~ARIQPpj+#7+tTw*l!EbUj0Cx64 z$eKyD9_FWd*@Fc^8bk$UHdgPMv$;Q{?no1B?IMqxEUH*X$A%4Z!P{T^Ab zS8@H*e3N+0fUG~8hW2||_wq8R&7c8w&*wY_wtruYoK$b$`<6JBn^Ok=`z?Tujz*ux z_sg7oiik)#^W})m3*21{tRh(OJqR6o(NW*cI^Wc)XbyjkH(Fw>q#cI%b_jPuWPg<- zmN|>ZLJm-#*Kkne_Wh}E%KfLSCkN-}-0G!E|Jx{$qC^0ypPZN4hBp4(78{dRcog-z z&x~>4zaY(b%dp|lq|Nw9gEmF3&^(9K|EIpP@X<@+&!5!E>s;K6PV*?UEbYp34JtWz z9%3cJw}F9R=44!;U9Vb&b2uFxJr$pZ#8K=tMSwx(DE6JpD8^DK=N;4E-MZnU7ISeV zcIK~>2x^gOb0wl`?`+t@|7_N&H)R#T2|8y(nBGk1hLe<5WSES(*9E4jipquvq;thL zg38x<;beH_l$KrVbW`x|u-+H0QE!M-&KBg0KZ7;d->{qI4n|%MeE<(Ks7xjWym!jI z$>|V%59AA*DDf$5koc_p2Sp>uK1VS>41OO^GNtgj9O`}n6AeyOfLmbwRXlTvbaRo6 z7|1Q6spp7rcb2LP&`v*N^E%u#4~;&6MDghGL_)Ri}%PM{PJ&nGN%0 zT=QL<3SNn*jgMaDx|tx%TWbj_z=h|%G(-y)z0BWJL~bR{eTiqUyd)5Pd;!+Q`Y~Jl zheA0nw?BYdNj?fR?`a?8#QiJ(-|Mlz?&Zz!DJSAnlchny^o`utQh%$&uLwwT;dkH3 z?OOw_S?`B3Z7HKE^mTV2?hyM)o~=I_qlNlpylCft4%eG$>Bq3AXcTTA?%g--2lFzd z$xJSIU@D?&-D(UU1Sx;)TMyZtE z%NpfrewB=G;(>nLImLBXKPlCq;_)=vMmm+9tKFttwX^cKtoV59p?~aiPlGqqCWiC& zzfI_U(iWLBT4?_Y`K-nu_WDPKox??XMJdmYHriP4ZBu-O9e2_p^VoMIMCQuJ}u`>w9BU{l}?d}A)3-q;BMWF!E9KlTc{hV zgEw8v`F&E2xnvxYp*rdwAELa8h{McgzG!{5#w+>LE*-U2IkI4vEyBm9BwpRU*)g{c zH@O0OsIa+EsXPtQtH@=jUp^A>l59fh}>55XzDVMz@o`mnn3g|vB2CM``4E zcW8Cg`l}hMQ_4y~L^vMMbtB%IB{`QSU!dG#V1`7d&1+gx|%kx_zriaL}Ak zPk~ow|AoF5j2RG?*AUIO6Ykn|g-i*a8c`7b*Q)=2LVt#_5g%r3^Z#E2BklhufF=Bd z(TDzjV%32o0LsBPPCB~PK@Y~cw^+eoF^?dcj)3hf&k4}fLDb=}*m3uMWjk)b=xsy$ zgM+@*fkx2T0YU=J)Z;UT-s4+@99MvD2KYO8S35YX7Kd6~SLDyWwQ;0&z^k>$iP;FJ z_ij}k`x?RE?o+wLABG;}Gao@>x6d|}lz2ba9R*Uu37L2n67$9TDlw^`VRa0^;Rc~N zmD?HA{*+Md4g5&w*ic;4d8yrPal)S0tR^h@2iG#w?M?SO#>R=4H|9m}d-C)1O;`xo zTr+W`08+JGL)JTo=MlDDzpA7!>El z(zOaU4o<-Q&he=#hC+|Ffi6gq5zgG<=^!(sB>W1K~HSMvLWebZx>53Dcr1%k% zwFCT<3odFy-V@JDK>LT`mS3s2B6#S#9=7O^&F0H^Rr#o$FDZfGM&bN>rRvaG|JTxE z-={1jru>5k*{SLJwHhfzGy>bsF{QjjfDMNO9IyR<1%CoNT_`$bdKdq2anE}I`aL>8 zCQ!l)&dtbm*pm>y0irgVNTstS`saH90LOR!4-a?o_2s3!@(W&eCj8YS1b6)YHG;Ar zfiuj$laPek?fGn1>eZEf^oEmI1yk*&1GTfen566TCJSt(u%OKQ%RayO^EDa0!85Vj z4*KmX7Da(yK%g*kkSd|-+rd%*w{gQLPFAYGe9Qr?>KHgtzTBH z{dxhi-;?lYI%$D1URv`bKL)6pGc3pe5N3QPMrZ|C3;l!N0UTP1(|mmVMrtS@m87$e zTt#kPmrYDDVb@d$X>;yt=fF(5^9Z_Ke}8Lus@NE1U+?|kNF@yA_W~QDVtwtOC$Wk~ zC|0coo7Y}zF$->F*#p=22y|20-T(x9BJ+Mn^?6dS`96YQ|^i~rYtLeXMNTB+(+LVJwIu+ zGI-&sRH*vix2waT4#{Jgf%BYUv#`wl{?mj)^u)~b)zs2DcwjcLzaJm4*vm9brrDGf zcp|5%t0%Uhc<>gacRJhIE)aZKFTRo~so~C?kTCh-z?+tyt~-%EycUZ63ph3jI!QyC zAKA|Q8rX^W&8xAQqn>;_(Zofu{D%C`W4P6WKfl@dkU=($RD zeL0+$pW6|-Y}a!2Iix>XsYhqtqw9(<7qy-4U9t$jjCpSzHjXu-fdKbyc>*gO*AAwL zz|nh};-O($>L#Veax=|>$OK}o>s&ULh|3LTo0cc^1+TvS|BQm;tygW+2D<7K6rS#n z`bqnVXvowsl&q+&EiL_57is3z_oN9*kR=t<=U9$cJFFntk{7yOT|@CwyFQouF*if+ z68y@mpM*!XyRc0)7L#)1@EqY%h5cp6Sky#1VEA1l6DMWSylZUtT5i4DIRSYklmLW4 zqz(yE@+h&0nk?LB$eam2<~3xN^ff@O+h=M_lUFBh0w4uBy4`vk~Cr>04`1jn}4(q*CE4)T46DJC?nqY z*{(K=GPdtTKgsyKUhz)Kiu1_Y{GP&JA9iit{Ed!*N;hiay!^$0rEnfk9s@l5!?w|! z?YX%m9sPg)Ko8=tX1RCRhS32X9Z%F__KF@49lHKGBb}}Db8lqWQ;+YRrrlFbI(oB( zqpCIT@W$WPC0_+gs+|yz7*akm}7H~_uSmMv_y4x~8 z3c2b3_W6}^bflolnpz&k}`O?v)dqu~=E(rlJ}>zk3~ z+ZxfT_>UIgKP`Q7;LsoJmc4QN$PM2S^7Od3F8pk5por|HQVjjogX7RaFz@L^?#KD7 z42xp3AD_d_w1=J%>xQ$>w2Fcdz*fqk@Rq0xt_rnkH|DPY=0H-WRKzwi^KP3X)@hixKAW4UuTrRkor>mEw2j#D@_67x0svO`uwlS=;;3sPaMH zz!}C3NG1Cbg8niG09N~+9hpK@XTHv8)&)HS4{?$cP|v9|88fru;aZDJW%!~VY-Q2i z7^hNS?r4c}DG=L*TkAl<`g7pw(0TWF0wCe~r`xpSeducTnzqx@?9@e3A2hawCfH*m zPUrBUXG@O(1Wo!)5E;pT^Heghpcee_e4zYB<)4r zdnQb;bw*FT-4yZvp*!AokWDgcxa3m4<~rYY(B>Q1a-ab;E7)tgF&P-ny$$;&4s(aK zLZ;fs52PbsOdk0IDAT~^BCF=2X$a^-Z|k$V1c-J(AS}Y7qG?ZKzxP|~g;4rRtK0R` zRK~^8X>kpgwL|L$Vfyr;CFXO5L-&4F+0OrrhYm<^a2sU^o@< zGEf7Nc#wQLb1c%FR|ZY*Cg(I@rCd{IO|o0xF?bqVTDU*C&?GiD%rq<~)h}D!pU>5w z6?|n~(emf+`U)--+Vbpi{yv7x?iC0H2aVtuf4`c_&1bSVM#%e%7%J!cCPx-Ai|$&g z@t9AQ<+|6smMzbB_Fed)8#9wc=-b5e_Gg(&f?&>bGnp;EIh!MDQ0bL0){Nr!dAz-- zy$s^bhgaaifF7tJC(mzk;M3RFH_eav!>NdQfsgZl#Y2?7B;$X7^!^df{zE-^Du`M7>lNeG6Ha$_Wp zR}}}tKPCTDnR>m*T-Thzc9+D$)pV89uyL7Y10ma!S_htovt{?+MIAjSQ{4EmV1w1Y z(**}g$PkzEfvwr&%i(S;jz$wI<8RBMAhql$WPab(RV00OE&Zi9C zzQ*Gxqv1t;c0TWJj#@@bP0PcC=9DsqdVD6Sa{l3XJV|IKUldo$>9`^RnP~6$mB{m$e)Ev{YU}$V=I+1KZReuUYge}V7pM9Vdcsn4;jbBiO7Mx8dpjYD9i#`i zkjrWR5pqkcqFmsphO_SNoUjCk7nF@>J1(^u^}=5_0+q65KZx{)*z9r=)MYm7{Cn-?L6+;ySQc|Of(j~r8(Xm~gJ;RWX=MFWzNzF_fE-%OrEQtoXyRU=G-TBy; znv6^TaNNPy-!jm0CH$5<28gVpJj)J{3Qu7>aA{suLl0o|dhgQEsnvn=e_e{~?&kS3 zuw3oEOuAt8xIpe?HT!fLDm~o0)OTHN)MLyWd7?=$GT09keOEg#>$R<%IK%4SS&6vH zP~4o5-&T9Di=3>5LdG#J*l!?hIS^KvQC^w|yLX$Ftu_*pwnURPOrVUS^k(w}*Ilhx za^oZZ{E5>go4^B!B7Nj4KoVSk)sK2z-`Qc0JX5SeC`qkmx>AL&Z=k;!>t1_5NUbU@ zN`l=i-c;3I5OgkHF-us!r+V+}n?=f%ZA2>Iu$wa8#mu$w|X*Ly5_dnoutU zRe$%XJXB&>xI%i0Zu_nnGo;#k8auGB@CPWe&#x?>IX=cpwdNJ=?=(iWagTG^vh$}y zYWN4eISe}WDqM{iQL?X$2&Lp5xh4u#j$_|a8Xmv=)tA+4+i2Q%W$6}f(ET%WPrP3t zrl5_k{}^ex<~JIWC#R~LP(KiTke91kXH9k|o)7os$^mRhzKA@N8$C%L&fit{Ub`%r zD=YQfS90p43QPBXZ*<|W7Zn>3SLv~VQHAkit7vEvg6E6C7nRCo|3IlfBUd@*Q(28I z>ViA>Cy9TP>Sc+341J4D07adfd>xqT8@Bzzgs1oHY_NLw3dfo3Ke6huv$zyCli_K( zQcF0@ekLsA&F5^r6p3X~Ps&LFf4%>$|Hx>#`cB|ewAH#Vs*id^>u*iVWM{k6xqvTK z!tcYwp$X1Th{;wwku%KCP#w4#yzRut(M4puXSKSmh$ith@;g;S*SgU8C#XNTo83=g z$c>Hk7pIg}+l;^NS;JwL@|cCVd{1wKzl?{$iBKN7s&-lxqf@I!r&freSf1M1(GAG= z*gnJjGBS#m(V#b*+%uSfAmpLpjm;*(^)t{?+*})+Ey%L#>b50L8>+EMm3-A1wAApE z0nNj2N-5TFcUZ+>`VB5$4Aj}2`CP5M1{tRioN>&No{@)>BfRv=&}G-RB+Y@B9gh4X zSrYe{(dAZq(128V+AqbRg~4T!YeeHO%Fv>yYP;>%Ih)n6ZIgs*^HXdyooJE-C!151 zvNd~%CN)V_;=gJmsHE(q0Q{(IAmee^j*cFc)67n_L63IMaw%e^)l)S;pBY2HD*17d z2qp7C(LNzPE|j9Q;j`uvY{H&EZ?2buEZcYP#IN-Vm-*IBP2o1x%N-W5b7k;?=GM7c zR2uR`Y}ScSpuae&3dDEc(;Lihjq@YC7B(SO+w=&WvqwAsDIZtc4O?e?mmI(k^Lah9 z%~0_`|6-)&IkrE%-MBx8PB?w&g-Qsu|m#RA=OBs_5@&>;@*Pzln;-5!`}Q zW>8SX-m1}hC7;t$K_Qy15+3qc#x=niH{>jb?C2Wz84%>FM0|Yym558Vr=iVjZd2IU zq&eW5%l$WlJF1LfQ`f+eKu_VP=5l!?6aY6ichbz>upA%W-3F&O@Q*0$OEju*lE8VldmnJ=Bg_ps zsBLUf=zZrab2jC?v{kYWe<3>t8^Xy3AIuhp2w%LU&2oQKZhh)6b#>TNFMHg@~F_WbZn`z|v0M=I3tqe zpyFgb2RE_D$43g34<~SdNC=DRS}W&AU{OvXUG8M(qCM>~+Isj0fz z8Blgn_^jQR+XGG>MG+OdFI~X6`x|peI)g)=ovgii4+Cdg_q{J84l3qu4ED`UM;##R zzWc&Hz5}f?U8AGY4fX2f&E}dsyu40-y8xeZ8~yF!H0(#!qeP%M6GD%c8_o51A*lGR zzTV!AA*$?NU>0@!D?Z1KanE}@qiE#r!T};)Kwb9g#SbWDR>OCo5qyaQ26 zv?RM+tXq1#3?R8b=S?4jkg%LT9Vy^YcZE*YyLjW?lgHn{ zVT_w&emJ5akB57XdkOD0!yRFi^VeL1%{qpHTpF$X|9(Jo&>F+gCqN7J=JZ@Q=b?LD z;9n#n`o~E(4;ESx=7O^Vf5;QTtj;0IryG;ftRt4I*ZEQCb1SU!#AYN0-mSL$4o`V?XrKH$TNm^yTcu~9vX+uJ5RiZ+%)V<1t4ugc;vpz zAJ<~?BPt_Ht{@_!v#AFDj+ayDMc3!yThsY+vLhHbQd(Znz$xp-FAwZ%wrsz)iQth7 zLb#}g+`^x1-tfH9gz_ji$4el3?X}{?R>&8x*GXVu&{zZ#_w*(OUHQCpssy^#_W8cG zp&y(^+@yRl#n#E-NCGMffVI4x>iy`x>CA7ev^jX8xYa=H)8(9Y4H{=6xPfoXzkci7 z-xVwNA(98#%hbv0vO1bC%FT_q==oy)bjw=Tx|1lI9y zcCyLMs?ku4^eZpc520uSxtKXP+j+EVtFL3`tdr$l!k%?6BrIxVb?)l1wlpYSFvy*8 z<;y?}PDWMTd0=C&LiLk9)ZPm@OB|y&tB;FhJY{z_q~L5o0TGPB>Qx;Vdb)6=Q=A*h zWcLn1pa2f6j7=8uFLS3jdrO?L-xx2v0TX{KaInjlsNXEMea^oLR^->1mueTMIm0d5 zQQ2}VM)GN;k!_p8T^+NDts4_P*qyOGn23@#su9#8-}P1}RQv9Q-C3!VzV(vsfZ3+7 zkoWg?@^?Io$SxJn^}Nl^biIIiiTw{`0xK$dDjU>X zNd&!gDVbq;~PGa^cy2yzsUpHv%YA!1KB!|gBbG&+8}?b9F3)}zdgrUuAl zF7{ytNJ3UTx4n)SAYy)xB&UYrvl_u?30msvoT6QahjVK(X`F z);^t1%zVXbxeM8j$Zp7WxtB3jDf&Az;2B7@m#ZE?d9bp8lg=Ilk%s(|UgwGPbbB5S zlhh{n$pv?r%t4+#2TjK+B3O6|*G?C;zED~4ehk@`h7A@P+Du}wp)>1K&`gRg-6B>L z8^+!}L9{Rt*&A*d{U~q(M~knf5;srg`9yR^KPWNYKe5?UWjYDt*XdVtN8)%L-d%yq zZQiuIU4xaY>c#;JnLkz}0_tCK)nTy>>wOZIw9PNl+lcL2sJ6z@@^g0$+PfC5KB)ntD6`;%aSE?%b32%^|OYXO9;;3AbR z-Dha>TiQ@wIyZO$SvNM>GZeo(JqtrZ%^0gqwW=Y9W|J}Yi^@f~*OoeAnHf@$@c*JU>Aq+!oFcj)zs~^7rn>GE_T7n5DH;T?zUVjOfqa#%#s(wI!_=I#Yi;bt(f{tM()Y8dOw*D8A0EJ3V zw^F7Ub0_R(K~>3Sj>wJxr>jz)S>y~w&@dO(oYexBUsl#^TZ4@Kih-q+I9hx!&!kA@ zLI68IE$4ftyT2NmO8FY)tz5t-bW7*XGX{fyvHc5Fx1WzJLCsFZuq`_S<}hO-VnCB# zWPVS2Ts-Z<_i8gvlgsJ(a|0hi-kZ{61ejhfxP;)02i%=zb@|Z@|A~aK39?uoZe2mm z2W!vwo_UVM6x14H92<<31=Wi<$tx1g%i^ zDCjdm?5|H@Y7X9AORtO=1;M|&g&gr2;J7=y5dQ?Bz>h@__VUcwhU`F2^*47nTi0KvIxzlci2h#_bEmYg@Au#TGYUTlqsMMO661G-YyS644QOdp zf*UWEg#`thBdN?Axei2y-x7mbtd{FD&n3=War2x{mrSSf;bD+)!HDQKH{;Z5jQ#XN z6Vi_cUVs*J?3D*1Y;2WyXCmKyJ=Z;_E`Ml>yT=fFtP?2~$@FdZgp4~3@5hdlNy^|+2JH?p0T#u# z-U?gZX^J12)?8#AEpi z#2W*=gnHK0zJ8-OVK2CioL*n=sJ%2=zxHJ#bO7z`?FGy7JwlOxF6qB7_fCCJ9jf0aD^tA2R0ffLSJ%RzA(P*25^)&GA6>wL+;xdg_D7)r0r(jzO(LSA zemkM$U}g(dq?y0qrj@ku80d6#bYd_3p!`8Tb|`*MMdZE?X&=4>!^{kEE|dIEL7m7^ zVA&BrMw?bA@Z`c2|G)WoBU#+nB4vbpfC?xv6_JpD%kq9Qi`C`l=O>;nlAWK|Jun7x zgi4N^X>hC`?LM$+4x`5JZ?78*(R)3?$axBdwmjQBeA~E@J3)>kj2z0*e#HtL#=rkL z%}J-T9q!ly3k3)cZAw9co`0jGv-5?A(fX0qKy#|AhaZCszP)GPCC`ADW{4-Sa56>O zE7j@nZuSPA!sdTJbahFvVmqbhU&aszl9Bwk=}Ho5zhYJhPrk=f{BVTei$0cs8*tJ{ zhTVtYpx;izU&T{(;Q1&X!snD+R3~fGT&7(X?UP29%AA+t3}z7m4lHj$-;-$Y8lGT3 zyDAd>$tx-<()O7LqN*Q3&J9oKfhWy|y(Q9Du826QeI|-Yiq*M4im(9ab}o~^)$3+b ze4*WoyZ!ym!}jDm#tU$RZUK!sf&v0y5>Soqx8|#|Qc{r>SKUnoz$c4BX+)vfhHLtz ztygL=xwD}=hs+)b>|T-KwU+irWOKKtb~z_eVX6nL>Uo%++NE{{-ZENqUGkGEDs`(cWoV>XDzqqVB3$CetGoj`jCLt;itUX!@c(vlLJqzGrz zwRUnwZ$=v^{cn}dsZ*aR%-~I`%DqW%?W8~=(aADl2ub21mY*g~%mu$TgT?T>)^1u2 zXC;^x46-n!i@-D#W(YDgiiDSA-+B>h0yz#i9kL`X4Qqd=*xAF)aCTh07F6NT))}SS zP=fh^?;@QM9kq)@W~ACZ8Hy-*C%M@)Ih2Gt?R;5u#*R{x0he!}CuRwBV*sPT%OW&$ z7#gSZ&o=s}hsG|_@wlPUK)m&DLPC1zBT^w7xn}Og7}z%)CzQxN{U`(esQg0UbiT%d zyE$N{R}4XcS-n$1HC4|NQ1ycja3O|hS5(kx=mar*22|S#^Jl%$Sfz2l8~4aV0MAfTZ(!w3;XYfZO$z$IE2*>Dk~*G-V=$XwStW>dM?+*I z5^3kbq-1oISQMPnk~7`@DgOK)EdYl-UT4sOPF1a(E(D@6<>aDt8VVKJJR$^kz8@$1 zJv0yAt*TLDbFml|#<@7a^AB;FWI&%j#Pn9Ir?K&FcU=|QXv@9ud`X4-f<`i3cSX&k zud%<161lOj*47*g_Z6W^W4KQke!S8r$rMqA4pJx5VFetr<$0lKr8A*wRt>G#^aRw1 z#Hc>~WY^Iz7)VnxL_I%`KT}9a|1AS@T^6Ix2cXy})DCUm8%^#NEr&^`84<^dWAM=( z0b}>9#2V;|3i_(Fn!dGY{L^QB$Ndro9cf>dxwKjEahf`ccc;$%r3$l)tJ?3#RXe-3^^j8J+jP`Ol5rKXjWN(UEjk}rW_mh`uFF&|}T zSHH7(vUs~3-Z2PHho4vjWuTMXPGXQj(t8v*lO3LgdEwnHt68p5P9aGiG_jCG!%GXg8+FXZ>; zZr5oB@V6>C1fOfb_r?v!1?^S*9)j{Ar|2k1A?gZP9VOI97Cb(K$C^M~6`4u>dPvyk zrJ%;cmXsCLntrtE^s1>w%SyOO=k5RO z#{Y8wm`4D|s`#H#v9S(~VO4!mzUlvx_2l3*DWEFs7|zbl+>x-=HXR%sXeW>Hi-s3# zOm4Y}@M9t)XHbi6w_iVeu-3^`=#V%KPU7rcL9jA_!zGWnSEtrgUNXFCGArHERKOp+ zWEUQ_)bnxo*M`_D@XpWLk3`G?W*FY_vQ`2E2fkCc(Cl8n;EN0X(I)U%aLD*rIN(p|I4hxZNZLUrv*E;DHke^e_Vp%cr%qwU413mmRfxB#W2er+a5$ z2#JK0wr~$o6T!Fnk zWC1Y9-GH!++&>&ZffQiqMqaqBM@a@E64}&CVKy1V6~ie;iZS%3lFgbqrBP4*nT9iG zu;uykV8^>=;iT90*$yt-C7!;2U?5K{3g6u;7jN4n(=IyOsxO7n;G>#eAD}vIkTUY= zeALGSjfkDXI>8?M0pdKJ{qBQLLrkwgt^H(&k58ia*uk&c48W{YD)V`;hl~7K7f&IS z_7qu9Yu~R7$oTo%0sJR?mHj_uio3kr`~=QZaxOsN;!G5r3oFAj4Q|N6FQ?399yfneCi zLL*Y?Fq3@}-&evb5-#O`c`RzSKtHsbl z>NOWR?B)u@J~D7l%!;pNI?XsHeIy&uch9%qdx z3`7NCX6;wcARogInE#5%+{`rmLQcnWmQ;e)s0}BT#sY7tBjM=Kwxx9WzYHijXvJ_4 zFKC!y*AhoE-OS!#(c1>msGRg$9I4yrcRfvf-F39VJ|Fe|$0|T{GlkEKt5Kz!5xi%U zBkzh6gRR*qIgQoAzxPF@RGED*0isA;(CUS*Sn2Zn}s@W=p?Ri9) zyekwZkypQ|R)K-W6?E#%m1&;viz^;8arS;K*pG;0S z*K1nrs78x~fwChUZ0UyW^RtM9wi~mIMyiSCS(^H#9V%|)SF+A3KhEz~j9ZE%%k)7pTOhyiHq5v~IAuMF<4Gzj>WFy?Eb?X3g1HG0t2c?W+Md>aR-d>aGyYPa-chZYVs?W>qvve_$*5%Jsq2s5xlZuX=u2N zuEYu!5|a_6M%%rqC^=!tIXLo9*jWX8>hIsUxa5G7R?mgaa1>UA>gNe+#&1H}D)dau z2ywr3LO~%|XQE~tyORjeCbD|_Sq8<^?XU=zzC+f+fAhaSo-m#)ci_Mm3b2$Mp@!r` zzA!hDP#N>TUHxk*Ubgvk^w`p)HK#smOnX#+5Z*F?+J89F_Qmm5^d?vOVW%|vvag#r z#eN>wQilPv(ub8G$zran_>!#3=CRWC^g8>-BO-!8O2s7-cMg`n#{0bm3Iq!5NJZ9xVgs7R{JD^(I$QV(KI!Fzcc3U`js!Dg z{F$$qm3%D5S7W=06SGi>LD9?&8ryqY@w=e_i4d$XM)}b3YEtSNw6vFbn+b?X0vu99 zk1rSrim_Rl0g0Z>piA+pZB;sZ`x=IgdLq>hC#tdjA~LOux*|~$$~?H#Mf~Q5N`EYZ zd!THa;PA5O@`!++EIU6CrE_+x(@)XvOD)dU;AUQx+e5B%4s1M=J~`^=Cp?!a3a%kLpiA5FA^ z>ae?HI$z6pXR{Pmm)1; zg^gr*=8ID&Yq*7fM$}>79<{G))Dcj5L#5dMz?^$5L zBZ`q}TQ+$1BjZTh3U)?rja5_)?9M=PYe%%*+mTQ443JwLCj{rS=5QqeCAEF!!1RLQ zd~}nL9ThZIhp|UQh_kp8Sa&xrTdcwqCsT|~iVLgVVQJ+2YkMVCGE)E=!o#e{RYqnX zQEwv%YZCoZyaHAj$&tZ<2{~#Q3>MOiOz`16Qny(l!&t+`c%QH#4i&H*){kk|6hghNA{AD5nX2nMT};K9y{1rq{2&;Twm2m z40q`>!bU}Yw|Z<5o)zQl1fi^|e@}1!apXc1ZqK}{l|Xh&g9^>biOZS8Szo3RqXpX& z7nevMj}+fW#P5ksnLzlcU_!xFd%S|dU$)>^oUduv;+mrKC;L5^T{`y;43M(ZLQYN=q2Xsi{~QN%GdBNBwaL*9Z6e{8|DEsJ zemXA2CMYHZFU&qW0h{V{Sg&lU6;Zp6`*(s3j58r;@M}v$w?a7~z8f})R#kYkr0~2p zZWJ!2Eyj#|7Bl=Gg{UPp2&s?QX>I7G7=IX|p?J}u>+A>#(E4$p0ERBtcT zm{4`^z9z-$iO1`rQ;tWAW>FBIlg#|V^PM1EmLoZ($S)s{z2jkeVL%~7>WkinFP>_| zf?)1O`|H7t{qMQJIkQAUR#I3&i02A%AUvid(-fFWC+^)Qj^Ll*VH5(5~$^%+O27c<}65zb338xlRy+5xvG9ZY?3 zG;2uw#u?1WvlHJ{Z^Neq%~{$1O9_;X@rC%0xrjd8_waZ9KZXDP5&=@%1QOdCis`;S zQQ5zu*dEAjYS{gb!bLv>1bn^OJs)gsg}G6`cmlO-8>CmQtvnaDT&N`n(boQm*PT4f ze|S0tl7xP@WB(-ew%q~waKA~NGFL#nf}6q6Q*~-R(wlxYqT|)g6BfNkwQ;P&D!)1=(#u^ z6N|+4+t2clnJ2h}f`tv(A?0BaY%qd9t~isVr@JyI8C(QEx)i<$ih@=F)B51IEVHy!ZF=+BlY z15jB($xKo^ifnKqPrK-yf?wJY!+{|g^;XL;7#6WeJ9o=A^Qd=KAP0MU$8Y_5pNO0n zff-nGfew?;!t$2{wtiy~mGtyYfcZ?#%UA|y9;P*5-boVU!b8YzS#5DSzHh}flH9^9 z4DC9Fc$_K36T`_{Wp9wf@NhE4Jg_lPF?r({;G;=hSq_w- zGPbFowjV+bUqBvJD{AZ-EGxCySpsI?i0(*m@6v#D^t?){T(9xjB4@v2j+ zA61)Iq|~rIZ@@(n>_%LYpPHKLY#wOl02&1GbAQ{#4hHOsjd1FGL_sof^?=La?%MkB z_$WUap{@x{}G^R*n_ zWQ?EBzy0K(*UOHzknQ!&w*%cX6M_twKowpJ1)7qn6U5go`h5s;Mon=k(Z`9J`&;UG zjJe#xxZ^Dp;Wow(&tlb4131LlYU$iNrvAFRl065> zV!)dCyG28Cipyc^@xI1##NJM-<{4<|Jvz{bn5_Wh3l1Ie#Ri+~_IKa6gW%)v8G>$} zgxVO34G@9NQmtfz`(_Xh1CTz^8voJae0t;dIhp?)_$a9yH?pMKUX=Z!nTRmQyv55^p2t;kIGZ%;1gf%r+Sy7reM*T!FM=MUD3XUhoAi21<`&b=@I z7|#IYy_8?kkbghqS$Ax-G^6W`2-3+EbR|DCdM2z?_kwlQME*GW%^#e=x4bivY-43c z$15+~nHofMn1|oMnaq^JZcs@KO6mRYe_|3w8HHY<$ z6p=c=_%qE=qC>@VGss(fcpP8?NO^pj8lO9RfJT*^CfKbvGt7w=2igZ$s2te_XC@+$ z?}qP@tJTw&+Oru%)KyNX?ek{X(-PMs?^aq^1FoLKC2T=(Ki7lHXSvyVtZ|v_@U_>c z?IsUv;X1Ye+j*-t+vimmJ&|8e5A!uH`Wp+9jTUkajs#pNWY3Ph+p_C1dxCs`Ck~n} zja)5%KhzF)t`u_3)f=MO`6%)%lWXIRQES3@14`;_9(4MACtiwuI@#dHibTYZ-lj3z za{-$rHg2rUU_T{-bTA43{x*PFtXPRo8AIf2-3F8M1JXy5{f0kb7IRd+u4_jxb3>;9 z<&0nv`c*tqWT1bR@oo)vlB5$E{~bD=Yt(%s?k$S(>23&jv6AZTZOiMT3VVC5N*J~E zeZ|%BYyyT%EJomdPkB>551J^A2UlyE#kax7sr7mdNP*Ku9ORC5|r-{?U1#zqk_kH`z9+~S$EN}Id&<-iom2^3D< z;4~0`x)#*jPCvmSSujK>Y)#-lW|fw!SVWJz)$$j z2B~L3|n)oX3`c<;_Cid|6C?Do4h3BM4_QU)^bi+3NF?qZuSWJ0`HD5ZC=Gj)x5qu^VznBSvo;SpcNc52YhORtz02jvDtWTjmy0ivDen9*4T!?S}z)k zc2ci;R~4!B1@4`Tw@#y%JWgTa@dB^)sax8HA!#u8sNnj4CkROq6mr)5Eo> zDPYUo>N?IKsVF>SwFH7(Ziwfs+$^5|8xd{xi!EyNNC#DRbq$9Vzpjg)=pZ0?6=rj6 z^8exMt)r@H*S=9oLb|&bAl=eki|+0gMY26ROLAtxUK|;E_yU*l#_kO>jpVs&V>GRl)+_yVyIS>l6WO+)e(jZbO8yuUp+vKE_6hMrN4+?pR! zK+e8K;|dox7f`PwIGX$yPw}5t^LVn{+}?X2;f32Df9W)vTH7WKU4P~?+PYi+q}Gf= z;(4WTbux?7mgR#dWKQ%T&GRSm<8fQasl*`x34G}yMzkD3XxZ;W@(&G=FXwyk94D-J zuF;3#%_q%-*PqpTWl>T53&XK9VWWCK6-T?SxZ=WIABMLJ2rBfWtJr(B=udiHnQay5achSO}N!mPjbe6XQOI4*Drb1>v767Tjc{iY9bqi>jQ9M7*W(>DHrjo_)FY1kWStln(#a$aD8A)#zdhIWlGm;huiYbl3b`UNiaF`CCPd-{%%j3+m8#C?<*}UGD6vIP$gS0(1cDCgTe|!GZb9 zIrH28W)nH36ec?|w2dzeY1=*O)1xi3(XSd+=9UXOg8K%enbz@*N)dIkPNSndRy*h) zBG0t{$2j`Npe#ke7je-4&(}JxB|4nEb5$$wdcQ#}B{vdu>462bur87^(m$+?4vwq}_jrVsnOw>R)5MprS~{wWHb{0JnrT9{Je9 zg@USNr~`!8K$29g8+(y3{b--EDeLpLu_+^o04Sg`gM+xt%t*lEjpVxGPSY1fT*4>h zv=>vxYY2uN^i0wR>c@&(f2n9`XN4tdq8%M!SPM3!i6sisHMrS(UGe0~@HNa>-eWU7f{g;zD+b0J3AIUK?DmovJdR+n7}Tzx-X8q z6O;z<9XTG?2Qzg4!9uPn211|?#(PD=CA^9+v{6+JwGoF6f=~J?Q3e-J+FyMHZ22eT zryxkqXzV#2uZhIEy8ev?fPOv#eA@cSNmOq*?&h0X4Op%_D`P@JLRQ+%vSY7*I=$YQ z*zcn!*&Dal0*oC{OXGxJmu%V7#_~AIk7xK7PWnY!Nh&eWre;?w;hysRTY5SnI0Ni( z1*ra}n)Jv;I)O0vNL&Lq$SchxF_LemfG|;`Os`ni_vL<1$%(qigKbv^`wY+wfO zMMXuO*e(J4lAj}Gp`koN`@CVj~9RZ)(^# zXz90U8m#!u3FA}DUJg*%Y~%&&4*Sf1GjHm)5k}(#g@8dng*we{yTTun2ch7bOb5-2 zjD!RenR(@Qb%c6tMC0*^C#;p8ItgBO{YvMRQJ0ZY`co)lB^ zoBR7%)+lmrivp@$nIc}qxp8ib_4%|Ny~TB%aFGZ}cCoukmMGPTHmp&elLGwdff|77 za+H}akiV`>b<`r-oh0s0cT!EVv+m?@MCz%86T<7O%&uOBKsFC4AM&d4+HiLqgrs>?P3B5(7>bcD}Fm(FGe)Ns-Gu( z%9!9VN^jRPb8`u{KZ$|g5h!t`>k8mydd>~fvvj`cX&UtGlTZ))zm%q<(S8imWGoP8H&9*@PhS2q z6b4x?Zs`F16&tD=hJSW$PgaDnCdMVW(O0fTN@n3d;|cw;F|Ml?yv=OmC4rZeO}a+o z;j0Y2C)riBg*p+*(7u0uk#&BVW#dhiA%o!(lNY%`bBmO`gOqF$%;KYnij4JunozNy zw9|$`I(@tidA4$x!N)8uW{$Afk9me+EQptNDKNde3n#F;l10$M57A^w^7I7JV+5%Bl-!C*O2o!C}Ut%UCiQ1mZ}mIl_I>$P&X3c(6G%hiq_Gp=i9YNpDp4nWBj zE)HR`@3xQX_`TgH7k;kKESQOB@COjlHh-V(yx3?ax}3VF^Y-O2#L^99<}h)pbx_Ii02J66qUilroiP1)v0SiGU|E(PKBQBQ7XbWo#1VUkp z13i;~v-|+VJySw{Cb!P=rB5Kpm7^48XK~6Vtq=%RreDFBx zX{6W({)j%$+}}S}w2{2Dea3bq+wPJ0(&HI|#YsVCJPup%NED)gMuywLrTpqY5Spb2 zc)P63#;qk@bt*1isNF)_krY-kbSUX#_xUWihvF&hM>i1M8u?eiLkXtn_aQ?qLM7mU z=hsqH;c4Ou6#oYLo%=aOxm8QAhFQ^VEzM`Rx}C_8B+nPXT!)=xzCqnoOBX1>5jDqn zMfO0qST66}6>I#~X=yEDS%qa4cSi}M4ciwL6BDtPrUqA?PMrV|H3&D&oWI?yRsOCt zyyd3=t&xU!^?;_wcQ}c04KI_f-ye|IlY*x@e1rz!zr(a5*sX2{pZ++Y|_+tIE!`vXzEn~WVTL$K{}^5BZFue zkT&ynl84dmWzk9BMDjo{Pc{zc5BZH5cM^of+YAeY1PI26Xw~9AStyV?(1hEu#dOliErWeWSt}XI(2Bm@N8v#T|)87NcK&g4S>9 z2Dkh5;@xcFeh)#r%FnnBw8y*SF5{<0gv%~~7+B1gedhhB8E>@QnNEIcO2eaicl+xj zMw;5WUDuvYZ&BB8G$<9}m&m5g*hRRmxn8H~q-YB$I<5o%-BV(Sk}c^HH2B`A{r*Bp z)0X>aDKxTU($ny-GuJv4MsXLv=DcCD+CAa<#mnv5IsRG{pZeC_9!Dk_?%uxU%gQzW zm$2l_Qc8H+@E*GTin3zyt$;lpPmj(<;ev+ZC6z1gtBOl4cmir9o}RwG z^Ym2UrzT^bCWLc6T^~M4nm}Zhg z!i)}KV3(7m(Px_ZRvHjoj}kd6t3N;BwHx>T!s;2VgGg5qiB>d~4gj zUG)_Lv+$VqA)$4X`aYop8^^n4R<>W}qpcGsxA2Fg2$SG~`z}OgHSQwWM3Erq7AVx% z*w`lK0B+TGWn6$)5%v3uw#_S1nDZaI*juU+xp0oNH!`~AGn@tXNBFiS2YrFy%+6>!yS9)#50I2zwFNRa z+*>r+h6UyO8IiVLrX{J)-GBv(1=X5!j(jd<_iaL2d&DeV`y9kc7pf&R2j z-SYo_t)UMdtD0SJ6KqqnhHN5) zaiu?6!^&?-J{eHWjR~vr3PiweK0BJ^4JtL-PiTX&OyQ+vkXT1D)Gd7_-SX7~1}gXy z_nQ;AcaKdxEair#3`g0NjA>zfP@&#vCh(pZ)Q?q6l;^hdK0>lE#P*SqMtLtUYY&GUQe&Bn0Dj=w}9k?nMUv7afN_f5hhqgL@J48dsfa3r5dRs&N)>!8A^K*|2FE1}6A|)Zu8-|F{vo{4G>SSR- zK@NvM(crjSsDGYCUx9lZ153xmgc9BMcaangbWsruZI+Iy{U6#^_kdq3CNVJxD5pEn z04Z#WL;!r7|0(kF+0ypU5R$3oShZL)=%eQNi3Y&gm%?HUrBSNozj|r8m1rDOGmgiV zpbc4t@jm|*DXuM(&o#$se(YAj<4V}YrS3$4msdwKvTDv& zM&B(ZSh6Rct}^d)^+Hhstt39axyIjEW19y0ufA07#(0u$nz^R~XG8I?kL|C}((j~e z23@{62j2qe0bK#8g76p`+>eoAVUxC*VR}vhj<~r|c-tmh+1uR#VhL|)8!2+{BUJv4 z1+bZaUtx;P3p`fe_quR5aaSID_Z!ocO#tbwe&WX}Kp5}O!a|ZCCOHz*{$?&Ao`F`v z{SULGjSdVLt;T#9$Ij>bL;6QbP1<$36kSxvsPR<#DClCk#x{66lJ&PpzBgw03Ha`C zLP^~`7-Ir@;|WfOv&fgb<5B>(S!P+I$;dQo>htuo1yx6{HdIacf1k>K-2?tY2vGUe zgPeu|N-?Cg!0&>7HJX4^#&FyN7!4C2w9 zK$>ZBQo=GjjNQ3Os!u@Y^B+IKKPz@eFS=6Q|NRaBCok0o9S-@lkgiZ<^cahi|`Hz+Ovuv6*5R>(r@~a(*W|E;RVG0-F^Iggt!4RWyAtuXtP8z9 zUH(quOw9gH{zH!*#)k_EC@JX%WDnPNUf$l$Y@I)TkUg*5o5c8xrg0*=F4@BcqY%H3 z>vTSvM+YX3ZonMs+|C7!py}XHmBk6T@y=p+ZNVme$mcVf#VQgsSRiFx4-ei*nXP_O zUvUEi63J*1eUsTLb6I^~T2YYz7DgcQu)5-A0@qqz|FbnBmK>ad~QOH2K za8>=UaJ&s7x30mC}6s=(!zYQgO#S^XFq1phJ* zGq!ACJnmy*E@$BUz2R<51e{S}H=kTNgPafFIN3MOzHJ+kxdmcFCIb90;9>@(LsBUd zgvid9CE)Q|MeKI0+wBz`y{d>gC?@f310L2Obn5K6ygU#ukD`NvgYeM;lRZ)2IsTyF zf+Q;v2FXPu=aBC7P+#hG_~w^5`|7c){psBnx0(O6odV>n*Q#r5<6Sxn7v11{e_4tS zABMRMz|iL+T|dX%_v>33A(#1I^_+h#Y5!KL1c$)pwaUe~fQ@=bu`7O$)qbJ(^^RT~Jm3zW4*Q9t}K?~{&YX7Wr zTzpV;&;P%VeG!oXITXKGliRsTOhBk*#+yI*tUC;l=|k*xVRx=!LzT4rga7&qLHHx4 zlE3(g>z#gZcZ-FAOEC0(R;Rfr3T*<82R#|^2NxcPVmqYAVR_O^C)QLz)?JW|Nn*zy z7{Zeogop3YI$T(KH$h{becTVM5{>%!#q5jYM13_gDR`Zo}meGbaN++YW;=N(r) z6jDK?UDiRs)?MLs?+~+f+>I(Eo-dQg1fL0$1X`okUUnQ8fXmI0;o~^7TC6*Ew`XYs zWIO@hHhq^skUVmlh8)P!I*aou2_^m(6qzUERYYLs+LLx`9;SQ)i*IbjCF#YGJLS^C zbwnSB`@jxnj)W%WXin;~3=q$Y7Pv`KFc__*2qO$T9A<9U!>CmrM@Eum7_*89)1_R7 zwHZz4Vx}GD{4%=+G@i~aroG*T&i;W5yWb|TH~JcYS3$4W?Je-!3nG?BS8wO8o+^w@TZiw%K8?WS6H9ybJ>GkizA%58A zR_^=P^KBPE*70opRs$7^PI>lb=YF(|5SZrzW2mz+Vfq6?p<$=ujO7pTcFabA7rkLT z!IPvh`dCsr{jHTtILP@onw?&WpL)ap*ZWe$0yWef`3+)si2(Qz@4vm3`fw6^#Md|>UB(*Y4%B=4_o&0RVxg-E%gv2+C{ee z!(l2E^Vy2^jE&_jEDRGGZsiPr)3N_SK29jD6&PHN_-9l@Ew_gf&wDTx{fwzVpgr+# zz(oo@D6-$D9pS{&ziItnc+ZnGy3)db!Dnwz?*BggYqL^oido(9G>YFyaVe4Nmt6?4 z|3}cXmIMDbF!cj2eWn9RZMuKaZluv2z%qC(uH=3AyT0Su`$_3c=;a*MdZ|IVUN!kk zIK(YEzGuNuc-Z4u#x4IO@h!uJ62mnx6tDwn2*^HbDJtzg-e;zzHL4Dq6djlHPhh6o zhI8nK#k#N4gYUFgu$ST7Hg_(lq+52{ z30YSq)5_d;Y^UInyb|c5Ps{~nHNXFn*O5@G0&Xk+VevJYMcD1rzqRej+D=2M|7?a0 zm1s)EjppcU+LORpYyzmH+yK(X9?+!a0_Vxvz3N!IH&D>9rgsN)D+@_5xed=kC9(o< z$(n}9kCe0JqFMPdte}Ua0ZVfEbw}a{aO$C z<>)q3Z7NEei9+ce{5dcCc8-VzyHnmDB20^dlJa~;RdL_!gJh0$!8Cy0GZ?hsE#*mJ z6auMrlr%I_?Y47e#7Rv0pSj_F5l^4Ef0tqG?#^fVo87OPecVmjug3{6;_22?v&I2Q zaO4Qnmf7CHz`zx7PxR3m52(jTcC5ptOO9XRTJ^#d3r2$Mc0utcWNj$k0WR+*dx>Gu zTM%x6EueP%^ye2gEGkJvdHV}Ne*4SdO&+kzasxU?!G}G{2z++Q@m1jdC^cp3+!HE@ zwQ9N?4H(;WKG0=Sf@$%K7CuAP&Ybk#_C@Tb4|(@L@2;Fp0KB3>u>((V~lVqUDb z2)Lp@RDyyAn%Y7|2=CwLd;{96^%=d_Ju}lCtPIKx1n6)>WBbArsRZy(irR^cTl1T% z1};DO2!P1Qet-yONmnXXlsPN%RE&tTqgP-(HU=Z;9V}-S{t^R4ZY#uZ&u=rN;#xzf9khDn8x%n~(@R{o-kFmf^A^;S( z;R1u*MD9YPBMp!%4R><6OJY}`T+i(~$$`wTX?LPQ%k=?@!7)x0=y$|8aKB4KS`fg79u>*)A$~T znG#V}vMo=s;JRB=wzjb`ZxS@^ynH?Yl+tbRic;qC!tn_E_LCQHVMq$AFO@}HeVnId zt78^SJjU(Vj^+;ua; zdl5N&*pW{Ie}1hdxf(Bu+t;;|xVMnlbMNkZ?1kN4hZb^2y(iPs=o(ASR8?w1!RojF zS{{*pyq{R3zgsJBZ3+ZPZF;Jm!f`h?b_jJhU^J>V)7Z1UTwb`1McXhvVDQ-wJ0;ar zYsO`jY|+r%_I-9O|0>_&EJkw*F}@VU9}8 z=4mgmp<=Jc2jljVpW)w7?MDZt5^FO z8^{|k)89}V_}8(Q? zgO|js2>?7hB@Ql7gzPs?Q!TR~rDNKjE@U$sqI!6Wi;K-|_U4>I(Z$R~K8{xbNq|4mH+Xcyiq9Dkj(Zp2dLI^N{cvU*3RMcJpHY1|P1}tg;vw(p9D%slp zK7zt~yG!`%yarjRoaMSRxJn15{k`4w<>pi>@u3Jvzoy@k(E?Sez%b5ySw}oYm5#j!c z>-7xGK)8IS&4_DWnSImQvP_o_iR4m^RlH62EpZsEJDMuj2WLRfOnMV`mMM0zrZS7& z#(81KL$WYV?$5UT0^|cR(Za15%F$s+0i4fud8}RT3J`U3Wdw|ls6tN=H~#a?KZqaI zU@Ix4{r6+MncJp|U6X(_Kw9W*0a%Q<;}3b7S*P48tMWX%iLa9}Zm7V)(ym8bO075; zgoNP$K-Sq;-kF3Bd59S)T`+(=ID={V3!t8UI%HKS)*E#~Ek}HX<18&v8y*t6ya$kv zLvQt2={i0q*`Gp52!|*%-z>*65N-mj`d(&bnOoI%ES9S_jNSfIBGEt%UnKlCdc3FT z5d8R9gMC$y@o%xxsjv~CxnD~|Lv??NGD?^ug!iwgV6iK+1rmlHT2_%0I1&@yli4+H z54eNJ5(zG&utPUcorj!XfNly5dX3UMvFV=_ns2UuH5M*zsNcHvl0XEJ@@(1$a+Xsf z|9@NtZ!5S1a5A?>3%%g^J}$0y2$(IEj|dDbd5(C-ojRgk0ja2GKmeBh4V=|**hx-b zgzZ9=Iax8;Exf_ZxpUQ)fz-*uPSY^Z5#}RrvJLmO5iZN~m_8MUi`2;0DorMRBF1k*cUJYvfIUnIH_%}9DGMSAg3s$ zBE$RMI!abdZYOzFFS9WBv}bd%!cG@&%#;~J2qgqLq`s`Ht~zyBI}^8q$_DR+DkH;E zA8^`z6J2z-n7iroSA}yinaqNT0hNt35V+;bQ@7A>cu zc9E8Jcpno73!>VlU_>0il9nA6v-Uz^tMV@$q3G!|r{Ec-c0tK2+@auU1z+{r>;q-3 zaIBU4+?a{q13CDrs)&FqQM@KaLb4DjqbEgTm+X?3sl|RAtsxg=MYOzxn#^&L2NnE{ zO^FE#%!67MJ7%ZWpiyX36XmWpC$U(dxg^1-W4Kn~F#NaB*f2BeJ0VW`362sW}=9-g4P``t$P@MI4v=WDKJU?20$ zj#UnXDGtDOJr&mQV8R*G|E48<*Sq|JtgI%yZ1k z+XcOA!?rm34+4y*e`{(u@+_sPVrD-W{>{nT;@EnfJ<5n2@Z$CSv9?NPijxxp6{yi?S}`)T1zd-fdI4i>cgLf`QQU{ z6O0(@)4V|0I(uuyvE;1;uf5}-n)29w)b-@;X7WGxdY;$mi(7dN``Kn>Y;^f~A|$ zNFYCP_MPG~!m~n(ch708Y2Uwy3XiOoHq>Eea&AOGuNZb5b$sQ=buV`O!exBJ1ZEo# zuLZLCo{YNRCHcnqcjk9gJNqhOl)2Pw2lqEd`$NN-bofE8;deR^zd+(-c$z-E_!X7w zCh(*3*(`DI(+>|{H}yXBOK!=rxB(ZIzaG(+)XywO2Yyu<6f|IV^vTGe?b%=J3}8En z#a$;&_rh-eXK%byr8Ig_-8C>bAO|7_(6F(cF$-V%qepk_1x4%CvDnw*TAh!~i;`4&_MZE0hn z)#AqL^K>qinGprYlp$bdVR4Wy4HoT*asp!MJ_5ye@jEd;LJ9FQmI)uiwz#>Fm!XmnCEx22*ylr4WsN3trvIFZ2z{qf)vM5PR$;MF?1ey7& zA+JLOcqAeJ`JVI+wd@J_zwa$Kb2V6nq`zwr@#|6OiEd!kdmlzx97kpkM2(Q)Z(M8- zca{h9l9G{Ip_~KI|KdIo$k8kn-z0`*KS}dB2kH&XeHnqbGfBNy1cQI%AfjfR35cqw zVw^5J&*^`N?nxraa@#;?l|Nc(9{4~LIa}bq_`;U8960=a2a)abnU)L&m}a)*hQV{wiRZq4v&q^2VbtZohtd#u6rii z=;`Sd>5+N8s=U!{Xw``>GnJ-N%c0M(pK+M z;$nQ#RJK1E$8&GUV0p`av=ajzs=43Wqx6S{Sh;>|PsvKZiE!`&1S!G}rZ#Ej&u>gm z=Pl=R^@?)-)!`g!hL%}tD`3W4drHLE7<@rlu8bC~Wni`YP|i>eVg_|`9K?r&^t(?^ zW$f#>`v|nXJbZZ~foiQ^@jyH(Wb;Lu3k@Bg0v0Af`z=VgY^B3`|KZWaslN>^EWNm} zV$6O$*qbw{dUBWjFCGT;6migXjQ0$HMM8io%k&!A-gYLP#L!U<{`=9IiI{Qx>A|L+ zHljh21uhG%V1Ym1XYiXe|2M(iUkDef-o^$1)L^2dY?g_DxO>Vlj$P{1003Au1sr`W z4-*`Z)q?=`k7|nK`uk!`o*!t6_c+VY^#(FooLZayfsFix=%M&KhFc8xz3`st8Y|Jr zlnGUPqLUM|_;MTL(xLr_8Kp2#*`zXj^E|3UE3=e5G9N6Y+Z}luQO1~C`O;~hBcuFe zR!-N_dBUaljxZy`*%I7i8-hAXLbqe~(S*084!#t_8IJ1wubthadL=LI zua81!xgVEGhN_{*JkQIBEp|gjoEP@G`6@XXVC~VRDlXlSh*0>zYMW%aG2DeR=)dQA zjOusE>nC6vV@dU=b}~X&J03d0py_nH$?Ox+=^veeYeu#p3+$x3KgS)qA%Ro`n>6;* zr?&Mqu0KBTK+&eY+o+o_To0z}U1(iC5&qnx94JwE*jH0{7W}#LY%KJ(o`vecB;0Y% zq`rM&dfqN~aZ(r;8ItqYy0r=lsM~`#-23O&_{oG)Z!3K9zIzk?v#MCF))n7!x!xTn z?U>N9vu;?1M{|*sE0F(Tp&UkN>DjdYyinv;iJRHLHL_K(Q2Cm>pJjV=SP`(d`N-JXrY zaUo%G9i|-A@?I`NMM`!)1h}Z6?kvoJxs?YZ?Vw(e3JQYlam1^bng*;2#&~EtJ6MrF z^j6RfS89VzDJ451MvUf~7a<;+#+9MJGUZcGw%~^w+JW$eaPvh}nY%%5XFGNcqVG~0 z=ko9f0^hF^s^`7PL_TK`M?I;PY6)U4=CEzGfevFfgg;<*Oelv|TSgt+ zhD0BWDJZ}yWbyx4&E_Wzz$#XNGL?ovX$<3UAS@r951emsV@SQGx3GOLX7ixka(=L= z<;e0r$i4V(CmnfUY_zj5drVwI1YL_6tbj+F9O@m{o)^DZ0pxuEwxCLjbtEG2P%!_; z-t&1(bSC@krFK|Zm%#Ob6@BoyLQl@S%b0}hFyiL!SPbIt?j?1dpJO-B4IB5RQ(h0{ zhz39S4Q7Qi(p#DWc8`jVD0XA1v+eS5=lTt`S1Xe&G;gH-ZWId93&_!^o|Mf2hML?D z%&urowxN=DJ8{I7jzfuSfDg~OAKRDYg9&nyn&!8LN zEGGu49!=XNli&v2>4oHt1?B}>U+pjaobPNbSy#AaT%S&{2>!h1ULM{MOZua+b2K(2 zLNvqxXDu6M<9HL0P`a5>S^h8`Kd~!pY?ycs&HC&>7n7J47nn9-E@CHx&KuQ&mST8DQ;m*~jJHa<_ldC`*IJsSe#*&I|LrPu6n!mrRRMEP zNjf1EB4&)PS$u<1h9p9U`{&efV4!PU-Q%GqDRK;*P;0ykbonyQ>~Z{f+5M{~V$W9&Z>+ zlg+CJN{Q@5!@#Ez?u-a|$jg{CyZ41A7-Z#mF%gLQFIr<*1gd}X?_is{Yy9gl>N#?Ce>oYJx+>AvLY@_=;MyZh;Z2AW;eQO~TRHUj8;*KVoc|gA z)Rb~ei6@!lfv)XOIg)0ehrF7m5GhuEPnU&jLLTN5CSP#zmt!Efl7&bRCy1DwzEXgf zl&_8?u8x+#(D!3?PdNwybg6rD{aWz?=IDw#>cg>Ozdc5c_aNJk@z~ig#GgdK$4CZ6 z`-iiTgef?gP!rrg7tA^Dj*RbTCYrQIZJhN`4ztkD)1qHCjVoHB6G#y~kmmOZedNxF!4%BY?grIK%v{~jh%$IUh( zUecV12vq2h(XuA$bTN!kA)QNcIjCOH-wZE0-fRTB24gMaKGM};xCZAJr3KpDT!hH_ zq%BD+^rAllN1v5HC0w&;^rX%dweh5YHFw2VJ_mAVdV0+J4?VNU>9O?3ZR>`&MtXZv z;yHcAxl%DYYaRRX=mTSx_jpz;M7Slr>q@>%3J<%-JkqkcLhj6&@V(9KI~0ah)^Rt( zp9+gUtB@|ZRA%N4-9#Mc_97ASIp9g;OerR&smG?K!G=r!WwnaltLG+wt0}F%bLo^Z z+W~E?-C*CDZ=!QwU{vnz(b}I*ERx(<&PTDL$YW+x%uMt137}YMzvFf3wLr0lsPN{L z<;x&)hAND!VyZ}1V7Cri=O%K;i4Ea0SzsNk2u#m(BeM0r0;>JqS6FPi1O^fJYFnvV z@6%LT%n6!NXZ4-uZE)i$EBhqX{DjNTcEGdZaksQFTa_Zgn)t|9wHS<*j=XClgcI zH^K5uM+XuZ7#JhqqMl=l3lH{sW>8gCwcqGLz~{?^xhF3(97&D}+oc(7wzo>=Di0qS zk&EG;bRrmZ2BlY@irbn3tSNG;bh(t%toX(k@S{_3@i63P&S-JZr*1_}zOQc_Kv z!_iaO*I@I$=SaM(Y0F&VHF{a$rz3h6<&UYf=O#2Zi7r4 z9XHwi6_C^InSFbCdD%v307r<`A3dosG7_;&N5EOlqkn|g6MQ-o16YxC4XQ2B<77Y|He)#8{h1(q%b6A+T?*}z zXDc+vh!*z;q89%gyGzT;=6-wYL*HAhFE6vyjyI#Bqm#j*HjmZjVr;8mD5CTS{bAeA zSO+Nj4zbSs?Q#Ay9=J%AH^k>XnNbZNY-iSb;_=yAQlgEpoT6fX^|)Yo6?N`>k^@EX z3m)tu^#L;#$Yv8{>*jW+o?Zb|&_L2e-MyGTd7UcN4*!B%t(}Q4O`=0sD2khjpyTpT zW@PlT1j69exeOW|^2?Ii@B%GxzxV1;qM;BRr?0VV$kIzIt2G>is4 z6L!W#r#`Nf>(-;lL9Z?Xv|O~6$idlmUoCeD36bc^?V@r4wr zy#^Sl6<14#Tq&28?_LUq5T2(_A|Kxp^bEbPu`~C3`eqV#v)m7XILQ>loopN0qxOo^ zE(B`~xUqDu=)M#oUqOJn4FL>b-@Hkdm6*I%t9*OH*k`4ZIGyUDvlwPBMLPuKEDwfAyi(96i;rB; z^BE#hl4*y>7os%!{=w6aJM5i4Tc;>{Y*0q8DO!5L)ATNYWH@JBf(^pvh;@g?-B6ia z`W5JF)mFA0YW*LA^e5Vy4$3YIce#TYl^oU1ceFMB4|CWH*=tL5y8-1N$hP-UC4NwB z4+w6Nrp?nwEX`}lcLmWSZ3Lh9Sw=c^gZ2oh0ym+`5bzEy=02oV1*jLiv3$s35OY-# zsCCOR2x?&}@M>s~WeARp*@v}QWz!D7TfTLE*!>sAZltP!r4Hy&KHdSM3^A~`6aHNXN#prXDVa85!5-|Pvf^Ve=Y(aXFh3a zXyfNO^kqpjsX74q9f7>1@B=xfflHDM#~nf4GT#>6mT#kj+)>p#Fi$StK3lOB9ujZ0}Z4T<%aQ#^>cuhjhTYJTeR=VpI?S*E$)2CfDO5MrIORQm7pf~*Kv*To zOp>2GAa{K3c~B(Gjdy{1=%!C3U2#?R4-*C>I!%y5V>wS8F zF%O8C=6rdnb{>-iHE#7tubn_vqpW9T`uuJ^{gl;p5ToU0L8gaz(VtW!kV4QJ&gU;? z?V8ORtA5 zZ+RBj$cfqvx82{6^09A<513tsQ0#{`Db<-{>^`%N5O?KC8o#kYwTUwJ^^jkk|`xs9*LSxVPuXKPD9^=QHWlT9LbF2V|5YWrQjCg=->T zea43&lmpAli!_sTR|=TXd63)bQ@^p?h%{vn`8BW!(P>s-w4+t;zXw*xE1kZ9&vBLBUU}KZ1=mu|jC!e-mCie?*pRW>|vWQ#LqgCu~^e1+inP37*IVl=%pS!FNJ zedGdG7jMOpU*Bay>D50UheUi|VLdyi)nv}q_IyQLxbl$_%a^9(!a{i}2rTH^v+tZV7DPLM(&)Kt9v|K&U(pz=4oShFey1q0#VcG{#WhY=VPmp=Y370ga@I=5`6IBV1F9+7gpDG zy1>5e_rPMpNSZ!dmRM)`4n?A{8+43bImK#+Wwd;uuGMz$M`kSQF{5nFLljne1uiwH zM;BsVbw1&N1;gy0;QIABmk6ivVm037n3mkYm*Gb=R98;Cg4P=1A1myRsl`G0BGubQ z&qL-~m2QFxH0Cn+JTb`*7^l8`gn(j(c$Snmpmd&63kQSZSQ382L~%Xa);o+}7gD24 zCurafCL>}zu5K48soWq)Vpt>h!!tH%^M|0kRf`HnSjg5;JqVJ zc>c4qU*DOI({hb7jm#`9*39mtYpni2FqZJzQBdQyHn|FCdPK&giEgw*5%D;|Tz`hy zsDFthp6vpA-7TQbH++F}A?1twQ{C1xJ}g?HoK;zo;PrI1;LGZ`&+GMiO`~PcM$9hs z4BxL>9pmPNxuRQvY9R}0F?vUI>hnVUUjCad3CN3hdm}tyS+W?~(I+ctX2i_v?%Xwn z&lcT+VKL-P|64aReTChF5|{s9*~;vv(7Y?p#^diRw8otKjSCP7A+Siyy98+W&V#b-wL0WSdR}x^3GfvVxS*WLS>-kf*PD?FiL7vOL>ZCWBA; zS`~JT3YLE%Xy=A%337FJEs8V+AkbCH1Rh*OFD)Y1lvAh${mXsz!uUu1i#DZ{fKb%d zueA*gKSh>xKF#Ds)jVUs>wgxunbP)pU6w0dB8;4whO1C|fT+fmewK^qH8gxwUSU79 zznE8M&_n-LoX_7(w~Ye$sH(eo12Ji&HDi zat{-AtP}m}(}{y}jcc5JG3FZ=)u`g)?Go_vzCi|rU$6duM%u>;G zN71q3#g1r+!<#2cs|zh9Lm=Mc?s0=vDOaDy3RFmYBhYOr%=5xN_M?yktkuc?UXqZO!ZsH zZjC0*7rM!s>F2ya@wk3o0Lv+eX^Asf2f3#(J6oP_P|Z7W{FQ^h1lD@EK-Ab2f-gDd#H8lM(^{g5(CtM zJ|PpS>yM`Uk{(rVBx_Uqh`SjIZ;^r4{|wM9N5)s{voRR zn5xFt$8h=vy=O%{_zw68cv`9{sD^{j_nMTNCbgIJ%%)$J#hq=I2wei{cWuP58}fm1 zJuC9}`xzq7mUbzf70j~OB%SX{w;@%BxAzbGn=gr^oh|pp!u;a6|pLUO6 zfI53nUpOu5XlC*8arnzhs}qHu_bq1dxXgdSO4jh zP;&2S$Bz3!C3vlRc>8Icm>JvhtJ7yF&9^u0)LH{Z?1^UxlGnD6pW%{slbVH-pOeDv zH~tbH*W{JVsAQ75bXuZqJ>LU6|MDFEJ>0urGLM(iw9_OB5)OMK@!b?Z%Mb6vqlx^I zSnoIA|8T1%)b^T&cw_Qg0UED=TB#(qu6-$XyTXc3GH@GXO>3pp@=;bl%U;gc1UJnBk zQ#3(zO669*vbvhtT{6X7RrqNS^A(7g05x3i03c(5&<*HH{<(j20f2=8sPZ*{rL5$? zMnDf^OiycCm^NP=ozs5@_$^3iLN>X3KnZ&cEmGZaGY0dAV{2Qb%w+5r0Gq%9^%HZN z)u+j(89g#iD|Gw5u>jX{!J(l>zU7;JVCIWzd(^eoXPd;!S4Q2O9QOY69D; z`XbV?00WXE`e z@L`Gjy}i99I<1ZfWcX_~>3C0->XrCFf6@gaEe#!ZahTW(iBg^3-k4-_omz|X1l-D= zrB9mK^H&{Pl-qs-Njw_LGLw{jqQnt08iHjqdOqzn_F!rbxZpq{7SO!pzj~W^K<1Wl zG{%2RV2C%gN)H8=2S!U3TJAu4H#4ZDCj03X*zFW34bc>qByv1KR0OSAzztCyrh%l%0o*t1b%>>&C-U5sw`^~PcLgpOf zP#MHOE~~H(s_9R(jG5BZGGv3P2F1ev$1rS3hX;=s0s$M8*O7h=eIJ;q{uQ8*)5+f-WbYc&PKb^82^~jOXy!&HR0A?S>4xGYB~7@RJ>@|I22- z15&NnewR;+N{gk zGc8RMt{3SNxsa7CkjwcBTLD~ul4NN@Pxo~E4!?I94txINkOo=rgsxT=Ix;>3n!uR{ zmJQh_RgWiN9QXKs(f!n^>ZyA)9kw@_Vr<-v^bq7=GttS0DtL#M`S8_AepIl3LKldH zmuAwO4TFR~3BQi|C<8b4x)FlI{BD~*+&~#X-AMg=e=T>&0XV1s&3wu$&_Z#0xajd( zWvKrh_MXsqb_y-Fc7=rXV*KmF82=I@A-rm}atPM#~{1_BRu1$(dZe zEV?^GbyT8!(9oTzbYN+$c#@)+HeJ@T`aQ9b08!0A@!6zn|1uX_%e#6P%X-$P4S!l#|STuvcx{kRh;lm#)mxA4^5 zOF&`=XZHBVzp-321;8WSiLYVDpdFb?nsv!&Abzy9P;PF!5Mm%BIBh2Cf86!~EvE{V z93O@Tg1v3D+OhlL?j=*`R##jFh>`?!SUtheCIgbYJ$Zs7*QL=NB~U9qN3?zUH!Oup z1e%n2_%@pLuBdk1l{jT>SP;Z|HT(O0gWY^*AcN(lES9Gya?@p4iQ)q>{uC+TIuxH% zWpNEl%I!=lKpbfR^pZS@%atemd$Bq&AB@Yeffg(4>#NyH@$uakph6pwz8d}M-QJE0 z>>zA;h9hGvhwn<*_?7jX>jx5=t5@1l%NCYIBJd}xEbrYMjD3A2U$9grcqcX^jG79K zD=amghB(^K2xN#t4Ls!#F}3De`hrb9!il5pN|>zieWNm!v(OM6uw^}K;^z_q)T zy>78s#D8-;l@vl7a$|EOY9V5nhkL~BU#T3lJ_VY_3*Y&{p{3i&V$|2^ZeXKC2=+s} zASSK}V;-IpRJj5*_fbB!eOK7Q>FzzOp_rM5^A%kLy<|0$4H5@mziDqD&BCjdeT5T+ z=zG=0!bnz z3v9chY0v!6xF>p)KErwn=66cUtS@Nldr^6U+H#$ZWFym1 zFfbt?C&YxqQIg_5MRE-gPRU)4_}v$I=*z;hNp(x8{yxwlk@%oQkQTkj$dGL+TLn!Z z)awrnCqiwCI_1UT*v@U0nZj%@PnZwci!81Z<^#bw1Iea{GsPKuv&(F7YXG7(QL);r1r62(1(gHY?wsFDw| zwc+xKhy8;@Zi@K9-^#iAcW}Z}ciW2?AT&HKn$G!S4Jo|xM05FXrp}~}R-N57&on!k zRc^LE6zZiipak3ShAY};kkhl1s7E1SyU~AiLd=ulcd$CexI0}F?Gp^}SJ&M}0VHY@ zR4yxdY1`Z9VOv|C7T^+uimHq72>9WR{^HpZPxK~YIAYH;hYp^%&m4D6fSC}>{_j14 zz{@_{W29QXY#TV zI_d{o2A99kX3Q(_`hNO0>+T=A0s=~AtGHp8=l42G@;vX;Ep*3`tx+h+mFH@NOmH|9 zh&3%r2y~#BenFl^H6tc-Kn>u&mJ{h<#bzR9hL86D$r@HJQm|gQW;+>Q1QT?yLb)@c8(8M$H^_~f2%-|qQA zp4{NBrscV3XD4jb4auK^9S4(IaUg=Cc>DA?vZ8{p;?&iY9 zdyz1;-kAoH?updIr=%gnb>+71YB7KP3gxP|YyCx~vW?{T!%58Z1`Lny-lruhwV`kb zpIKgbO)nly@uE$T*}SKTmq!nGi4bwdDb4ov|Ly{2kmC_}OVD+QborOWspKHOyAgz6 zOj_sKeN!4B+>HAPNm^s33ug7jRiDtOvDN?avyuSiOeh>O;}=w&?~|2Uh1hd=S4LI5ASN}wEUM3&P)R}6B+qSdYJH*F2MtM3EP}J z9~!O~@`eU)Od+!8y#z_qTd?+RM61De4Ff$)Je~lP+7Qm*{J;kz4rj>@Ata?8=cMsC zLiFB7ngLp;L9DQ7Xt&Ud|L$}{Z=;*qQoO8hZJDH4DJ%H;1XyS*4VbX?+BN%MI=Oia z?;|uNSwZ*g>B0qRzZfkxu{=J%7!K#{u3+QG_6EHe^z~H1C%CDUn<>;dRW`UmwHJsR zkTr$U^bVT!A0hP5_H1IVdcbJ58bEm7A4P<2c&vbEzxzG(K(uJut~CGU`1PkeV5XC1 zrb(MVwXlXr9p|5{ob#2_`|j9HdTc~YB`0>5^TK9a z9ytV_uMkrgim4dV5wN|;)XxQ?hl#zRr#FQm(DV3Jwhkajjl%l+?@|&k^!@hKV@v9tIp>r8y~kX`TNVHqO>Og+zye|I&Vz%#!(l?u=#15#KH$ zG4cNGW2XK#UI$RR!?v`v4CQp6s&>2Fn4=Mh1W*P#+2>8}d+|~~($Y%Xw}CgtZg5!G z>BCUStp?bBjFoM=V%=ewh;LQ{7-4J8r-^|a(X+nq)8JL$KM;rb`R~SmK7cI50Bc&R z3IMRqKklX_eU@_^4`%nAsfdl&{Rzy_!}DqN=@Yqm|Ml+hG-B9` z!*Co)_3%GC9!sZdd*=Z1gR+wk4J9Qs(85j8gSF?)LZ*uN4m>L50SM^`=A%M?-8Sdh zN#jIncfV8k8aLI=0}J_@OqI%9JwHiA(lrfr576lDbL{dmwF^<&-6dJ>kYdAF-c_ zv0S5iDaS$Ru*mdZJ%fG3d`fF&=*mV$>jqef_&YW1Be2pj4%`4Um4xNf=HK_?W!t68 zy5NCQoq7hj6|NcK`N{f;0kQc)B~t1A{r%&C5WtVN*zX4@NA7Rg1laq{p8=f4j_lii z^beq2`kf3&G(ePt{%5HY6a4|M;Vd1@Bs4YUEEs`MI@@4WQBp1KiToPfa+K2-Azl{R`U@+}kID9#bal1MS?enM z53t4g$kTcaaG(OA6$uS~Zt#dTOM2fKhgVluS8;MB9C16cj{P*HZN_=)e7zYbC7$X- z7J+@oxvyaOpO?c6{m(#ehfl-1!dr0r2?qxUq#B;+re1z8z`q-s*q7O}CvmdhBuYtC z;HN14wG+Q@@>;$a9h;^|h7PE)S78L|C@CprEljUSOe5R@ZT_As)nC7xY_+rC<4l50 zdA9~AWwhLt>lwTh)$ITl@cyj`vLjF*L#k&#cCCXTCO{E)Vap+Yc44iOqj~ zWkLb>8cLxABhXEiK%aQ=7Ly$RKQoNuvb2-O2>?3Kz}Ns*K3@~EZ@}~30SsMu**vS` zgD~m(@;rG~k9prKzjOKo7y$`sDju-wnr)qh#c+9bmn;oVcnZT#onp=9Kub8ui>iw$ z44G!ir;hU_fhMzPQBxfl}jVdV)dQ}TR(mChVjNf2j@Mb>{h9-ObW7ylz z2uzy5X#pDJ)}CHp>NUuOSKb$gDa4myfYbz)^HuSK{@GJ8f7@Yjr;~eVHX^Y+4L1y+ zXBfG|^`KSSzumgLRAT z&Zqyg99{=JXOK<${o=UsPn)e~qNVLg`icJHx(vlGgt*K{jEWj}%SEFb^_b3K3F+qM zCU`_Yn3*juCf4JCFr0RlqLj`dlOw#P>A#EKrt*KeV}K{SeC__2;ovCF^o^>UtY@+q z;3VPuzCW3R>@K-82;?+o9VtIUIBgvsO2Pco;dE0@3gDBJ%re^5M2XV6m$pj#_JkR8 z*dZOX-5@8&BE--&J=G3W0FOd~+{1`9kbo(917x=5nJT;(pc zciqi^1@_i(XsdmcS9VKrG|8UHN`g3FJfdGJd*JTN+7;3t;m{*&tv^V6&2X=7Kf zChCdNcG%_Xg%_PQYD>NLLEM8g5Xg>xa0G#B>TBop381UIO3utd_McA~AFdsQ0#2PX zhvzsH^v!pj1~|FO&Vp($2R%J2F$g^PARDz^d;R`;kf=_F_8UR!OrS(eLDvr=)sI3W zqj1=xg)bs<^*8TIL${@(t99agJ`jY{ynGAQf}(t)9chNx88&L{Iok>4VocxN_Y;UP zAVH?)tI^!ruQvR%b8fL-$OWdV8+scywxJOQP6|3K#8N732i3xXX2|$}FhSu93@vS7 zVSjW!IUL7i;pHiZ9KHeES(-VETfb$4jW(2eIkhX-o{T3EM)#^og1bVEtN>cQ7{Z82 zW1k5y71s|!My&>>$KV^D>?#@b^ccFEc*}WT9hi?yGzZz1AN&xAFrFkM<2fTOjfFBx z9mrX=`I2~`aD645BlSj#Ds8ee2U#A5>YLX2aWP{#thpR!Ciia|Aqooz@cN?$KXTjK zH`vW$%nvsO^dEfK^$)hpAA*jUVc_{rsmTtXBk?h66vo2?#^}&LBMc_}HNz3}s{ba) zVk1vTr^25aCLdyklK4q9kpS7O&Kurn|ETeq-D-+*q#3W(Z`Hnl&iY0k> z8koe7=?vDXP`?HM^mlB=+U}VP$Rl2Yc+C$MLDz}H6vszoEnb$MB4+H$t%^?a`0O9u zT#yHbe5AIi5z5xOgo(XD7#;QVKPXI1(80R85DH^_Y)l0HFrCkLy$dQnAnF?iuuf%- zY+r^85oB{vH~FL?I=6o)d2kNARQc4~)m#vTgdgPj??nkQM-%}t=Sn@>wt6>Sf+9(n zUw@PPaVrhTX4-eQvW~H!_)>(6^xB&kaM<><- z^%tR|3!<2yR_xRdE%3w>$m0@aXpuMUhE-r()J`Nyz9svXfm)z7!sIY?sP-PFd+M7luE(aM2$aURqGWz$lX~&QkqV5IC`4nZiUjPa zPYqg76Y8xgj#$<_e}Ug9fR8U$>|Y-yVQDpZM*J)C*mXV<)E;b`pkrB+9?T4oBtsYnV;_>qxk`H=FpuRrz|DrZRGM|*84X-h4p&B3gF|XYg+<-vr`Kb3YWmevQ)Fku^ z=pGSCEC=F^rPAx0^kU!vZO`^P|Ll9yb&2jM&;-*PNpR(16hibB-3S-(MQfslnyqUi zsk?OqnXFM~%1;bz7|*iE==#4};v2YJOWdb(qVL&;i2v^Wj4BWkxADkd*3#N5CnsrR zL>GIh73U%~zg?q!wUa@z)hQ)OF})p-<%K#%C_$(=Xl}e+7R1udV?aN#Jb#E*p^9QZ z^t)iy;u|xX`sh#bod$T?kihaqn?M;1QsGZnAK{JcF&#eBi52~_b+Fk)_!QxlILhD) ze5!Pza?>VvWYwbJ`X20uM`e*!_O^q~IA~eu8WV75+g`%X6QbPOfb{d3pNkG0q+#U`4$@(ZGq;z1kUnAoJUloLI*yNGV>|3%BKu&A%MkuK6Gx zClr#%yOB!gqBqa6w~s^KPKtW$AXNie#yjI93@ABrzrwRpZfA46bt03&VC^?zJ+^Gn zWK>O|?7Tt3{(ZL92}s|w7`1Bf74~%x_wB?o)`pD4K* zbEWkNM;RC=+@(?mnI%HS;Bx@59Zt<7q5s_lY(VHo1vA?bvGkH(ucfhkNH1-X?^~J- zRcbsb!8n5W3tM^BER%ILTD(ai6gHE_vU6=dyR^$;R>kwd-kyZRehJzS{cJK_26EP5 zSzxBaR9nFJ(!x^s9PO)xSz>l~W~NTnOwXA~j64&@|uB5Z`{m`DL@AwJ*( zh`_6{Tm)pT!ubhdh>!0}1B~;w_o#hmPXvWI$|M_1)D}o$-kLfqHB|UO*5w181^#_7lO!GwL1&VN0ojwD)=}Y?;;6dp^tfLol@_f1#c@ zQ0#Xfbg*QJpr5n}{iS7qj$~Lz&R;KbV-OfsI9ic5pcu4B_h)C+CfO@7V?{2q@b6ax z_I}EP8}Unohx{*#5))ut*!uEsemK%e{-ZmPqA+L^AEPK06A@mWYSU+148;W=2XssF zR|h*`+ch;A&04YlPB4k+NRru+%p$xEfg{e?!?xkeVo-b|G_%#PzP(j|oE{`oni#K} zUtoLkc@2zg(qXXcVe3a3%Af$xW{W0gOG|pK!|b%hY6tPFfbJmibIvOHF;*rROgil; zG`AkObxGk1ScZ)QM+;>#i~`$JQ2CndgQTRIQ@AKdToa-6vdzqpsiVG(Nuy!0w|Bxn z-_pLrx0|u`8ga=HE6fxUxs4!>lDEJ|ZndBEY(QDe+T(f;ny8Zh$&&u! z=!y*%^w}~W6YKmAr1&!sg_(tcW+jBGuOmd^heC_OGgY*lZ{e~RRV;Ge)W}zN2>xM$ z5DNT%0&}8}UHFj(HU4@Ld~JK|U$+u9QKMulKsD-ZgSxtQ9A2%DuQ8R{Ufw5AA-zlavamLj$J|L95M&)W_G|&p78^=K|sZxlow~Yn^(WU694^a+OLn=CBqI-H;T@2 zR}uXiv9<&-9}IpN#Qga*_3-a7?_fDxg9vqd;{JHA7no5yXt3oBH~ zE3~(D6u>wlWNz*fPSRI*Kpw>1svdS6S#CeW3{T&Uw@UZNTGdQcUQPT4BIAfRRLasU zNBjFQ8X6jW@ef|;Eji&%eBh{F2fopjRN?giomfI%$OB6N4*1;S0|Xb0KE8oV0Pq87 zDy)SsCyt|n`5UY})Ps^tX&eV6x)>vzIW9G71 z$@OdLnV-iLFqg&P4jpWOhJ_8hbr;|t_Y#+;9(|+3wtQe}Mv@*HVk5Pa??z9~t0P8t z6W7#8r3TPI{SjTmsqY?5KMEcHVUP6xK5Nt{{^V&xn#5ERfWSDY&1NUw>ETr^sL+yP z`sRm+df^)CP-NM@eYL%9sQ)z)9K+daW$=)(7( z6fd06N|`5SL<-40tVt7lwzs#R_iEi4pBxfV?4uvUF+(z_acRzxwhf}5L)osSlN=2_ zE$N)Tv-N88buuwAwG~|tLcK{cxlTDpj*Wg)xf|s!OVP##{Eh`qpsmROVVX}on#&x> zgsHgObLh7c0N0*J`A~2?vW$%I^{c+#>YU>LNG)1c(GAvyna5a2D2ofqB*;LF=v#U5 z-y5ySfTdGrLr1bhY0ZC&hkqzOz%if>Ujp(&g`_MdMdv~o^q3h*O)*NTR!^eWY^Mu?LJ@XVRY7Xu4T{Rv8Q7DIvi`Ot zpgi3wH1)(vZ1<_u;yd$xwv*owc&`Y!_7~)qae%^jbE3fH?o$S4yA+xy@6MYs`mG@} zVvfDgPj(-6!rJ zG1OR}rK%7KtbYOKfyMeh2jp&)X@Xeel8x{_7Z-qnr&+laMSb}%Z1FMy{xlxbh~x4K zr|Fp3Rl76=1${QpZ3ot*sorw3_&L3(@S6lPJtv1G+v5Na37ab))Eq)<>* z>lfx%H2g!3E}#}pAQYz2uCO({l4{viP>RpycA;~XH7V|J#(dMy@E`ja??!}d^D=Zz z`^$cZp0hK@ioJ6-V)wV3;+yM3QGXJ7U?;=!kFE>=kBtDt*dfB!Lp$6~x`encRq{VWGz!0+h6vNcd$%o@tfu z(l(h{S-Orb8JyX0Dy>p!p5iOTXY<8zU8pDaelHn@73K27QOsQ>m_><4HVq3zU2qno zQ1fc7!|lNKbRjT|#U*Awv~@{#$2vrOa@?iv6|d z$3ncsG1S zhHYZ(>nhxyd+J{Merp~tYH1x(sr_s|Oww(z*O;X;Ab+AeMA+SGJ8S$jRSD{TkNMo% z@@;Ogt^&|UWqaSqylIj0Ldsyf#|F6wGcd^0xEK(O2;r{bOcAmEJ^U8A>9Gs?kerWH z0jQ);U59h+t5HhSidmbgz_ELTaBRDY2G`C~fZ5xTjU7EF)qkZ%kmq;_m(%96X16WL zT$KC_W#;!u?E=Rgp^A0F(98zHhD$JZREo_&7ba`XaWE|k<&YUEFCA8I0CojGZVa6s z43CEaGfMWPNK{j0E{>I;Zv5We21JTf=KXv4;gat# zn%#$Jgm^L*tBs7V6*^JpVTwUICIjpgpNao0Sa6i=$5pN==Boanw}Ij6EaY=O4J_)e zkZ}J+6mm7_?<%U<=)k@6wccQvgOX;y=j0qY!wbvZgxX;Gnl?2dQ6(25Wc7HYK`UNG z4QtYejn#f%5~z`g{u+g8mjL845d@#7`lYvf*7c?-yWAZ6=Cil{$p;{jc z55XM7QijHh;(ucCJCI1$2sGL|??z$p~+zbL{;Mes^H;HQGWcMU-1%=`%cC(0e~V6^D<_Dz~fa zHk{31`JAl&NX>%vlKiysx<%8wqN$}_i4!<9LouZ0eV>2mX6~MDk-t}QBiyu z&RT-G6?!(HxkA}(uIf}&#lLj|nQC(kAMeeqjUG6){=1iY-<6UHadx(5I>pcOLuB_qTE{jDlGN!TZJCYmmlr3BL( zvaEkc7kPeYGxQ|MdmA|P(+O39+?H$X-WdqTpw7|}j$6OX!AfVz$pugdLs_!)o+p^+mG8UFp%!=-R`9s>)1K0oiTj=1K2&h~SB!}D|DhNmQPTpXljvCf%Ba(j* z`v@lGa8?>Rnam3xca&aa?QL|_b*?%M2@xssWf7Vh<0F^L(8 z@tuV{U6p@_^5VXfDD(ovJ#Imxg=CD=fq6k*25!>uuEep}0{)O0p;MKohTC9d>1NNo znPvnl?fM#Vje|RmEYzSKXc8s%ax<=f|X$A_jYxZ%qtMj@&wg$r!amCD|EqUT8!@>8sH9AZtLt3zv^Qr;KAaBV zjpFKMZXuIIJrCLzT+3}1Fb|PIzo|GI`ZGayv`|9*0r^h{A0g(}|Ly|hHKT6g)3xCz z_j*R!sdto*^e9*8^UQtR9yJ`}AFRnv7RrK?_?2?&a$trB-j(IC+gz<;t`>z2-{R{N zT={J#Hsc=)+>bbM65>w+ai5;A!AYs>qP^!iCyJuS$h9Ypj)?iRFc;C}lBtygo z+(w`PcNbJW$z=OoC_%M8K3+E*|Jz%Q@0!YIRA!U?J+c->7aLt1x>R@4>Fp@Gsweo> zHn?3WXVEAFl8RNbN9dMZk>7+P`ql62EY^eAgh)yf0qd}djBpNVTqfpN;f%_(E7iZf zJ|@;3GU0FK}23&z@8C zlwLKVC>|lZ=OyC8K{cTqmdzRu>#s+k8$KWE`<4N^vB6-Ix09Amtf3;RW!+ht#KfC} zZA5G`T2FpE;<;9Q^h%}FMIl^kCx~YavCv-ApG%KhNkwwD{f?X`#Wn*h1}iq}a2mak zztnWY*l2jg;04+8yBa>!O0S&5fLu&SwKh6oJ<9tbQa>hwUeyR4qXZ1-Yx?KoLv+J- zW;>OHIjogQK*%D^T#c;OtFDA`Q}NjI0pJM^6KOwMc2aQLn|{$!>k#+~ zZIW>=VgPs@xzSbb?&wHei>lVs^t&a&>bISDFk-Vh{HgrmKbivXqWmi6VkSF}|OpN^O2)Xmh@d5cToQwXHV;qD6>#?SBl` zo8Byh-3jqsNFoA{=2x7ku@avff8211CK9Gr5|Gq+eaxBGi^?;mrr5p0_ilG)hJCP%@)aK30z(Ixmen>7{Z zi5ojt0nn#FH^smz}Pmk(Aeo62H^guIDf%qx2ki86-3w;*WLiUF0PUZX7{~?uz>U3?1|XUeVq%a%vmst$ zExx_pv%r2KQ8wZ#`0SYK*?R2M~H*{M$a{T+)!~1LyhPR%Hxy$1Vjo(v-V9 z=T=C-D%l4|;{73k)iFEz!Wpp`@d5E4qt@s7&Vh|_Nv{kk+C6pp#}BklB%bLZ-pw5} ze<04Co16RLRbR*Nae=TDjXMOhJ0XGTTXrgtbF8HAG|b5(uk(3v;gTBz>Lp4Er)_3P`Rik zKNJLMNJ>;;Q3%7;($Ee_V;_E&l+ga@%y9?A!3mOWYLuNr{yhc`G(!`pG|+cFQ@V8D zu?d}L=xHRQ>$U{pRtMgIl+bo16EQI{n@lzg3P5^x!a>n1H5DqwSMBbS|2Z}Z=nD7C zeE+9Mvm~(vNJ3`Vhek61rOc713!sXVgXU>{1c0_Di8GlEhXXf_(Mlne{}l%Q+xdL> z0MmyY(sMLh&^u@~^#IcAe?p@=)aBXi<3;ej3Lrp@9-yJ3I*ytW*!sF5@N-+e6wrT= z^|T#$Z^aNWwy1;+5DF9yKgm%<18-`O(*zK)?`c(M@^nN`ytSLUjR}3BSE;Y7yF(4_ z`19Mk&5byAHSeBWf-jKE|75UKq|QYFUr3+*Tu*!T{AMS28~T6==h0dfhBN$i_L z(`gEY=~Fjpj~p(jnteIGO2R!nJ}jhKf+tqD&LqN@rInm+xQmcPL!u@255R<%6W-EB zPYP=y@wrn`lV};vJasDy*=3C7b)1TasMmDgx&cyW3#dG|8|&-3O1nU-B5clBrt0>( zhiToxyWb^l&AwY#*neC+9jMvlV*%EGzaw@NyQ`H_G zRri*KzP9ThLAk|UIq{D`gG|yK5Idlw>JvNxGDMNSE7L4{+uw|)-oR?ew^5~;a9g-B z*0Q1e#M#B!P9FtmmCkrH`dp}EH|g5C@+@)m=eN7uhE_W~oUUrjta$0FMfAG2K!%fc5#v8LiuD2evp{d{u+?z5c`r_Pzjv&{J)qc;Fl$1@?+ zX_?ddqoAky@(HrGv2=ATE>8(+`r=iP#-gM<$k8u4iv=5MZE=_)Zat`ML!ENv_4+Z3 zg2h3TU4mu}w05+OyU|Tg*A9U+JlIc?c!?Y4J7)&wufw$BvWR`5Mv;72x;MarOE(jH zW`$qy25UuAOG?jwc4uU2lrcmMW;2#nDoidY!CIa)Jw%8^mt01mPQ5>A7F3 z$#6HjIbW?7`mZ*!SUffD)lf>J!-!KMnU(y&euoBXrK&^^o1FMTo=svwLzAq9`Z&?} zGZ0K>n2#FmU*N!;Wh5uxZUS|kdQ;bEa_wJS-9cig3ni;)51T@SP<-4WQCdMJn7uLD zyS>|tGmU>qs6VpS2>;!wfM~$L}v)V_fYlQ{Y z84|uA+u2b!953Mo@hyZP;0I>7^=^_71z9zw8=ckIfs&%Ju+mx0G&LS!7W%RjwOi2e;2ZtccLZEnIZ7;a_L>!?o_FC6nwo; z^P1_Ff&+8euzX*->Kk|=>0b#DoUPVpjy_$6xYq`-2weA+RQNh?C;4u>W1tm?u>N3A zTTcU#xL90)T$(bE_I|TJVmU(Vvjt9GcPV_kmsVm1K}{`{`Z#x(x6}a}77JC}q0Y9H z+i5EGrleAz@-i?ffZ&|h-44uFrX@S}!x=u4=Z zNYGLiX!Y+~}hX z=!=a-fY9w`{5xy++P}ePN8$ugxxm33%v#5M(elF7P^yg#B^5g;ZTV34+{P}}@~Aev z+x#GU|DDkR=yBZ$0P0r{#n3;e5X>@ll_Sx!;+{P_Gs=~A)&iWh`~t7mhC7ewxHFYl z40_){(~m+W>gBw|olfv{i&g=nLBB_D=aGZjTn18m*SE3I7>@A~l-SYKx&?nl6Ghrp zo{ra3%KWUWUdu#@+cUROjy{@hoiH*`_iC@u9!MUY8IC=34uI{c^mDAM{kI z*^fIPh~df9pj5FwpVU=YLp(IMojz-5EuU9us_Uvi6v;@HEzIykOIIhdC7Mv1QqQk- z{=M~}vG2g68Kn&Vaii#XF~8>V>@mfAY0BrLlXjr*o))T=qvyN-1z%k)xBUG8|9)(8 zfm0*1nk|D_{|zjr>p5tOzu6r(^>zpIoyR<~>v@$ooyWLJ$oge$bNx!|o`g?DV^!y3 z-7mUI&^$9#KC@CziJ%Cg>0QTj;~4+z_uP1{uqmRfa;+$)<-6X&@1Sj%bhbiGr)eQ6 zoE&y-aWB(wVVsYT5>IP>n!T8^qM|GB)JdFf2F^%;yKRNUQlBbIS{NcVZ~ZZ+!Q^Xx~5sn4cI zNHOR7CGW<+ECMP=akBZ9csG92Qkg!?r!Zw#Z9okjMd3`Ue$O%Ff-62D%=qfD>hZkv z_a*u!ahKEgkGF0cD7ou;U&(T8!SXxH@Cmz%KY6F5wR|@@{pSjIeiHAu>Zz~Hr_I*Y zd`eopU!K?G%&f0gM%ym((`17=02OBWR?cG zY*67?KKIy|J`fa?3v+5{Xm85na>^dAZun-O6UZ2jwnF#sAE&dM#||MgEX;hqbsps{ zwlwJ$Ky3KSRFTJyeKe;uxqKwr$+=$<#o6SRKGk_NkFT9jIWO$ewUP*jb7(cupq0*P zTsM^|AVSqobDDljLu;VSW2FFL^=^pm?86%WVcIeR>bB7MFeXOglYK1HYJ` zIIm3){ZUvhY`t}v)pELP?Cz4lQ#spHYx$EsHz`A9oguDVsW{{{Or za$477w^~I1b#1!bPcf2u8n7}gr5q}JPHbMryP%%VD$trYw^Xz2sx*(XK{~V?DrQ;| z*y}bA$ zshj3vX!Gb9;#5aCP0xiO9$Ja`mPNwGE}Ao?RE?hh=oA3Zymd;y1U2@I@mOyl6$KalKce0;pvgCE z#^2{9_POn!-L8;XE&2=}1T@3T5*;SKWcaM!*zLU=R~Q1r(+yHZ zODmq{ydSBl8A5vr&q#5osb%=vzO_V+9iubaEv)0otYWoXJ%D#7;N-&N-cVHTVFRmj zA8O3$J~1pdtK``K_PF=aR$7*kxhF7Rz<+ZHRlr<6Q)nuoGJNnGTzc&fs4a(^&Cp2@SRlh-7{6V_tC=cx` z5)5#RF~ABZ>tN;nZpCM?@AH1-XF=L16W4znD(~K%1pQba_}QS>MK40L9}_CAkn=-BKa3giB8rqBK=bSV$?LF#f!8XsP_}B2tar8dh272hBifD} z?h`DAxL$))_EQ2?rU%ScMKqOu@YZTLWpyS>P~hV*0Ah`GuhvKfD3UA_6NY1FES4Dv zo7Lsz1IM2@_tEL?v?51q++5$B3|z?3pSm#@eHovgMp;dkT22x(maVdL5zclA|(y4hL#YeUssY})`?OVB&NN;Y!4BMsk$b`! z$*L*0^R^PWV>v!)L!+UqyS4kX^6@d~aNs2to| z0z^~=;_gmPAMJdzy1-27jy=RO)mO5FRI*s?(Ya#lZC7v_5rvcP>-@Xu=d`*%-PQZ? zPyh1r^Hc2O26|;>WgBp-`2;yN;XB59~6wkC{n$C06qdcK9f7~e-5U53f zFUanSyXNYOO;ZQf&R{qIoFq?CoXHeRET5a~&56zX18(q667RceW0~c^(x*5tc8&FA ztz$=wJ!CJ6)V-n^1pR!mDVcLvn)SCWT!xo>XUoS>J!7hGW1B=>3-ZB4Uc`P2E3365 zx%(BEy^3keSu@l@>m*ijDI+AbQS2tRw!WpWA*Ht24(Ui7|~H9dfaLL9{_O{MM_OD zMI1pn|B0#dJWv3SiijFdIsg>GfbG>?ggiuh20r?q^QNK0r|P6?&BX}5|3pM(j))L) zW+e6cdOhHeR+7ikvckgSq$8OA=f61kxI}p51dQUgLO87J3?0{@SBd}pufzQ{K7U?o zuUCj&!=(=+Nr*a~Zxax#Bw)NIVU)9R#ztQlR+6vMy7n@`56sm}wS5L)_P17Bo2 zZ=|iD^Ua?I%HxK9gR;4}xF~3hLV!j8mj3V$|6_J))f^9|X4=5#CLW|AV&6$dtjW3f z`k#d_Y+;}N%eKp3p`oE`jvZs{*aH-&XCxUU5p<6H6wnqVRvnAS#XLv_-D2r90!HU6 zmG}vMb=}%QeOJOD?y)G*GS7nGUq2yAaDI!GFW=@^o!J_(Df_)mxnOZGIp%Ou5z%Nj zz;-OQ_oJV{%IqQTK`XAM2j^1`50ZhiNJu$j)+mx{=pP)+Bmd)p=H3wo&@h@{iS~%+ zT%AY4jzbu8*Gwr$x%u=~I&KfYQ(?L?Wx{q2Dz1itd;v4ChCciG^Jgz}G2Q-Mc)O~E z;5To!%U~?tcw))K{K1yAQk!g%8=2FZpo`HAHFw!nf=G9PpmuV8z7)`r11Od z_FL!Sqy87 ztt?RCP=y>~@-6JimYZV~g(SEA638aEftE*XbMHubAk%`Ku(8yn#6NPPtkk$Z*rPoM)` zZR)j2M*);w(h8yXp-*`QrdOU$oIRb&!f10#1c!B{us^icAEi0qZ=}`;y9_jE2ugKo zyGY_D^Cpl!#QGT7Q;ACl0=6r&7)(9o$9a?Z4Aw|tsma_lvhHwOgvr3M1_GI+r>lDu zrNZhWS0R^@0brKnl@DOKpKojg5Y#fadmQ-?N8;aw%RXUYG4~+c;UcN^xZvVHHfimF zrpw*SO_3r_=t7~|={X`)pD;(WX4oJFy>i;sRx=M)AaLd|J>JdHOmtLY>~MHMV!KU8 zjd>Z%e!`TSF8|1v=piE&x<>kM8(TAt^{zlHR>+_!)*fLrYb+l283>l6w#T%|=E>>L zwp-1{zEb)W0PEEX_Q~V#euWG7NM9d{4EIRf3IVr$wdl7Nmt|WH#-bj^@VpS#b2+4N zy~Z^Sh5gE=tMB zfXMblM#dzpJNCX>ylQY$TkRDYNs&-HeImVi*B72q{W2r642*R96aBRSZA{wHjpv2& z+A>R-dsOjvjc!Z%*CVy2t(9M+UXJLOS6hi`GrP%_r`0d>g4%4WUrJ8VZ>Sp3D>4lq z*cV6#ryq>IZ1d%(;M7R4-ZVnnv&WzFxZ<6;4Ue6Tj`s7@ZAw`h-53z{(Q}QVYic&J zshWE#1_`QAoYkhLjMYXrK9l@9Ad80C*d)Gkd6(xYd6^K(@jb za~i+kC+1l#FVrTO;@(qP#uASXa;<$I(W&9tfhr@^pn!Sq_mdZwc z9y=Zjw&e9K&mVkwty8uYj@NJHMg#0fqA%cdGrF{MszHyy?egbtE_>eD)QQI=>8X~) z3xk$)Yjdf$6Bj?*);lKil&tA2fkTR0v00WgXM0Y{8!XQ=er>tFoboak6+WEnKI~Y? zki1W~hK!0`p(Ot;fEKdwTb=(&YzJNow`@$q^nZ8%@u*|Me1VQioHD$eYEqMOJPFt} zF356IqXYob7bs4Isa}kUr2QI|=)>gYy^E&qSJVuQabXtNwN={{Er0Y{E^dSw%{b@P zq(&%uImvI@9^)mj^uGTy)KS~OKonzNYPBdnROQ)b52X&5h%hi;7ar=a^jV+kw~5Oe zdl@gD()+L8m$4>6Sr+?49K+I|CBA`AyI{O)AD-ZJ>6@ksZ)|9$8D%M;xVE%3U?t0N zwa0iN`_>T0p=m%co^6Uc)TW4y6sEYB7|2)qWD9LAs-*l_V7x!aMERS-SL=2_sp)q zq4gjp-R-hO&40|%Q8>dbGwWci>F#iA=F!%Ts@hLCw2D=nweXcJ4VfeUjsMm*b^*#2 zaQQ^Ljk<|%OZE(JvUt?|J+(k=ESYw0E{=#4FoZ48rL&J<+OdnYN5Xn{n)GKnMPmc~ z|Mdc%ZC@u|ZKp48drYvY;3 zwltN0IdVW^>@x;Nrl$4~J}MzmL^E8T0|83A6St9|dBMJ)`G5M|k))=5*lD*qTK^ ztL7F;{4&Fhz~CH|b{iuk;jZXnDt$a4o$ltkY2To#j1bOb34VNut*=XgZ|VCbdzyPt-OXK+Ka;`x!DUW2UiDB*Da(1upNX5= z?|h9csz*i*71(Z)xc1A4eda#SzIQsTJvT6T2&Ubqw9L^fn;*2!7_5C+h;JKZ&p(L0 z(Me{faMVYli@|#7$g41|0aKqjm$PAWf5E@!Yk#F;Hw-hr^`xrFV1*!AIa31z`hnS= zwKgve*?oS8;fA`@YT=i8-Npq6_TPL-tU)Jx_J;-VKVw4D<^t8NF7X{JNq9z(wq`?v zg;}+|uBM`KXR`LF(ir7$YSs6@+ECyn9AszC`f+TFtGcZTmxVMuGkZWVHqMV(%A-^x zbEdAq7e-wB8bpqvT=}jno6@TK8BcLwwI%u8vA{N?TJcxL_N#9LdSw?$6&Kx*ncIw)u@Y%D^I%Tq!_ z@dlel?Sp!@W7eJF7Cu9K{@bj*`37HXXCi=zWJE~x!Nn%U_gLr76+#f!M!jZE0cG`y3H$O+F@#%`B0WbqtibUs3tY@&`18-WUNo~s`T+$b-mZF&{p@erGdu!H^yM^p zr0=V61X!id#`9L62UEs4(k*f4f64fh;eQ43-`?eJI-gV}^jGJ@sJ*)VmYW^x-QDw7 za(vmd7vL4kPIxBs&>X||B0J(rzjJkV-~2R|KrCEk%E9dJBwW(izrU|Y)Jc8%lIaoR zO_{gG@&D|US!9XKM-jQbfi?SY%fXIVJTmfyD5fhRm^Yc`g-~y3;FHUb0JrdtPphoB=Rg7v5Qg<~P;>k|$9I2bhSNG3i@KYrU*Xm=~P(hGDen|-Khw)o&V%|^YPTU6cpHvv^h?`^rgyW z2sXSAS@5nT*b2pX{pUl7{|$^nK`HC2NzfTSwtyfJ{NJhz2Y-NuC|mupNJwsiJ|`)g zk(Y0{XcsXZTIqPb=t$l~O`5#Z#$`rFkMs#oJNgD&cRxUJL=!^6=5_(IL|Qn}&&K6G z(f%DAJo|khO#OX*oio~O$5&9fb9_yyu&nH&o%X>LZmk$2kA@L~>X$mCJj&s5k z(eutJCY{){x8-fWO=?0(U-!w_shJSX9c+n8134@IWU}nrMxzMa$u{Y^R^Y8&EXM>& zb;|J(;rRpvu9M=I#<%{ea%5A#kkl|Se;jfXgPe=Q^C3F+Q+hCzEWm&_r-avv%n8_j z7ub+f?n8G3yuTh`8*E3-RCrs>0Y~Y$&n=xS112M%%CCB1#M!l-MsIMK<`s(myzO~0BamL zi;zT?hQKJ}8+BFHsaJDYa}fyP_ucKG#ZG>j<3p#G*2V7YL!}LL(4=h0otICj0WGJ9 zbLE$R4?!?lq{badrn!icCbMOaezdvFqwJLO7B|vQIOPAZk%o2RQBMv4S}#188eM*i zCsP+lWv_T*&4~Zy+r{Rjx@kaM{6H`wxAbE;7NxCkp^9)QYyohqgxe1su9%L4 zKvOzfw!*vL$%@R+WYytpd1gJ55k=>Ovz_&0Kb2Uzhu7fgXQUPRSca6IZ-Vn$?>Ezr zqh-VvwfQ6I3z`qQno=dZEINHpUy64@8=2WzI$7kK5M>SUVkf_SBY2C9(@pxqU45=G z701I9D?u)eOV^-RVueRS-8lPF$c3g3+V2vII^wI5@}GFzA|C22 z@t4V^d~i6oSrdXQ8&+jC18$|=FBXIE5xh40Hw56T?`$YnK5P8KN-j;mJ?(!KI zV;$oCXl$v1WPO=BmCy_BiyTq7P8VbA_Qo5x%XYYS;QUaEBcp;zk-F~r9ZPzMQ^O@_ z(N7NW2S}fEn!PDFT!Q4pIQJ_#A_SiPA{IX-yc}sd2Kk8AQo@az@hk#FWN@KNbdlTe}pmRpHH{%(-bMGSXJXt^R=J!Oa&9mHhB6hWE z|7z0Ge1G}Gy$hGjrEWVr&zeq$sV0`p?i~DjP5ZLL=5-yL7wSVU&t$U_Wci}dL-eh* z7-;z7u5<9Z#(%n0)BWoka>+Lam+Wga6k;9;zYg`0?WRUmiGyCN(=)OA3;bMU(>`Oe z`Ke*L0-#9`{k757r*>r(6Au2qs)w_p9q%VUiwPulTt(K;H5k@Y*VT#aK*a9!XM7Ax zTPcGhjJf~RfbO1C9A|76i9Nd?ZT)R3ezcwCr7Q*e6R}Dp=73Xaq|<8X4N9T{3Deef zS3y#gjrU%&EVb0zk6Sn;#pguOETkzb`Gn85Uz9?T*SGYqCLbwUHSz&LnG$XH)cZXJ zz;-hMCmW%qul-k*$9*voe>7{v4&mj;=yRbuLy3g@B#(k%3rN}jfhEV^ioN;Q+&XQ?Y`E0D8Nj(%V z*jZAu87xyRR{Cj<^R5T9Qmz=avdeIKW`Y`w@;(S{&{?LPX%@?xTz4wHKz9jzbsJo& zcS+1N(_$yvDGlGe*>2?rviRhbtHIjabjPG`t6}Lg&nAm!R82Ka{+Q%wOye``jsMhR zo5{FZ&Qro}c9nC8mLV(4&B)A_x?0zQwVp%otFq*ar6GaB{_&}gHS$)kclufexrX%iT2Ks~DTcs(HOGvg zQbtd|AOgvhmA`3ncs~y9hJj;wp1_w}G()jT=o_GL4$gP0m6v@SYST|SIN!9PKE+1G z^1QG=<@0M@$XLY_hOdc;ylat~ur0!%{mnXzR^pU;Q6hF!LcU7FzUYMpof_MwcH|JK zXaqHp``qqR3bpWViP)h@{!DdmM^m{W2(!x%pZ^W|ExK~1qO@0x93ab3n*DVN`dr11 z>N$3t`xz<9td_tsgBTVXQi1*A4UXvXvaB)c-ujPj)g`Ihkt}o2u;F z8D()ZeONdRT0!OJ`XD1yl=b<3)R$ScK>d%izD&)zewu&V_Oft+S)i@-thq4sZ7=$9 zY=j;ISibB9^L=o2L^ z(z5!%Fs&m0+pDyh>1v&^)|##!eA}IS~^4gmFR@Mx&_S$}S~dwRTMGY3|eDZb*}zuKZZg}q(* zy0#=adUkprPjs^6gUp6s|C$;KuKeD%xdyCyCH>JXr@++2QC`=7KP$#bI&VexG*Cxk zE$<0{Z0V{)IO8JOQpI$7pwy>_A20+|D)67~(FxydF>~M#Opg84dvSmmT>67tyCuEc zYA|C#?)Pe0KdbnjG#h2X>4lPmg3Wx4uUadIQH4EVEqmH-m-za+Ce14uu%8oKBd&_) z#XrzqU_(ip9~@b8QaFPvC4Msa60|gJ*%Jw=`@^$#!3Cw?czX&R?lM5s-(zxkz^QF6 z$}9r*$LhV#)K%!`X|97SKAN%ZMvgae1%a#ag&E=z`Yk)<5p(qso9c!E=e_YUEdAt; z=+l~c@0)MLb)H5wutj!H16fT0z)<&6hR2z3_)}4a60!2}v_-?qz9@Ye(%;|X+AavQ zE6A8wCW-D z25;(uS>5Zd>Bm&T`9OisyH8D_P-b>JhtioV%x2Q4o6h?bJ>3%;^K3FAPm8wW_FDqh zdu_svnH=^L+&*mfu*pe7$N^@OP$yFj4?WHwKpKPBPI>U^)hk91HgX?Mx9OUBz*izT zX|`p`l-4zIMd;XKBo9KAz2UsJ?1TH~ezmb?QH138=u8W!?!HW=G4a05$4YtT#6C_oaPR5&{+EZLFawPLssrv^NND z>G5ce9hX0+>*n1w1X+-EZ^sX@i=V8t#0($+=WFd`1x(}nrZ4aV$GL?S-yONl!%^K!t>8^!iSVQ3~*YDK!{Sm zKA&7{covAhQ_Nk4sq@+*`ght!{h}lClE@S5Wj>LY7YNVnM~B4jg)uvxT(|XqXXV{< z6Bz`YiPtllFJ}W=f}>tEzf*dELAf?^UPu^=>oQ6$d9(6i0#D8~(Xq7^&G}Ng*W`mY zJB%cL=X^md|H%~C#{QZ)P8T?YgNjl@yX@0TrR<-XG0C)Z`ch zP9Q0PeG~W7bGZyECQkV3C84cGkS8{Pjm%+-Bni7M!dEDaXeGG{#OGrGy>M*@a)!{r z205r9e2-~sJWoGYfY2DsL@abe$gsCx>enHaghn(eluA_o9sX)weA9^hA|81<52HDS z5=mTJ*xjDC?G-6(G#mCm!p(nmS7#3nphddUxdJI2lx6W9H(?zqKKvRbB+#lFC|&%Y zo~htmud0ENCKU?!EMlWO{!wF)+#+b@eS7C$lZ`uVL$0eucPLqF58AXI*cZwRP>J5%2jl!X|2(+<&b@ju$YgG_yQl7#b9kn|^oq|pYn+jU z2WXD?(~on^TY6twz@_k7b299+2)yAttvUI|YYU|Z++QvHr5|P=2>9O&Nj@~MSjPto zZuVc&J-GJN+Kh>9d1ue)k#KSvCp1cTU^brpX?kOXKJe?>HICL3r*c8FZu5Wbs*Fw^ z=}#*0xhY;(v0onh9s9t29uFSkoGCrdYJNyrDbRB=baS2Df!>5h-itd?5u3;6*~9HE z5=Ty7DBgVwJ`+!g_2N=|&J2w<8{UQFFfUws`bQ!eaFbJ46ss!{CR%9MJHAQJ*v_ zH28x3CRc+=(NuOR?6bTqxzgR=;2O4kY;FJc8}P6X&^p;L|H*MPy|0PvDlkBJ#4_20 zlUBGpTH3r5N9eNgJ{!@gu9W2p%_TpHyklOu4)fg3ZWpZ89P>vN_@Bi`2s6JQ7To_2 zI>->2^+*hn;KurX>Go+_sF-zslEKyO80xJVR`Qn0^&JgAq3Oi$)PMYPP@v09uiv2s0q;Jo*R9 zozW%D==;$Vq@Usau>aTa3Isv-dVX_KRe(lG1|{sy}9QG%2_-{S;QCp#RcoiE+EUwx0h zU>=3|c+bg?E{Dj(T(F{uu2evj5Qc+Rb?31@s34-W?~ZV@Whqc|ZI}%OxIY2ha;!tc ziA9Lscd(4U#bBcD1I@>?<=5Irh@WW40`5i8XX(c__z=Cp0~LI64QM;4_Oa(^Q|ubH zyr5FZ=R@OMFWBOXa4yNS^vesgt7G)wixw2ru7K1&Z=b~r&szqyPo5SZI5+y;pf zE|0`QYKK`D>kFIhT0BHW?6xme$`)%)ST&29$`!$LPP%>Hz4I);JeQDo`_Dxa3qp`L z0vk=|RJyvpY_mHkh39F~^gri!sSr1>)nOhIGgxwm)wby}&!!pFDMc!3SJ~Fw%oOGo zX_koEPn^+#YfEx;%J?Y^YoPHSqV>h?9tE>WPP!&w?YPEgmiZjs5Bz4G<_n8ct+16F zcscAtaj`?abXj#AC5IKZhcGJYu#{V;J3z6xKhx+F&*pdO@Tyi(J0-bD7fiF8RAF2I zgP9n%+hy!6K7GKE$Ma-^*4B2ipMORry1~B8(ukKwr@cvK!X}Na{r&2Y|3jjk`zQA|f0CLr!q)lOWcMI?X?``SFv;mg>txYG z8;$9wZ)Y6+YLz!ipy`#kgD|^ z;jCMDY}X)5sAp8nJPp?ddoGqHh9R3pi^_1XI2~4&zev2TE6Y{5m@WT)88P#_W@OQ0 z#vtXc!KDU#_fQ7i{j$!$%&FQ#_hA0_oBf8y?;cT)4@+VB7ikTu<*%d6%!;}(d4rS< zB|>>w{p8#qRV~_d%NI*6hxAJ7t3Iqc2f2P+d!w%BSTx-nV?@}_)1Yk=9D_@Cf>A0h ziupkO>HuD@2S>~4y4UF&=?eI(k4#WX^vF-kiL!erow;KzSFik0j7>>QiQiLm)Uz7o zdLo7E)^0%D?w!sf86qk!Wv`lVGWA}$&)Uau^Piy7rMdkPe~ToYx{UMkHl9CcSGUe| z$){Ii%AWlBRptuyawJn&9w_Y{Uhn9o#Jm^(3hbPD3;F-P8etY!W;vTar6ilW*xm2Pd0sNE6N!bro;9Dsjz5Rx_b z;T}=~Jwx74`7lFl)~ogS4#b)dSFLBpmrCcdT8%17%RWwx)}eaX#}>tH#%cUpl|VN$ z4&Il`I(D{+8Y$K@^H&{pj>)qNEOPSJ7iY;AgT(uF%d=_N(Z=HL*^q-$5e|+#?n&+6 zbiA|P$guV|UM7A0BX%~nny!ZV$!4l|jzURmt(Kg{4vC2{b3ZnBwbdWnw%~cuGJ%T9 z)9r+~pV^eJ?X}T$yzIiSCuXh64D`wqdFP5JXUpnJ=8BtzitW;(z;h0hduI-!{#bWF zRnP1%qOzJBvkv#fOkejRCJN&HGXBlQOMRB2oO(ke2bqV#&tT>J_4Q?o#{64?9GFMx zJdjy#sCsDqJW3HHCU#JD)1d4wdjD~9GVuVW-41QT@?}cS9Hi{q9Wt|Ab3^O$Ej8Ki6Itm(JVWX_cj3{&=ZH9w_(D5OV*)aAa-Z1YRNP zLFSi9>FDX?$nZN9!<%(l(%AQGN~>PY!)BLOmGq`EmuDgFkqsCdC(7qiG7H^Li;L$E z%EAv%|3$`%fJcg7!DgmkEWql$rZ{{2>%zxOM6G6>4vc~PIoUU_j*2G2d50V*q6*8J zx_Y)VlOnq7!yKw=!D9AWj#iO{`)74@&$LvR9i60)<}D)XBw8l=_4`KK_M;V4RKE+S zJ5Itzq*`U+du7Br4?-U%P}$CSFB)NQ$@E99yvV%_m|@*(!aVj@#d@h8`nLv3hNVZ$ z_R(bqEo#gSbARun484pR>?crdKK5X(w)xn>hMD5YJtJ%JFL$;LRkc;shKY%bwRw}y z&3+~Ib4m$miFQLe(_0v;SBq~f06Ueq)m^YkKfT{((bmSZYyCQE(19Pl4&GFVTcS_HFCB4+d1a_$n%BH6<&b$eE2S=5yvYpV@ldaP zDtW(%YImPfG&1_V7E@eS_YYNVTsLwaM-h6dYcx=rWhB)rUg%(_DX*5=5O!D&cSL@U zf|bG_*%q0yrms2$AL`Bcq-txm=`fe64bADo;7^#jE=<#S9NrIbTz6H4PD$@xKcblGqrZ}2t8ambl@*0W3XB4gcmOxSl&3y z67z}{j$C%lwz>JmW?0wTmrv{NPwk;Z9Tr;+_C+1zUzG@}GMgdlx?m=@>wgw5Eev?4 zrnIzcO0XtrCmkPc57EWLx=-q=Ef=csDM%xaSKx&;>+`)cmAC5;6MiA=OKWY1w)hR} zTw}^y%8EbxI>PMS?HWWj4cn|T1{;nvnqsC#lG;bC)YLqh`EvTo#=|1*>R^woE>Qe% zSZhi9+cdow6K*BErK5+%m8f8L|2AZQO_@KlsDqZOMMfEJn$9BU+wN~F>fh#yA*K^j z%*FPxHkwT_4G#5JVn?u}k(|NeWtgS)M4bnbU6tZbXj_J5dJM(cimjV@Mwu95iiZ&m z5IkXEoX1K7h{O)86^X#C=NsiXgw1>BiOg3LPxR?PXg42Dd*a@n-Q8Jo2W{=6qf!4r zZX`E9Kb)=b)Ut@qfJlgD#^UVln^Ank+A0mfk@6N{a!?(&g@Yhs8Jd6Zz56(T?jZYCvrr zox>sgB}8Fu4Up3nX=L9Kpw`0}&_N){fC<4rx3mYX5zFxC#<4+91UjQASRYAaDb@fd zfVdlLF#xu>D8s}no(DY_^1xwZd>I5Hm3?~sG`o+Qs8jfZxbtZrLsS)7;QmY?C~GH> zn2iekCRP^3-6ey!M^-^DB6i)4m8C!r+BuwelV{>jhr~nJ{;}NrQ-?kc@HMbTN6IDV zwui`@No}XQy~(;>o!-=FbQ}G4+KmoWBU8&Je3`tXewGUqvc=~dcb7&GJBeES5W)q~ zv~qC|JUh@1K%u;2fl)56TkiKeFhl!do+!jv(_V3jbY`!U?>aMFI=p`v2H`<)+E@ex z;+sD{p%gs%_BlH~^6H!J6K?7MtejX;krLmRm3rj<-#@CpSd*rK+&}S64g+}p@{hv9 zakta2`UqcK8(%&a=}gBHB9O1>8RCy%{a+g>A-=rS|4EdHH@!Hq=`~g(ANho(4iTEP zgl`1r5SVAUpYRE|RaI1E|Jkv`S9`sG`wI^cJn*NJjkcRnZaz*4y&eefv_N8^-`ZMQ zHD-riwf{K;pjZL!XnRGAIJV-y*mcy!zEA422nYe=3Gf1tM5{=e0xYT_dN-o-0zf?PYFIQSbV2{jBWFxc7}y=~ty*rhrZINxGiRLfg{vx}{A)wA9!btR3?_6BDPU0;6 zHh-Geq1hh+^Z{WjboQmMQy)A@!|YF@yI*#^citj|0sM&A=mkve%SZ1w{xx>LUG{Q% zjSIt0PCqB8K8+>ZQ~!maRD2)O|LK}Tt@KCD3en*9i+3QGu*ar);@Y6xCE|RIgz+vx zbs*j_{#g)i`Yovkj&V-!nDw)Q7lK=pYNLUIls$;U^$3wF9Cp#@tycdYIm#E@fINT1 z6*ig?&X6H%W&gAjr>6#pQ?7aaSG?Ql=4=x#0g!_5yx+pLmLGLZAcX#9eoI9^WAKrfdEthP~4Hya!ec7+hv?I_z z7KejOuMcpeRelN5c(>a?o%+y|2rx`Wz>IdKLYTj&77Ng#!H*`L4bZB&P@3Hf2_e9C zM^=yoP<>)eO2`)pR#ToGl0S0uL?}j&5J{>8ucM}IY5AwKU(hZ1Tavc}KF4iyCMR5L z+sEoqA4=VC>JN^IOQyQIvy&gc>0XEuHncY$t&ivY@X&%7H8G=Sc1Q?R^Yw<>5k@*1#3~0o7Ur~;goO!mUjzeF01H)m>^LgvJ-BC|JBZ(HcMP0d2H}aL zeG%_FAH_&z976=-#puogtpce8JPE0!760K{11?SP)poY~WSG;Puli$SKb^c#T+C7a zuk!*|qA2984JyZR^t#<8&6W#@4L+y6{y|tfkclJmEaCYjEtU7S?-Y$(<6X{cZk>~! z96EWkeNwrCp#Dj%01V+_K9^ie_H#V$cXAT!DuOwi^7!9aokrbxsQ<)L+l6sO2ocDs zK4!I8x53{o;Rm)CTZ0OxtFPdb78RxAMT?$`Fn5izg^_HKcU_Z+akj@>68HN91 zpACwrKeQbWyP^lzCEl*4j_mEsm#wUvrgX3Vfcg!5)+se9P6PU?^XlsDTwsUEla?1R zYK-px*c5(%NMAO?ebza23}lAHX5Ym{Jk_mOK_95qeLa}OA8Rk50Ji3Dx<9!)E%&K) z-F95|K+1$6BTW4r@=_tXdlP!PypxqW7bBW7sPTAMO^xwYN0SaBMX|$k>{w@NzPy0V z>%FR2=^X3vGa6fu-MhiFLY;X~wm0K{uNgc8hf?SF)%`C}cZ6Qe>uR zbkBDVnE6qBV;cUX%;(UO-&CuD;kfzjBG}0O?^~TJluTQrj`!9oajm^|cwbaXM`4g1 z*lxyd9g9qBR^p$%I@EPW*3&g#m8r-$T9_LdX{)bbjC76{%3AKPn=iE;W;@_D+KUak zMRi`WP)K-8V5+6}+42K$GHsPHu=R#sXI821x{9lIXpi<=n6^oiPFe}G&K(A6XfpN3 zn$7>C&g|%AM4kJXq|Djm104rXRRM>n!XETf%>q5PCiNFjG}Yl(*)hR~vtsJplg33Y zSvMLj^$xRHvP(sYW1!Lou>%d6$O2Km30`Io@X(}~`#m^~?%SK0*%$keg3_R;>Ng2G z>dzl}@r)|Nqk=sE4Vqw|j{|Dzzy75SiT>^5DE_?cDsz8k1gowwt>|bmPE=i)eLdD@ zvF{b*5%TkVDT{5&XTR9Kw9e3!KeAbbg2}kJaW;cV%po0h$)l+WO_kMee{H!?#5BpP z13|9}HOUL>%=?5$7VGY1Zm-P#(i&>T)W1(iHz^%65n1e)j~Nw*1U^iw2mAPh<$uV? zFZxYva~oy}GhDQ{RB`ywa=yBkkt*p`Z1sU9XW3|$_oJv%vM=gkBB%DgQir!b*{GEI zzeUq2R`s^BL+0dNJOhyYAfG*7mhie9hlCJFm%XPyz(uy*3-7VO$B@%SfemCn;>2+w$pBKZ!(>i z8;(eBuoU2{Ffcp#Hod!jf9LZ`WNv3mDpPyti0959bQfPHpuSr-(^7j@S5RA;^BS^z z)ylMJcX7K2)ZNc~pmSu0EvGEj^_!0yI_9=m=}?D2dS2QGMf?wEeFOw%dDEEc4i5*; zyONeoDw9>zhvKDW zt9{3`+&Ia*%Wr_%jl|@0RKAr?`{@ta`C8>zS!5>6sCdTS4gRw3@~wk$o$Xk$b)Dx8 zXUWxiQvC-|)4EQYp8sUHjzh6wliEna0`&w8Yx20gpuU^!|5O8>m1$ThDTV;2nv1=4 z92S+6*xpDMDuuH(U(g@g+E0u&bC&t86FS(|R5^V5SaWo}EVCCeyG?HzKlP5vB-F}w`AF^Ej_zgH^bub5^YGinoan65w6@!q|#EG{xEyM>omL!(rZ zw%1ym^!!xcs7s$0ioP;5OI!I)SAor$rZc=lO%+#q-yfX<>Ux~-_6L%fzUPKX6@X+= zwIjbdm(l)^5)Z89W%Xafbfrbikxxl?)bH<#cbMc3t>BSuccbF-E;4m+vVtKRA!BHF z*t%Y>MEe~)Q5M_!d#`L!dwD6R%n6iZN%u;W4XEd?8U;P|zuJwt(zVgkdc&JkQ7NhF z?|rQfvl?2ifxvSe4g_W~4x2;nb5c?>jutXsF8oj1Z)qR&?IsbMYEF04+0M0vjh!uz z7+!RR+u1rzy!Q82_o?TbF;VZRxZFBy2A?v$wYPuEf46_NRLpw8+I+vdUF+Tx?ro)& zX6nE3q^&B)5VGvraFIAwtg~2K=Nl7KC0b@=RCH;={B>^KiD|1V_WZghwxpX#9c&an zZJHOJX;!>92)O7)=~i`!*c+9sNS`F-E+*T})JwMAuGPR;fwT8_$0o4)OV;K4HI+kC zOfGy$vjilIj!sSU*ai9DakU|P+q^H^biB9gAntQUQrZoxCNgJdXQLjl?vrpS;Ph6$ zhu;Z|xxV}_x=f}1@)a!ge6p>xvMo-TjxXxO z;9bR`?C$2qjwc4s_))<#Rpoh#_cutT>3X+dxIv4-46|4v$42dST)0CUc(w-uw?16l zIUHcNcYx_OnK%q(O|*b{&If#e@owp8VDbO;0-j*M(Ao{BCOz9cbu;$k!A_2~BBGZR z{9X4r_*IOE7vv^u(o!|fKp+U(N=elFOU9?3k`TE)b|s7BIV!QuG98lXx?q{SYwo<6 zsP_Q6m)VK+sqR0Q3+}iucV2d%+f_9~{Ul~E`5HGkG(=dI;q%+A9=HGL^L|Pb!sek0 z=mqcLd{vK@0?D$)?d72<-_F~UI&*I}AAiIl$%1zfjp@%7^p;rAQP(oPB#lGJ=o@i4 zUs;>LWn!C;OAtTUL(E3#62#4|W`KbO2#jqYKIey6u$%;3yLW#N@<%r~F7u#(D5|d{ z=yvRwnYWXa*z#8zHELqAW71wEZYm9$C8UcC{~jB2gvhwmfFJwc`*fMTWjWdE$Uq!D zK+u|cq4L1`rMDV>o#C-Izhj*ygNQd=d_m4P$gKM%AL39-+i>8nrwv$zA zpn7Kb9fE-}eB^TbemoA5lMi6j^QVkc8u)FGE~F7ZJ%qv$iLPC|(jw7h2RN^!mDmWbu9Ca-wt{Z_-bHbw$mQ>{UMbp62Iy)iLnP*YP_I3=xA#q4)_v87 z{-vCL0pFz)xF8$!EIunjQb?U~A9~ZO+%<;paDF-foP%`Sng}sGQtjRScg?|8J6L-jIyRkAP`L~Z5sEyVCnI`t;oj&gZ#6=90fT7F;Db)sL5xftid6-zntKt zMXHn>yO%F9S1BEFq!P0ed7|%o;g;8_-FRo}QjAY(Z;yx-2?0ctt*` zf_(kzY4GIPhVk}w@Xdz*{guBAp<}`w78Lh@=%>1CTdI&nm}j)o^>m5ziQAGzz^jeL z6->QGx%^5SYOjQih7fFOzxfH(Il>h9&zq!&U_BXQMVYe`Cb;v)_kggg3`=^G8zx16 zGF5noHYX=Ypcz7($KGGZetz+zy#O(mj8A$M2l&J-kaH(E^CvHFcgbyx4$ouw!`g|Z zc8VR<n?z_A}K7uoaw(N${>-D4<3T58Mf9J1$e~DQo}iLNxVPCms0VILI?i4)*d3EO#{u-K*TjWvh++_q+k zkvH_Zl_TwAGW@2k)8D4FR8~?s0V33ym5<3ddPIiqaJFn=!>rN5_@rp@^eLACJo0uy z-R|>2HZwy*Cgy_$TVnAJ3~Jx~W-~cTiXdp7n=Yuy1MBZLm4=#EUOpQ5RJq9yxIYSz z2295;vF`{le$^~}Z}x-OT8c5L%8l5d-u{s;pt`zRdP;9R0zVKpalOc@u#Me)~trzn_2YF|8eE$pBeGctM$ zJ$v-UX-087yJlL=K*S2CJ)*tmeV(ihn~!|p%g7yg62FCNu=zZbd3CZD+7Nm?_-82) z>CL^C$GY&D8S`_vquyleerLcDSmxTxir)ki#QQGT9ZI7Z8$s`r~lqh6e37niwjq?GCTC3 z>)3o6Yzp%mDe(IdD)^xrHqPOBeX)v!ei3+yek^Wz@%YAS%W#+aGVhUxv4eld zDn|b0NV*(m!X#%G53!FOWCYcU~2?uwGBWNl1(@y7_?{5jh(W_{dGu zpo8bLk(icV8tNuD-B7A-CXER{<{rWg*Olyzyg*bUqfCqPexd#*U6hfc!Ki7av?Wb# z@s)m{_f>jO)}}OFdyYcyul~PJCnq7M`A4ZdHY0r)GrU~%!kiNHXC{7)UyB%K?Nkjv zh2AAzPCRzB$+@lfjG{L2ZTzO4MEto#?1ifmI% z3Vua;YaIxO`*(f48jhNp1XIk?!pPa4pKS?=kj$7Xfik0Z#Z(WT!hGh^+#cLKZg`Qp=|=nGnoJB@>U;)5Ie)y%*lrQV4rY2$#MN5q|oc0!W#LZk2c1erjr+ z-y?@YZDn?=eAAUhTfJ+;9X8!eK&xcpY!4&2H%GTQPkN%V=6nJ15IMxvUs&h z!LF^3afsV$ZwYN*Ei8_&ow- zFV49v4nH5ww=0bD``L)6gI&gQ_R;w@?3c5@O!XBNeoYR=qqSb<@$&x@N&TUq?3ev~ zbD2%$*-!gTHeOaaq9SVs5)OGwd1e(0-MFtWH`J=RTzhb(uGJZ5?r6ReeYMPI9Nl(z z*K9`Ugb~-sayRE{TZg|t^4wG)S@h$wmJEmc8lNC#eV?8vbvxj-g28pUc~TblLG!Lp z9%qAtpH=jITb*61xjp|#;_aAQ%~b}SyLj z4X?5c{T-rz3Ed~y=;b2&aUzEF{uci6r01lPa9ZcngE_0)91L_CdhPQ%XWr$z(-A9b zO2>uZA!c4RtmdEJVNn-Y7JGDXq=}SgU|>XY`8u*5m4j5>oWrHBC~`M~Eso;8PW6G0 z{ON36Xw^1lV&io|>S}srjVq6d36T7#T30**3r1RAxwEVv)y^(l;K|R3u~AiT-Jp8= zqVe1>Ib3%8e2ETA3`B~0i}eg`wz;U6^va>!lrxS5^=Cig((^s_c(oktrb8nH5Dder zJF8fAme(`mA|bLdujpB*6|AklEHpc{(WHrdGS9IDDSv9+c&El~JpP%ww!y}(7b`lA zPjbpaX#x_Vxh37O7gGSAhkPWNI0sMK3Mcb9)w=oAXjT-BFPvjU?HF zTK|aHX9!?C$i$*zj zG>nt_pvSgPiS=l69Ml9E*^|gr+_mFH^z<@-VFzNdWx3G!0Rcg5EwtJtL5LSHS9KWb z+IN%UDWAmO7i@tVtal67iFr(NS9IE?7J+6jHMr8N(d4YC%P7SM%lvr}{DP%cLkPP| zHtHX0>)o3oV%}QiqJft-+BNEG+p+4a53V6Ir43rVMZ@sMz}vTejagsb(%R`-9IV61 zY`%|a@Ff%mWs65s=;X)r2@L2cltmNq5cD>FR;qUTVdEh4f|$oUd4E6kBg|1|1j|o3 zHRnCbz13BtDzkxBo|CyBm$`EO$h|Pb@3EQ8uAH(Cy~G4)@i0_~+3P@9!*-q~NrRG_ zV1KoIzibBZ2x&lyYNx*?QzcR#LSZ%%(!WY-F)Sy-qMU$|^Ff8-G!0@trewq0vwA{qfMct%a&4ag?wtO^7JjigR{GNXiyqH;zq8RRQyr!jo9)^Cc2e+Ty^ z^==To)ZOW0q76N?u$IsAsdkWlY?OHu6|V$*k2=$6n>gR}-l<=}{BpmffgCJWMn6z5 zL$k2(%j7@<@@}KMc%?}O=-bnPre*U;)mc1x+buNf(a{bM466DICSmTU6$QGFGV%yX z+Qp6xe^y@%)Ve?`m4`M&FXcxsK^EMY?+0g_T2Byy`;pRf8&W>KF|RQkkM+g#3b z8V-Mshl^{|1^oi#ymayKT5NrHwEZ{|p@fz@Y3hi*q=FenM)f+k)bsmabnKi8ZE{0g zX5uL#+J@!l2GKUQOXX!{^u*H*os-ms-J=9AP|7mGVkRQ62l1-v=jb#~35+T6QK+c_ zxLS7P^P?caOT?^E#R2xSp1{BB%1CX*D}fToC+)3WWUm`HyZq;IGWD&f!=B;B7Ho46pjYWKVMrs&u>+6o~s93Rh;c(MB0mkj)Mg->~Mr-j|2d5^{q zIOq56BfAoLe({tDaM=7uC3=U0)5Zq&)H;#%C}0xd(pFX$OYp0-nPJ%4*?9%|E231R zj3(l0rD@>Qix*@ck|xM8__q=$9*?YdMFaZUufwx}V_n4}-vPW#tpohn%J&c;DB|0t zM}K>^-Fc5{g5=9O-e2i~R-4i=y0o-(9CUpPI68n{7aWvBmLuAT$jB)G1e5#X75