From faae7ebe0538d062ecd51e33e9783cbc30fa8d06 Mon Sep 17 00:00:00 2001 From: Gonzalo Mellizo-Soto Date: Wed, 31 Jan 2024 11:15:02 +0100 Subject: [PATCH 1/4] Add proof capabilities to deployments --- giza/client.py | 111 ++++++++++++++++++++++++++++- giza/commands/deployments.py | 133 +++++++++++++++++++++++++++++++++++ giza/schemas/proofs.py | 4 ++ 3 files changed, 247 insertions(+), 1 deletion(-) diff --git a/giza/client.py b/giza/client.py index 5cb8a2e..f137ebc 100644 --- a/giza/client.py +++ b/giza/client.py @@ -17,7 +17,7 @@ from giza.schemas.jobs import Job, JobCreate from giza.schemas.message import Msg from giza.schemas.models import Model, ModelCreate, ModelList, ModelUpdate -from giza.schemas.proofs import Proof +from giza.schemas.proofs import Proof, ProofList from giza.schemas.token import TokenResponse from giza.schemas.versions import Version, VersionCreate, VersionList, VersionUpdate from giza.schemas.workspaces import Workspace @@ -512,6 +512,115 @@ def list(self, model_id: int, version_id: int) -> DeploymentsList: __root__=[Deployment(**deployment) for deployment in response.json()] ) + @auth + def list_proofs( + self, model_id: int, version_id: int, deployment_id: int + ) -> ProofList: + """ + List proofs. + + Returns: + A list of proofs created by the user + """ + headers = copy.deepcopy(self.default_headers) + headers.update(self._get_auth_header()) + + response = self.session.get( + os.path.join( + self.url, + self.MODELS_ENDPOINT, + str(model_id), + self.VERSIONS_ENDPOINT, + str(version_id), + self.DEPLOYMENTS_ENDPOINT, + str(deployment_id), + "proofs", + ), + headers=headers, + ) + self._echo_debug(str(response)) + + response.raise_for_status() + + return ProofList(__root__=[Proof(**proof) for proof in response.json()]) + + @auth + def get_proof( + self, model_id: int, version_id: int, deployment_id: int, proof_id: int + ) -> Proof: + """ + Return information about a specific proof. + `proof_if` is the identifier of the proof that can be a integer or the request id. + + Returns: + A proof created by the user + """ + headers = copy.deepcopy(self.default_headers) + headers.update(self._get_auth_header()) + + response = self.session.get( + os.path.join( + self.url, + self.MODELS_ENDPOINT, + str(model_id), + self.VERSIONS_ENDPOINT, + str(version_id), + self.DEPLOYMENTS_ENDPOINT, + str(deployment_id), + "proofs", + str(proof_id), + ), + headers=headers, + ) + self._echo_debug(str(response)) + + response.raise_for_status() + + return Proof(**response.json()) + + @auth + def download_proof( + self, model_id: int, version_id: int, deployment_id: int, proof_id: int + ) -> bytes: + """ + Download a proof. + + Args: + proof_id: Proof identifier + + Returns: + The proof binary file + """ + headers = copy.deepcopy(self.default_headers) + headers.update(self._get_auth_header()) + + response = self.session.get( + os.path.join( + self.url, + self.MODELS_ENDPOINT, + str(model_id), + self.VERSIONS_ENDPOINT, + str(version_id), + self.DEPLOYMENTS_ENDPOINT, + str(deployment_id), + "proofs", + f"{proof_id}:download", + ), + headers=headers, + ) + + self._echo_debug(str(response)) + response.raise_for_status() + + url = response.json()["download_url"] + + download_response = self.session.get(url) + + self._echo_debug(str(download_response)) + download_response.raise_for_status() + + return download_response.content + @auth def get(self, model_id: int, version_id: int, deployment_id: int) -> Deployment: """ diff --git a/giza/commands/deployments.py b/giza/commands/deployments.py index 759cda6..03e1be7 100644 --- a/giza/commands/deployments.py +++ b/giza/commands/deployments.py @@ -11,6 +11,7 @@ from giza.frameworks import cairo from giza.options import DEBUG_OPTION from giza.schemas.deployments import DeploymentsList +from giza.schemas.proofs import Proof, ProofList from giza.utils import echo, get_response_info from giza.utils.enums import Framework, ServiceSize @@ -142,3 +143,135 @@ def get( raise e sys.exit(1) print_json(deployment.json()) + + +@app.command( + name="list-proofs", + short_help="🔒 List proofs from a deployment.", + help="""🔒 List proofs from a deployment. + This command retrieves and displays the proofs generated by a specific deployment stored in the server. + The proofs' information is printed in a json format for easy readability and further processing. + If the deployment is not available, an error message is printed. + """, +) +def list_proofs( + model_id: int = typer.Option(None, help="The ID of the model"), + version_id: int = typer.Option(None, help="The ID of the version"), + deployment_id: int = typer.Option(None, help="The ID of the deployment"), + debug: Optional[bool] = DEBUG_OPTION, +) -> None: + echo(f"Getting proofs from deployment {deployment_id} ✅ ") + try: + client = DeploymentsClient(API_HOST) + proofs: ProofList = client.list_proofs(model_id, version_id, deployment_id) + except ValidationError as e: + echo.error("Could not retrieve proofs from deployment") + echo.error("Review the provided information") + if debug: + raise e + echo.error(str(e)) + sys.exit(1) + except HTTPError as e: + info = get_response_info(e.response) + echo.error(f"⛔️Could not get deployment {deployment_id}") + echo.error(f"⛔️Detail -> {info.get('detail')}⛔️") + echo.error(f"⛔️Status code -> {info.get('status_code')}⛔️") + echo.error(f"⛔️Error message -> {info.get('content')}⛔️") + echo.error( + f"⛔️Request ID: Give this to an administrator to trace the error -> {info.get('request_id')}⛔️" + ) if info.get("request_id") else None + if debug: + raise e + sys.exit(1) + print_json(proofs.json()) + + +@app.command( + name="get-proof", + short_help="🔒 Retrieves information about a proof from a deployment.", + help="""🔒 Retrieves information about a proof from a deployment. + This command retrieves and displays the proof generated by a specific deployment stored in the server. + The proof information is printed in a json format for easy readability and further processing. + If the deployment is not available, an error message is printed. + """, +) +def get_proof( + model_id: int = typer.Option(None, help="The ID of the model"), + version_id: int = typer.Option(None, help="The ID of the version"), + deployment_id: int = typer.Option(None, help="The ID of the deployment"), + proof_id: str = typer.Option(None, help="The ID or request id of the proof"), + debug: Optional[bool] = DEBUG_OPTION, +) -> None: + echo(f"Getting proof from deployment {deployment_id} ✅ ") + try: + client = DeploymentsClient(API_HOST) + proof: Proof = client.get_proof(model_id, version_id, deployment_id, proof_id) + except ValidationError as e: + echo.error("Could not retrieve proof from deployment") + echo.error("Review the provided information") + if debug: + raise e + echo.error(str(e)) + sys.exit(1) + except HTTPError as e: + info = get_response_info(e.response) + echo.error(f"⛔️Could not get deployment {deployment_id}") + echo.error(f"⛔️Detail -> {info.get('detail')}⛔️") + echo.error(f"⛔️Status code -> {info.get('status_code')}⛔️") + echo.error(f"⛔️Error message -> {info.get('content')}⛔️") + echo.error( + f"⛔️Request ID: Give this to an administrator to trace the error -> {info.get('request_id')}⛔️" + ) if info.get("request_id") else None + if debug: + raise e + sys.exit(1) + print_json(proof.json()) + + +@app.command( + name="download-proof", + short_help="🔒 Downloads a proof from a deployment to the specified path.", + help="""🔒 Downloads a proof from a deployment to the specified path. + This command retrieves the proof created in Giza from a specific deployment. + The proof information is stored in the specified path, defaulting to the current path. + If the deployment is not available, an error message is printed. + """, +) +def download_proof( + model_id: int = typer.Option(None, help="The ID of the model"), + version_id: int = typer.Option(None, help="The ID of the version"), + deployment_id: int = typer.Option(None, help="The ID of the deployment"), + proof_id: str = typer.Option(None, help="The ID or request id of the proof"), + output_path: str = typer.Option( + "zk.proof", help="The path where the proof will be stored" + ), + debug: Optional[bool] = DEBUG_OPTION, +) -> None: + echo(f"Getting proof from deployment {deployment_id} ✅ ") + try: + client = DeploymentsClient(API_HOST) + proof: bytes = client.download_proof( + model_id, version_id, deployment_id, proof_id + ) + with open(output_path, "wb") as f: + f.write(proof) + except ValidationError as e: + echo.error("Could not retrieve proof from deployment") + echo.error("Review the provided information") + if debug: + raise e + echo.error(str(e)) + sys.exit(1) + except HTTPError as e: + info = get_response_info(e.response) + echo.error(f"⛔️Could not get deployment {deployment_id}") + echo.error(f"⛔️Detail -> {info.get('detail')}⛔️") + echo.error(f"⛔️Status code -> {info.get('status_code')}⛔️") + echo.error(f"⛔️Error message -> {info.get('content')}⛔️") + echo.error( + f"⛔️Request ID: Give this to an administrator to trace the error -> {info.get('request_id')}⛔️" + ) if info.get("request_id") else None + if debug: + raise e + sys.exit(1) + echo(f"Proof downloaded to {output_path} ✅ ") diff --git a/giza/schemas/proofs.py b/giza/schemas/proofs.py index 8c117a5..555cf26 100644 --- a/giza/schemas/proofs.py +++ b/giza/schemas/proofs.py @@ -11,3 +11,7 @@ class Proof(BaseModel): cairo_execution_time: Optional[float] = None metrics: Optional[dict] = None created_date: datetime.datetime + + +class ProofList(BaseModel): + __root__: list[Proof] From b7b057a20d1c7536d56fe58bc5e264b200e44ad1 Mon Sep 17 00:00:00 2001 From: Gonzalo Mellizo-Soto Date: Wed, 31 Jan 2024 11:38:49 +0100 Subject: [PATCH 2/4] Add shorthand commands --- giza/commands/deployments.py | 66 +++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/giza/commands/deployments.py b/giza/commands/deployments.py index 03e1be7..063f08c 100644 --- a/giza/commands/deployments.py +++ b/giza/commands/deployments.py @@ -21,10 +21,13 @@ def deploy( data: str = typer.Argument(None), model_id: int = typer.Option( - None, help="The ID of the model where a deployment will be created" + None, + "--model-id", + "-m", + help="The ID of the model where a deployment will be created", ), version_id: int = typer.Option( - None, help="The ID of the version that will be deployed" + None, "--version-id", "-v", help="The ID of the version that will be deployed" ), size: ServiceSize = typer.Option(ServiceSize.S, "--size", "-s"), framework: Framework = typer.Option(Framework.CAIRO, "--framework", "-f"), @@ -74,8 +77,10 @@ def deploy( """, ) def list( - model_id: int = typer.Option(None, help="The ID of the model"), - version_id: int = typer.Option(None, help="The ID of the version"), + model_id: int = typer.Option(None, "--model-id", "-m", help="The ID of the model"), + version_id: int = typer.Option( + None, "--version-id", "-v", help="The ID of the version" + ), debug: Optional[bool] = DEBUG_OPTION, ) -> None: echo("Listing deployments ✅ ") @@ -114,9 +119,13 @@ def list( """, ) def get( - model_id: int = typer.Option(None, help="The ID of the model"), - version_id: int = typer.Option(None, help="The ID of the version"), - deployment_id: int = typer.Option(None, help="The ID of the version"), + model_id: int = typer.Option(None, "--model-id", "-m", help="The ID of the model"), + version_id: int = typer.Option( + None, "--version-id", "-v", help="The ID of the version" + ), + deployment_id: int = typer.Option( + None, "--deployment-id", "-d", help="The ID of the version" + ), debug: Optional[bool] = DEBUG_OPTION, ) -> None: echo(f"Getting deployment {deployment_id} ✅ ") @@ -155,9 +164,13 @@ def get( """, ) def list_proofs( - model_id: int = typer.Option(None, help="The ID of the model"), - version_id: int = typer.Option(None, help="The ID of the version"), - deployment_id: int = typer.Option(None, help="The ID of the deployment"), + model_id: int = typer.Option(None, "--model-id", "-m", help="The ID of the model"), + version_id: int = typer.Option( + None, "--version-id", "-v", help="The ID of the version" + ), + deployment_id: int = typer.Option( + None, "--deployment-id", "-d", help="The ID of the version" + ), debug: Optional[bool] = DEBUG_OPTION, ) -> None: echo(f"Getting proofs from deployment {deployment_id} ✅ ") @@ -196,10 +209,16 @@ def list_proofs( """, ) def get_proof( - model_id: int = typer.Option(None, help="The ID of the model"), - version_id: int = typer.Option(None, help="The ID of the version"), - deployment_id: int = typer.Option(None, help="The ID of the deployment"), - proof_id: str = typer.Option(None, help="The ID or request id of the proof"), + model_id: int = typer.Option(None, "--model-id", "-m", help="The ID of the model"), + version_id: int = typer.Option( + None, "--version-id", "-v", help="The ID of the version" + ), + deployment_id: int = typer.Option( + None, "--deployment-id", "-d", help="The ID of the version" + ), + proof_id: str = typer.Option( + None, "--proof-id", "-p", help="The ID or request id of the proof" + ), debug: Optional[bool] = DEBUG_OPTION, ) -> None: echo(f"Getting proof from deployment {deployment_id} ✅ ") @@ -238,12 +257,21 @@ def get_proof( """, ) def download_proof( - model_id: int = typer.Option(None, help="The ID of the model"), - version_id: int = typer.Option(None, help="The ID of the version"), - deployment_id: int = typer.Option(None, help="The ID of the deployment"), - proof_id: str = typer.Option(None, help="The ID or request id of the proof"), + model_id: int = typer.Option(None, "--model-id", "-m", help="The ID of the model"), + version_id: int = typer.Option( + None, "--version-id", "-v", help="The ID of the version" + ), + deployment_id: int = typer.Option( + None, "--deployment-id", "-d", help="The ID of the version" + ), + proof_id: str = typer.Option( + None, "--proof-id", "-p", help="The ID or request id of the proof" + ), output_path: str = typer.Option( - "zk.proof", help="The path where the proof will be stored" + "zk.proof", + "--output-path", + "-o", + help="The path where the proof will be stored", ), debug: Optional[bool] = DEBUG_OPTION, ) -> None: From 410c7cb49b9f8e91b633a6e6a8fd1ac31c48e4e5 Mon Sep 17 00:00:00 2001 From: Gonzalo Mellizo-Soto Date: Wed, 31 Jan 2024 11:44:24 +0100 Subject: [PATCH 3/4] Bumping version from 0.8.2 to 0.9.0 --- docs/README.md | 2 +- docs/examples/full_transpilation.md | 2 +- examples/mnist/mnist_pytorch.ipynb | 2 +- examples/mnist/requirements.txt | 2 +- giza/__init__.py | 2 +- pyproject.toml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 41f444f..1b4069c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,5 @@ --- -description: Giza CLI 0.7.0 +description: Giza CLI 0.9.0 --- # Giza CLI diff --git a/docs/examples/full_transpilation.md b/docs/examples/full_transpilation.md index 4e321b4..bcf03f3 100644 --- a/docs/examples/full_transpilation.md +++ b/docs/examples/full_transpilation.md @@ -21,7 +21,7 @@ pip install -r requirements.txt Or: ```bash -pip install giza-cli==0.7.0 onnx==1.14.1 torch==2.1.0 torchvision==0.16.0 +pip install giza-cli==0.9.0 onnx==1.14.1 torch==2.1.0 torchvision==0.16.0 ``` We will use the libraries for the following purposes: diff --git a/examples/mnist/mnist_pytorch.ipynb b/examples/mnist/mnist_pytorch.ipynb index b21f8a2..81f944f 100644 --- a/examples/mnist/mnist_pytorch.ipynb +++ b/examples/mnist/mnist_pytorch.ipynb @@ -41,7 +41,7 @@ "Or:\n", "\n", "```bash\n", - "pip install giza-cli==0.7.0 onnx==1.14.1 torch==2.1.0 torchvision==0.16.0\n", + "pip install giza-cli==0.9.0 onnx==1.14.1 torch==2.1.0 torchvision==0.16.0\n", "```\n", "\n", "We will use the libraries for the following purposes:\n", diff --git a/examples/mnist/requirements.txt b/examples/mnist/requirements.txt index be98075..452c3a9 100644 --- a/examples/mnist/requirements.txt +++ b/examples/mnist/requirements.txt @@ -1,4 +1,4 @@ -giza-cli==0.7.0 +giza-cli==0.9.0 onnx==1.14.1 tf2onnx==1.15.1 torch==2.1.0 diff --git a/giza/__init__.py b/giza/__init__.py index 4e5d683..4f9e9c3 100644 --- a/giza/__init__.py +++ b/giza/__init__.py @@ -1,5 +1,5 @@ import os -__version__ = "0.8.0" +__version__ = "0.9.0" # Until DNS is fixed API_HOST = os.environ.get("GIZA_API_HOST", "https://api.gizatech.xyz") diff --git a/pyproject.toml b/pyproject.toml index 0849bfc..9b036dd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "giza-cli" -version = "0.8.2" +version = "0.9.0" description = "CLI for interacting with Giza" authors = ["Gonzalo Mellizo-Soto "] readme = "README.md" From 6e2770f833d7b889df8ab2bf098a565347ddac05 Mon Sep 17 00:00:00 2001 From: Gonzalo Mellizo-Soto Date: Wed, 31 Jan 2024 11:53:04 +0100 Subject: [PATCH 4/4] Add bumpversion tool for poetry --- pyproject.toml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 9b036dd..c79d518 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,3 +60,19 @@ ignore = [ "B008", # do not perform function calls in argument defaults "C901", # too complex ] + +[tool.poetry_bumpversion.file."giza/__init__.py"] + +[tool.poetry_bumpversion.file."docs/README.md"] + +[tool.poetry_bumpversion.file."examples/mnist/requirements.txt"] +search = 'giza-cli=={current_version}' +replace = 'giza-cli=={new_version}' + +[tool.poetry_bumpversion.file."docs/examples/full_transpilation.md"] +search = 'giza-cli=={current_version}' +replace = 'giza-cli=={new_version}' + +[tool.poetry_bumpversion.file."examples/mnist/mnist_pytorch.ipynb"] +search = 'giza-cli=={current_version}' +replace = 'giza-cli=={new_version}'